Repository: diegomura/react-pdf
Branch: master
Commit: 16cf5bd7006e
Files: 831
Total size: 3.0 MB
Directory structure:
gitextract_95ou86zy/
├── .changeset/
│ ├── README.md
│ ├── config.json
│ ├── dirty-rocks-jam.md
│ ├── eighty-taxis-cross.md
│ ├── five-rockets-battle.md
│ └── pretty-carrots-obey.md
├── .gitattributes
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── no-response.yml
│ └── workflows/
│ ├── main.yml
│ └── release.yml
├── .gitignore
├── .husky/
│ └── pre-commit
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── babel.config.js
├── e2e/
│ ├── node-cjs/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ └── package.json
│ └── node-esm/
│ ├── CHANGELOG.md
│ ├── index.js
│ └── package.json
├── eslint.config.ts
├── lerna.json
├── package.json
├── packages/
│ ├── examples/
│ │ ├── dev.sh
│ │ ├── next-14/
│ │ │ ├── .gitignore
│ │ │ ├── CHANGELOG.md
│ │ │ ├── README.md
│ │ │ ├── app/
│ │ │ │ ├── globals.css
│ │ │ │ ├── layout.js
│ │ │ │ └── page.js
│ │ │ ├── jsconfig.json
│ │ │ ├── next.config.mjs
│ │ │ ├── package.json
│ │ │ ├── postcss.config.mjs
│ │ │ └── tailwind.config.js
│ │ ├── next-15/
│ │ │ ├── .gitignore
│ │ │ ├── CHANGELOG.md
│ │ │ ├── README.md
│ │ │ ├── app/
│ │ │ │ ├── globals.css
│ │ │ │ ├── layout.js
│ │ │ │ └── page.js
│ │ │ ├── jsconfig.json
│ │ │ ├── next.config.mjs
│ │ │ ├── package.json
│ │ │ ├── postcss.config.mjs
│ │ │ └── tailwind.config.js
│ │ ├── package.json
│ │ └── vite/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── declarations.d.ts
│ │ ├── package.json
│ │ ├── postcss.config.js
│ │ ├── src/
│ │ │ ├── examples/
│ │ │ │ ├── duplicated-images/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ellipsis/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── emoji/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── font-family-fallback/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── font-weight/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── forms/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── fractals/
│ │ │ │ │ ├── Fractal.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── go-to/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── image-stress-test/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── jpg-orientation/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── knobs/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── link/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── media-queries/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── min-presence-ahead/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── multiline-text/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── object-fit/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── page-wrap/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── resume/
│ │ │ │ │ ├── Education.tsx
│ │ │ │ │ ├── Experience.tsx
│ │ │ │ │ ├── Header.tsx
│ │ │ │ │ ├── List.tsx
│ │ │ │ │ ├── Skills.tsx
│ │ │ │ │ ├── Title.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── soft-hyphens/
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── svg/
│ │ │ │ │ ├── Car.tsx
│ │ │ │ │ ├── Heart.tsx
│ │ │ │ │ ├── Pattern.tsx
│ │ │ │ │ ├── Star.tsx
│ │ │ │ │ ├── Svg1.tsx
│ │ │ │ │ ├── Svg2.tsx
│ │ │ │ │ ├── Svg4.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── svg.tsx
│ │ │ │ ├── svg-transform/
│ │ │ │ │ └── index.tsx
│ │ │ │ └── transform-origin/
│ │ │ │ └── index.tsx
│ │ │ ├── index.css
│ │ │ ├── index.html
│ │ │ └── index.tsx
│ │ ├── tailwind.config.js
│ │ └── vite.config.js
│ ├── fns/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── adjust.ts
│ │ │ ├── asyncCompose.ts
│ │ │ ├── capitalize.ts
│ │ │ ├── castArray.ts
│ │ │ ├── compose.ts
│ │ │ ├── dropLast.ts
│ │ │ ├── evolve.ts
│ │ │ ├── get.ts
│ │ │ ├── index.ts
│ │ │ ├── isNil.ts
│ │ │ ├── last.ts
│ │ │ ├── mapValues.ts
│ │ │ ├── matchPercent.ts
│ │ │ ├── omit.ts
│ │ │ ├── parseFloat.ts
│ │ │ ├── pick.ts
│ │ │ ├── repeat.ts
│ │ │ ├── reverse.ts
│ │ │ ├── upperFirst.ts
│ │ │ └── without.ts
│ │ ├── tests/
│ │ │ ├── adjust.test.ts
│ │ │ ├── asyncCompose.test.ts
│ │ │ ├── capitalize.test.ts
│ │ │ ├── castArray.test.ts
│ │ │ ├── compose.test.ts
│ │ │ ├── dropLast.test.ts
│ │ │ ├── evolve.test.ts
│ │ │ ├── get.test.ts
│ │ │ ├── isNil.test.ts
│ │ │ ├── last.test.ts
│ │ │ ├── mapValues.test.ts
│ │ │ ├── matchPercent.test.ts
│ │ │ ├── omit.test.ts
│ │ │ ├── parseFloat.test.ts
│ │ │ ├── pick.test.ts
│ │ │ ├── repeat.test.ts
│ │ │ ├── reverse.test.ts
│ │ │ ├── upperFirst.test.ts
│ │ │ └── without.test.ts
│ │ └── tsconfig.json
│ ├── font/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── declarations.d.ts
│ │ ├── globals.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── font-family.ts
│ │ │ ├── font-source.ts
│ │ │ ├── index.ts
│ │ │ ├── standard-font.ts
│ │ │ └── types.ts
│ │ ├── tests/
│ │ │ ├── fallback-weights.test.ts
│ │ │ ├── font-store.test.ts
│ │ │ └── standard-fonts.test.ts
│ │ └── tsconfig.json
│ ├── image/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── declarations.d.ts
│ │ ├── globals.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── cache.ts
│ │ │ ├── index.ts
│ │ │ ├── jpeg.ts
│ │ │ ├── png.ts
│ │ │ ├── resolve.ts
│ │ │ └── types.ts
│ │ ├── tests/
│ │ │ ├── cache.test.ts
│ │ │ ├── resolve.test.ts
│ │ │ └── types.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.config.js
│ │ └── vitest.setup.js
│ ├── layout/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── globals.d.ts
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── setupTests.js
│ │ ├── src/
│ │ │ ├── canvas/
│ │ │ │ └── measureCanvas.ts
│ │ │ ├── image/
│ │ │ │ ├── fetchImage.ts
│ │ │ │ ├── getRatio.ts
│ │ │ │ ├── getSource.ts
│ │ │ │ ├── measureImage.ts
│ │ │ │ └── resolveSource.ts
│ │ │ ├── index.ts
│ │ │ ├── node/
│ │ │ │ ├── createInstances.ts
│ │ │ │ ├── getBorderWidth.ts
│ │ │ │ ├── getDimension.ts
│ │ │ │ ├── getMargin.ts
│ │ │ │ ├── getOrigin.ts
│ │ │ │ ├── getPadding.ts
│ │ │ │ ├── getPosition.ts
│ │ │ │ ├── getWrap.ts
│ │ │ │ ├── isFixed.ts
│ │ │ │ ├── removePaddings.ts
│ │ │ │ ├── setAlign.ts
│ │ │ │ ├── setAlignContent.ts
│ │ │ │ ├── setAlignItems.ts
│ │ │ │ ├── setAlignSelf.ts
│ │ │ │ ├── setAspectRatio.ts
│ │ │ │ ├── setBorderWidth.ts
│ │ │ │ ├── setDimension.ts
│ │ │ │ ├── setDisplay.ts
│ │ │ │ ├── setFlexBasis.ts
│ │ │ │ ├── setFlexDirection.ts
│ │ │ │ ├── setFlexGrow.ts
│ │ │ │ ├── setFlexShrink.ts
│ │ │ │ ├── setFlexWrap.ts
│ │ │ │ ├── setGap.ts
│ │ │ │ ├── setJustifyContent.ts
│ │ │ │ ├── setMargin.ts
│ │ │ │ ├── setOverflow.ts
│ │ │ │ ├── setPadding.ts
│ │ │ │ ├── setPosition.ts
│ │ │ │ ├── setPositionType.ts
│ │ │ │ ├── setYogaValue.ts
│ │ │ │ ├── shouldBreak.ts
│ │ │ │ └── splitNode.ts
│ │ │ ├── page/
│ │ │ │ ├── getContentArea.ts
│ │ │ │ ├── getOrientation.ts
│ │ │ │ ├── getSize.ts
│ │ │ │ ├── getWrapArea.ts
│ │ │ │ ├── isHeightAuto.ts
│ │ │ │ ├── isLandscape.ts
│ │ │ │ └── isPortrait.ts
│ │ │ ├── steps/
│ │ │ │ ├── resolveAssets.ts
│ │ │ │ ├── resolveBookmarks.ts
│ │ │ │ ├── resolveDimensions.ts
│ │ │ │ ├── resolveInheritance.ts
│ │ │ │ ├── resolveLinkSubstitution.ts
│ │ │ │ ├── resolveOrigins.ts
│ │ │ │ ├── resolvePagePaddings.ts
│ │ │ │ ├── resolvePageSizes.ts
│ │ │ │ ├── resolvePagination.ts
│ │ │ │ ├── resolvePercentHeight.ts
│ │ │ │ ├── resolvePercentRadius.ts
│ │ │ │ ├── resolveStyles.ts
│ │ │ │ ├── resolveSvg.ts
│ │ │ │ ├── resolveTextLayout.ts
│ │ │ │ ├── resolveYoga.ts
│ │ │ │ └── resolveZIndex.ts
│ │ │ ├── svg/
│ │ │ │ ├── getContainer.ts
│ │ │ │ ├── getDefs.ts
│ │ │ │ ├── inheritProps.ts
│ │ │ │ ├── layoutText.ts
│ │ │ │ ├── measureSvg.ts
│ │ │ │ ├── parseAspectRatio.ts
│ │ │ │ ├── parseViewbox.ts
│ │ │ │ └── replaceDefs.ts
│ │ │ ├── text/
│ │ │ │ ├── emoji.ts
│ │ │ │ ├── getAttributedString.ts
│ │ │ │ ├── heightAtLineIndex.ts
│ │ │ │ ├── ignoreChars.ts
│ │ │ │ ├── layoutText.ts
│ │ │ │ ├── lineIndexAtHeight.ts
│ │ │ │ ├── linesHeight.ts
│ │ │ │ ├── linesWidth.ts
│ │ │ │ ├── measureText.ts
│ │ │ │ ├── splitText.ts
│ │ │ │ └── transformText.ts
│ │ │ ├── types/
│ │ │ │ ├── base.ts
│ │ │ │ ├── canvas.ts
│ │ │ │ ├── checkbox.ts
│ │ │ │ ├── circle.ts
│ │ │ │ ├── clip-path.ts
│ │ │ │ ├── defs.ts
│ │ │ │ ├── document.ts
│ │ │ │ ├── ellipse.ts
│ │ │ │ ├── field-set.ts
│ │ │ │ ├── g.ts
│ │ │ │ ├── image.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── line.ts
│ │ │ │ ├── linear-gradient.ts
│ │ │ │ ├── link.ts
│ │ │ │ ├── node.ts
│ │ │ │ ├── note.ts
│ │ │ │ ├── page.ts
│ │ │ │ ├── path.ts
│ │ │ │ ├── polygon.ts
│ │ │ │ ├── polyline.ts
│ │ │ │ ├── radial-gradient.ts
│ │ │ │ ├── rect.ts
│ │ │ │ ├── select.ts
│ │ │ │ ├── stop.ts
│ │ │ │ ├── svg.ts
│ │ │ │ ├── text-input.ts
│ │ │ │ ├── text-instance.ts
│ │ │ │ ├── text.ts
│ │ │ │ ├── tspan.ts
│ │ │ │ └── view.ts
│ │ │ └── yoga/
│ │ │ └── index.ts
│ │ ├── tests/
│ │ │ ├── image/
│ │ │ │ ├── getSource.test.ts
│ │ │ │ └── resolveSource.test.ts
│ │ │ ├── node/
│ │ │ │ ├── getBorderWidth.test.ts
│ │ │ │ ├── getDimension.test.ts
│ │ │ │ ├── getMargin.test.ts
│ │ │ │ ├── getOrigin.test.ts
│ │ │ │ ├── getPadding.test.ts
│ │ │ │ ├── getPosition.test.ts
│ │ │ │ ├── removePaddings.test.ts
│ │ │ │ ├── setAlignContent.test.ts
│ │ │ │ ├── setAlignItems.test.ts
│ │ │ │ ├── setAlignSelf.test.ts
│ │ │ │ ├── setAspectRatio.test.ts
│ │ │ │ ├── setBorderWidth.test.ts
│ │ │ │ ├── setDimension.test.ts
│ │ │ │ ├── setDisplay.test.ts
│ │ │ │ ├── setFlexBasis.test.ts
│ │ │ │ ├── setFlexDirection.test.ts
│ │ │ │ ├── setFlexGrow.test.ts
│ │ │ │ ├── setFlexShrink.test.ts
│ │ │ │ ├── setFlexWrap.test.ts
│ │ │ │ ├── setGap.test.ts
│ │ │ │ ├── setJustifyContent.test.ts
│ │ │ │ ├── setMargin.test.ts
│ │ │ │ ├── setOverflow.test.ts
│ │ │ │ ├── setPadding.test.ts
│ │ │ │ ├── setPosition.test.ts
│ │ │ │ ├── setPositionType.test.ts
│ │ │ │ └── shouldBreak.test.ts
│ │ │ ├── page/
│ │ │ │ ├── getOrientation.test.ts
│ │ │ │ ├── getSize.test.ts
│ │ │ │ ├── isHeightAuto.test.ts
│ │ │ │ ├── isLandscape.test.ts
│ │ │ │ └── isPortrait.test.ts
│ │ │ ├── steps/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ ├── resolveLinkSubstitution.test.ts.snap
│ │ │ │ │ ├── resolveOrigins.test.ts.snap
│ │ │ │ │ ├── resolvePagePaddings.test.ts.snap
│ │ │ │ │ ├── resolvePercentHeight.test.ts.snap
│ │ │ │ │ └── resolveStyles.test.ts.snap
│ │ │ │ ├── resolveBookmarks.test.ts
│ │ │ │ ├── resolveInhritance.test.ts
│ │ │ │ ├── resolveLinkSubstitution.test.ts
│ │ │ │ ├── resolveOrigins.test.ts
│ │ │ │ ├── resolvePagePaddings.test.ts
│ │ │ │ ├── resolvePageSizes.test.ts
│ │ │ │ ├── resolvePagination.test.ts
│ │ │ │ ├── resolvePercentHeight.test.ts
│ │ │ │ ├── resolveStyles.test.ts
│ │ │ │ ├── resolveSvg.test.ts
│ │ │ │ └── resolveTextLayout.test.ts
│ │ │ └── text/
│ │ │ ├── heightAtLineIndex.test.ts
│ │ │ ├── layoutText.test.ts
│ │ │ ├── lineIndexAtHeight.test.ts
│ │ │ └── measureText.test.ts
│ │ └── tsconfig.json
│ ├── pdfkit/
│ │ ├── .gitignore
│ │ ├── .prettierrc
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── abstract_reference.js
│ │ │ ├── data.js
│ │ │ ├── document.js
│ │ │ ├── font/
│ │ │ │ ├── afm.js
│ │ │ │ ├── data/
│ │ │ │ │ ├── Courier-Bold.afm
│ │ │ │ │ ├── Courier-BoldOblique.afm
│ │ │ │ │ ├── Courier-Oblique.afm
│ │ │ │ │ ├── Courier.afm
│ │ │ │ │ ├── Helvetica-Bold.afm
│ │ │ │ │ ├── Helvetica-BoldOblique.afm
│ │ │ │ │ ├── Helvetica-Oblique.afm
│ │ │ │ │ ├── Helvetica.afm
│ │ │ │ │ ├── Times-Bold.afm
│ │ │ │ │ ├── Times-BoldItalic.afm
│ │ │ │ │ ├── Times-Italic.afm
│ │ │ │ │ ├── Times-Roman.afm
│ │ │ │ │ ├── compressData.js
│ │ │ │ │ └── expandData.js
│ │ │ │ ├── embedded.js
│ │ │ │ └── standard.js
│ │ │ ├── font.js
│ │ │ ├── font_factory.js
│ │ │ ├── gradient.js
│ │ │ ├── image/
│ │ │ │ ├── jpeg.js
│ │ │ │ └── png.js
│ │ │ ├── image.js
│ │ │ ├── index.js
│ │ │ ├── line_wrapper.js
│ │ │ ├── metadata.js
│ │ │ ├── mixins/
│ │ │ │ ├── acroform.js
│ │ │ │ ├── annotations.js
│ │ │ │ ├── attachments.js
│ │ │ │ ├── color.js
│ │ │ │ ├── fonts.js
│ │ │ │ ├── images.js
│ │ │ │ ├── markings.js
│ │ │ │ ├── metadata.js
│ │ │ │ ├── outline.js
│ │ │ │ ├── pdfa.js
│ │ │ │ ├── pdfua.js
│ │ │ │ ├── subsets.js
│ │ │ │ ├── text.js
│ │ │ │ └── vector.js
│ │ │ ├── name_tree.js
│ │ │ ├── number_tree.js
│ │ │ ├── object.js
│ │ │ ├── outline.js
│ │ │ ├── page.js
│ │ │ ├── path.js
│ │ │ ├── pattern.js
│ │ │ ├── reference.js
│ │ │ ├── security.js
│ │ │ ├── spotcolor.js
│ │ │ ├── structure_content.js
│ │ │ ├── structure_element.js
│ │ │ ├── tree.js
│ │ │ ├── utils/
│ │ │ │ └── range.js
│ │ │ ├── utils.js
│ │ │ └── virtual-fs.js
│ │ └── tests/
│ │ └── font/
│ │ └── standard.test.ts
│ ├── png-js/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ └── src/
│ │ └── index.js
│ ├── primitives/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tests/
│ │ │ └── index.test.ts
│ │ └── tsconfig.json
│ ├── reconciler/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── build/
│ │ │ └── trim-reconciler.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ ├── propsEqual.ts
│ │ │ ├── reconciler-23.ts
│ │ │ ├── reconciler-31.ts
│ │ │ ├── reconciler-33.ts
│ │ │ └── types.ts
│ │ ├── tests/
│ │ │ └── propsEqual.test.ts
│ │ └── tsconfig.json
│ ├── render/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── globals.d.ts
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ ├── operations/
│ │ │ │ ├── addBookmarks.ts
│ │ │ │ ├── clipNode.ts
│ │ │ │ ├── embedImage.ts
│ │ │ │ ├── setDestination.ts
│ │ │ │ ├── setLink.ts
│ │ │ │ └── transform.ts
│ │ │ ├── primitives/
│ │ │ │ ├── renderBackground.ts
│ │ │ │ ├── renderBorders.ts
│ │ │ │ ├── renderCanvas.ts
│ │ │ │ ├── renderCheckbox.ts
│ │ │ │ ├── renderCircle.ts
│ │ │ │ ├── renderDebug.ts
│ │ │ │ ├── renderEllipse.ts
│ │ │ │ ├── renderFieldSet.ts
│ │ │ │ ├── renderGlyphs.ts
│ │ │ │ ├── renderGroup.ts
│ │ │ │ ├── renderImage.ts
│ │ │ │ ├── renderLine.ts
│ │ │ │ ├── renderList.ts
│ │ │ │ ├── renderNode.ts
│ │ │ │ ├── renderNote.ts
│ │ │ │ ├── renderPage.ts
│ │ │ │ ├── renderPath.ts
│ │ │ │ ├── renderPolygon.ts
│ │ │ │ ├── renderPolyline.ts
│ │ │ │ ├── renderRect.ts
│ │ │ │ ├── renderSelect.ts
│ │ │ │ ├── renderSvg.ts
│ │ │ │ ├── renderSvgImage.ts
│ │ │ │ ├── renderSvgText.ts
│ │ │ │ ├── renderText.ts
│ │ │ │ └── renderTextInput.ts
│ │ │ ├── svg/
│ │ │ │ ├── getBoundingBox.ts
│ │ │ │ └── parsePoints.ts
│ │ │ ├── types.ts
│ │ │ └── utils/
│ │ │ ├── parseColor.ts
│ │ │ ├── parseFormOptions.ts
│ │ │ └── resolveObjectFit.ts
│ │ ├── tests/
│ │ │ ├── ctx.ts
│ │ │ ├── operations/
│ │ │ │ └── setDestination.test.ts
│ │ │ ├── primitives/
│ │ │ │ ├── renderBackground.test.ts
│ │ │ │ ├── renderCanvas.test.ts
│ │ │ │ ├── renderCircle.test.ts
│ │ │ │ ├── renderEllipse.test.ts
│ │ │ │ └── renderForm.test.ts
│ │ │ ├── svg/
│ │ │ │ ├── getBoundingBox.test.ts
│ │ │ │ └── parsePoints.test.ts
│ │ │ └── utils/
│ │ │ ├── objectFit.test.ts
│ │ │ └── parseColor.test.ts
│ │ └── tsconfig.json
│ ├── renderer/
│ │ ├── .gitignore
│ │ ├── .size-limit.cjs
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── index.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── dom/
│ │ │ │ ├── BlobProvider.js
│ │ │ │ ├── PDFDownloadLink.js
│ │ │ │ ├── PDFViewer.js
│ │ │ │ ├── index.js
│ │ │ │ └── usePDF.js
│ │ │ ├── index.js
│ │ │ ├── node/
│ │ │ │ ├── index.js
│ │ │ │ └── renderTo.js
│ │ │ ├── renderer.js
│ │ │ └── utils.js
│ │ ├── tests/
│ │ │ ├── components.test.jsx
│ │ │ ├── debug.test.jsx
│ │ │ ├── dom.test.jsx
│ │ │ ├── emoji.test.jsx
│ │ │ ├── environment/
│ │ │ │ └── jsdom.js
│ │ │ ├── flex.test.jsx
│ │ │ ├── gap.test.jsx
│ │ │ ├── images.test.jsx
│ │ │ ├── link.test.jsx
│ │ │ ├── namedDestinations.test.jsx
│ │ │ ├── node.test.jsx
│ │ │ ├── orphanTexts.test.jsx
│ │ │ ├── pageWrap.test.jsx
│ │ │ ├── renderComponent.js
│ │ │ ├── resume.test.jsx
│ │ │ ├── svg.test.jsx
│ │ │ ├── svgs.jsx
│ │ │ ├── text.test.jsx
│ │ │ ├── transform.test.jsx
│ │ │ └── usePDF.test.jsx
│ │ ├── vitest.browser.config.js
│ │ ├── vitest.config.js
│ │ └── vitest.setup.js
│ ├── stylesheet/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── globals.d.ts
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── flatten/
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── mediaQueries/
│ │ │ │ └── index.ts
│ │ │ ├── resolve/
│ │ │ │ ├── borders.ts
│ │ │ │ ├── boxModel.ts
│ │ │ │ ├── colors.ts
│ │ │ │ ├── dimensions.ts
│ │ │ │ ├── flex.ts
│ │ │ │ ├── gap.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layout.ts
│ │ │ │ ├── margins.ts
│ │ │ │ ├── paddings.ts
│ │ │ │ ├── positioning.ts
│ │ │ │ ├── svg.ts
│ │ │ │ ├── text.ts
│ │ │ │ ├── transform.ts
│ │ │ │ └── utils.ts
│ │ │ ├── types.ts
│ │ │ └── utils/
│ │ │ ├── castFloat.ts
│ │ │ ├── castInt.ts
│ │ │ ├── colors.ts
│ │ │ ├── offsetKeyword.ts
│ │ │ └── units.ts
│ │ ├── tests/
│ │ │ ├── borders.test.ts
│ │ │ ├── colors.test.ts
│ │ │ ├── dimensions.test.ts
│ │ │ ├── flatten.test.ts
│ │ │ ├── flex.test.ts
│ │ │ ├── gap.test.ts
│ │ │ ├── layout.test.ts
│ │ │ ├── margins.test.ts
│ │ │ ├── mediaQueries.test.ts
│ │ │ ├── paddings.test.ts
│ │ │ ├── positioning.test.ts
│ │ │ ├── resolve.test.ts
│ │ │ ├── text.test.ts
│ │ │ └── transform.test.ts
│ │ └── tsconfig.json
│ ├── textkit/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── src/
│ │ │ ├── attributedString/
│ │ │ │ ├── advanceWidth.ts
│ │ │ │ ├── advanceWidthBetween.ts
│ │ │ │ ├── append.ts
│ │ │ │ ├── ascent.ts
│ │ │ │ ├── descent.ts
│ │ │ │ ├── dropLast.ts
│ │ │ │ ├── empty.ts
│ │ │ │ ├── end.ts
│ │ │ │ ├── fromFragments.ts
│ │ │ │ ├── glyphWidthAt.ts
│ │ │ │ ├── height.ts
│ │ │ │ ├── indexAtOffset.ts
│ │ │ │ ├── insertGlyph.ts
│ │ │ │ ├── leadingOffset.ts
│ │ │ │ ├── length.ts
│ │ │ │ ├── prepend.ts
│ │ │ │ ├── runAt.ts
│ │ │ │ ├── runIndexAt.ts
│ │ │ │ ├── slice.ts
│ │ │ │ ├── sliceAtOffset.ts
│ │ │ │ ├── start.ts
│ │ │ │ ├── trailingOffset.ts
│ │ │ │ └── trim.ts
│ │ │ ├── engines/
│ │ │ │ ├── bidi/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── fontSubstitution/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── justification/
│ │ │ │ │ ├── getDistances.ts
│ │ │ │ │ ├── getFactors.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── linebreaker/
│ │ │ │ │ ├── bestFit.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── knuthPlass.ts
│ │ │ │ │ ├── linkedList.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── scriptItemizer/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── textDecoration/
│ │ │ │ │ └── index.ts
│ │ │ │ └── wordHyphenation/
│ │ │ │ └── index.ts
│ │ │ ├── glyph/
│ │ │ │ ├── fromCodePoint.ts
│ │ │ │ ├── isWhiteSpace.ts
│ │ │ │ └── slice.ts
│ │ │ ├── index.ts
│ │ │ ├── indices/
│ │ │ │ ├── append.ts
│ │ │ │ ├── normalize.ts
│ │ │ │ ├── prepend.ts
│ │ │ │ └── resolve.ts
│ │ │ ├── layout/
│ │ │ │ ├── applyDefaultStyles.ts
│ │ │ │ ├── bidiMirroring.ts
│ │ │ │ ├── bidiReordering.ts
│ │ │ │ ├── finalizeFragments.ts
│ │ │ │ ├── generateGlyphs.ts
│ │ │ │ ├── generateLineRects.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── layoutParagraph.ts
│ │ │ │ ├── preprocessRuns.ts
│ │ │ │ ├── resolveAttachments.ts
│ │ │ │ ├── resolveYOffset.ts
│ │ │ │ ├── splitParagraphs.ts
│ │ │ │ ├── typesetter.ts
│ │ │ │ ├── verticalAlign.ts
│ │ │ │ └── wrapWords.ts
│ │ │ ├── paragraph/
│ │ │ │ ├── height.ts
│ │ │ │ ├── sliceAtHeight.ts
│ │ │ │ └── truncate.ts
│ │ │ ├── positions/
│ │ │ │ └── advanceWidth.ts
│ │ │ ├── rect/
│ │ │ │ ├── area.ts
│ │ │ │ ├── bottomLeft.ts
│ │ │ │ ├── bottomRight.ts
│ │ │ │ ├── copy.ts
│ │ │ │ ├── crop.ts
│ │ │ │ ├── empty.ts
│ │ │ │ ├── equals.ts
│ │ │ │ ├── intersects.ts
│ │ │ │ ├── maxX.ts
│ │ │ │ ├── maxY.ts
│ │ │ │ └── partition.ts
│ │ │ ├── run/
│ │ │ │ ├── add.ts
│ │ │ │ ├── advanceWidth.ts
│ │ │ │ ├── advanceWidthBetween.ts
│ │ │ │ ├── append.ts
│ │ │ │ ├── ascent.ts
│ │ │ │ ├── concat.ts
│ │ │ │ ├── descent.ts
│ │ │ │ ├── dropLast.ts
│ │ │ │ ├── empty.ts
│ │ │ │ ├── filter.ts
│ │ │ │ ├── flatten.ts
│ │ │ │ ├── getFont.ts
│ │ │ │ ├── glyphIndexAt.ts
│ │ │ │ ├── height.ts
│ │ │ │ ├── indexAtOffset.ts
│ │ │ │ ├── insert.ts
│ │ │ │ ├── isEmpty.ts
│ │ │ │ ├── isWhiteSpace.ts
│ │ │ │ ├── leadingOffset.ts
│ │ │ │ ├── length.ts
│ │ │ │ ├── lineGap.ts
│ │ │ │ ├── offset.ts
│ │ │ │ ├── omit.ts
│ │ │ │ ├── prepend.ts
│ │ │ │ ├── runIndexAt.ts
│ │ │ │ ├── scale.ts
│ │ │ │ ├── slice.ts
│ │ │ │ ├── sort.ts
│ │ │ │ ├── subtract.ts
│ │ │ │ └── trailingOffset.ts
│ │ │ ├── types.ts
│ │ │ └── utils/
│ │ │ ├── isNumber.ts
│ │ │ └── stringFromCodePoints.ts
│ │ ├── tests/
│ │ │ ├── attributedString/
│ │ │ │ ├── advanceWidth.test.ts
│ │ │ │ ├── advanceWidthBetween.test.ts
│ │ │ │ ├── append.test.ts
│ │ │ │ ├── ascent.test.ts
│ │ │ │ ├── descent.test.ts
│ │ │ │ ├── dropLast.test.ts
│ │ │ │ ├── empty.test.ts
│ │ │ │ ├── end.test.ts
│ │ │ │ ├── fromFragments.test.ts
│ │ │ │ ├── height.test.ts
│ │ │ │ ├── indexAtOffset.test.ts
│ │ │ │ ├── insertGlyph.test.ts
│ │ │ │ ├── leadingOffset.test.ts
│ │ │ │ ├── length.test.ts
│ │ │ │ ├── prepend.test.ts
│ │ │ │ ├── runAt.test.ts
│ │ │ │ ├── runIndexAt.test.ts
│ │ │ │ ├── slice.test.ts
│ │ │ │ ├── sliceAtOffset.test.ts
│ │ │ │ ├── start.test.ts
│ │ │ │ ├── trailingOffset.test.ts
│ │ │ │ └── trim.test.ts
│ │ │ ├── engines/
│ │ │ │ ├── bidi.test.ts
│ │ │ │ ├── fontSubstitution.test.ts
│ │ │ │ ├── linebreaker.test.ts
│ │ │ │ ├── scriptItemizer.test.ts
│ │ │ │ └── wordHyphenation.test.ts
│ │ │ ├── glyph/
│ │ │ │ ├── fromCodePoint.test.ts
│ │ │ │ ├── isWhiteSpace.test.ts
│ │ │ │ └── slice.test.ts
│ │ │ ├── indices/
│ │ │ │ ├── append.test.ts
│ │ │ │ ├── normalize.test.ts
│ │ │ │ ├── prepend.test.ts
│ │ │ │ └── resolve.test.ts
│ │ │ ├── internal/
│ │ │ │ ├── bidiEngine.ts
│ │ │ │ ├── font.ts
│ │ │ │ ├── fontSubstitutionEngine.ts
│ │ │ │ ├── pluck.ts
│ │ │ │ └── scriptItemizer.ts
│ │ │ ├── layout/
│ │ │ │ ├── applyDefaultStyles.test.ts
│ │ │ │ ├── bidiMirroring.test.ts
│ │ │ │ ├── bidiReordering.test.ts
│ │ │ │ ├── generateGlyphs.test.ts
│ │ │ │ ├── layoutParagraph.test.ts
│ │ │ │ ├── preprocessRuns.test.ts
│ │ │ │ ├── resolveAttachments.test.ts
│ │ │ │ ├── resolveYOffset.test.ts
│ │ │ │ ├── splitParagraphs.test.ts
│ │ │ │ ├── verticalAlign.test.ts
│ │ │ │ └── wrapWords.test.ts
│ │ │ ├── rect/
│ │ │ │ ├── area.test.ts
│ │ │ │ ├── bottomLeft.test.ts
│ │ │ │ ├── bottomRight.test.ts
│ │ │ │ ├── copy.test.ts
│ │ │ │ ├── crop.test.ts
│ │ │ │ ├── empty.test.ts
│ │ │ │ ├── equals.test.ts
│ │ │ │ ├── intersects.test.ts
│ │ │ │ ├── maxX.test.ts
│ │ │ │ ├── maxY.test.ts
│ │ │ │ └── partition.test.ts
│ │ │ ├── run/
│ │ │ │ ├── add.test.ts
│ │ │ │ ├── advanceWidth.test.ts
│ │ │ │ ├── advanceWidthBetween.test.ts
│ │ │ │ ├── append.test.ts
│ │ │ │ ├── ascent.test.ts
│ │ │ │ ├── concat.test.ts
│ │ │ │ ├── descent.test.ts
│ │ │ │ ├── dropLast.test.ts
│ │ │ │ ├── empty.test.ts
│ │ │ │ ├── filter.test.ts
│ │ │ │ ├── flatten.test.ts
│ │ │ │ ├── getFont.test.ts
│ │ │ │ ├── glyphIndexAt.test.ts
│ │ │ │ ├── height.test.ts
│ │ │ │ ├── indexAtOffset.test.ts
│ │ │ │ ├── insert.test.ts
│ │ │ │ ├── isEmpty.test.ts
│ │ │ │ ├── leadingOffset.test.ts
│ │ │ │ ├── length.test.ts
│ │ │ │ ├── lineGap.test.ts
│ │ │ │ ├── offset.test.ts
│ │ │ │ ├── omit.test.ts
│ │ │ │ ├── prepend.test.ts
│ │ │ │ ├── runIndexAt.test.ts
│ │ │ │ ├── scale.test.ts
│ │ │ │ ├── slice.test.ts
│ │ │ │ ├── sort.test.ts
│ │ │ │ ├── subtract.test.ts
│ │ │ │ └── trailingOffset.test.ts
│ │ │ └── utils/
│ │ │ ├── isNumber.test.ts
│ │ │ └── stringFromCodePoints.test.ts
│ │ └── tsconfig.json
│ └── types/
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── bookmark.d.ts
│ ├── context.d.ts
│ ├── font.d.ts
│ ├── image.d.ts
│ ├── index.d.ts
│ ├── node.d.ts
│ ├── package.json
│ ├── page.d.ts
│ ├── pdf.d.ts
│ ├── primitive.d.ts
│ ├── style.d.ts
│ └── svg.d.ts
├── vitest.config.js
└── vitest.workspace.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .changeset/README.md
================================================
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "diegomura/react-pdf" }
],
"commit": false,
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"updateInternalDependents": "always"
},
"ignore": []
}
================================================
FILE: .changeset/dirty-rocks-jam.md
================================================
---
"@react-pdf/textkit": patch
---
feat(textkit): various improvements
================================================
FILE: .changeset/eighty-taxis-cross.md
================================================
---
"@react-pdf/fns": patch
---
feat(fns): various improvements
================================================
FILE: .changeset/five-rockets-battle.md
================================================
---
"@react-pdf/textkit": patch
---
fix: cannot read units for Em
================================================
FILE: .changeset/pretty-carrots-obey.md
================================================
---
"@react-pdf/font": patch
---
feat(font): various improvements
================================================
FILE: .gitattributes
================================================
packages/* linguist-vendored=false
examples/* linguist-vendored=false
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at diegomuracciole@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contribute
## Introduction
First, thank you for considering contributing to react-pdf!
We welcome any type of contribution, not only code. You can help with
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
- **Marketing**: writing blog posts, howto's, printing stickers, ...
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
- **Code**: take a look at the [open issues](https://github.com/diegomura/react-pdf/issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-pdf).
## Your First Contribution
Working on your first Pull Request? You can learn how from this _free_ series, [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
## Set up your development environment
react-pdf is a monorepo. That means the whole solution is broken into small pieces, or packages, each of which solves a specific problem. No need to worry much about it, since [Lerna](https://lerna.js.org/) does most of the work for us. If you are not familiarized with it it's always helpful to have an overall idea of how it works.
Here I present a quick guide about how to setup your development environment exactly as I have it when working on react-pdf. Please bare in mind small differences can be present depending on which environment you are running this library (on the web, node, electron, etc).
### 1. Clone react-pdf project
This goes without saying but first you need to download the code:
```sh
git clone https://github.com/diegomura/react-pdf.git
cd react-pdf
```
### 2. Install Node 18
If you have `nvm` installed all you have to do is:
```sh
nvm install 18
nvm use
```
Other versions should work although I can't guarantee it.
### 3. Install dependencies and boostrap monorepo
We need to download this project dependencies in order to make it work. Because this is a monorepo, we also have to bind all the internal packages together so they are aware of each other. Both things can be done by running:
```sh
yarn install
```
### 4. Build & watch codebase
In order to to quickly iterate in your development process, react-pdf has a watch script that builds all the required modules and waits for changes to happen to re-compile the affected packages. This is handy because enables you to have this process running on the background and just focus on coding what you want. All you have to do is:
```sh
yarn watch
```
### 5. Setup testing project
Now that we have react-pdf built and running, we need to setup a testing project to use as a development target. This might not be the most straightforward way to set up your dev environment but enables use of the lib as an "external" agent, just as end users will do. It's also extensible for testing in different environments, whether it is a web or node project, or electron or native app. I usually have a web project (just a plain [create react app](https://reactjs.org/docs/create-a-new-react-app.html) project), and a Node one.
### 6. Link your react-pdf build to your testing project
Now all we have to do is make our testing project point to our react-pdf watch instance so we can apply changes to it and see them working. For that I use `yarn link`.
On another terminal:
```sh
cd react-pdf/packages/renderer # navigate to react-pdf renderer package
yarn link
```
In our testing project:
```sh
yarn link @react-pdf/renderer
```
If everything went well, now your testing project should be running your local react-pdf build and any change in the codebase should be immediately accesible from your project.
A comment about react and react-dom
I observed that it's sometimes needed to apply the same linking process to both react and react-dom. This is becuase otherwise your local react-pdf build and your testing project will be using each a different react and react-dom instance, making react complain. All you have to do is
# on your react-pdf project
cd react-pdf/node_modules/react
yarn link
cd ../react-dom
yarn link
# on your testing project
yarn link react
yarn link react-dom
## Submitting code
Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests.
## Code review process
The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge.
It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you?
## Financial contributions
We also welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-pdf).
Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed.
## Questions
If you have any questions, create an [issue](https://github.com/diegomura/react-pdf/issues) (protip: do a quick search first to see if someone else didn't ask the same question before!).
You can also reach us at hello@react-pdf.opencollective.com.
## Credits
### Contributors
Thank you to all the people who have already contributed to react-pdf!
### Backers
Thank you to all our backers! [[Become a backer](https://opencollective.com/react-pdf#backer)]
================================================
FILE: .github/FUNDING.yml
================================================
github: diegomura
open_collective: react-pdf
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior including code snippet (if applies):
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
_You can make use of [react-pdf REPL](https://react-pdf.org/repl) to share the snippet_
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. MacOS, Windows]
- Browser [e.g. chrome, safari]
- React-pdf version [e.g. v1.1.0]
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: new feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/no-response.yml
================================================
# Configuration for probot-no-response - https://github.com/probot/no-response
daysUntilClose: 14
responseRequiredLabel: incomplete
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.
================================================
FILE: .github/workflows/main.yml
================================================
name: CI
on:
pull_request:
branches:
- '**'
push:
branches:
- '**'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FORCE_COLOR: 2
HUSKY: 0
NODE_VERSION: 20
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Yarn cache
uses: actions/cache@v4
env:
cache-name: yarn-cache
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies and build
run: yarn --frozen-lockfile
- name: Check size
run: yarn lint
size:
name: Check size
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Yarn cache
uses: actions/cache@v4
env:
cache-name: yarn-cache
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies and build
run: yarn --frozen-lockfile
- name: Check size
run: yarn --cwd packages/renderer run size
test:
name: Run unit tests (Node.js ${{ matrix.node_version }}; React ${{ matrix.react_version }})
runs-on: ubuntu-latest
strategy:
matrix:
# We aim to test all maintained LTS versions of Node.js as well as the latest stable version
node_version: [18, 20, 21]
react_version: [16, 17, 18]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Yarn cache
uses: actions/cache@v4
env:
cache-name: yarn-cache
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
- name: Install dependencies and build
run: yarn --frozen-lockfile
- name: Run tests
run: REACT_VERSION=${{ matrix.react_version }} yarn test
e2e-node:
name: Run E2E tests (Node.js ${{ matrix.node_version }}; ${{ matrix.cjs_or_esm == 'cjs' ? 'CJS' : 'ESM' }}) runs-on: ubuntu-latest
strategy:
matrix:
cjs_or_esm: [cjs, esm]
node_version: [18, 20, 21]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Yarn cache
uses: actions/cache@v4
env:
cache-name: yarn-cache
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
- name: Install dependencies and build
run: yarn --frozen-lockfile
- name: Run E2E tests
run: yarn --cwd e2e/node-${{ matrix.cjs_or_esm }} run start
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FORCE_COLOR: 2
HUSKY: 0
NODE_VERSION: 20
jobs:
test:
name: Run tests (Node.js ${{ matrix.node_version }}; React ${{ matrix.react_version }})
runs-on: ubuntu-latest
strategy:
matrix:
# We aim to test all maintained LTS versions of Node.js as well as the latest stable version
node_version: [18, 20, 21]
react_version: [16, 17, 18, 19]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Yarn cache
uses: actions/cache@v4
env:
cache-name: yarn-cache
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node_version }}
- name: Install dependencies and build
run: yarn --frozen-lockfile
- name: Run tests
run: REACT_VERSION=${{ matrix.react_version }} yarn test
release:
# Prevents this action from running on forks
if: github.repository_owner == 'diegomura'
name: Create Release PR or Publish to npm
needs: [test]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- name: Cache Yarn cache
uses: actions/cache@v4
env:
cache-name: yarn-cache
with:
path: ~/.cache/yarn
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install dependencies and build
run: yarn --frozen-lockfile
- name: Create Release PR or Publish to npm
uses: changesets/action@v1
with:
# This expects you to have a script called release which does a build for your packages and calls changeset publish
publish: yarn release
version: yarn version-packages
commit: 'chore: release packages'
title: 'chore: release packages'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .gitignore
================================================
node_modules
*.log
dist
coverage
.jshintrc
.idea
.DS_Store
.cache
.parcel-cache
================================================
FILE: .husky/pre-commit
================================================
yarn lint-staged
================================================
FILE: .nvmrc
================================================
18
================================================
FILE: .prettierignore
================================================
yoga-layout
lib
packages/pdfkit
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Diego Muracciole
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
React renderer for creating PDF files on the browser and server
## Lost?
This package is used to _create_ PDFs using React. If you wish to _display_ existing PDFs, you may be looking for [react-pdf](https://github.com/wojtekmaj/react-pdf).
## How to install
```sh
yarn add @react-pdf/renderer
```
## How it works
```jsx
import React from 'react';
import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'row',
backgroundColor: '#E4E4E4',
},
section: {
margin: 10,
padding: 10,
flexGrow: 1,
},
});
// Create Document Component
const MyDocument = () => (
Section #1
Section #2
);
```
### `Web.` Render in DOM
```jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { PDFViewer } from '@react-pdf/renderer';
const App = () => (
);
ReactDOM.render( , document.getElementById('root'));
```
### `Node.` Save in a file
```jsx
import React from 'react';
import ReactPDF from '@react-pdf/renderer';
ReactPDF.render( , `${__dirname}/example.pdf`);
```
## Contributors
This project exists thanks to all the people who contribute. Looking to contribute? Please check our [[contribute]](https://github.com/diegomura/react-pdf/blob/master/.github/CONTRIBUTING.md) document for more details about how to setup a development environment and submitting code.
## Sponsors
Thank you to all our sponsors! [[Become a sponsors](https://opencollective.com/react-pdf#sponsors)]
## Backers
Thank you to all our backers! [[Become a backer](https://opencollective.com/react-pdf#backer)]
## License
MIT © [Diego Muracciole](http://github.com/diegomura)
---
[](https://www.npmjs.com/package/@react-pdf/renderer)
================================================
FILE: babel.config.js
================================================
export default {
presets: [
[
'@babel/preset-env',
{
loose: true,
targets: {
node: '18',
browsers: '>0.25%, not dead',
},
},
],
['@babel/preset-react', { runtime: 'automatic' }],
],
plugins: [
['@babel/plugin-transform-runtime', { version: '^7.19.6' }],
['@babel/plugin-proposal-class-properties', { loose: true }],
'@babel/plugin-proposal-optional-chaining',
],
};
================================================
FILE: e2e/node-cjs/CHANGELOG.md
================================================
# @react-pdf/e2e-node-cjs
## 2.0.24
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.3.2
## 2.0.23
### Patch Changes
- Updated dependencies [[`dcc7b403`](https://github.com/diegomura/react-pdf/commit/dcc7b40313b5662b9bd16678fbc0b62eeaf65d71)]:
- @react-pdf/renderer@4.3.1
## 2.0.22
### Patch Changes
- Updated dependencies [[`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982), [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/renderer@4.3.0
## 2.0.21
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.4
## 2.0.20
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.3
## 2.0.19
### Patch Changes
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6)]:
- @react-pdf/renderer@4.2.2
## 2.0.18
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.1
## 2.0.17
### Patch Changes
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`685890bd`](https://github.com/diegomura/react-pdf/commit/685890bd841b7d2480157117fcd3cbb1334f6324)]:
- @react-pdf/renderer@4.2.0
## 2.0.16
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.6
## 2.0.15
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.5
## 2.0.14
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.4
## 2.0.13
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.3
## 2.0.12
### Patch Changes
- Updated dependencies [[`aab7d958`](https://github.com/diegomura/react-pdf/commit/aab7d95870d9073e4acb004aa0cce9cfa19b7f0e)]:
- @react-pdf/renderer@4.1.2
## 2.0.11
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.1
## 2.0.10
### Patch Changes
- Updated dependencies [[`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd)]:
- @react-pdf/renderer@4.1.0
## 2.0.9
### Patch Changes
- Updated dependencies [[`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b)]:
- @react-pdf/renderer@4.0.2
## 2.0.8
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.0.1
## 2.0.7
### Patch Changes
- Updated dependencies [[`afe4bcfe`](https://github.com/diegomura/react-pdf/commit/afe4bcfe6f4b991cf22341242fc27d169b758d47), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/renderer@4.0.0
## 2.0.6
### Patch Changes
- Updated dependencies [[`ed94775`](https://github.com/diegomura/react-pdf/commit/ed94775f4d44db0886ff08c71d09f446bace6392)]:
- @react-pdf/renderer@3.4.5
## 2.0.5
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.4
## 2.0.4
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.3
## 2.0.3
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.2
## 2.0.2
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.1
## 2.0.1
### Patch Changes
- Updated dependencies [[`fab09cc`](https://github.com/diegomura/react-pdf/commit/fab09cc9814326fdb44d2bcb7097ba9960d441d1)]:
- @react-pdf/renderer@3.4.0
================================================
FILE: e2e/node-cjs/index.js
================================================
const fs = require('node:fs/promises');
const assert = require('node:assert');
const { test } = require('node:test');
const { jsx } = require('react/jsx-runtime');
const { Document, Page, Text, renderToBuffer } = require('@react-pdf/renderer');
const MyDocument = () =>
jsx(Document, {
children: jsx(Page, {
size: 'A4',
children: jsx(Text, {
children: 'Hello world',
}),
}),
});
function removeMovingParts(buffer) {
return Buffer.from(
buffer
.toString('ascii')
.replace(/\(D:[0-9]{14}Z\)/g, '(D:20240101000000Z)')
.replace(
/\/ID \[.*\]/,
'/ID [<00000000000000000000000000000000> <00000000000000000000000000000000>]',
),
);
}
test('rendering a PDF', async () => {
const bufferPromise = renderToBuffer(jsx(MyDocument, {}));
const referenceBufferPromise = fs.readFile('../reference.pdf');
const [buffer, referenceBuffer] = await Promise.all([
bufferPromise,
referenceBufferPromise,
]);
const bufferAsciiWithIDsRemoved = removeMovingParts(buffer);
const referenceBufferAsciiWithIDsRemoved = removeMovingParts(referenceBuffer);
assert.deepStrictEqual(
bufferAsciiWithIDsRemoved,
referenceBufferAsciiWithIDsRemoved,
);
});
================================================
FILE: e2e/node-cjs/package.json
================================================
{
"name": "@react-pdf/e2e-node-cjs",
"version": "2.0.24",
"license": "MIT",
"private": true,
"type": "commonjs",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"repository": "git@github.com:diegomura/react-pdf.git",
"scripts": {
"dev": "node --watch ./index.js",
"start": "node ./index.js"
},
"dependencies": {
"@react-pdf/renderer": "^4.3.2",
"react": "^18.2.0"
}
}
================================================
FILE: e2e/node-esm/CHANGELOG.md
================================================
# @react-pdf/e2e-node-esm
## 2.0.24
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.3.2
## 2.0.23
### Patch Changes
- Updated dependencies [[`dcc7b403`](https://github.com/diegomura/react-pdf/commit/dcc7b40313b5662b9bd16678fbc0b62eeaf65d71)]:
- @react-pdf/renderer@4.3.1
## 2.0.22
### Patch Changes
- Updated dependencies [[`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982), [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/renderer@4.3.0
## 2.0.21
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.4
## 2.0.20
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.3
## 2.0.19
### Patch Changes
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6)]:
- @react-pdf/renderer@4.2.2
## 2.0.18
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.1
## 2.0.17
### Patch Changes
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`685890bd`](https://github.com/diegomura/react-pdf/commit/685890bd841b7d2480157117fcd3cbb1334f6324)]:
- @react-pdf/renderer@4.2.0
## 2.0.16
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.6
## 2.0.15
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.5
## 2.0.14
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.4
## 2.0.13
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.3
## 2.0.12
### Patch Changes
- Updated dependencies [[`aab7d958`](https://github.com/diegomura/react-pdf/commit/aab7d95870d9073e4acb004aa0cce9cfa19b7f0e)]:
- @react-pdf/renderer@4.1.2
## 2.0.11
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.1
## 2.0.10
### Patch Changes
- Updated dependencies [[`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd)]:
- @react-pdf/renderer@4.1.0
## 2.0.9
### Patch Changes
- Updated dependencies [[`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b)]:
- @react-pdf/renderer@4.0.2
## 2.0.8
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.0.1
## 2.0.7
### Patch Changes
- Updated dependencies [[`afe4bcfe`](https://github.com/diegomura/react-pdf/commit/afe4bcfe6f4b991cf22341242fc27d169b758d47), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/renderer@4.0.0
## 2.0.6
### Patch Changes
- Updated dependencies [[`ed94775`](https://github.com/diegomura/react-pdf/commit/ed94775f4d44db0886ff08c71d09f446bace6392)]:
- @react-pdf/renderer@3.4.5
## 2.0.5
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.4
## 2.0.4
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.3
## 2.0.3
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.2
## 2.0.2
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.1
## 2.0.1
### Patch Changes
- Updated dependencies [[`fab09cc`](https://github.com/diegomura/react-pdf/commit/fab09cc9814326fdb44d2bcb7097ba9960d441d1)]:
- @react-pdf/renderer@3.4.0
================================================
FILE: e2e/node-esm/index.js
================================================
import fs from 'node:fs/promises';
import assert from 'node:assert';
import { test } from 'node:test';
import { jsx } from 'react/jsx-runtime';
import { Document, Page, Text, renderToBuffer } from '@react-pdf/renderer';
const MyDocument = () =>
jsx(Document, {
children: jsx(Page, {
size: 'A4',
children: jsx(Text, {
children: 'Hello world',
}),
}),
});
function removeMovingParts(buffer) {
return Buffer.from(
buffer
.toString('ascii')
.replace(/\(D:[0-9]{14}Z\)/g, '(D:20240101000000Z)')
.replace(
/\/ID \[.*\]/,
'/ID [<00000000000000000000000000000000> <00000000000000000000000000000000>]',
),
);
}
test('rendering a PDF', async () => {
const bufferPromise = renderToBuffer(jsx(MyDocument, {}));
const referenceBufferPromise = fs.readFile('../reference.pdf');
const [buffer, referenceBuffer] = await Promise.all([
bufferPromise,
referenceBufferPromise,
]);
const bufferAsciiWithIDsRemoved = removeMovingParts(buffer);
const referenceBufferAsciiWithIDsRemoved = removeMovingParts(referenceBuffer);
assert.deepStrictEqual(
bufferAsciiWithIDsRemoved,
referenceBufferAsciiWithIDsRemoved,
);
});
================================================
FILE: e2e/node-esm/package.json
================================================
{
"name": "@react-pdf/e2e-node-esm",
"version": "2.0.24",
"license": "MIT",
"private": true,
"type": "module",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"repository": "git@github.com:diegomura/react-pdf.git",
"scripts": {
"dev": "node --watch ./index.js",
"start": "node ./index.js"
},
"dependencies": {
"@react-pdf/renderer": "^4.3.2",
"react": "^18.2.0"
}
}
================================================
FILE: eslint.config.ts
================================================
import { version } from 'react';
import reactPlugin from 'eslint-plugin-react';
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import vitestPlugin from '@vitest/eslint-plugin';
import prettierPlugin from 'eslint-plugin-prettier';
const baseConfig = {
languageOptions: {
parser: tsParser,
sourceType: 'module',
},
plugins: {
'@typescript-eslint': tsPlugin,
},
};
const ignoreConfig = {
ignores: [
'**/dist',
'**/lib',
'**/node_modules',
'**/packages/pdfkit/**',
'**/packages/png-js/**',
'**/packages/yoga/**',
'**/packages/examples/**',
],
};
const globalsConfig = {
languageOptions: {
globals: {
atob: false,
Blob: false,
BROWSER: false,
Buffer: false,
console: false,
fetch: false,
global: false,
module: false,
process: false,
TextDecoder: false,
TextEncoder: false,
URL: false,
window: false,
},
},
};
const jsConfig = {
rules: {
'array-callback-return': ['error', { allowImplicit: true }],
'block-scoped-var': 'error',
complexity: ['off', 20],
'constructor-super': 'error',
'default-case': ['error', { commentPattern: '^no default$' }],
'default-case-last': 'error',
'dot-notation': ['error', { allowKeywords: true }],
eqeqeq: ['error', 'always', { null: 'ignore' }],
'for-direction': 'error',
'grouped-accessor-pairs': 'error',
'guard-for-in': 'error',
'getter-return': 'error',
'max-classes-per-file': ['error', 1],
'no-alert': 'error',
'no-caller': 'error',
'no-async-promise-executor': 'error',
'no-case-declarations': 'error',
'no-class-assign': 'error',
'no-compare-neg-zero': 'error',
'no-constructor-return': 'error',
'no-await-in-loop': 'error',
'no-console': 'warn',
'no-cond-assign': 'error',
'no-const-assign': 'error',
'no-constant-condition': 'warn',
'no-else-return': ['error', { allowElseIf: false }],
'no-control-regex': 'error',
'no-debugger': 'error',
'no-delete-var': 'error',
'no-dupe-args': 'error',
'no-dupe-class-members': 'error',
'no-dupe-else-if': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty': 'error',
'no-eval': 'error',
'no-empty-character-class': 'error',
'no-empty-pattern': 'error',
'no-empty-static-block': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-ex-assign': 'error',
'no-extra-boolean-cast': 'error',
'no-fallthrough': 'error',
'no-func-assign': 'error',
'no-global-assign': 'error',
'no-import-assign': 'error',
'no-invalid-regexp': 'error',
'no-implied-eval': 'error',
'no-iterator': 'error',
'no-irregular-whitespace': 'error',
'no-loss-of-precision': 'error',
'no-lone-blocks': 'error',
'no-loop-func': 'error',
'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
'no-misleading-character-class': 'error',
'no-new-native-nonconstructor': 'error',
'no-nonoctal-decimal-escape': 'error',
'no-obj-calls': 'error',
'no-new-func': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-proto': 'error',
'no-prototype-builtins': 'error',
'no-script-url': 'error',
'no-return-await': 'error',
'no-redeclare': 'error',
'no-return-assign': ['error', 'always'],
'no-regex-spaces': 'error',
'no-new-wrappers': 'error',
'no-self-assign': 'error',
'no-setter-return': 'error',
'no-extra-label': 'error',
'no-sequences': 'error',
'no-throw-literal': 'error',
'no-template-curly-in-string': 'error',
'no-shadow-restricted-names': 'error',
'no-sparse-arrays': 'error',
'no-this-before-super': 'error',
'no-undef': 'error',
'no-unreachable': 'error',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'no-unsafe-optional-chaining': 'error',
'no-unused-labels': 'error',
'no-negated-in-lhs': 'off',
'no-unused-vars': ['error', { ignoreRestSiblings: true }],
'no-useless-backreference': 'error',
'no-useless-concat': 'error',
'no-useless-catch': 'error',
'no-useless-escape': 'error',
'no-useless-return': 'error',
'no-void': 'error',
'no-with': 'error',
'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }],
'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
'prefer-const': 'error',
'prefer-rest-params': 'error',
'prefer-spread': 'error',
radix: 'error',
'require-yield': 'error',
'use-isnan': 'error',
'valid-typeof': 'error',
yoda: 'error',
},
};
const reactConfig = {
settings: {
react: { version },
},
plugins: {
react: reactPlugin,
},
rules: {
'react/display-name': 'error',
'react/jsx-key': 'error',
'react/jsx-no-comment-textnodes': 'error',
'react/jsx-no-duplicate-props': 'error',
'react/jsx-no-target-blank': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-uses-vars': 'error',
'react/no-children-prop': 'error',
'react/no-danger-with-children': 'error',
'react/no-deprecated': 'error',
'react/no-direct-mutation-state': 'error',
'react/no-find-dom-node': 'error',
'react/no-is-mounted': 'error',
'react/no-render-return-value': 'error',
'react/no-string-refs': 'error',
'react/no-unescaped-entities': 'error',
'react/no-unknown-property': 'error',
'react/require-render-return': 'error',
},
languageOptions: {
parserOptions: {
jsxPragma: null,
ecmaFeatures: {
jsx: true,
},
},
},
};
const vitestConfig = {
files: ['**/*.test.js', '**/*.test.ts'],
plugins: {
vitest: vitestPlugin,
},
rules: {
'vitest/expect-expect': 'error',
'vitest/no-identical-title': 'error',
'vitest/no-commented-out-tests': 'error',
'vitest/valid-title': 'error',
'vitest/valid-expect': 'error',
'vitest/valid-describe-callback': 'error',
'vitest/require-local-test-context-for-concurrent-snapshots': 'error',
'vitest/no-import-node-test': 'error',
'vitest/max-nested-describe': ['error', { max: 3 }],
},
};
const tsConfig = {
files: ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'],
rules: {
'constructor-super': 'off',
'getter-return': 'off',
'no-class-assign': 'off',
'no-const-assign': 'off',
'no-dupe-args': 'off',
'no-dupe-class-members': 'off',
'no-dupe-keys': 'off',
'no-func-assign': 'off',
'no-import-assign': 'off',
'no-new-native-nonconstructor': 'off',
'no-promise-executor-return': 'error',
'no-obj-calls': 'off',
'no-redeclare': 'off',
'no-setter-return': 'off',
'no-this-before-super': 'off',
'no-undef': 'off',
'no-unreachable': 'off',
'no-unsafe-negation': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/ban-ts-comment': 'error',
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-empty-object-type': 'error',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
'@typescript-eslint/no-unsafe-function-type': 'error',
'@typescript-eslint/no-unused-expressions': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
},
};
const prettierConfig = {
plugins: {
prettier: prettierPlugin,
},
rules: {
'prettier/prettier': 'error',
},
};
const config = [
baseConfig,
ignoreConfig,
globalsConfig,
jsConfig,
reactConfig,
vitestConfig,
tsConfig,
prettierConfig,
];
export default config;
================================================
FILE: lerna.json
================================================
{
"version": "independent",
"packages": ["packages/*", "packages/examples/*", "e2e/*"],
"npmClient": "yarn"
}
================================================
FILE: package.json
================================================
{
"private": true,
"name": "@react-pdf/root",
"version": "2.0.0",
"license": "MIT",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"repository": "git@github.com:diegomura/react-pdf.git",
"workspaces": [
"packages/*",
"packages/examples/*",
"e2e/*"
],
"scripts": {
"prepare": "husky",
"build": "lerna run build",
"watch": "lerna run watch --parallel",
"typecheck": "lerna run typecheck --parallel",
"prepublish": "lerna run build",
"lint": "eslint packages",
"test": "vitest",
"dev": "lerna run dev --scope @react-pdf/examples --",
"changeset": "changeset",
"version-packages": "changeset version",
"release": "changeset publish"
},
"devDependencies": {
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.7",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-optional-chaining": "^7.20.7",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.0",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-babel": "^6.0.0",
"@rollup/plugin-commonjs": "^25.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.0",
"@rollup/plugin-replace": "^5.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@testing-library/react": "^14.0.0",
"@typescript-eslint/eslint-plugin": "^8.23.0",
"@typescript-eslint/parser": "^8.23.0",
"@typescript-eslint/utils": "^8.23.0",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/eslint-plugin": "^1.1.27",
"babel-plugin-add-module-exports": "^1.0.0",
"canvas": "^2.11.2",
"chalk": "^2.4.2",
"eslint": "^9.20.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react": "^7.37.4",
"husky": "^9.0.0",
"jest-image-snapshot": "^6.1.0",
"jiti": "^2.4.2",
"jsdom": "^23.2.0",
"lerna": "^8.0.2",
"lint-staged": "^10.5.4",
"pdfjs-dist": "3.2.146",
"prettier": "^3.2.0",
"react": "^18.2.0",
"react-16": "npm:react@^16.8.0",
"react-17": "npm:react@^17.0.0",
"react-19": "npm:react@19.0.0-rc-66855b96-20241106",
"react-19-2": "npm:react@^19.2.0",
"react-dom": "^18.2.0",
"react-dom-16": "npm:react-dom@^16.8.0",
"react-dom-17": "npm:react-dom@^17.0.0",
"react-dom-19": "npm:react-dom@19.0.0-rc-66855b96-20241106",
"react-dom-19-2": "npm:react-dom@^19.2.0",
"rimraf": "^2.6.3",
"rollup": "^4.34.6",
"rollup-plugin-copy": "^3.5.0",
"rollup-plugin-delete": "^2.1.0",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-ignore": "^1.0.10",
"rollup-plugin-local-resolve": "^1.0.7",
"rollup-plugin-polyfill-node": "^0.13.0",
"vitest": "^1.2.0",
"vitest-fetch-mock": "^0.2.2"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"yarn lint",
"prettier --write"
]
},
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/react-pdf",
"logo": "https://opencollective.com/opencollective/logo.txt"
},
"packageManager": "yarn@1.22.19"
}
================================================
FILE: packages/examples/dev.sh
================================================
#!/bin/bash
# Get the directory of the script
scriptDir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Get the list of directories adjacent to the script
dirs=()
for dir in "$scriptDir"/*/ ; do
[ -d "$dir" ] && dirs+=("$(basename "$dir")")
done
# Check if any directories were found
if [ ${#dirs[@]} -eq 0 ]; then
echo "No example directories found."
exit 1
fi
if [ -n "$1" ]; then
# First argument provided
selectedDir="$1"
if [[ " ${dirs[@]} " =~ " $selectedDir " ]]; then
echo "Selected example: $selectedDir"
else
echo "Example '$selectedDir' does not exist adjacent to the script."
exit 1
fi
else
# No argument provided, prompt the user to select one
echo "Please select an example:"
select selectedDir in "${dirs[@]}"; do
if [ -n "$selectedDir" ]; then
echo "You selected: $selectedDir"
break
else
echo "Invalid selection."
fi
done
fi
# Run 'yarn dev' inside the selected directory
cd "$scriptDir/$selectedDir" || { echo "Failed to change directory to $scriptDir/$selectedDir"; exit 1; }
echo "Running 'yarn dev' in $scriptDir/$selectedDir"
yarn dev
================================================
FILE: packages/examples/next-14/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
================================================
FILE: packages/examples/next-14/CHANGELOG.md
================================================
# next-14
## 0.1.17
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.3.2
## 0.1.16
### Patch Changes
- Updated dependencies [[`dcc7b403`](https://github.com/diegomura/react-pdf/commit/dcc7b40313b5662b9bd16678fbc0b62eeaf65d71)]:
- @react-pdf/renderer@4.3.1
## 0.1.15
### Patch Changes
- Updated dependencies [[`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982), [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/renderer@4.3.0
## 0.1.14
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.4
## 0.1.13
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.3
## 0.1.12
### Patch Changes
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6)]:
- @react-pdf/renderer@4.2.2
## 0.1.11
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.1
## 0.1.10
### Patch Changes
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`685890bd`](https://github.com/diegomura/react-pdf/commit/685890bd841b7d2480157117fcd3cbb1334f6324)]:
- @react-pdf/renderer@4.2.0
## 0.1.9
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.6
## 0.1.8
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.5
## 0.1.7
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.4
## 0.1.6
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.3
## 0.1.5
### Patch Changes
- Updated dependencies [[`aab7d958`](https://github.com/diegomura/react-pdf/commit/aab7d95870d9073e4acb004aa0cce9cfa19b7f0e)]:
- @react-pdf/renderer@4.1.2
## 0.1.4
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.1
## 0.1.3
### Patch Changes
- Updated dependencies [[`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd)]:
- @react-pdf/renderer@4.1.0
## 0.1.2
### Patch Changes
- Updated dependencies [[`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b)]:
- @react-pdf/renderer@4.0.2
## 0.1.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.0.1
================================================
FILE: packages/examples/next-14/README.md
================================================
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
================================================
FILE: packages/examples/next-14/app/globals.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
================================================
FILE: packages/examples/next-14/app/layout.js
================================================
import './globals.css';
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
export default function RootLayout({ children }) {
return (
{children}
);
}
================================================
FILE: packages/examples/next-14/app/page.js
================================================
'use client';
import {
Document,
Page,
PDFViewer,
PDFDownloadLink,
Text,
} from '@react-pdf/renderer';
export default function Home() {
const doc = (
Hello world from client
);
return (
);
}
================================================
FILE: packages/examples/next-14/jsconfig.json
================================================
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}
================================================
FILE: packages/examples/next-14/next.config.mjs
================================================
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default nextConfig;
================================================
FILE: packages/examples/next-14/package.json
================================================
{
"name": "next-14",
"version": "0.1.17",
"private": true,
"scripts": {
"dev": "next dev",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@react-pdf/renderer": "^4.3.2",
"react": "^18",
"react-dom": "^18",
"next": "15.4.10"
},
"devDependencies": {
"postcss": "^8",
"tailwindcss": "^3.4.17"
}
}
================================================
FILE: packages/examples/next-14/postcss.config.mjs
================================================
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;
================================================
FILE: packages/examples/next-14/tailwind.config.js
================================================
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
background: 'var(--background)',
foreground: 'var(--foreground)',
},
},
},
plugins: [],
};
================================================
FILE: packages/examples/next-15/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
================================================
FILE: packages/examples/next-15/CHANGELOG.md
================================================
# next-15
## 0.1.17
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.3.2
## 0.1.16
### Patch Changes
- Updated dependencies [[`dcc7b403`](https://github.com/diegomura/react-pdf/commit/dcc7b40313b5662b9bd16678fbc0b62eeaf65d71)]:
- @react-pdf/renderer@4.3.1
## 0.1.15
### Patch Changes
- Updated dependencies [[`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982), [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/renderer@4.3.0
## 0.1.14
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.4
## 0.1.13
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.3
## 0.1.12
### Patch Changes
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6)]:
- @react-pdf/renderer@4.2.2
## 0.1.11
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.1
## 0.1.10
### Patch Changes
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`685890bd`](https://github.com/diegomura/react-pdf/commit/685890bd841b7d2480157117fcd3cbb1334f6324)]:
- @react-pdf/renderer@4.2.0
## 0.1.9
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.6
## 0.1.8
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.5
## 0.1.7
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.4
## 0.1.6
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.3
## 0.1.5
### Patch Changes
- Updated dependencies [[`aab7d958`](https://github.com/diegomura/react-pdf/commit/aab7d95870d9073e4acb004aa0cce9cfa19b7f0e)]:
- @react-pdf/renderer@4.1.2
## 0.1.4
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.1
## 0.1.3
### Patch Changes
- Updated dependencies [[`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd)]:
- @react-pdf/renderer@4.1.0
## 0.1.2
### Patch Changes
- Updated dependencies [[`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b)]:
- @react-pdf/renderer@4.0.2
## 0.1.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.0.1
================================================
FILE: packages/examples/next-15/README.md
================================================
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
================================================
FILE: packages/examples/next-15/app/globals.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
================================================
FILE: packages/examples/next-15/app/layout.js
================================================
import './globals.css';
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
export default function RootLayout({ children }) {
return (
{children}
);
}
================================================
FILE: packages/examples/next-15/app/page.js
================================================
'use client';
import {
Document,
Page,
PDFViewer,
PDFDownloadLink,
Text,
} from '@react-pdf/renderer';
export default function Home() {
const doc = (
Hello world from client
);
return (
);
}
================================================
FILE: packages/examples/next-15/jsconfig.json
================================================
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}
================================================
FILE: packages/examples/next-15/next.config.mjs
================================================
/** @type {import('next').NextConfig} */
const nextConfig = {};
export default nextConfig;
================================================
FILE: packages/examples/next-15/package.json
================================================
{
"name": "next-15",
"version": "0.1.17",
"private": true,
"scripts": {
"dev": "next dev",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@react-pdf/renderer": "^4.3.2",
"react": "19.1.0",
"react-dom": "19.1.0",
"next": "15.4.10"
},
"devDependencies": {
"postcss": "^8",
"tailwindcss": "^3.4.17"
}
}
================================================
FILE: packages/examples/next-15/postcss.config.mjs
================================================
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;
================================================
FILE: packages/examples/next-15/tailwind.config.js
================================================
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
background: 'var(--background)',
foreground: 'var(--foreground)',
},
},
},
plugins: [],
};
================================================
FILE: packages/examples/package.json
================================================
{
"name": "@react-pdf/examples",
"version": "0.0.0",
"license": "MIT",
"private": true,
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"repository": "git@github.com:diegomura/react-pdf.git",
"scripts": {
"dev": "./dev.sh"
}
}
================================================
FILE: packages/examples/vite/.gitignore
================================================
lib
node_modules
================================================
FILE: packages/examples/vite/CHANGELOG.md
================================================
# @react-pdf/examples
## 3.3.20
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.3.2
## 3.3.19
### Patch Changes
- Updated dependencies [[`dcc7b403`](https://github.com/diegomura/react-pdf/commit/dcc7b40313b5662b9bd16678fbc0b62eeaf65d71)]:
- @react-pdf/renderer@4.3.1
## 3.3.18
### Patch Changes
- Updated dependencies [[`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982), [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/renderer@4.3.0
## 3.3.17
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.4
## 3.3.16
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.3
## 3.3.15
### Patch Changes
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6)]:
- @react-pdf/renderer@4.2.2
## 3.3.14
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.2.1
## 3.3.13
### Patch Changes
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`685890bd`](https://github.com/diegomura/react-pdf/commit/685890bd841b7d2480157117fcd3cbb1334f6324)]:
- @react-pdf/renderer@4.2.0
## 3.3.12
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.6
## 3.3.11
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.5
## 3.3.10
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.4
## 3.3.9
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.3
## 3.3.8
### Patch Changes
- Updated dependencies [[`aab7d958`](https://github.com/diegomura/react-pdf/commit/aab7d95870d9073e4acb004aa0cce9cfa19b7f0e)]:
- @react-pdf/renderer@4.1.2
## 3.3.7
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.1.1
## 3.3.6
### Patch Changes
- Updated dependencies [[`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd)]:
- @react-pdf/renderer@4.1.0
## 3.3.5
### Patch Changes
- Updated dependencies [[`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b)]:
- @react-pdf/renderer@4.0.2
## 3.3.4
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@4.0.1
## 3.3.3
### Patch Changes
- Updated dependencies [[`afe4bcfe`](https://github.com/diegomura/react-pdf/commit/afe4bcfe6f4b991cf22341242fc27d169b758d47), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/renderer@4.0.0
## 3.3.2
### Patch Changes
- [#2747](https://github.com/diegomura/react-pdf/pull/2747) [`5af35ec`](https://github.com/diegomura/react-pdf/commit/5af35ec9743cc0d7bf75f5ca789627517ff35816) Thanks [@andrew-spare](https://github.com/andrew-spare)! - fix: font selection regression
- Updated dependencies [[`ed94775`](https://github.com/diegomura/react-pdf/commit/ed94775f4d44db0886ff08c71d09f446bace6392)]:
- @react-pdf/renderer@3.4.5
## 3.3.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.4
## 3.3.0
### Minor Changes
- [#2640](https://github.com/diegomura/react-pdf/pull/2640) [`67c265a`](https://github.com/diegomura/react-pdf/commit/67c265a7e39cc0baa319f49137219677904695e6) Thanks [@nikgraf](https://github.com/nikgraf)! - Add support for fontFamily fallbacks e.g. fontFamily: ['Roboto', 'NotoSansArabic']
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.3
## 3.2.13
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.2
## 3.2.12
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.4.1
## 3.2.11
### Patch Changes
- Updated dependencies [[`fab09cc`](https://github.com/diegomura/react-pdf/commit/fab09cc9814326fdb44d2bcb7097ba9960d441d1)]:
- @react-pdf/renderer@3.4.0
## 3.2.10
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.3.8
## 3.2.9
### Patch Changes
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/renderer@3.3.7
## 3.2.8
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.3.6
## 3.2.7
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.3.5
## 3.2.6
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.3.4
## 3.2.5
### Patch Changes
- Updated dependencies [[`b5380a1`](https://github.com/diegomura/react-pdf/commit/b5380a1a0a7397b4111d68ce97b4acb702d34d51)]:
- @react-pdf/renderer@3.3.3
## 3.2.4
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.3.2
## 3.2.3
### Patch Changes
- [#2529](https://github.com/diegomura/react-pdf/pull/2529) [`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8) Thanks [@diegomura](https://github.com/diegomura)! - fix: jpeg exif orientation rendering
- Updated dependencies [[`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8)]:
- @react-pdf/renderer@3.3.1
## 3.2.2
### Patch Changes
- [#2518](https://github.com/diegomura/react-pdf/pull/2518) [`3c62070`](https://github.com/diegomura/react-pdf/commit/3c6207035d2f02109bb2b5ef8804febc5a05b488) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fix invalid prop (style) in Resume example
* [#2521](https://github.com/diegomura/react-pdf/pull/2521) [`214207b`](https://github.com/diegomura/react-pdf/commit/214207b62bc8061a46a7cb220901e193d327effe) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fix invalid display property in objectFit example
- [#2517](https://github.com/diegomura/react-pdf/pull/2517) [`bc0d4f4`](https://github.com/diegomura/react-pdf/commit/bc0d4f42fe5d8b8bd2fb560b753041fbf013ab33) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fix invalid props (xmlns, id) in SVG example
- Updated dependencies [[`64f7bba`](https://github.com/diegomura/react-pdf/commit/64f7bba0d840d17188e50086169c84c415abd8d5), [`e817223`](https://github.com/diegomura/react-pdf/commit/e8172231d07d10ece4ca960641f9ee52c5d4660d), [`cf73180`](https://github.com/diegomura/react-pdf/commit/cf7318069e63170e160a36602359fc8cbc3386c2), [`0f5c43f`](https://github.com/diegomura/react-pdf/commit/0f5c43fa6f3c0b53c067200cc1ac21e651504760), [`66a40b2`](https://github.com/diegomura/react-pdf/commit/66a40b2e41cefe11f1ef8d467ba449a8861adb69)]:
- @react-pdf/renderer@3.3.0
## 3.2.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.2.1
## 3.2.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
* [#2496](https://github.com/diegomura/react-pdf/pull/2496) [`c8fe2c8`](https://github.com/diegomura/react-pdf/commit/c8fe2c86639cb8e44f26f78e62fc67379a8e3ceb) Thanks [@diegomura](https://github.com/diegomura)! - fix: copyright and registered symbol rendering
### Patch Changes
- Updated dependencies [[`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37)]:
- @react-pdf/renderer@3.2.0
## 3.1.0
### Minor Changes
- [#2491](https://github.com/diegomura/react-pdf/pull/2491) [`ed8524f`](https://github.com/diegomura/react-pdf/commit/ed8524f867f71fc8407faeb74edc4574e99a1137) Thanks [@diegomura](https://github.com/diegomura)! - feat: add minPresenceAhead example
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.1.17
## 3.0.0
### Major Changes
- [#2487](https://github.com/diegomura/react-pdf/pull/2487) [`3f31046`](https://github.com/diegomura/react-pdf/commit/3f310460dcadb7bd65adeab0309812aa757cde29) Thanks [@diegomura](https://github.com/diegomura)! - add dev script
### Patch Changes
- [#2479](https://github.com/diegomura/react-pdf/pull/2479) [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4) Thanks [@diegomura](https://github.com/diegomura)! - fix linting
- Updated dependencies [[`8654d00`](https://github.com/diegomura/react-pdf/commit/8654d003023dd0899cddfc2ea2f5a552e01cf570)]:
- @react-pdf/renderer@3.1.16
## 2.0.14
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.1.15
## 2.0.13
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.1.14
## 2.0.12
### Patch Changes
- Updated dependencies [[`3b5e1c7`](https://github.com/diegomura/react-pdf/commit/3b5e1c7c71a0f830ae2b70da8aac2b2bd5015ca3)]:
- @react-pdf/renderer@3.1.13
## 2.0.11
### Patch Changes
- Updated dependencies [[`6d408c8`](https://github.com/diegomura/react-pdf/commit/6d408c838b1aa9bea0db63bf36b2a6932a20404c)]:
- @react-pdf/renderer@3.1.12
## 2.0.10
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.1.11
## 2.0.9
### Patch Changes
- Updated dependencies [[`113de53`](https://github.com/diegomura/react-pdf/commit/113de537b0fa9bae06a69e7c8daa988fe319fc6a), [`d6018d5`](https://github.com/diegomura/react-pdf/commit/d6018d5a80492270ff5f5b4c00e694f7dc1cd93f)]:
- @react-pdf/renderer@3.1.10
## 2.0.8
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.1.9
## 2.0.7
### Patch Changes
- Updated dependencies [[`5832ff2`](https://github.com/diegomura/react-pdf/commit/5832ff20e1ce4a0e49cf5249dcdf4b304eab04c6), [`37bfa1b`](https://github.com/diegomura/react-pdf/commit/37bfa1ba26386d1725f42ba5e108d8c72aa71e85)]:
- @react-pdf/renderer@3.1.8
## 2.0.6
### Patch Changes
- Updated dependencies [[`b194b61`](https://github.com/diegomura/react-pdf/commit/b194b619b19a7683b64d47eaa2573635e6884e8d)]:
- @react-pdf/renderer@3.1.7
## 2.0.5
### Patch Changes
- Updated dependencies [[`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905), [`f6667e7`](https://github.com/diegomura/react-pdf/commit/f6667e75449c241d02f9f44fb717a71443c555c1)]:
- @react-pdf/renderer@3.1.6
## 2.0.4
### Patch Changes
- Updated dependencies [[`f4d2b68`](https://github.com/diegomura/react-pdf/commit/f4d2b68765d146e4718140f65eeceb7e69e2cfee), [`75150ca`](https://github.com/diegomura/react-pdf/commit/75150ca137b709fcab6e7cefee9dfac6b48d5aaa)]:
- @react-pdf/renderer@3.1.5
## 2.0.3
### Patch Changes
- Updated dependencies []:
- @react-pdf/renderer@3.1.4
## 2.0.2
### Patch Changes
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81), [`d1f3d5b`](https://github.com/diegomura/react-pdf/commit/d1f3d5b9b4103705e95e2160347ee253d842ed5d), [`7eefc33`](https://github.com/diegomura/react-pdf/commit/7eefc3323390c59bf6d4f923749526831572ef1a), [`3b054b7`](https://github.com/diegomura/react-pdf/commit/3b054b711f5dc0b1c4fd29feaf85b430baad2663), [`9996158`](https://github.com/diegomura/react-pdf/commit/9996158636edf2118c4a6dcce08a00408b982993)]:
- @react-pdf/renderer@3.0.0
## 2.0.1
### Patch Changes
- [#1827](https://github.com/diegomura/react-pdf/pull/1827) [`7c1d373`](https://github.com/diegomura/react-pdf/commit/7c1d373a06b04369e762069be4b96d4e40371ecc) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from layout package
- Updated dependencies [[`6c799ec`](https://github.com/diegomura/react-pdf/commit/6c799ec1bbe17106df6db109df4a62c70e39bd24)]:
- @react-pdf/renderer@2.1.2
================================================
FILE: packages/examples/vite/README.md
================================================
> React-pdf examples
## Catalog
## License
MIT © [Diego Muracciole](http://github.com/diegomura)
================================================
FILE: packages/examples/vite/declarations.d.ts
================================================
declare module '*.jpg' {
const src: string;
export default src;
}
declare module '*.jpeg' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.ttf' {
const src: string;
export default src;
}
================================================
FILE: packages/examples/vite/package.json
================================================
{
"name": "@react-pdf/vite-example",
"version": "3.3.20",
"license": "MIT",
"private": true,
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"repository": "git@github.com:diegomura/react-pdf.git",
"scripts": {
"dev": "vite ./src --open",
"build:site": "vite build ./src"
},
"dependencies": {
"@react-pdf/renderer": "^4.3.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.17",
"vite": "^5.0.11"
}
}
================================================
FILE: packages/examples/vite/postcss.config.js
================================================
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
================================================
FILE: packages/examples/vite/src/examples/duplicated-images/index.tsx
================================================
import React from 'react';
import { Document, Page, Image, StyleSheet } from '@react-pdf/renderer';
import Quijote1 from '../../../public/quijote1.jpg';
const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 65,
paddingHorizontal: 35,
},
image: {
marginVertical: 15,
marginHorizontal: 0,
width: 520,
height: 200,
backgroundColor: 'red',
objectFit: 'fill',
objectPositionX: 'center',
objectPositionY: 'center',
borderWith: 2,
padding: 2,
borderColor: 'blue',
borderStyle: 'solid',
},
image2: {
marginVertical: 15,
marginHorizontal: 0,
width: 300,
backgroundColor: 'green',
objectFit: 'fill',
objectPositionX: 'center',
objectPositionY: 'center',
borderWith: 2,
padding: 2,
borderColor: 'blue',
borderStyle: 'solid',
},
});
const MyDoc = () => {
return (
);
};
const DuplicatedImages = () => {
return (
);
};
export default {
id: 'duplicated-images',
name: 'Duplicated Images',
description: '',
Document: DuplicatedImages,
};
================================================
FILE: packages/examples/vite/src/examples/ellipsis/index.tsx
================================================
import React from 'react';
import {
Document,
Page,
Text,
View,
StyleSheet,
Font,
} from '@react-pdf/renderer';
import RobotoFont from '../../../public/Roboto-Regular.ttf';
const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 65,
paddingHorizontal: 35,
},
text: {
fontSize: 15,
maxLines: 1,
fontColor: '#000000',
textOverflow: 'ellipsis',
fontFamily: 'Roboto',
},
});
Font.register({
family: 'Roboto',
fonts: [
{
src: RobotoFont,
fontWeight: 400,
},
],
});
const MyDoc = () => {
return (
And here here
);
};
const Ellipsis = () => {
return (
);
};
export default {
id: 'ellipsis',
name: 'Ellipsis',
description: '',
Document: Ellipsis,
};
================================================
FILE: packages/examples/vite/src/examples/emoji/index.tsx
================================================
import React from 'react';
import {
Document,
Page,
View,
Text,
Font,
StyleSheet,
} from '@react-pdf/renderer';
const styles = StyleSheet.create({
container: {
height: 700,
marginVertical: 70,
marginHorizontal: '10%',
},
text: {
fontSize: 100,
textAlign: 'center',
},
});
Font.registerEmojiSource({
format: 'png',
url: 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/',
});
const Emoji = () => (
😀💩👻🙈
);
export default {
id: 'emoji',
name: 'Emoji',
description: '',
Document: Emoji,
};
================================================
FILE: packages/examples/vite/src/examples/font-family-fallback/index.tsx
================================================
import React from 'react';
import { Document, Page, Text, StyleSheet, Font } from '@react-pdf/renderer';
import RobotoFont from '../../../public/Roboto-Regular.ttf';
import RobotoBoldFont from '../../../public/Roboto-Bold.ttf';
import RobotItalicFont from '../../../public/Roboto-Italic.ttf';
import NotoSansArabicFont from '../../../public/NotoSansArabic-Regular.ttf';
const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 45,
paddingHorizontal: 35,
position: 'relative',
},
regular: {
fontFamily: ['Roboto', 'NotoSansArabic'],
fontSize: '14',
fontWeight: 900,
},
default: {
fontFamily: ['Courier-Bold', 'NotoSansArabic'],
fontSize: '14',
},
});
Font.register({
family: 'Roboto',
fonts: [
{
src: RobotoFont,
fontStyle: 'normal',
fontWeight: 'normal',
},
{
src: RobotItalicFont,
fontStyle: 'italic',
fontWeight: 'normal',
},
{
src: RobotoBoldFont,
fontStyle: 'normal',
fontWeight: 'bold',
},
],
});
Font.register({
family: 'NotoSansArabic',
fonts: [
{
src: NotoSansArabicFont,
fontWeight: 400,
},
],
});
const MyDoc = () => {
return (
This font is default Courier
The following is partially Roboto and Noto Sans Arabic
Roboto / امتحان
The following is partially Courier-Bold and Noto Sans Arabic
Courier-Bold / امتحان
The following are multiple font families, weights, and styles all on the
same line
Roboto Normal{' / '}
Roboto Bold
{' / '}
Roboto Italic
{' / '}
Courier
);
};
const FontFamilyFallback = () => {
return (
);
};
export default {
id: 'font-family-fallback',
name: 'Font Family Fallback',
description: '',
Document: FontFamilyFallback,
};
================================================
FILE: packages/examples/vite/src/examples/font-weight/index.tsx
================================================
import React from 'react';
import { Document, Page, Text, StyleSheet, Font } from '@react-pdf/renderer';
import RobotoFont from '../../../public/Roboto-Regular.ttf';
import RobotoFontMedium from '../../../public/Roboto-Medium.ttf';
import RobotoFontBold from '../../../public/Roboto-Bold.ttf';
import RobotoFontBlack from '../../../public/Roboto-Black.ttf';
const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 45,
paddingHorizontal: 35,
position: 'relative',
},
regular: {
fontFamily: 'Roboto',
fontWeight: 400,
},
medium: {
fontFamily: 'Roboto',
fontWeight: 500,
},
bold: {
fontWeight: 600,
fontFamily: 'Roboto',
},
black: {
fontWeight: 900,
fontFamily: 'Roboto',
},
});
Font.register({
family: 'Roboto',
fonts: [
{
src: RobotoFont,
fontWeight: 400,
},
{
src: RobotoFontMedium,
fontWeight: 500,
},
{
src: RobotoFontBold,
fontWeight: 700,
},
{
src: RobotoFontBlack,
fontWeight: 900,
},
],
});
const MyDoc = () => {
return (
Regular text
Medium text
Bold text
Black text
);
};
const FontWeight = () => {
return (
);
};
export default {
id: 'font-weight',
name: 'Font Weight',
description: '',
Document: FontWeight,
};
================================================
FILE: packages/examples/vite/src/examples/forms/index.tsx
================================================
import React from 'react';
import {
Document,
Page,
View,
Text,
Checkbox,
FieldSet,
TextInput,
Select,
List,
StyleSheet,
} from '@react-pdf/renderer';
const styles = StyleSheet.create({
fieldset: {
flexDirection: 'column',
backgroundColor: 'rgba(182,28,28,0.62)',
width: '50%',
marginBottom: 50,
},
});
const MyDoc = () => {
return (
TextInput
{/* Nested works as well */}
TextInput
Checkbox (not checked)
Checkbox (checked)
Select
List
TextInput (multiline)
TextInput (no FieldSet)
Checkbox (checked, no FieldSet)
);
};
const Forms = () => {
return (
);
};
export default {
id: 'forms',
name: 'Forms',
description: '',
Document: Forms,
};
================================================
FILE: packages/examples/vite/src/examples/fractals/Fractal.tsx
================================================
import React from 'react';
import { Text, View, StyleSheet } from '@react-pdf/renderer';
const palette = [
'#781c81',
'#521b80',
'#442f8b',
'#3f4c9f',
'#4069b4',
'#4582c1',
'#4e96bd',
'#5aa6a9',
'#68b090',
'#7ab878',
'#8dbc64',
'#a2be56',
'#b7bd4b',
'#c9b843',
'#d8ae3d',
'#e29e37',
'#e78632',
'#e6672d',
'#e14427',
'#d92120',
];
const styles = StyleSheet.create({
row: {
flexGrow: 1,
width: '100%',
flexDirection: 'row',
},
column: {
flexGrow: 1,
height: '100%',
flexDirection: 'column',
},
text: {
margin: 10,
fontSize: 10,
color: 'white',
},
});
const toggle = (direction) => (direction === 'column' ? 'row' : 'column');
const Fractal = ({ steps, direction = 'column' }) => {
if (steps === 0) {
return null;
}
const fractalStyle = {
flexGrow: 1,
minWidth: 40,
minHeight: 40,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: palette[steps % palette.length],
};
return (
{steps}
);
};
export default Fractal;
================================================
FILE: packages/examples/vite/src/examples/fractals/index.tsx
================================================
import React from 'react';
import { Page, Document } from '@react-pdf/renderer';
import Fractal from './Fractal';
const Fractals = () => (
);
export default {
id: 'fractals',
name: 'Fractals',
description: '',
Document: Fractals,
};
================================================
FILE: packages/examples/vite/src/examples/go-to/index.tsx
================================================
import React from 'react';
import { Page, Document, Link, View, Image } from '@react-pdf/renderer';
const GoTo = () => (
Link to Image
);
export default {
id: 'go-to',
name: 'Go To',
description: '',
Document: GoTo,
};
================================================
FILE: packages/examples/vite/src/examples/image-stress-test/index.tsx
================================================
import React from 'react';
import { Document, Page, Image } from '@react-pdf/renderer';
const IMAGES = [
'https://images.unsplash.com/photo-1726557116827-5f2a95d57cab?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726669251120-46ff8c7ce9a3?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726706805887-0ac0e0d3a721?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726527612459-54b061d9c48d?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726533815259-8fe320ac2493?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726392660865-cbf2dc1459b6?q=80&w=3475&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726533862204-8110e6193fe9?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726688205209-c80317c116d3?q=80&w=3493&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726486896376-4d1340e2f672?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725727532120-8b2d88f47fe3?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726121678240-9126d5017990?q=80&w=3558&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726408093361-238693a8d51d?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724279797190-8371a9939494?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726090102306-49df28adaf0f?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1723877896976-8eb1cc6f07b1?q=80&w=2821&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725817901136-70a686d60386?q=80&w=3428&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726247419938-a8980d9fa429?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726092707889-c4ef049d22df?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726436877670-020a158bef47?q=80&w=3542&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725610588109-71d0def86e19?q=80&w=3500&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726182916337-38dca644bc65?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725610588095-f117c0e2a921?q=80&w=3500&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726138400966-63461367804d?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726182886720-9bcfa08da27a?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725714356329-f56f6054f169?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726182875049-a8283fed88da?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxleHBsb3JlLWZlZWR8MjU3fHx8ZW58MHx8fHx8',
'https://images.unsplash.com/photo-1725882393508-6652bd21b22c?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726059968922-0396248fdaea?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725652800358-ae3a752cfb68?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726044781679-7c3f20a185ec?q=80&w=3329&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725715443838-1574b8eb1c3a?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725714835081-118a2b0456b2?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725961476494-efa87ae3106a?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725714834280-0c7584637d06?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1726041453467-5fa7dce0251d?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725733802754-c2a87bda47b2?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725610588086-b9e38da987f7?q=80&w=3500&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725663656850-7bc515816fcd?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725900737080-54b5a571b38c?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1709141425206-f5cdeab3e718?q=80&w=3301&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725922638181-3dbab8df0f95?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725864832531-f50f4639dd00?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725961475845-a656bc03c758?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1723662887372-b6f42b6ccd50?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725493280276-658ff7d29fd3?q=80&w=3542&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725832062946-2ec9aae5c4e2?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725638265979-4ff4b828ed5c?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725006705487-36dd870acb7a?q=80&w=3304&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725610588145-a508e5cfe90b?q=80&w=3500&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725610588149-adc351ad606d?q=80&w=3500&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725615357444-6123528686cf?q=80&w=3538&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724589613596-e269be5c0849?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725113114049-31121918636c?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725565175662-3618048d8be2?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1723039914210-a6f13a6931af?q=80&w=3542&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725492114409-01a24b173dbe?q=80&w=3000&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725133306731-fd82b613300f?q=80&w=3542&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725493280155-e8f61af1b65b?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724582586529-62622e50c0b3?q=80&w=3328&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725493279974-ab7bc4e537c8?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725468697616-e35f25d5b0c4?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725449670931-b53a7cb689b9?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724123301969-22859c2a3823?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724437208913-3b82b15fc078?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724699174715-ac3751fe8995?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725053864071-f37ebb5a9d22?q=80&w=3473&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725042893312-5ec0dea9e369?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725072730410-51ca1348c521?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxleHBsb3JlLWZlZWR8NjQ1fHx8ZW58MHx8fHx8',
'https://images.unsplash.com/photo-1724525647096-116d4bacbd5f?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724596314963-c71d1e58204d?q=80&w=3328&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725113160838-9efa2a25aa0b?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725267385461-cab515fc1bbe?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxleHBsb3JlLWZlZWR8NjY5fHx8ZW58MHx8fHx8',
'https://images.unsplash.com/photo-1725067807346-7340abf76b0d?q=80&w=3536&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725181959662-af4acf689235?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724591634731-5c6004fe6136?q=80&w=3542&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724748860101-589aa7ee8b29?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxleHBsb3JlLWZlZWR8NjgyfHx8ZW58MHx8fHx8',
'https://images.unsplash.com/photo-1724786594301-9a00b6ee8704?q=80&w=3295&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724963475892-a3274091955e?q=80&w=3432&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725006709387-d820b307a1f2?q=80&w=3538&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1725014880788-9faccc7ca16e?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxleHBsb3JlLWZlZWR8NzIyfHx8ZW58MHx8fHx8',
'https://images.unsplash.com/photo-1724908549265-06972c22ca37?q=80&w=3540&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724858103760-62648ebfa2a3?q=80&w=3130&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724757090342-59922ed19e39?q=80&w=3300&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
'https://images.unsplash.com/photo-1724689545475-67ff5bc78fac?q=80&w=3360&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
];
const ImageStressTest = () => (
{IMAGES.map((src) => (
))}
);
export default {
id: 'image-steess-test',
name: 'Image Stress Test',
description: '',
Document: ImageStressTest,
};
================================================
FILE: packages/examples/vite/src/examples/index.ts
================================================
import duplicatedImages from './duplicated-images';
import ellipsis from './ellipsis';
import emoji from './emoji';
import fontFamilyFallback from './font-family-fallback';
import fontWeight from './font-weight';
import fractals from './fractals';
import goTo from './go-to';
import imageStressTest from './image-stress-test';
import JpgOrientation from './jpg-orientation';
import knobs from './knobs';
import link from './link';
import mediaQueries from './media-queries';
import minPresenceAhead from './min-presence-ahead';
import multilineText from './multiline-text';
import objectFit from './object-fit';
import pageWrap from './page-wrap';
import resume from './resume';
import svg from './svg';
import svgTransform from './svg-transform';
import transformOrigin from './transform-origin';
import forms from './forms';
import softHyphens from './soft-hyphens';
const EXAMPLES = [
duplicatedImages,
ellipsis,
emoji,
fontFamilyFallback,
fontWeight,
fractals,
goTo,
JpgOrientation,
knobs,
link,
mediaQueries,
minPresenceAhead,
multilineText,
objectFit,
pageWrap,
resume,
svg,
svgTransform,
transformOrigin,
imageStressTest,
forms,
softHyphens,
];
export default EXAMPLES;
================================================
FILE: packages/examples/vite/src/examples/jpg-orientation/index.tsx
================================================
import React from 'react';
import { Document, Page, Image, View } from '@react-pdf/renderer';
import Orientation1 from './images/orientation-1.jpeg';
import Orientation2 from './images/orientation-2.jpeg';
import Orientation3 from './images/orientation-3.jpeg';
import Orientation4 from './images/orientation-4.jpeg';
import Orientation5 from './images/orientation-5.jpeg';
import Orientation6 from './images/orientation-6.jpeg';
import Orientation7 from './images/orientation-7.jpeg';
import Orientation8 from './images/orientation-8.jpeg';
const JpgOrientation = () => (
);
export default {
id: 'jpg-orientation',
name: 'Jpg Orientation',
description: '',
Document: JpgOrientation,
};
================================================
FILE: packages/examples/vite/src/examples/knobs/index.tsx
================================================
import React from 'react';
import { Document, Page, View, Text, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
select: {
height: '9%',
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: '30px',
},
bar: {
flexGrow: 1,
height: '10px',
backgroundColor: 'gray',
},
barMiddle: {
width: '50%',
height: '100%',
backgroundColor: 'lightgray',
margin: 'auto',
},
knob: {
alignItems: 'center',
justifyContent: 'center',
width: '20px',
height: '20px',
borderRadius: 10,
borderWidth: 3,
borderColor: 'orange',
position: 'absolute',
backgroundColor: 'white',
fontSize: 8,
top: -6,
},
text: {
fontSize: 10,
},
});
const Knob = ({ value }) => (
{value}
);
const Select = (props) => (
0%
100%
);
const Knobs = () => (
);
export default {
id: 'knobs',
name: 'Knobs',
description: '',
Document: Knobs,
};
================================================
FILE: packages/examples/vite/src/examples/link/index.tsx
================================================
import React from 'react';
import { Document, Page, Link, Text, View } from '@react-pdf/renderer';
const LinkExample = () => (
Some text link
Some stylized text link
Some stylized text
link
);
export default {
id: 'link',
name: 'Link',
description: '',
Document: LinkExample,
};
================================================
FILE: packages/examples/vite/src/examples/media-queries/index.tsx
================================================
import React from 'react';
import { Document, Page, View, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
body: {
padding: 35,
},
content: {
padding: 20,
'@media max-width: 400': {
flexDirection: 'column',
},
'@media min-width: 400': {
flexDirection: 'row',
},
},
block: {
height: 150,
width: 150,
backgroundColor: 'red',
},
});
const MediaComponent = () => (
);
const MediaQueries = () => (
);
export default {
id: 'media-queries',
name: 'Media Queries',
description: '',
Document: MediaQueries,
};
================================================
FILE: packages/examples/vite/src/examples/min-presence-ahead/index.tsx
================================================
import React from 'react';
import { Document, Page, View, Text } from '@react-pdf/renderer';
const palette = [
'#781c81',
'#521b80',
'#442f8b',
'#3f4c9f',
'#4069b4',
'#4582c1',
'#4e96bd',
'#5aa6a9',
'#68b090',
'#7ab878',
'#8dbc64',
'#a2be56',
];
const MinPresenceAhead = () => (
{palette.map((color, i) => {
const minPresenceAhead = i === 8 ? 82 : 0;
return (
Index: {i}
MinPresenceAhead: {minPresenceAhead}
);
})}
);
export default {
id: 'min-presence-ahead',
name: 'Min Presence Ahead',
description: '',
Document: MinPresenceAhead,
};
================================================
FILE: packages/examples/vite/src/examples/multiline-text/index.tsx
================================================
import React from 'react';
import { Document, Page, View, Text, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
body: {
margin: 50,
},
highlight: {
backgroundColor: 'tomato',
textDecoration: 'line-through underline',
},
});
const MultilineText = () => (
Single line text with{' '}
inline text highlighted Again
Black Text
Nested Text with{' '}
inline text highlighted in a
long, long, long, long, long, long long
);
export default {
id: 'multiline-text',
name: 'Multiline Text',
description: '',
Document: MultilineText,
};
================================================
FILE: packages/examples/vite/src/examples/object-fit/index.tsx
================================================
import React from 'react';
import {
Document,
Page,
View,
Image,
Text,
StyleSheet,
} from '@react-pdf/renderer';
const styles = StyleSheet.create({
image: {
objectFit: 'contain',
objectPosition: '0%',
width: '100%',
height: '100%',
},
surrounding: {
width: '200pt',
height: '200pt',
border: '1px solid red',
backgroundColor: 'tomato',
marginBottom: '10',
},
});
const ObjectFit = () => (
Object Fit Contain
Object Fit: Auto
Object Fit: None
);
export default {
id: 'object-fit',
name: 'Object Fit',
description: '',
Document: ObjectFit,
};
================================================
FILE: packages/examples/vite/src/examples/page-wrap/index.tsx
================================================
import React from 'react';
import {
Document,
Font,
Text,
Page,
Image,
StyleSheet,
} from '@react-pdf/renderer';
import Quijote1 from '../../../public/quijote1.jpg';
import Quijote2 from '../../../public/quijote2.png';
Font.register({
family: 'Oswald',
src: 'https://fonts.gstatic.com/s/oswald/v13/Y_TKV6o8WovbUd3m_X9aAA.ttf',
});
const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 65,
paddingHorizontal: 35,
},
title: {
fontSize: 24,
textAlign: 'center',
fontFamily: ['Oswald', 'Helvetica'],
},
author: {
fontSize: 12,
textAlign: 'center',
marginBottom: 40,
},
subtitle: {
fontSize: 18,
margin: 12,
fontFamily: 'Oswald',
},
text: {
margin: 12,
fontSize: 14,
textAlign: 'justify',
fontFamily: 'Times-Roman',
},
image: {
marginVertical: 15,
marginHorizontal: 100,
},
header: {
fontSize: 12,
marginBottom: 20,
textAlign: 'center',
color: 'grey',
},
pageNumber: {
position: 'absolute',
fontSize: 12,
bottom: 30,
left: 0,
right: 0,
textAlign: 'center',
color: 'grey',
},
});
const PageWrap = () => (
~ Created with react-pdf ~
Don Quijote de la Mancha
Miguel de Cervantes
Capítulo I: Que trata de la condición y ejercicio del famoso hidalgo D.
Quijote de la Mancha
En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha
mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga
antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que
carnero, salpicón las más noches, duelos y quebrantos los sábados,
lentejas los viernes, algún palomino de añadidura los domingos,
consumían las tres partes de su hacienda. El resto della concluían sayo
de velarte, calzas de velludo para las fiestas con sus pantuflos de lo
mismo, los días de entre semana se honraba con su vellori de lo más
fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina
que no llegaba a los veinte, y un mozo de campo y plaza, que así
ensillaba el rocín como tomaba la podadera. Frisaba la edad de nuestro
hidalgo con los cincuenta años, era de complexión recia, seco de carnes,
enjuto de rostro; gran madrugador y amigo de la caza. Quieren decir que
tenía el sobrenombre de Quijada o Quesada (que en esto hay alguna
diferencia en los autores que deste caso escriben), aunque por
conjeturas verosímiles se deja entender que se llama Quijana; pero esto
importa poco a nuestro cuento; basta que en la narración dél no se salga
un punto de la verdad
Es, pues, de saber, que este sobredicho hidalgo, los ratos que estaba
ocioso (que eran los más del año) se daba a leer libros de caballerías
con tanta afición y gusto, que olvidó casi de todo punto el ejercicio de
la caza, y aun la administración de su hacienda; y llegó a tanto su
curiosidad y desatino en esto, que vendió muchas hanegas de tierra de
sembradura, para comprar libros de caballerías en que leer; y así llevó
a su casa todos cuantos pudo haber dellos; y de todos ningunos le
parecían tan bien como los que compuso el famoso Feliciano de Silva:
porque la claridad de su prosa, y aquellas intrincadas razones suyas, le
parecían de perlas; y más cuando llegaba a leer aquellos requiebros y
cartas de desafío, donde en muchas partes hallaba escrito: la razón de
la sinrazón que a mi razón se hace, de tal manera mi razón enflaquece,
que con razón me quejo de la vuestra fermosura, y también cuando leía:
los altos cielos que de vuestra divinidad divinamente con las estrellas
se fortifican, y os hacen merecedora del merecimiento que merece la
vuestra grandeza.
Con estas y semejantes razones perdía el pobre caballero el juicio, y
desvelábase por entenderlas, y desentrañarles el sentido, que no se lo
sacara, ni las entendiera el mismo Aristóteles, si resucitara para sólo
ello. No estaba muy bien con las heridas que don Belianis daba y
recibía, porque se imaginaba que por grandes maestros que le hubiesen
curado, no dejaría de tener el rostro y todo el cuerpo lleno de
cicatrices y señales; pero con todo alababa en su autor aquel acabar su
libro con la promesa de aquella inacabable aventura, y muchas veces le
vino deseo de tomar la pluma, y darle fin al pie de la letra como allí
se promete; y sin duda alguna lo hiciera, y aun saliera con ello, si
otros mayores y continuos pensamientos no se lo estorbaran. Tuvo muchas
veces competencia con el cura de su lugar (que era hombre docto graduado
en Sigüenza), sobre cuál había sido mejor caballero, Palmerín de
Inglaterra o Amadís de Gaula; mas maese Nicolás, barbero del mismo
pueblo, decía que ninguno llegaba al caballero del Febo, y que si alguno
se le podía comparar, era don Galaor, hermano de Amadís de Gaula, porque
tenía muy acomodada condición para todo; que no era caballero
melindroso, ni tan llorón como su hermano, y que en lo de la valentía no
le iba en zaga.
En resolución, él se enfrascó tanto en su lectura, que se le pasaban las
noches leyendo de claro en claro, y los días de turbio en turbio, y así,
del poco dormir y del mucho leer, se le secó el cerebro, de manera que
vino a perder el juicio. Llenósele la fantasía de todo aquello que leía
en los libros, así de encantamientos, como de pendencias, batallas,
desafíos, heridas, requiebros, amores, tormentas y disparates
imposibles, y asentósele de tal modo en la imaginación que era verdad
toda aquella máquina de aquellas soñadas invenciones que leía, que para
él no había otra historia más cierta en el mundo.
Capítulo II: Que trata de la primera salida que de su tierra hizo el
ingenioso Don Quijote
Hechas, pues, estas prevenciones, no quiso aguardar más tiempo a poner
en efeto su pensamiento, apretándole a ello la falta que él pensaba que
hacía en el mundo su tardanza, según eran los agravios que pensaba
deshacer, tuertos que enderezar, sinrazones que emendar y abusos que
mejorar y deudas que satisfacer. Y así, sin dar parte a persona alguna
de su intención y sin que nadie le viese, una mañana, antes del día, que
era uno de los calurosos del mes de Julio, se armó de todas sus armas,
subió sobre Rocinante, puesta su mal compuesta celada, embrazó su
adarga, tomó su lanza y por la puerta falsa de un corral salió al campo
con grandísimo contento y alborozo de ver con cuánta facilidad había
dado principio a su buen deseo. Mas apenas se vio en el campo cuando le
asaltó un pensamiento terrible, y tal, que por poco le hiciera dejar la
comenzada empresa; y fue que le vino a la memoria que no era armado
caballero, y que, conforme a ley de caballería, ni podía ni debía tomar
armas con ningún caballero; y puesto que lo fuera, había de llevar armas
blancas, como novel caballero, sin empresa en el escudo, hasta que por
su esfuerzo la ganase. Estos pensamientos le hicieron titubear en su
propósito; mas pudiendo más su locura que otra razón alguna, propuso de
hacerse armar caballero del primero que topase, a imitación de otros
muchos que así lo hicieron, según él había leído en los libros que tal
le tenían. En lo de las armas blancas, pensaba limpiarlas de manera, en
teniendo lugar, que lo fuesen más que un arminio; y con esto se quietó18
y prosiguió su camino, sin llevar otro que aquel que su caballo quería,
creyendo que en aquello consistía la fuerza de las aventuras
Yendo, pues, caminando nuestro flamante aventurero, iba hablando consigo
mesmo, y diciendo: —¿Quién duda, sino que en los venideros tiempos,
cuando salga a luz la verdadera historia de mis famosos hechos, que el
sabio que los escribiere no ponga, cuando llegue a contar esta mi
primera salida tan de mañana, desta manera?: Apenas había el rubicundo
Apolo tendido por la faz de la ancha y espaciosa tierra las doradas
hebras de sus hermosos cabellos, y apenas los pequeños y pintados
pajarillos con sus arpadas lenguas habían saludado con dulce y meliflua
armonía la venida de la rosada Aurora, que, dejando la blanda cama del
celoso marido, por las puertas y balcones del manchego horizonte a los
mortales se mostraba, cuando el famoso caballero don Quijote de la
Mancha, dejando las ociosas plumas, subió sobre su famoso caballo
Rocinante y comenzó a caminar por el antiguo y conocido Campo de
Montiel.
Y era la verdad que por él caminaba; y añadió diciendo: —Dichosa edad y
siglo dichoso aquel adonde saldrán a luz las famosas hazañas mías,
dignas de entallarse en bronces, esculpirse en mármoles y pintarse en
tablas, para memoria en lo futuro. ¡Oh tú, sabio encantador, quienquiera
que seas, a quien ha de tocar el ser coronista desta peregrina historia!
Ruégote que no te olvides de mi buen Rocinante, compañero eterno mío en
todos mis caminos y carreras.
Luego volvía diciendo, como si verdaderamente fuera enamorado: —¡Oh
princesa Dulcinea, señora deste cautivo corazón! Mucho agravio me
habedes fecho en despedirme y reprocharme con el riguroso afincamiento
de mandarme no parecer ante la vuestra fermosura. Plégaos, señora, de
membraros deste vuestro sujeto corazón, que tantas cuitas por vuestro
amor padece. Con estos iba ensartando otros disparates, todos al modo de
los que sus libros le habían enseñado, imitando en cuanto podía su
lenguaje. Con esto caminaba tan despacio, y el sol entraba tan apriesa y
con tanto ardor, que fuera bastante a derretirle los sesos, si algunos
tuviera
Casi todo aquel día caminó sin acontecerle cosa que de contar fuese, de
lo cual se desesperaba, porque quisiera topar luego luego con quien
hacer experiencia del valor de su fuerte brazo. Autores hay que dicen
que la primera aventura que le avino fue la del Puerto Lápice, otros
dicen que la de los molinos de viento; pero lo que yo he podido
averiguar en este caso, y lo que he hallado escrito en los anales de la
Mancha, es que él anduvo todo aquel día, y, al anochecer, su rocín y él
se hallaron cansados y muertos de hambre, y que, mirando a todas partes
por ver si descubriría algún castillo o alguna majada de pastores donde
recogerse y adonde pudiese remediar su mucha hambre y necesidad, vio, no
lejos del camino por donde iba, una venta,que fue como si viera una
estrella que, no a los portales, sino a los alcázares de su redención le
encaminaba. Diose priesa a caminar, y llegó a ella a tiempo que
anochecía.
`${pageNumber} / ${totalPages}`}
/>
);
export default {
id: 'page-wrap',
name: 'Page Wrap',
description: '',
Document: PageWrap,
};
================================================
FILE: packages/examples/vite/src/examples/resume/Education.tsx
================================================
import React from 'react';
import { Text, View, StyleSheet } from '@react-pdf/renderer';
import Title from './Title';
const styles = StyleSheet.create({
container: {
marginBottom: 10,
},
school: {
fontFamily: 'Lato Bold',
fontSize: 10,
},
degree: {
fontFamily: 'Lato',
fontSize: 10,
},
candidate: {
fontFamily: 'Lato Italic',
fontSize: 10,
},
});
const Education = () => (
Education
Jedi Academy
Jedi Master
A long, long time ago
);
export default Education;
================================================
FILE: packages/examples/vite/src/examples/resume/Experience.tsx
================================================
import React from 'react';
import { Text, View, StyleSheet } from '@react-pdf/renderer';
import Title from './Title';
import List, { Item } from './List';
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 30,
paddingLeft: 15,
'@media max-width: 400': {
paddingTop: 10,
paddingLeft: 0,
},
},
entryContainer: {
marginBottom: 10,
},
date: {
fontSize: 11,
fontFamily: 'Lato Italic',
},
detailLeftColumn: {
flexDirection: 'column',
marginLeft: 10,
marginRight: 10,
},
detailRightColumn: {
flexDirection: 'column',
flexGrow: 9,
},
bulletPoint: {
fontSize: 10,
},
details: {
fontSize: 10,
fontFamily: 'Lato',
},
headerContainer: {
flexDirection: 'row',
marginBottom: 10,
},
leftColumn: {
flexDirection: 'column',
flexGrow: 9,
},
rightColumn: {
flexDirection: 'column',
flexGrow: 1,
alignItems: 'flex-end',
justifySelf: 'flex-end',
},
title: {
fontSize: 11,
color: 'black',
textDecoration: 'none',
fontFamily: 'Lato Bold',
},
});
const ExperienceEntry = ({ company, details, position, date }) => {
const title = `${company} | ${position}`;
return (
{title}
{date}
{details.map((detail) => (
- {detail}
))}
);
};
const experienceData = [
{
company: 'Jedi Temple, Coruseant',
date: 'A long time ago...',
details: [
'Started a new Jedi Temple in order to train the next generation of Jedi Masters',
'Discovered and trained a new generation of Jedi Knights, which he recruited from within the New Republic',
'Communicates with decesased Jedi Masters such as Anakin Skywalker, Yoda, Obi-Wan Kenobi in order to learn the secrets of the Jedi Order',
],
position: 'Head Jedi Master',
},
{
company: 'Rebel Alliance',
date: 'A long time ago...',
details: [
'Lead legions of troops into battle while demonstrating bravery, competence and honor',
'Created complicated battle plans in conjunction with other Rebel leaders in order to ensure the greatest chance of success',
'Defeated Darth Vader in single-combat, and convinced him to betray his mentor, the Emperor',
],
position: 'General',
},
{
company: 'Rebel Alliance',
date: 'A long time ago...',
details: [
'Destroyed the Death Star by using the force to find its only weakness and delivering a torpedo into the center of the ship',
'Commanded of squadron of X-Wings into battle',
'Defeated an enemy AT-AT single handedly after his ship was destroyed',
'Awarded a medal for valor and bravery in battle for his successful destruction of the Death Star',
],
position: 'Lieutenant Commander',
},
{
company: 'Tatooine Moisture Refinery',
date: 'A long time ago...',
details: [
'Replaced damaged power converters',
'Performed menial labor thoughout the farm in order to ensure its continued operation',
],
position: 'Moisture Farmer',
},
];
const Experience = () => (
Experience
{experienceData.map(({ company, date, details, position }) => (
))}
);
export default Experience;
================================================
FILE: packages/examples/vite/src/examples/resume/Header.tsx
================================================
import React from 'react';
import { Link, Text, View, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
borderBottomWidth: 2,
borderBottomColor: '#112131',
borderBottomStyle: 'solid',
alignItems: 'stretch',
},
detailColumn: {
flexDirection: 'column',
flexGrow: 9,
textTransform: 'uppercase',
},
linkColumn: {
flexDirection: 'column',
flexGrow: 2,
alignSelf: 'flex-end',
justifySelf: 'flex-end',
},
name: {
fontSize: 24,
fontFamily: 'Lato Bold',
},
subtitle: {
fontSize: 10,
justifySelf: 'flex-end',
fontFamily: 'Lato',
},
link: {
fontFamily: 'Lato',
fontSize: 10,
color: 'black',
textDecoration: 'none',
alignSelf: 'flex-end',
justifySelf: 'flex-end',
},
});
const Header = () => (
Luke Skywalker
Jedi Master
luke@theforce.com
);
export default Header;
================================================
FILE: packages/examples/vite/src/examples/resume/List.tsx
================================================
import React from 'react';
import { Text, View, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
item: {
flexDirection: 'row',
marginBottom: 5,
},
bulletPoint: {
width: 10,
fontSize: 10,
},
itemContent: {
flex: 1,
fontSize: 10,
fontFamily: 'Lato',
},
});
const List = ({ children }) => children;
export const Item = ({ children }) => (
•
{children}
);
export default List;
================================================
FILE: packages/examples/vite/src/examples/resume/Skills.tsx
================================================
import React from 'react';
import { Text, View, StyleSheet } from '@react-pdf/renderer';
import Title from './Title';
import List, { Item } from './List';
const styles = StyleSheet.create({
title: {
fontFamily: 'Lato Bold',
fontSize: 11,
marginBottom: 10,
},
skills: {
fontFamily: 'Lato',
fontSize: 10,
marginBottom: 10,
},
});
const SkillEntry = ({ name, skills }) => (
{name}
{skills.map((skill) => (
- {skill}
))}
);
const Skills = () => (
Skills
);
export default Skills;
================================================
FILE: packages/examples/vite/src/examples/resume/Title.tsx
================================================
import React from 'react';
import { Text, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
title: {
fontFamily: 'Lato Bold',
fontSize: 14,
marginBottom: 10,
textTransform: 'uppercase',
},
});
const Title = ({ children }) => {children} ;
export default Title;
================================================
FILE: packages/examples/vite/src/examples/resume/index.tsx
================================================
import React from 'react';
import {
Text,
Font,
Page,
View,
Image,
Document,
StyleSheet,
} from '@react-pdf/renderer';
import Header from './Header';
import Skills from './Skills';
import Education from './Education';
import Experience from './Experience';
const styles = StyleSheet.create({
page: {
padding: 30,
},
container: {
flex: 1,
flexDirection: 'row',
'@media max-width: 400': {
flexDirection: 'column',
},
},
image: {
marginBottom: 10,
},
leftColumn: {
flexDirection: 'column',
width: 170,
paddingTop: 30,
paddingRight: 15,
'@media max-width: 400': {
width: '100%',
paddingRight: 0,
},
'@media orientation: landscape': {
width: 200,
},
},
footer: {
fontSize: 12,
fontFamily: 'Lato Bold',
textAlign: 'center',
marginTop: 15,
paddingTop: 5,
borderWidth: 3,
borderColor: 'gray',
borderStyle: 'dashed',
'@media orientation: landscape': {
marginTop: 10,
},
},
});
Font.register({
family: 'Open Sans',
src: `https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-UFVZ0e.ttf`,
});
Font.register({
family: 'Lato',
src: `https://fonts.gstatic.com/s/lato/v16/S6uyw4BMUTPHjx4wWw.ttf`,
});
Font.register({
family: 'Lato Italic',
src: `https://fonts.gstatic.com/s/lato/v16/S6u8w4BMUTPHjxsAXC-v.ttf`,
});
Font.register({
family: 'Lato Bold',
src: `https://fonts.gstatic.com/s/lato/v16/S6u9w4BMUTPHh6UVSwiPHA.ttf`,
});
const IMAGE_SRC =
'https://i.guim.co.uk/img/media/a23aeb1f7ff20bb80f68852da17743b0e557f8ed/0_224_3504_2102/master/3504.jpg?width=1200&height=1200&quality=85&auto=format&fit=crop&s=9e9a99e479ee60270b69ede4d869b20f';
const Resume = (props) => (
This IS the candidate you are looking for
);
const ResumeDocument = () => (
);
export default {
id: 'resume',
name: 'Resume',
description: '',
Document: ResumeDocument,
};
================================================
FILE: packages/examples/vite/src/examples/soft-hyphens/index.tsx
================================================
import React from 'react';
import { Document, Page, Font, Text, StyleSheet } from '@react-pdf/renderer';
const shy = '\u00ad';
Font.register({
family: 'Oswald',
src: 'https://fonts.gstatic.com/s/oswald/v13/Y_TKV6o8WovbUd3m_X9aAA.ttf',
});
const styles = StyleSheet.create({
body: {
padding: 20,
},
text: {
fontFamily: 'Oswald',
fontSize: 20,
width: 100,
border: '1px solid red',
},
});
const SoftHyphens = () => (
{`Potentieel broeikas${shy}gas${shy}emissie${shy}rapport`}
);
export default {
id: 'soft-hyphens',
name: 'Soft Hyphens',
description: '',
Document: SoftHyphens,
};
================================================
FILE: packages/examples/vite/src/examples/svg/Car.tsx
================================================
import * as React from 'react';
import {
Svg,
Defs,
LinearGradient,
RadialGradient,
Stop,
Path,
G,
} from '@react-pdf/renderer';
const Car = () => (
);
export default Car;
================================================
FILE: packages/examples/vite/src/examples/svg/Heart.tsx
================================================
import React from 'react';
import { Svg, G, Path } from '@react-pdf/renderer';
const Heart = () => (
);
export default Heart;
================================================
FILE: packages/examples/vite/src/examples/svg/Pattern.tsx
================================================
import React from 'react';
import { Svg, G, Path } from '@react-pdf/renderer';
const Chart = () => {
return (
);
};
export default Chart;
================================================
FILE: packages/examples/vite/src/examples/svg/Star.tsx
================================================
import React from 'react';
import { Svg, Path } from '@react-pdf/renderer';
const Star = () => (
);
export default Star;
================================================
FILE: packages/examples/vite/src/examples/svg/Svg1.tsx
================================================
import React from 'react';
import { Rect, Svg, G, Path, Text, Tspan } from '@react-pdf/renderer';
const Svg1 = () => (
USD
USD
EUR
EUR
CHF
CHF
);
export default Svg1;
================================================
FILE: packages/examples/vite/src/examples/svg/Svg2.tsx
================================================
import React from 'react';
import {
Rect,
Svg,
G,
Path,
Text,
Defs,
ClipPath,
Tspan,
LinearGradient,
Stop,
} from '@react-pdf/renderer';
const Svg2 = () => (
2015
2016
2017
2018
2019
0%
5%
10%
15%
20%
25%
30%
35%
Zoom
YTD
All
From
Nov 17, 2014
To
Nov 22, 2019
);
export default Svg2;
================================================
FILE: packages/examples/vite/src/examples/svg/Svg4.tsx
================================================
import React from 'react';
import {
Svg,
Stop,
Defs,
Circle,
LinearGradient,
RadialGradient,
} from '@react-pdf/renderer';
const Svg4 = () => (
);
export default Svg4;
================================================
FILE: packages/examples/vite/src/examples/svg/index.tsx
================================================
import React from 'react';
import { Document, Page, StyleSheet } from '@react-pdf/renderer';
import Svg0 from './svg';
import Svg1 from './Svg1';
import Svg2 from './Svg2';
import Svg4 from './Svg4';
import Star from './Star';
import Heart from './Heart';
import Pattern from './Pattern';
import Car from './Car';
const styles = StyleSheet.create({
page: {
fontSize: 20,
color: 'black',
padding: '10',
},
});
const App = () => {
return (
);
};
export default {
id: 'svg',
name: 'Svg',
description: '',
Document: App,
};
================================================
FILE: packages/examples/vite/src/examples/svg/svg.tsx
================================================
import React from 'react';
import { Svg, G, Polygon } from '@react-pdf/renderer';
const Tiger = () => (
);
export default Tiger;
================================================
FILE: packages/examples/vite/src/examples/svg-transform/index.tsx
================================================
import React from 'react';
import { Document, Page, Svg, G, Rect } from '@react-pdf/renderer';
const COLORS = ['red', 'green', 'blue', 'yellow', 'purple'];
const randBetween = (min, max) =>
Math.floor(Math.random() * (max - min + 1) + min);
const SvgTransform = () => {
return (
{Array.from({ length: 200 }).map((_, i) => (
))}
);
};
export default {
id: 'svg-transform',
name: 'Svg Transform',
description: '',
Document: SvgTransform,
};
================================================
FILE: packages/examples/vite/src/examples/transform-origin/index.tsx
================================================
import React from 'react';
import { Document, Page, View } from '@react-pdf/renderer';
const Box = ({ origin }) => (
);
const TransformOrigin = () => {
return (
);
};
export default {
id: 'transform-origin',
name: 'Transform Origin',
description: '',
Document: TransformOrigin,
};
================================================
FILE: packages/examples/vite/src/index.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
================================================
FILE: packages/examples/vite/src/index.html
================================================
Vite + React
================================================
FILE: packages/examples/vite/src/index.tsx
================================================
import './index.css';
import React, { useEffect, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { PDFViewer } from '@react-pdf/renderer';
import EXAMPLES from './examples';
const ExamplesPage = () => {
const [hash, setHash] = useState(
window.location.hash.substring(1) || 'page-wrap',
);
const index = EXAMPLES.findIndex((example) => example.id === hash);
useEffect(() => {
const listener = (event) =>
setHash(event.target.location.hash.substring(1));
window.addEventListener('popstate', listener);
return () => window.removeEventListener('popstate', listener);
});
const { Document } = EXAMPLES[index];
return (
);
};
const MOUNT_ELEMENT = document.createElement('div');
document.body.appendChild(MOUNT_ELEMENT);
const root = createRoot(MOUNT_ELEMENT);
root.render( );
================================================
FILE: packages/examples/vite/tailwind.config.js
================================================
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {},
},
plugins: [],
};
================================================
FILE: packages/examples/vite/vite.config.js
================================================
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
});
================================================
FILE: packages/fns/.gitignore
================================================
lib
================================================
FILE: packages/fns/CHANGELOG.md
================================================
# @react-pdf/fns
## 3.1.2
### Patch Changes
- [#3092](https://github.com/diegomura/react-pdf/pull/3092) [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert layout package to TS
## 3.1.1
### Patch Changes
- [#3082](https://github.com/diegomura/react-pdf/pull/3082) [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45) Thanks [@diegomura](https://github.com/diegomura)! - feat: rework and type stylesheet package
- [#3077](https://github.com/diegomura/react-pdf/pull/3077) [`442ce355`](https://github.com/diegomura/react-pdf/commit/442ce35534f916b9146a35fd03870387ed488d92) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert textkit package to TS
- [#3070](https://github.com/diegomura/react-pdf/pull/3070) [`3007d34a`](https://github.com/diegomura/react-pdf/commit/3007d34ad3e10bf32ada3631938f5bb08e1c549f) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert fns package to TS
## 3.1.0
### Minor Changes
- [`d36ace66`](https://github.com/diegomura/react-pdf/commit/d36ace66c77d57d845894e89772be7ae0cdd25ee) Thanks [@diegomura](https://github.com/diegomura)! - feat: add without fn
## 3.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
## 2.2.1
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
## 2.2.0
### Minor Changes
- [#2600](https://github.com/diegomura/react-pdf/pull/2600) [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7) Thanks [@diegomura](https://github.com/diegomura)! - feat: bidi support
## 2.1.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
## 2.0.1
### Patch Changes
- [#2215](https://github.com/diegomura/react-pdf/pull/2215) [`eff1ff0`](https://github.com/diegomura/react-pdf/commit/eff1ff0fefcd710994e4654904ef55843af76a17) Thanks [@jeetiss](https://github.com/jeetiss)! - add @babel/runtime as dependency
## 2.0.0
### Major Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
## 1.0.0
### Major Changes
- [#1838](https://github.com/diegomura/react-pdf/pull/1838) [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de) Thanks [@diegomura](https://github.com/diegomura)! - feat: create fns package
================================================
FILE: packages/fns/README.md
================================================
# @react-pdf/fns
> Lightweight utility functions for react-pdf
A collection of functional programming utilities used internally by react-pdf. Zero dependencies, tree-shakeable, and fully typed.
## Installation
```bash
yarn add @react-pdf/fns
```
## Table of Contents
- [adjust](#adjust)
- [asyncCompose](#asynccompose)
- [capitalize](#capitalize)
- [castArray](#castarray)
- [compose](#compose)
- [dropLast](#droplast)
- [evolve](#evolve)
- [get](#get)
- [isNil](#isnil)
- [last](#last)
- [mapValues](#mapvalues)
- [matchPercent](#matchpercent)
- [omit](#omit)
- [parseFloat](#parsefloat)
- [pick](#pick)
- [repeat](#repeat)
- [reverse](#reverse)
- [upperFirst](#upperfirst)
- [without](#without)
## Functions
### adjust
Applies a function to the value at the given index of an array.
```js
import { adjust } from '@react-pdf/fns';
adjust(1, (x) => x * 2, [1, 2, 3]); // => [1, 4, 3]
adjust(-1, (x) => x + 10, [1, 2, 3]); // => [1, 2, 13]
```
---
### asyncCompose
Performs right-to-left function composition with async functions support. `asyncCompose(f, g, h)(x)` is equivalent to `await f(await g(await h(x)))`.
```js
import { asyncCompose } from '@react-pdf/fns';
const addAsync = async (x) => x + 1;
const double = (x) => x * 2;
const fn = asyncCompose(double, addAsync);
await fn(5); // => 12
```
---
### capitalize
Capitalizes the first letter of each word in a string.
```js
import { capitalize } from '@react-pdf/fns';
capitalize('hello world'); // => 'Hello World'
capitalize('foo bar baz'); // => 'Foo Bar Baz'
```
---
### castArray
Wraps a value in an array if it isn't one already.
```js
import { castArray } from '@react-pdf/fns';
castArray('foo'); // => ['foo']
castArray(['foo']); // => ['foo']
castArray(123); // => [123]
```
---
### compose
Performs right-to-left function composition. `compose(f, g, h)(x)` is equivalent to `f(g(h(x)))`.
```js
import { compose } from '@react-pdf/fns';
const add1 = (x) => x + 1;
const double = (x) => x * 2;
const fn = compose(double, add1);
fn(5); // => 12
```
---
### dropLast
Drops the last element from an array or string.
```js
import { dropLast } from '@react-pdf/fns';
dropLast([1, 2, 3]); // => [1, 2]
dropLast('hello'); // => 'hell'
```
---
### evolve
Applies transformations to an object's values based on a transformation map.
```js
import { evolve } from '@react-pdf/fns';
evolve(
{ count: (n) => n + 1, name: (s) => s.toUpperCase() },
{ name: 'item', count: 5 },
);
// => { name: 'ITEM', count: 6 }
```
---
### get
Retrieves a value at a given path from an object with a default fallback.
```js
import { get } from '@react-pdf/fns';
get({ a: { b: 1 } }, ['a', 'b'], 0); // => 1
get({ a: { b: 1 } }, ['a', 'c'], 0); // => 0
get({ a: { b: 1 } }, 'a', {}); // => { b: 1 }
```
---
### isNil
Checks if a value is `null` or `undefined`.
```js
import { isNil } from '@react-pdf/fns';
isNil(null); // => true
isNil(undefined); // => true
isNil(0); // => false
isNil(''); // => false
```
---
### last
Returns the last element of an array or last character of a string.
```js
import { last } from '@react-pdf/fns';
last([1, 2, 3]); // => 3
last('abc'); // => 'c'
last([]); // => undefined
```
---
### mapValues
Maps over the values of an object, applying a function to each value.
```js
import { mapValues } from '@react-pdf/fns';
mapValues({ a: 1, b: 2 }, (v) => v * 2); // => { a: 2, b: 4 }
mapValues({ x: 'foo', y: 'bar' }, (v, k) => `${k}:${v}`);
// => { x: 'x:foo', y: 'y:bar' }
```
---
### matchPercent
Parses a percentage string and returns both the numeric value and decimal percent.
```js
import { matchPercent } from '@react-pdf/fns';
matchPercent('50%'); // => { value: 50, percent: 0.5 }
matchPercent('-25%'); // => { value: -25, percent: -0.25 }
matchPercent('abc'); // => null
```
---
### omit
Creates a new object excluding specified keys.
```js
import { omit } from '@react-pdf/fns';
omit('b', { a: 1, b: 2, c: 3 }); // => { a: 1, c: 3 }
omit(['a', 'c'], { a: 1, b: 2, c: 3 }); // => { b: 2 }
```
---
### parseFloat
Parses a string to a float. Non-string values pass through unchanged.
```js
import { parseFloat } from '@react-pdf/fns';
parseFloat('3.14'); // => 3.14
parseFloat('10px'); // => 10
parseFloat(42); // => 42
parseFloat(null); // => null
```
---
### pick
Creates a new object with only the specified keys.
```js
import { pick } from '@react-pdf/fns';
pick(['a', 'c'], { a: 1, b: 2, c: 3 }); // => { a: 1, c: 3 }
pick(['x'], { a: 1, b: 2 }); // => {}
```
---
### repeat
Creates an array with an element repeated a specified number of times.
```js
import { repeat } from '@react-pdf/fns';
repeat('a', 3); // => ['a', 'a', 'a']
repeat(0, 4); // => [0, 0, 0, 0]
```
---
### reverse
Returns a new array with elements in reverse order (does not mutate original).
```js
import { reverse } from '@react-pdf/fns';
reverse([1, 2, 3]); // => [3, 2, 1]
reverse(['a', 'b', 'c']); // => ['c', 'b', 'a']
```
---
### upperFirst
Converts the first character of a string to uppercase.
```js
import { upperFirst } from '@react-pdf/fns';
upperFirst('hello'); // => 'Hello'
upperFirst('hELLO'); // => 'HELLO'
```
---
### without
Returns a new array excluding the specified values.
```js
import { without } from '@react-pdf/fns';
without([2, 4], [1, 2, 3, 4, 5]); // => [1, 3, 5]
without(['b'], ['a', 'b', 'c']); // => ['a', 'c']
```
## License
MIT
================================================
FILE: packages/fns/jest.config.js
================================================
export default {
testRegex: 'tests/.*?(test)\\.js$',
};
================================================
FILE: packages/fns/package.json
================================================
{
"name": "@react-pdf/fns",
"version": "3.1.2",
"license": "MIT",
"description": "React-pdf helper functions",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/fns"
},
"scripts": {
"test": "vitest",
"build": "rollup -c",
"watch": "rollup -c -w",
"typecheck": "tsc --noEmit"
},
"files": [
"lib"
]
}
================================================
FILE: packages/fns/rollup.config.js
================================================
import typescript from '@rollup/plugin-typescript';
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
const config = [
{
input: 'src/index.ts',
output: { format: 'es', dir: 'lib' },
plugins: [typescript()],
},
{
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
},
];
export default config;
================================================
FILE: packages/fns/src/adjust.ts
================================================
/**
* Applies a function to the value at the given index of an array
*
* @param index
* @param fn
* @param collection
* @returns Copy of the array with the element at the given index replaced with the result of the function application.
*/
const adjust = (
index: number,
fn: (value: T) => T,
collection: T[],
): T[] => {
if (index >= collection.length) return collection;
if (index < 0 && Math.abs(index) > collection.length) return collection;
const i = index < 0 ? collection.length + index : index;
return Object.assign([], collection, { [i]: fn(collection[i]) });
};
export default adjust;
================================================
FILE: packages/fns/src/asyncCompose.ts
================================================
/* eslint-disable no-await-in-loop */
type Fn = (arg: any, ...args: any[]) => Promise | any;
type ComposedInput = T extends [
...any,
(arg: infer A, ...args: any[]) => Promise | any,
]
? A
: never;
type ComposedOutput = T extends [
(arg: any, ...args: any[]) => Promise | infer R,
...any,
]
? R
: never;
/**
* Performs right-to-left function composition with async functions support.
* asyncCompose(f, g, h)(x) is equivalent to f(g(h(x))), awaiting each result.
*
* @param fns - Functions to compose (can be sync or async)
* @returns Composed async function that applies functions from right to left
*/
const asyncCompose =
(...fns: T) =>
async (
value: ComposedInput,
...args: Parameters extends [any, ...infer Rest] ? Rest : []
): Promise> => {
let result = value;
for (let i = fns.length - 1; i >= 0; i -= 1) {
result = await fns[i](result, ...args);
}
return result as ComposedOutput;
};
export default asyncCompose;
================================================
FILE: packages/fns/src/capitalize.ts
================================================
/**
* Capitalize first letter of each word
*
* @param value - Any string
* @returns Capitalized string
*/
const capitalize = (value?: string | null): typeof value => {
if (!value) return value;
return value.replace(/(^|\s)\S/g, (l) => l.toUpperCase());
};
export default capitalize;
================================================
FILE: packages/fns/src/castArray.ts
================================================
/**
* Casts value to array
*
* @template T - The type of the value.
* @param value - The value to cast into an array.
* @returns The value as-is if already an array, otherwise wrapped in an array.
*/
const castArray = (value: T | T[]): T[] => {
return Array.isArray(value) ? value : [value];
};
export default castArray;
================================================
FILE: packages/fns/src/compose.ts
================================================
type Fn = (arg: any, ...args: any[]) => any;
type ComposedInput = T extends [
...any,
(arg: infer A, ...args: any[]) => any,
]
? A
: never;
type ComposedOutput = T extends [
(arg: any, ...args: any[]) => infer R,
...any,
]
? R
: never;
/**
* Performs right-to-left function composition.
* compose(f, g, h)(x) is equivalent to f(g(h(x)))
*
* @param fns - Functions to compose
* @returns Composed function that applies functions from right to left
*/
const compose =
(...fns: T) =>
(value: ComposedInput, ...args: any[]): ComposedOutput => {
let result: unknown = value;
for (let i = fns.length - 1; i >= 0; i -= 1) {
result = fns[i](result, ...args);
}
return result as ComposedOutput;
};
export default compose;
================================================
FILE: packages/fns/src/dropLast.ts
================================================
/**
* Drops the last element from an array or string.
*
* @param value - The array or string to drop the last element from
* @returns A new array or string with the last element removed
*/
function dropLast(value: string): string;
function dropLast(value: T[]): T[];
function dropLast(value: string | T[]): string | T[] {
return value.slice(0, -1);
}
export default dropLast;
================================================
FILE: packages/fns/src/evolve.ts
================================================
/**
* Applies a set of transformations to an object and returns a new object with the transformed values.
*
* @example
* evolve({ count: (n) => n + 1 }, { name: 'item', count: 5 })
* // => { name: 'item', count: 6 }
*
* @param transformations - The transformations to apply
* @param object - The object to transform
* @returns The transformed object
*/
function evolve>(
transformations: Partial<{ [K in keyof T]: (value: T[K]) => T[K] }>,
object: T,
): T {
const result: Record = {};
const keys = Object.keys(object);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
const transformation = transformations[key];
if (typeof transformation === 'function') {
result[key] = transformation(object[key]);
} else {
result[key] = object[key];
}
}
return result as T;
}
export default evolve;
================================================
FILE: packages/fns/src/get.ts
================================================
import isNil from './isNil.js';
import castArray from './castArray.js';
/**
* Retrieves the value at a given path from an object.
*
* @example
* get({ a: { b: 1 } }, ['a', 'b'], 0) // => 1
* get({ a: { b: 1 } }, ['a', 'c'], 0) // => 0
*
* @param target - The object to retrieve the value from
* @param path - The path of the value to retrieve
* @param defaultValue - The default value to return if the path does not exist
* @returns The value at the given path, or the default value if the path does not exist
*/
const get = (
target: any,
path: (string | number)[] | string | number,
defaultValue: any,
): any => {
if (isNil(target)) return defaultValue;
const _path = castArray(path);
let result = target;
for (let i = 0; i < _path.length; i += 1) {
if (isNil(result)) return defaultValue;
result = result[_path[i]];
}
return isNil(result) ? defaultValue : result;
};
export default get;
================================================
FILE: packages/fns/src/index.ts
================================================
export { default as adjust } from './adjust.js';
export { default as asyncCompose } from './asyncCompose.js';
export { default as capitalize } from './capitalize.js';
export { default as castArray } from './castArray.js';
export { default as compose } from './compose.js';
export { default as dropLast } from './dropLast.js';
export { default as evolve } from './evolve.js';
export { default as get } from './get.js';
export { default as isNil } from './isNil.js';
export { default as last } from './last.js';
export { default as mapValues } from './mapValues.js';
export { default as matchPercent } from './matchPercent.js';
export { default as omit } from './omit.js';
export { default as pick } from './pick.js';
export { default as repeat } from './repeat.js';
export { default as reverse } from './reverse.js';
export { default as upperFirst } from './upperFirst.js';
export { default as without } from './without.js';
export { default as parseFloat } from './parseFloat.js';
================================================
FILE: packages/fns/src/isNil.ts
================================================
/**
* Checks if a value is null or undefined.
*
* @example
* isNil(null) // => true
* isNil(undefined) // => true
* isNil(0) // => false
*
* @param value - The value to check
* @returns True if the value is null or undefined, false otherwise
*/
const isNil = (value: unknown): value is null | undefined =>
value === null || value === undefined;
export default isNil;
================================================
FILE: packages/fns/src/last.ts
================================================
/**
* Returns the last element of an array or last character of a string.
*
* @example
* last([1, 2, 3]) // => 3
* last('abc') // => 'c'
* last([]) // => undefined
* last('') // => ''
*
* @param value - The array or string
* @returns The last element/character, or undefined for empty arrays
*/
function last(value: string): string;
function last(value: T[]): T | undefined;
function last(value: string | any[]): any {
return value === '' ? '' : value[value.length - 1];
}
export default last;
================================================
FILE: packages/fns/src/mapValues.ts
================================================
type IteratorFn = (value: any, key: string, index: number) => any;
/**
* Maps over the values of an object and applies a function to each value.
*
* @example
* mapValues({ a: 1, b: 2 }, (v) => v * 2) // => { a: 2, b: 4 }
*
* @param object - The object to map over
* @param fn - The function to apply to each value
* @returns A new object with the mapped values
*/
const mapValues = (
object: Record,
fn: IteratorFn,
): Record => {
const result: Record = {};
const entries = Object.entries(object);
for (let i = 0; i < entries.length; i += 1) {
const [key, value] = entries[i];
result[key] = fn(value, key, i);
}
return result;
};
export default mapValues;
================================================
FILE: packages/fns/src/matchPercent.ts
================================================
interface PercentMatch {
percent: number;
value: number;
}
const PERCENT_REGEX = /(-?\d+\.?\d*)%/;
/**
* Parses a percentage string and returns both the numeric value and decimal percent.
*
* @example
* matchPercent('50%') // => { value: 50, percent: 0.5 }
* matchPercent('-25%') // => { value: -25, percent: -0.25 }
* matchPercent('abc') // => null
*
* @param value - The value to parse
* @returns Object with value and percent, or null if not a valid percentage
*/
const matchPercent = (value: string | number | null): PercentMatch | null => {
const match = PERCENT_REGEX.exec(`${value}`);
if (match) {
const numericValue = parseFloat(match[1]);
const percent = numericValue / 100;
return { percent, value: numericValue };
}
return null;
};
export default matchPercent;
================================================
FILE: packages/fns/src/omit.ts
================================================
import castArray from './castArray';
/**
* Creates a new object by omitting specified keys from the original object.
*
* @example
* omit('b', { a: 1, b: 2, c: 3 }) // => { a: 1, c: 3 }
* omit(['a', 'c'], { a: 1, b: 2, c: 3 }) // => { b: 2 }
*
* @param keys - The key or keys to omit
* @param object - The original object
* @returns The new object without the omitted keys
*/
const omit = (
keys: string | string[],
object: Record,
): Record => {
const _keys = castArray(keys);
const copy = { ...object };
for (let i = 0; i < _keys.length; i += 1) {
delete copy[_keys[i]];
}
return copy;
};
export default omit;
================================================
FILE: packages/fns/src/parseFloat.ts
================================================
/**
* Parse a string or number to a float. Non-string values pass through unchanged.
*
* @example
* parseFloat('3.14') // => 3.14
* parseFloat(42) // => 42
* parseFloat('10px') // => 10
* parseFloat(null) // => null
*
* @param value - The value to parse
* @returns Parsed float for strings, original value otherwise
*/
const parseFloat = (
value: T,
): T extends string ? number : T => {
return (typeof value === 'string' ? Number.parseFloat(value) : value) as any;
};
export default parseFloat;
================================================
FILE: packages/fns/src/pick.ts
================================================
/**
* Picks the specified keys from an object and returns a new object with only those keys.
*
* @example
* pick(['a', 'c'], { a: 1, b: 2, c: 3 }) // => { a: 1, c: 3 }
* pick(['x'], { a: 1, b: 2 }) // => {}
*
* @param keys - The keys to pick from the object
* @param object - The object to pick the keys from
* @returns A new object with only the picked keys
*/
const pick = (
keys: (string | number)[],
object: Record,
): Record => {
const result: Record = {};
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (key in object) result[key] = object[key];
}
return result;
};
export default pick;
================================================
FILE: packages/fns/src/repeat.ts
================================================
/**
* Repeats an element a specified number of times.
*
* @example
* repeat('a', 3) // => ['a', 'a', 'a']
* repeat(0, 4) // => [0, 0, 0, 0]
* repeat('x') // => []
*
* @param element - Element to be repeated
* @param length - Number of times to repeat element (default: 0)
* @returns Array with the element repeated
*/
const repeat = (element: T, length: number = 0): T[] => {
const result = new Array(length);
for (let i = 0; i < length; i += 1) {
result[i] = element;
}
return result;
};
export default repeat;
================================================
FILE: packages/fns/src/reverse.ts
================================================
/**
* Returns a new array with elements in reverse order. Does not mutate the original.
*
* @example
* reverse([1, 2, 3]) // => [3, 2, 1]
* reverse(['a', 'b']) // => ['b', 'a']
*
* @param array - Array to be reversed
* @returns New array with elements reversed
*/
const reverse = (array: T[]): T[] => array.slice().reverse();
export default reverse;
================================================
FILE: packages/fns/src/upperFirst.ts
================================================
/**
* Converts the first character of a string to uppercase. Does not affect other characters.
*
* @example
* upperFirst('hello') // => 'Hello'
* upperFirst('hELLO') // => 'HELLO'
* upperFirst('') // => ''
* upperFirst(null) // => null
*
* @param value - The string to transform
* @returns String with first character uppercased, or the original value if null/undefined/empty
*/
const upperFirst = (
value: T,
): T extends string ? string : T => {
if (!value) return value as any;
return (value.charAt(0).toUpperCase() + value.slice(1)) as any;
};
export default upperFirst;
================================================
FILE: packages/fns/src/without.ts
================================================
/**
* Returns a new array excluding the specified values.
*
* @example
* without([2, 4], [1, 2, 3, 4, 5]) // => [1, 3, 5]
* without(['b'], ['a', 'b', 'c']) // => ['a', 'c']
*
* @param exclude - Values to exclude from the array
* @param array - Array to filter
* @returns A new array without the excluded values
*/
const without = (exclude: T[], array: T[]): T[] => {
const result: T[] = [];
for (let i = 0; i < array.length; i += 1) {
const value = array[i];
if (!exclude.includes(value)) result.push(value);
}
return result;
};
export default without;
================================================
FILE: packages/fns/tests/adjust.test.ts
================================================
import { describe, expect, test } from 'vitest';
import adjust from '../src/adjust';
const add = (v: number) => v + 1;
describe('adjust', () => {
test('applies the given function to the value at the given index of the supplied array', () => {
const expected = [0, 1, 3, 3];
const result = adjust(2, add, [0, 1, 2, 3]);
expect(result).toEqual(expected);
});
test('offsets negative indexes from the end of the array', () => {
const expected = [0, 2, 2, 3];
const result = adjust(-3, add, [0, 1, 2, 3]);
expect(result).toEqual(expected);
});
test('returns the original array if the supplied index is out of bounds', () => {
const expected = [0, 1, 2, 3];
expect(adjust(4, add, expected)).toBe(expected);
expect(adjust(-5, add, expected)).toBe(expected);
});
test('does not mutate the original array', () => {
const expected = [0, 1, 2, 3];
adjust(2, add, expected);
expect([0, 1, 2, 3]).toEqual(expected);
});
test('returns the original empty array when given empty array', () => {
const empty: number[] = [];
expect(adjust(0, add, empty)).toBe(empty);
});
test('adjusts single element array', () => {
expect(adjust(0, add, [5])).toEqual([6]);
});
test('adjusts first element with index 0', () => {
expect(adjust(0, add, [1, 2, 3])).toEqual([2, 2, 3]);
});
test('adjusts last element with positive index', () => {
expect(adjust(3, add, [1, 2, 3, 4])).toEqual([1, 2, 3, 5]);
});
test('adjusts last element with index -1', () => {
expect(adjust(-1, add, [1, 2, 3, 4])).toEqual([1, 2, 3, 5]);
});
test('adjusts first element with negative index equal to length', () => {
expect(adjust(-4, add, [1, 2, 3, 4])).toEqual([2, 2, 3, 4]);
});
test('works with string arrays', () => {
const toUpper = (s: string) => s.toUpperCase();
expect(adjust(1, toUpper, ['a', 'b', 'c'])).toEqual(['a', 'B', 'c']);
});
test('works with object arrays', () => {
const increment = (obj: { value: number }) => ({ value: obj.value + 1 });
const arr = [{ value: 1 }, { value: 2 }, { value: 3 }];
expect(adjust(1, increment, arr)).toEqual([
{ value: 1 },
{ value: 3 },
{ value: 3 },
]);
});
});
================================================
FILE: packages/fns/tests/asyncCompose.test.ts
================================================
import { describe, expect, test } from 'vitest';
import asyncCompose from '../src/asyncCompose';
describe('asyncCompose', () => {
test('should compose two async functions', async () => {
const double = async (x: number) => x * 2;
const increment = async (x: number) => x + 1;
// asyncCompose(double, increment)(5) = double(increment(5)) = double(6) = 12
const result = await asyncCompose(double, increment)(5);
expect(result).toBe(12);
});
test('should compose three async functions', async () => {
const double = async (x: number) => x * 2;
const increment = async (x: number) => x + 1;
const square = async (x: number) => x * x;
// asyncCompose(double, increment, square)(3) = double(increment(square(3))) = double(increment(9)) = double(10) = 20
const result = await asyncCompose(double, increment, square)(3);
expect(result).toBe(20);
});
test('should work with single async function', async () => {
const double = async (x: number) => x * 2;
const result = await asyncCompose(double)(5);
expect(result).toBe(10);
});
test('should work with sync functions', async () => {
const double = (x: number) => x * 2;
const increment = (x: number) => x + 1;
const result = await asyncCompose(double, increment)(5);
expect(result).toBe(12);
});
test('should work with mixed async and sync functions', async () => {
const double = async (x: number) => x * 2;
const increment = (x: number) => x + 1;
const square = async (x: number) => x * x;
const result = await asyncCompose(double, increment, square)(3);
expect(result).toBe(20);
});
test('should work with functions that change types', async () => {
const toString = async (x: number) => `Value: ${x}`;
const double = async (x: number) => x * 2;
const result = await asyncCompose(toString, double)(5);
expect(result).toBe('Value: 10');
});
test('should return a promise', () => {
const double = (x: number) => x * 2;
const result = asyncCompose(double)(5);
expect(result).toBeInstanceOf(Promise);
});
test('should execute functions in right-to-left order', async () => {
const order: string[] = [];
const first = async (x: number) => {
order.push('first');
return x;
};
const second = async (x: number) => {
order.push('second');
return x;
};
const third = async (x: number) => {
order.push('third');
return x;
};
await asyncCompose(first, second, third)(1);
expect(order).toEqual(['third', 'second', 'first']);
});
});
================================================
FILE: packages/fns/tests/capitalize.test.ts
================================================
import { describe, expect, test } from 'vitest';
import capitalize from '../src/capitalize';
describe('capitalize', () => {
test('should return undefined for undefined', () => {
expect(capitalize(undefined)).toBe(undefined);
});
test('should return null for null', () => {
expect(capitalize(null)).toBe(null);
});
test('should return empty string when empty string', () => {
expect(capitalize('')).toBe('');
});
test('should return single word string capitalized', () => {
expect(capitalize('reactpdf')).toBe('Reactpdf');
});
test('should return multiple word string capitalized', () => {
expect(capitalize('lorem ipsum')).toBe('Lorem Ipsum');
});
test('should handle multiple spaces between words', () => {
expect(capitalize('lorem ipsum')).toBe('Lorem Ipsum');
});
test('should handle leading whitespace', () => {
expect(capitalize(' hello world')).toBe(' Hello World');
});
test('should handle trailing whitespace', () => {
expect(capitalize('hello world ')).toBe('Hello World ');
});
test('should handle tabs as word separators', () => {
expect(capitalize('hello\tworld')).toBe('Hello\tWorld');
});
test('should handle already capitalized string', () => {
expect(capitalize('Hello World')).toBe('Hello World');
});
test('should capitalize single character', () => {
expect(capitalize('a')).toBe('A');
});
test('should handle newlines as word separators', () => {
expect(capitalize('hello\nworld')).toBe('Hello\nWorld');
});
});
================================================
FILE: packages/fns/tests/castArray.test.ts
================================================
import { describe, expect, test } from 'vitest';
import castArray from '../src/castArray';
describe('castArray', () => {
test('should return [undefined] for undefined', () => {
expect(castArray(undefined)).toEqual([undefined]);
});
test('should return [null] for null', () => {
expect(castArray(null)).toEqual([null]);
});
test('should cast passed value in an array', () => {
expect(castArray('test')).toEqual(['test']);
});
test('should return array if passed array', () => {
expect(castArray(['reactpdf'])).toEqual(['reactpdf']);
});
test('should return empty array if passed empty array', () => {
expect(castArray([])).toEqual([]);
});
test('should cast number in an array', () => {
expect(castArray(42)).toEqual([42]);
});
test('should cast object in an array', () => {
const obj = { key: 'value' };
expect(castArray(obj)).toEqual([obj]);
});
test('should return same array reference if passed array', () => {
const arr = [1, 2, 3];
expect(castArray(arr)).toBe(arr);
});
});
================================================
FILE: packages/fns/tests/compose.test.ts
================================================
import { describe, expect, test } from 'vitest';
import compose from '../src/compose';
describe('compose', () => {
test('performs right-to-left function composition', () => {
const map = (fn: any) => (collection: number[]) => collection.map(fn);
const multiply = (a: number) => (b: number) => a * b;
const f = compose(map, multiply, parseInt);
expect(f('10')([1, 2, 3])).toEqual([10, 20, 30]);
expect(f('10', 2)([1, 2, 3])).toEqual([2, 4, 6]);
});
test('should compose two functions', () => {
const double = (x: number) => x * 2;
const increment = (x: number) => x + 1;
// compose(double, increment)(5) = double(increment(5)) = double(6) = 12
expect(compose(double, increment)(5)).toBe(12);
});
test('should compose three functions', () => {
const double = (x: number) => x * 2;
const increment = (x: number) => x + 1;
const square = (x: number) => x * x;
// compose(double, increment, square)(3) = double(increment(square(3))) = double(increment(9)) = double(10) = 20
expect(compose(double, increment, square)(3)).toBe(20);
});
test('should work with single function', () => {
const double = (x: number) => x * 2;
expect(compose(double)(5)).toBe(10);
});
test('should work with functions that change types', () => {
const toString = (x: number) => `Value: ${x}`;
const double = (x: number) => x * 2;
expect(compose(toString, double)(5)).toBe('Value: 10');
});
});
================================================
FILE: packages/fns/tests/dropLast.test.ts
================================================
import { describe, expect, test } from 'vitest';
import dropLast from '../src/dropLast';
describe('dropLast', () => {
test('skips the last element from a list, returning the remainder', () => {
expect(dropLast(['a', 'b', 'c', 'd'])).toEqual(['a', 'b', 'c']);
});
test('returns an empty array if passed 1 element array', () => {
expect(dropLast(['a'])).toEqual([]);
});
test('returns an empty array if passed empty array', () => {
expect(dropLast([])).toEqual([]);
});
test('can operate on strings', () => {
expect(dropLast('react-pdf')).toEqual('react-pd');
});
test('returns empty string if passed single character string', () => {
expect(dropLast('a')).toEqual('');
});
test('returns empty string if passed empty string', () => {
expect(dropLast('')).toEqual('');
});
test('should not mutate the original array', () => {
const original = [1, 2, 3];
const result = dropLast(original);
expect(result).toEqual([1, 2]);
expect(original).toEqual([1, 2, 3]);
});
});
================================================
FILE: packages/fns/tests/evolve.test.ts
================================================
import { describe, expect, test } from 'vitest';
import evolve from '../src/evolve';
const add = (a: number) => (b: number) => a + b;
describe('evolve', () => {
test('creates a new object by evolving the `object` according to the `transformation` functions', () => {
const transf = { elapsed: add(1), remaining: add(-1) };
const object = { name: 'Tomato', elapsed: 100, remaining: 1400 };
const expected = { name: 'Tomato', elapsed: 101, remaining: 1399 };
expect(evolve(transf, object)).toEqual(expected);
});
test('does not invoke function if object does not contain the key', () => {
const transf = { n: add(1), m: add(1) };
const object = { m: 3 };
const expected = { m: 4 };
expect(evolve(transf, object)).toEqual(expected);
});
test('is not destructive', () => {
const transf = { elapsed: add(1), remaining: add(-1) };
const object = { name: 'Tomato', elapsed: 100, remaining: 1400 };
const expected = { name: 'Tomato', elapsed: 100, remaining: 1400 };
evolve(transf, object);
expect(object).toEqual(expected);
});
test('returns empty object when given empty object', () => {
expect(evolve({}, {})).toEqual({});
});
test('returns copy of object when given empty transformations', () => {
const object = { a: 1, b: 2 };
expect(evolve({}, object)).toEqual({ a: 1, b: 2 });
});
test('transforms all keys when all have transformations', () => {
const double = (x: number) => x * 2;
const transf = { a: double, b: double };
const object = { a: 1, b: 2 };
expect(evolve(transf, object)).toEqual({ a: 2, b: 4 });
});
});
================================================
FILE: packages/fns/tests/get.test.ts
================================================
import { describe, expect, test } from 'vitest';
import get from '../src/get';
describe('get', () => {
const deepObject = {
a: { b: { c: 'c' } },
falseVal: false,
nullVal: null,
undefinedVal: undefined,
arrayVal: ['arr'],
};
test('takes a path and an object and returns the value at the path or the default value', () => {
const obj = {
a: {
b: {
c: 100,
d: 200,
},
e: {
f: [100, 101, 102],
g: 'G',
},
h: 'H',
},
i: 'I',
j: ['J'],
};
expect(get(obj, ['a', 'b', 'c'], 'Unknown')).toBe(100);
expect(get(obj, [], 'Unknown')).toBe(obj);
expect(get(obj, ['a', 'e', 'f', 1], 'Unknown')).toBe(101);
expect(get(obj, ['j', 0], 'Unknown')).toBe('J');
expect(get(obj, ['j', 1], 'Unknown')).toBe('Unknown');
expect(get(null, ['a', 'b', 'c'], 'Unknown')).toBe('Unknown');
});
test("gets a deep property's value from objects", () => {
expect(get(deepObject, ['a', 'b', 'c'], 'Unknown')).toBe('c');
expect(get(deepObject, ['a'], 'Unknown')).toBe(deepObject.a);
});
test('returns the default value for items not found', () => {
expect(get(deepObject, ['a', 'b', 'foo'], 'Unknown')).toBe('Unknown');
expect(get(deepObject, ['bar'], 'Unknown')).toBe('Unknown');
});
test('returns the default value for null/undefined', () => {
expect(get(null, ['toString'], 'Unknown')).toBe('Unknown');
expect(get(undefined, ['toString'], 'Unknown')).toBe('Unknown');
});
test('works with falsy items', () => {
expect(get(false, ['toString'], 'Unknown')).toBe(
Boolean.prototype.toString,
);
});
test('returns falsy values when they exist (not default)', () => {
expect(get(deepObject, ['falseVal'], 'Unknown')).toBe(false);
expect(get({ zero: 0 }, ['zero'], 'Unknown')).toBe(0);
expect(get({ empty: '' }, ['empty'], 'Unknown')).toBe('');
});
test('returns default for null/undefined values in object', () => {
expect(get(deepObject, ['nullVal'], 'Unknown')).toBe('Unknown');
expect(get(deepObject, ['undefinedVal'], 'Unknown')).toBe('Unknown');
});
test('accesses array values', () => {
expect(get(deepObject, ['arrayVal', 0], 'Unknown')).toBe('arr');
expect(get(deepObject, ['arrayVal', 1], 'Unknown')).toBe('Unknown');
});
test('returns default when path goes through null/undefined', () => {
expect(get(deepObject, ['nullVal', 'foo'], 'Unknown')).toBe('Unknown');
expect(get(deepObject, ['undefinedVal', 'foo'], 'Unknown')).toBe('Unknown');
});
});
================================================
FILE: packages/fns/tests/isNil.test.ts
================================================
import { describe, expect, test } from 'vitest';
import isNil from '../src/isNil';
describe('isNil', () => {
test('should return true for null', () => {
expect(isNil(null)).toBe(true);
});
test('should return true for undefined', () => {
expect(isNil(undefined)).toBe(true);
});
test('should return false for falsy non-nil values', () => {
expect(isNil(0)).toBe(false);
expect(isNil('')).toBe(false);
expect(isNil(false)).toBe(false);
expect(isNil(NaN)).toBe(false);
});
test('should return false for objects and arrays', () => {
expect(isNil([])).toBe(false);
expect(isNil({})).toBe(false);
});
});
================================================
FILE: packages/fns/tests/last.test.ts
================================================
import { describe, expect, test } from 'vitest';
import last from '../src/last';
describe('last', () => {
test('returns the last element of an array', () => {
expect(last([1, 2, 3])).toBe(3);
expect(last([1, 2])).toBe(2);
expect(last([1])).toBe(1);
});
test('returns undefined for empty array', () => {
expect(last([])).toBe(undefined);
});
test('returns the last character of a string', () => {
expect(last('abc')).toBe('c');
expect(last('ab')).toBe('b');
expect(last('a')).toBe('a');
});
test('returns empty string for empty string', () => {
expect(last('')).toBe('');
});
test('works with arrays of objects', () => {
const obj1 = { id: 1 };
const obj2 = { id: 2 };
expect(last([obj1, obj2])).toBe(obj2);
});
test('works with arrays containing falsy values', () => {
expect(last([1, 2, 0])).toBe(0);
expect(last([1, 2, false])).toBe(false);
expect(last([1, 2, null])).toBe(null);
expect(last([1, 2, ''])).toBe('');
});
});
================================================
FILE: packages/fns/tests/mapValues.test.ts
================================================
import { describe, expect, test } from 'vitest';
import mapValues from '../src/mapValues';
describe('mapValues', () => {
test('should apply function to each value', () => {
const double = (x: number) => x * 2;
const obj = { a: 1, b: 2, c: 3 };
expect(mapValues(obj, double)).toEqual({ a: 2, b: 4, c: 6 });
});
test('should pass value, key, and index to the function', () => {
const results: Array<{ value: number; key: string; index: number }> = [];
const obj = { a: 1, b: 2 };
mapValues(obj, (value, key, index) => {
results.push({ value, key, index });
return value;
});
expect(results).toEqual([
{ value: 1, key: 'a', index: 0 },
{ value: 2, key: 'b', index: 1 },
]);
});
test('should return empty object for empty input', () => {
expect(mapValues({}, (x) => x)).toEqual({});
});
test('should not mutate the original object', () => {
const original = { a: 1, b: 2 };
const result = mapValues(original, (x) => x * 2);
expect(result).toEqual({ a: 2, b: 4 });
expect(original).toEqual({ a: 1, b: 2 });
});
test('should work with different value types', () => {
const obj = { name: 'test', count: 5 };
const toUpper = (x: any) => (typeof x === 'string' ? x.toUpperCase() : x);
expect(mapValues(obj, toUpper)).toEqual({ name: 'TEST', count: 5 });
});
});
================================================
FILE: packages/fns/tests/matchPercent.test.ts
================================================
import { describe, expect, test } from 'vitest';
import matchPercent from '../src/matchPercent';
describe('match percent', () => {
test('should return null for null input', () => {
expect(matchPercent(null)).toBeNull();
});
test('should return null for numeric inputs', () => {
expect(matchPercent(40)).toBeNull();
});
test('should return null for wrong string inputs', () => {
expect(matchPercent('hey%')).toBeNull();
});
test('should return value for positive integer percents', () => {
const match = matchPercent('35%');
expect(match?.value).toBe(35);
expect(match?.percent).toBe(0.35);
});
test('should return value for positive real percents', () => {
const match = matchPercent('35.5%');
expect(match?.value).toBe(35.5);
expect(match?.percent).toBe(0.355);
});
test('should return value for negative integer percents', () => {
const match = matchPercent('-35%');
expect(match?.value).toBe(-35);
expect(match?.percent).toBe(-0.35);
});
test('should return value for negative real percents', () => {
const match = matchPercent('-35.5%');
expect(match?.value).toBe(-35.5);
expect(match?.percent).toBe(-0.355);
});
test('should return value for zero percent', () => {
const match = matchPercent('0%');
expect(match?.value).toBe(0);
expect(match?.percent).toBe(0);
});
test('should return value for 100 percent', () => {
const match = matchPercent('100%');
expect(match?.value).toBe(100);
expect(match?.percent).toBe(1);
});
test('should return value for percentages over 100', () => {
const match = matchPercent('150%');
expect(match?.value).toBe(150);
expect(match?.percent).toBe(1.5);
});
test('should return null for empty string', () => {
expect(matchPercent('')).toBeNull();
});
test('should match percent in longer string', () => {
const match = matchPercent('width: 50%');
expect(match?.value).toBe(50);
expect(match?.percent).toBe(0.5);
});
});
================================================
FILE: packages/fns/tests/omit.test.ts
================================================
import { describe, expect, test } from 'vitest';
import omit from '../src/omit';
describe('omit', () => {
const obj = { a: 1, b: 2, c: 3 };
test('copies an object omitting the listed property', () => {
expect(omit('a', obj)).toEqual({ b: 2, c: 3 });
});
test('copies an object omitting the listed properties', () => {
expect(omit(['a', 'c'], obj)).toEqual({ b: 2 });
});
test('returns copy of object when keys array is empty', () => {
expect(omit([], obj)).toEqual({ a: 1, b: 2, c: 3 });
});
test('returns copy of object when key does not exist', () => {
expect(omit('nonexistent', obj)).toEqual({ a: 1, b: 2, c: 3 });
expect(omit(['x', 'y'], obj)).toEqual({ a: 1, b: 2, c: 3 });
});
test('returns empty object when all keys are omitted', () => {
expect(omit(['a', 'b', 'c'], obj)).toEqual({});
});
test('does not mutate the original object', () => {
const original = { a: 1, b: 2 };
const result = omit('a', original);
expect(result).toEqual({ b: 2 });
expect(original).toEqual({ a: 1, b: 2 });
});
test('returns empty object when given empty object', () => {
expect(omit('a', {})).toEqual({});
expect(omit(['a', 'b'], {})).toEqual({});
});
});
================================================
FILE: packages/fns/tests/parseFloat.test.ts
================================================
import { describe, expect, test } from 'vitest';
import parseFloat from '../src/parseFloat';
describe('parseFloat', () => {
test('should return undefined for undefined', () => {
expect(parseFloat(undefined!)).toBe(undefined);
});
test('should return null for null', () => {
expect(parseFloat(null!)).toBe(null);
});
test('should parse integer', () => {
expect(parseFloat(10)).toBe(10);
});
test('should parse float', () => {
expect(parseFloat(10.1)).toBe(10.1);
});
test('should parse string integer', () => {
expect(parseFloat('10')).toBe(10);
});
test('should parse string float', () => {
expect(parseFloat('10.1')).toBe(10.1);
});
test('should parse negative numbers', () => {
expect(parseFloat(-5)).toBe(-5);
expect(parseFloat('-5.5')).toBe(-5.5);
});
test('should parse zero', () => {
expect(parseFloat(0)).toBe(0);
expect(parseFloat('0')).toBe(0);
});
test('should return NaN for invalid strings', () => {
expect(parseFloat('abc')).toBeNaN();
expect(parseFloat('')).toBeNaN();
});
test('should parse numbers from strings with trailing characters', () => {
expect(parseFloat('10px')).toBe(10);
expect(parseFloat('3.14rem')).toBe(3.14);
});
test('should parse strings with leading whitespace', () => {
expect(parseFloat(' 42')).toBe(42);
});
});
================================================
FILE: packages/fns/tests/pick.test.ts
================================================
import { describe, expect, test } from 'vitest';
import pick from '../src/pick';
describe('pick', () => {
const obj = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, 1: 7 };
test('copies the named properties of an object to the new object', () => {
expect(pick(['a', 'c', 'f'], obj)).toEqual({ a: 1, c: 3, f: 6 });
});
test('handles numbers as properties', () => {
expect(pick([1], obj)).toEqual({ 1: 7 });
});
test('ignores properties not included', () => {
expect(pick(['a', 'c', 'g'], obj)).toEqual({ a: 1, c: 3 });
});
test('returns empty object when keys array is empty', () => {
expect(pick([], obj)).toEqual({});
});
test('returns empty object when object is empty', () => {
expect(pick(['a', 'b'], {})).toEqual({});
});
test('picks single key', () => {
expect(pick(['a'], obj)).toEqual({ a: 1 });
});
test('does not mutate the original object', () => {
const original = { a: 1, b: 2 };
const result = pick(['a'], original);
expect(result).toEqual({ a: 1 });
expect(original).toEqual({ a: 1, b: 2 });
});
test('picks keys with falsy values', () => {
const objWithFalsy = { a: 0, b: false, c: '', d: null, e: undefined };
expect(pick(['a', 'b', 'c', 'd', 'e'], objWithFalsy)).toEqual({
a: 0,
b: false,
c: '',
d: null,
e: undefined,
});
});
});
================================================
FILE: packages/fns/tests/repeat.test.ts
================================================
import { describe, expect, test } from 'vitest';
import repeat from '../src/repeat';
describe('repeat', () => {
test('should repeat property times', () => {
expect(repeat('a', 5)).toEqual(['a', 'a', 'a', 'a', 'a']);
expect(repeat('b', 0)).toEqual([]);
expect(repeat('Lorem', 1)).toEqual(['Lorem']);
expect(repeat('Ipsum', 2)).toEqual(['Ipsum', 'Ipsum']);
expect(repeat(undefined, 3)).toEqual([undefined, undefined, undefined]);
});
test('should not repeat property', () => {
expect(repeat('Lorem')).toEqual([]);
});
test('should repeat numbers', () => {
expect(repeat(42, 3)).toEqual([42, 42, 42]);
expect(repeat(0, 2)).toEqual([0, 0]);
});
test('should repeat objects with same reference', () => {
const obj = { id: 1 };
const result = repeat(obj, 3);
expect(result).toEqual([obj, obj, obj]);
expect(result[0]).toBe(obj);
expect(result[1]).toBe(obj);
expect(result[2]).toBe(obj);
});
test('should repeat null', () => {
expect(repeat(null, 2)).toEqual([null, null]);
});
test('should repeat false', () => {
expect(repeat(false, 3)).toEqual([false, false, false]);
});
});
================================================
FILE: packages/fns/tests/reverse.test.ts
================================================
import { describe, expect, test } from 'vitest';
import reverse from '../src/reverse';
describe('reverse', () => {
test('reverses arrays', () => {
expect(reverse([])).toEqual([]);
expect(reverse([1])).toEqual([1]);
expect(reverse([1, 2])).toEqual([2, 1]);
expect(reverse([1, 2, 3])).toEqual([3, 2, 1]);
});
test('does not mutate the original array', () => {
const original = [1, 2, 3];
const result = reverse(original);
expect(result).toEqual([3, 2, 1]);
expect(original).toEqual([1, 2, 3]);
});
test('reverses array of strings', () => {
expect(reverse(['a', 'b', 'c'])).toEqual(['c', 'b', 'a']);
});
test('reverses array of objects', () => {
const obj1 = { id: 1 };
const obj2 = { id: 2 };
const obj3 = { id: 3 };
expect(reverse([obj1, obj2, obj3])).toEqual([obj3, obj2, obj1]);
});
test('reverses array with falsy values', () => {
expect(reverse([0, false, null, ''])).toEqual(['', null, false, 0]);
});
});
================================================
FILE: packages/fns/tests/upperFirst.test.ts
================================================
import { describe, expect, test } from 'vitest';
import upperFirst from '../src/upperFirst';
describe('upperFirst', () => {
test('should return undefined for undefined', () => {
expect(upperFirst(undefined)).toBe(undefined);
});
test('should return null for null', () => {
expect(upperFirst(null)).toBe(null);
});
test('should return empty string when empty string', () => {
expect(upperFirst('')).toBe('');
});
test('should return string with first char upperFirstd', () => {
expect(upperFirst('reactpdf')).toBe('Reactpdf');
});
test('should keep already capitalized strings unchanged', () => {
expect(upperFirst('Reactpdf')).toBe('Reactpdf');
});
test('should only capitalize first character', () => {
expect(upperFirst('HELLO')).toBe('HELLO');
expect(upperFirst('hELLO')).toBe('HELLO');
});
test('should handle single character strings', () => {
expect(upperFirst('a')).toBe('A');
expect(upperFirst('A')).toBe('A');
});
test('should handle strings starting with numbers', () => {
expect(upperFirst('123abc')).toBe('123abc');
});
test('should handle strings with spaces', () => {
expect(upperFirst('hello world')).toBe('Hello world');
});
});
================================================
FILE: packages/fns/tests/without.test.ts
================================================
import { describe, expect, test } from 'vitest';
import without from '../src/without';
describe('without', () => {
const array = ['a', 'b', 'c', 'd', 'e', 'f', 1];
test('filters passed keys', () => {
expect(without(['a', 'c', 'f'], array)).toEqual(['b', 'd', 'e', 1]);
});
test('handles numbers as keys', () => {
expect(without([1], array)).toEqual(['a', 'b', 'c', 'd', 'e', 'f']);
});
test('ignores keys not included', () => {
expect(without(['g'], array)).toEqual(array);
});
test('returns copy of array when keys is empty', () => {
expect(without([], array)).toEqual(array);
});
test('returns empty array when array is empty', () => {
expect(without(['a', 'b'], [])).toEqual([]);
});
test('returns empty array when all values are removed', () => {
expect(without([1, 2, 3], [1, 2, 3])).toEqual([]);
});
test('does not mutate the original array', () => {
const original = [1, 2, 3, 4];
const result = without([2, 4], original);
expect(result).toEqual([1, 3]);
expect(original).toEqual([1, 2, 3, 4]);
});
test('removes all occurrences of duplicate values', () => {
expect(without([2], [1, 2, 3, 2, 4, 2])).toEqual([1, 3, 4]);
});
test('handles falsy values', () => {
expect(without([0, false], [0, 1, false, 2, null])).toEqual([1, 2, null]);
});
});
================================================
FILE: packages/fns/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src"],
}
================================================
FILE: packages/font/.gitignore
================================================
lib
================================================
FILE: packages/font/CHANGELOG.md
================================================
# @react-pdf/font
## 4.0.4
### Patch Changes
- Updated dependencies [[`f034491b`](https://github.com/diegomura/react-pdf/commit/f034491b1f77ce6f18a5db88e70b10b9c502ca35)]:
- @react-pdf/pdfkit@4.1.0
- @react-pdf/types@2.9.2
## 4.0.3
### Patch Changes
- Updated dependencies [[`5cbe2fb0`](https://github.com/diegomura/react-pdf/commit/5cbe2fb0bde45c44eb68dde01f20feea245908c6)]:
- @react-pdf/pdfkit@4.0.4
- @react-pdf/types@2.9.1
## 4.0.2
### Patch Changes
- Updated dependencies [[`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a), [`106699e8`](https://github.com/diegomura/react-pdf/commit/106699e850dad2285e6999d59975111f217e8a81)]:
- @react-pdf/types@2.9.0
- @react-pdf/pdfkit@4.0.3
## 4.0.1
### Patch Changes
- [`e257f7ee`](https://github.com/diegomura/react-pdf/commit/e257f7ee18ff09f4895cd16c0b21b824678384c8) Thanks [@diegomura](https://github.com/diegomura)! - fix: font store types
- Updated dependencies []:
- @react-pdf/types@2.8.2
## 4.0.0
### Major Changes
- [#3102](https://github.com/diegomura/react-pdf/pull/3102) [`24690f52`](https://github.com/diegomura/react-pdf/commit/24690f5238e4eacf28351cf9996856a7d196d29e) Thanks [@diegomura](https://github.com/diegomura)! - feat: handle standard fonts in fonts package
### Patch Changes
- [#3087](https://github.com/diegomura/react-pdf/pull/3087) [`7cd66e4f`](https://github.com/diegomura/react-pdf/commit/7cd66e4fc37cd1393adc6250a919fe2629812082) Thanks [@diegomura](https://github.com/diegomura)! - fix: font exported types
- [#3093](https://github.com/diegomura/react-pdf/pull/3093) [`a2de2685`](https://github.com/diegomura/react-pdf/commit/a2de2685b25c797f266775c2e35a6535090393b7) Thanks [@diegomura](https://github.com/diegomura)! - refactor: font strict type checking
- [#3092](https://github.com/diegomura/react-pdf/pull/3092) [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert layout package to TS
- Updated dependencies [[`7cd66e4f`](https://github.com/diegomura/react-pdf/commit/7cd66e4fc37cd1393adc6250a919fe2629812082)]:
- @react-pdf/types@2.8.1
## 3.1.0
### Minor Changes
- [#3079](https://github.com/diegomura/react-pdf/pull/3079) [`700535c5`](https://github.com/diegomura/react-pdf/commit/700535c57ff1b105d923be70f4fc4bfdf4479f91) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert font package to TS
### Patch Changes
- Updated dependencies [[`96c2464d`](https://github.com/diegomura/react-pdf/commit/96c2464dfaa7294e0d79b7ed64743bfd7b1a8c72), [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45), [`700535c5`](https://github.com/diegomura/react-pdf/commit/700535c57ff1b105d923be70f4fc4bfdf4479f91)]:
- @react-pdf/types@2.8.0
## 3.0.2
### Patch Changes
- Updated dependencies [[`01944231`](https://github.com/diegomura/react-pdf/commit/01944231a342d502b832aeecb4c313020b8360c8)]:
- @react-pdf/types@2.7.1
## 3.0.1
### Patch Changes
- [#2947](https://github.com/diegomura/react-pdf/pull/2947) [`ed562b9b`](https://github.com/diegomura/react-pdf/commit/ed562b9b7f14bc76a1cd83aaaf1dab966bd7540b) Thanks [@diegomura](https://github.com/diegomura)! - feat: remove cross-fetch
## 3.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Patch Changes
- Updated dependencies [[`46c3047d`](https://github.com/diegomura/react-pdf/commit/46c3047de56ae82f062b72c4910a4e6096eee99f), [`55973278`](https://github.com/diegomura/react-pdf/commit/55973278ac8bc8f703b63844f57d6f155ae8d86f)]:
- @react-pdf/types@2.7.0
## 2.5.2
### Patch Changes
- Updated dependencies [[`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2), [`4bafab8`](https://github.com/diegomura/react-pdf/commit/4bafab8455c9003759f48bad20a720baf4ed189b)]:
- @react-pdf/types@2.6.0
## 2.5.1
### Patch Changes
- Updated dependencies [[`22a34a9`](https://github.com/diegomura/react-pdf/commit/22a34a91b16a201cd8288e0dbea9368b12ca73f5)]:
- @react-pdf/types@2.5.0
## 2.5.0
### Minor Changes
- [#2640](https://github.com/diegomura/react-pdf/pull/2640) [`67c265a`](https://github.com/diegomura/react-pdf/commit/67c265a7e39cc0baa319f49137219677904695e6) Thanks [@nikgraf](https://github.com/nikgraf)! - Add support for fontFamily fallbacks e.g. fontFamily: ['Roboto', 'NotoSansArabic']
## 2.4.4
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
## 2.4.3
### Patch Changes
- Updated dependencies [[`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235)]:
- @react-pdf/types@2.4.1
## 2.4.2
### Patch Changes
- Updated dependencies [[`fb5273d`](https://github.com/diegomura/react-pdf/commit/fb5273d8d80d919f7b9c214e02d67b79ce23fa19)]:
- @react-pdf/types@2.4.0
## 2.4.1
### Patch Changes
- Updated dependencies [[`9e5842b`](https://github.com/diegomura/react-pdf/commit/9e5842bbecca6e249af2c5fc50078bb7ddd5420f)]:
- @react-pdf/types@2.3.6
## 2.4.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
## 2.3.8
### Patch Changes
- [#2467](https://github.com/diegomura/react-pdf/pull/2467) [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2) Thanks [@JaeSeoKim](https://github.com/JaeSeoKim)! - feat: add withVariationSelectors option to registerEmojiSource [#2466](https://github.com/diegomura/react-pdf/issues/2466)
- Updated dependencies [[`e5c8fde`](https://github.com/diegomura/react-pdf/commit/e5c8fde9379a9a85ecac7e3d6273953e39d65f8d), [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2), [`4c40b14`](https://github.com/diegomura/react-pdf/commit/4c40b149cfed42f2513e1dd330a92ccc3363c04f)]:
- @react-pdf/types@2.3.5
## 2.3.7
### Patch Changes
- Updated dependencies [[`4a55c1b`](https://github.com/diegomura/react-pdf/commit/4a55c1b2ed19e460ccae6e749ed94c16729a23c4)]:
- @react-pdf/types@2.3.4
## 2.3.6
### Patch Changes
- Updated dependencies [[`1e1fbdc`](https://github.com/diegomura/react-pdf/commit/1e1fbdc3c33ced46d8c7ebba7a196733cb789d59), [`8636812`](https://github.com/diegomura/react-pdf/commit/86368122ed87621d19ae3bc248080e17703d9fcb)]:
- @react-pdf/types@2.3.3
## 2.3.5
### Patch Changes
- Updated dependencies [[`a25dbcb`](https://github.com/diegomura/react-pdf/commit/a25dbcb32b65c300f5b088e8b210bb0c1abca5c2)]:
- @react-pdf/types@2.3.2
## 2.3.4
### Patch Changes
- [#2252](https://github.com/diegomura/react-pdf/pull/2252) [`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59) Thanks [@jeetiss](https://github.com/jeetiss)! - implement function as emoji source to build more complex urls
- Updated dependencies [[`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59)]:
- @react-pdf/types@2.3.1
## 2.3.3
### Patch Changes
- Updated dependencies [[`2db67a3`](https://github.com/diegomura/react-pdf/commit/2db67a38b9be98b7816a2b5aa4733446b95e3724)]:
- @react-pdf/types@2.3.0
## 2.3.2
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
## 2.3.1
### Patch Changes
- [#2023](https://github.com/diegomura/react-pdf/pull/2023) [`ce1c43c`](https://github.com/diegomura/react-pdf/commit/ce1c43c1b450b3737a23a356c5143626ac2a43ad) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - Fix warning about 'buffer' dependency in CRA 5 and webpack 5
## 2.3.0
### Minor Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- [#1908](https://github.com/diegomura/react-pdf/pull/1908) [`d1f3d5b`](https://github.com/diegomura/react-pdf/commit/d1f3d5b9b4103705e95e2160347ee253d842ed5d) Thanks [@diegomura](https://github.com/diegomura)! - chore: use fontkit mainline repo + drop node 12
* [#1927](https://github.com/diegomura/react-pdf/pull/1927) [`27403f9`](https://github.com/diegomura/react-pdf/commit/27403f9a6ac1bbcfb144afc201c4a3e5aca25cbd) Thanks [@diegomura](https://github.com/diegomura)! - feat: remove Buffer dependency from font package
- [#1934](https://github.com/diegomura/react-pdf/pull/1934) [`1a89506`](https://github.com/diegomura/react-pdf/commit/1a89506b4d325822d1a60a8f964434a6f6eb2d3f) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - fix: ability to load fonts by relative URL in browsers
## 2.2.1
### Patch Changes
- [#1909](https://github.com/diegomura/react-pdf/pull/1909) [`3acf53b`](https://github.com/diegomura/react-pdf/commit/3acf53b45200fa1415315f7dc22cc4b84a6b54c6) Thanks [@diegomura](https://github.com/diegomura)! - fix: font store load method skip loading
- Updated dependencies [[`0fcc594`](https://github.com/diegomura/react-pdf/commit/0fcc594310d5af30ca1e752b3efc7a047e813dcb)]:
- @react-pdf/fontkit@2.1.2
## 2.2.0
### Minor Changes
- [#1841](https://github.com/diegomura/react-pdf/pull/1841) [`25a80eb`](https://github.com/diegomura/react-pdf/commit/25a80ebd5f96ade7101883624010bad51474967c) Thanks [@diegomura](https://github.com/diegomura)! - feat: support bold-italic standard fonts
### Patch Changes
- Updated dependencies [[`fe0f214`](https://github.com/diegomura/react-pdf/commit/fe0f214dbbf2f632b852ebfe65f886ecc4dd6953)]:
- @react-pdf/types@2.0.9
## 2.1.1
### Patch Changes
- [#1685](https://github.com/diegomura/react-pdf/pull/1685) [`90ab2f8`](https://github.com/diegomura/react-pdf/commit/90ab2f8c040afc3d42961404bdf2ae09fac599eb) Thanks [@jeetiss](https://github.com/jeetiss)! - updated cross-fetch
## 2.1.0
### Minor Changes
- [#1610](https://github.com/diegomura/react-pdf/pull/1610) [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e) Thanks [@jeetiss](https://github.com/jeetiss)! - updated rollup rollup-plugins and babel
* [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
- Updated dependencies [[`3217a89`](https://github.com/diegomura/react-pdf/commit/3217a892e92ff98e92b6c7ea6e3244d403f679b6), [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e), [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca), [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b)]:
- @react-pdf/fontkit@2.1.0
- @react-pdf/types@2.0.8
================================================
FILE: packages/font/README.md
================================================
# @react-pdf/font
Font registration, loading, and resolution library for react-pdf. Handles TTF, WOFF, and WOFF2 fonts from various sources including local files, remote URLs, and base64 data URIs. Includes built-in support for PDF standard fonts.
## Installation
```bash
yarn add @react-pdf/font
```
## Usage
```js
import FontStore from '@react-pdf/font';
const fontStore = new FontStore();
// Register a custom font
fontStore.register({
family: 'Roboto',
src: 'https://example.com/fonts/Roboto-Regular.ttf',
});
// Load the font
await fontStore.load({
fontFamily: 'Roboto',
fontStyle: 'normal',
fontWeight: 400,
});
```
## Font Sources
The library supports multiple font source types:
### Remote URL
```js
fontStore.register({
family: 'Open Sans',
src: 'https://example.com/fonts/OpenSans-Regular.ttf',
});
```
With custom request options:
```js
fontStore.register({
family: 'Open Sans',
src: 'https://example.com/fonts/OpenSans-Regular.ttf',
method: 'GET',
headers: {
Authorization: 'Bearer token',
},
body: null,
});
```
### Local File (Node.js)
```js
fontStore.register({
family: 'Custom Font',
src: '/path/to/font.ttf',
});
```
> **Note:** Local file resolution is only available in Node.js environments.
### Base64 Data URI
```js
fontStore.register({
family: 'Embedded Font',
src: 'data:font/ttf;base64,AAEAAAALAIAAAwAwT1MvMg...',
});
```
## Registering Font Families
### Single Font
```js
fontStore.register({
family: 'Roboto',
src: 'https://example.com/fonts/Roboto-Regular.ttf',
fontWeight: 400,
fontStyle: 'normal',
});
```
### Multiple Weights and Styles (Bulk Registration)
```js
fontStore.register({
family: 'Roboto',
fonts: [
{ src: 'https://example.com/fonts/Roboto-Regular.ttf', fontWeight: 400 },
{ src: 'https://example.com/fonts/Roboto-Bold.ttf', fontWeight: 700 },
{
src: 'https://example.com/fonts/Roboto-Italic.ttf',
fontWeight: 400,
fontStyle: 'italic',
},
{
src: 'https://example.com/fonts/Roboto-BoldItalic.ttf',
fontWeight: 700,
fontStyle: 'italic',
},
],
});
```
## Standard Fonts
The following PDF standard fonts are pre-registered and available without any additional setup:
- **Helvetica** (with Bold, Oblique, and BoldOblique variants)
- **Courier** (with Bold, Oblique, and BoldOblique variants)
- **Times-Roman** (with Bold, Italic, and BoldItalic variants)
Helvetica variants are pre-loaded by default, so no explicit `load()` call is needed for them.
```js
// Standard fonts are ready to use immediately
const font = fontStore.getFont({
fontFamily: 'Helvetica',
fontWeight: 700,
fontStyle: 'normal',
});
```
## Font Weight Resolution
The library implements CSS font-weight resolution rules. You can specify font weights as numbers or keywords:
| Keyword | Numeric Value |
| -------------------------- | ------------- |
| `thin`, `hairline` | 100 |
| `ultralight`, `extralight` | 200 |
| `light` | 300 |
| `normal` | 400 |
| `medium` | 500 |
| `semibold`, `demibold` | 600 |
| `bold` | 700 |
| `ultrabold`, `extrabold` | 800 |
| `heavy`, `black` | 900 |
When an exact weight match isn't available, the library uses CSS fallback rules to find the closest available weight.
## Emoji Support
Register an emoji source to enable emoji rendering:
```js
// Using a URL pattern (must end with trailing slash)
fontStore.registerEmojiSource({
url: 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/',
format: 'png',
});
// Using a custom builder function
fontStore.registerEmojiSource({
builder: (code) => `https://example.com/emojis/${code}.png`,
});
```
The `code` parameter passed to the builder is a hyphen-separated string of hex code points (e.g., `1f44d` for 👍 or `1f44d-1f3ff` for 👍🏿).
Set `withVariationSelectors: true` if your emoji source requires variation selectors in the code points.
## Hyphenation
Register a hyphenation callback for text wrapping:
```js
import hyphenationCallback from 'hyphen/en';
fontStore.registerHyphenationCallback(hyphenationCallback);
```
## API Reference
### FontStore
#### `register(data: SingleLoad | BulkLoad)`
Register a font or font family.
#### `load(descriptor: FontDescriptor): Promise`
Load a specific font variant.
#### `getFont(descriptor: FontDescriptor): FontSource`
Get a font source matching the descriptor.
#### `registerEmojiSource(source: EmojiSource)`
Register an emoji image source.
#### `registerHyphenationCallback(callback: HyphenationCallback)`
Register a hyphenation callback function.
#### `reset()`
Reset all loaded font data (keeps registrations).
#### `clear()`
Clear all font registrations, emoji source, and hyphenation callback.
#### `getRegisteredFontFamilies(): string[]`
Get list of registered font family names.
#### `getRegisteredFonts(): Record`
Get all registered font families with their sources.
#### `getEmojiSource(): EmojiSource | null`
Get the registered emoji source, if any.
#### `getHyphenationCallback(): HyphenationCallback | null`
Get the registered hyphenation callback, if any.
## Types
### FontDescriptor
```ts
type FontDescriptor = {
fontFamily: string;
fontStyle?: 'normal' | 'italic' | 'oblique';
fontWeight?: FontWeight;
};
```
### FontWeight
```ts
type FontWeight =
| number
| 'thin'
| 'hairline'
| 'ultralight'
| 'extralight'
| 'light'
| 'normal'
| 'medium'
| 'semibold'
| 'demibold'
| 'bold'
| 'ultrabold'
| 'extrabold'
| 'heavy'
| 'black';
```
### SingleLoad
```ts
type SingleLoad = {
family: string;
src: string;
fontStyle?: 'normal' | 'italic' | 'oblique';
fontWeight?: FontWeight;
postscriptName?: string;
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
headers?: Record;
body?: any;
};
```
### BulkLoad
```ts
type BulkLoad = {
family: string;
fonts: FontSource[];
};
```
### EmojiSource
```ts
type EmojiSource =
| { url: string; format?: string; withVariationSelectors?: boolean }
| { builder: (code: string) => string; withVariationSelectors?: boolean };
```
### HyphenationCallback
```ts
type HyphenationCallback = (word: string) => string[];
```
## Supported Font Formats
- **TTF** - TrueType Font
- **WOFF** - Web Open Font Format
- **WOFF2** - Web Open Font Format 2.0
## License
MIT
================================================
FILE: packages/font/declarations.d.ts
================================================
import type { Font, FontCollection } from 'fontkit';
declare module 'fontkit' {
export function create(
buffer: Uint8Array | Buffer,
postscriptName?: string,
): Font | FontCollection;
}
================================================
FILE: packages/font/globals.d.ts
================================================
declare global {
const BROWSER: boolean;
}
export {};
================================================
FILE: packages/font/package.json
================================================
{
"name": "@react-pdf/font",
"version": "4.0.4",
"license": "MIT",
"description": "Register font and emoji source for react-pdf document",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/font"
},
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"browser": {
"./lib/index.js": "./lib/index.browser.js"
},
"scripts": {
"test": "vitest",
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@react-pdf/pdfkit": "^4.1.0",
"@react-pdf/types": "^2.9.2",
"fontkit": "^2.0.2",
"is-url": "^1.2.4"
},
"files": [
"lib"
],
"devDependencies": {
"@types/fontkit": "^2.0.7",
"@types/is-url": "^1.2.32"
}
}
================================================
FILE: packages/font/rollup.config.js
================================================
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
import typescript from '@rollup/plugin-typescript';
import replace from '@rollup/plugin-replace';
import pkg from './package.json' with { type: 'json' };
const input = './src/index.ts';
const external = Object.keys(pkg.dependencies);
const getPlugins = ({ browser }) => [
typescript(),
replace({
preventAssignment: true,
values: {
BROWSER: JSON.stringify(browser),
},
}),
];
const serverConfig = {
input,
output: { format: 'es', file: 'lib/index.js' },
external,
plugins: getPlugins({ browser: false }),
};
const browserConfig = {
input,
output: { format: 'es', file: 'lib/index.browser.js' },
external,
plugins: getPlugins({ browser: true }),
};
const dtsConfig = {
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
};
export default [serverConfig, browserConfig, dtsConfig];
================================================
FILE: packages/font/src/font-family.ts
================================================
import FontSource from './font-source';
import { FontDescriptor, FontWeight, SingleLoad } from './types';
const FONT_WEIGHTS = {
thin: 100,
hairline: 100,
ultralight: 200,
extralight: 200,
light: 300,
normal: 400,
medium: 500,
semibold: 600,
demibold: 600,
bold: 700,
ultrabold: 800,
extrabold: 800,
heavy: 900,
black: 900,
};
const resolveFontWeight = (value: FontWeight) => {
return typeof value === 'string' ? FONT_WEIGHTS[value] : value;
};
const sortByFontWeight = (a: FontSource, b: FontSource) =>
a.fontWeight - b.fontWeight;
class FontFamily {
family: string;
sources: FontSource[];
static create(family: string) {
return new FontFamily(family);
}
constructor(family: string) {
this.family = family;
this.sources = [];
}
register({
src,
fontWeight,
fontStyle,
...options
}: Omit) {
const numericFontWeight = fontWeight
? resolveFontWeight(fontWeight)
: undefined;
this.sources.push(
new FontSource(src, this.family, fontStyle, numericFontWeight, options),
);
}
resolve(descriptor: FontDescriptor) {
const { fontWeight = 400, fontStyle = 'normal' } = descriptor;
const styleSources = this.sources.filter((s) => s.fontStyle === fontStyle);
const exactFit = styleSources.find((s) => s.fontWeight === fontWeight);
if (exactFit) return exactFit;
// Weight resolution. https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#Fallback_weights
let font: FontSource | null = null;
const numericFontWeight = resolveFontWeight(fontWeight);
if (numericFontWeight >= 400 && numericFontWeight <= 500) {
const leftOffset = styleSources.filter(
(s) => s.fontWeight <= numericFontWeight,
);
const rightOffset = styleSources.filter((s) => s.fontWeight > 500);
const fit = styleSources.filter(
(s) => s.fontWeight >= numericFontWeight && s.fontWeight <= 500,
);
font = fit[0] || leftOffset[leftOffset.length - 1] || rightOffset[0];
}
const lt = styleSources
.filter((s) => s.fontWeight < numericFontWeight)
.sort(sortByFontWeight);
const gt = styleSources
.filter((s) => s.fontWeight > numericFontWeight)
.sort(sortByFontWeight);
if (numericFontWeight < 400) {
font = lt[lt.length - 1] || gt[0];
}
if (numericFontWeight > 500) {
font = gt[0] || lt[lt.length - 1];
}
if (!font) {
throw new Error(
`Could not resolve font for ${this.family}, fontWeight ${fontWeight}, fontStyle ${fontStyle}`,
);
}
return font;
}
}
export default FontFamily;
================================================
FILE: packages/font/src/font-source.ts
================================================
import isUrl from 'is-url';
import * as fontkit from 'fontkit';
import { Font, FontSourceOptions, FontStyle, RemoteOptions } from './types';
import StandardFont, { STANDARD_FONTS } from './standard-font';
const fetchFont = async (src: string, options: RemoteOptions) => {
const response = await fetch(src, options);
if (!response.ok) {
throw new Error(
`Failed to fetch font from ${src}: ${response.status} ${response.statusText}`,
);
}
const data = await response.arrayBuffer();
return new Uint8Array(data);
};
const isDataUrl = (dataUrl: string) => {
const commaIndex = dataUrl.indexOf(',');
if (commaIndex === -1) return false;
const header = dataUrl.substring(0, commaIndex);
const hasDataPrefix = header.startsWith('data:');
const hasBase64Prefix = header.includes(';base64');
return hasDataPrefix && hasBase64Prefix;
};
class FontSource {
src: string;
fontFamily: string;
fontStyle: FontStyle;
fontWeight: number;
data: Font | null;
options: FontSourceOptions;
loadResultPromise: Promise | null;
constructor(
src: string,
fontFamily: string,
fontStyle?: FontStyle,
fontWeight?: number,
options?: FontSourceOptions,
) {
this.src = src;
this.fontFamily = fontFamily;
this.fontStyle = fontStyle || 'normal';
this.fontWeight = fontWeight || 400;
this.data = null;
this.options = options || {};
this.loadResultPromise = null;
}
async _load(): Promise {
const { postscriptName } = this.options;
let data = null;
if (STANDARD_FONTS.includes(this.src)) {
data = new StandardFont(this.src);
} else if (isDataUrl(this.src)) {
const raw = this.src.split(',')[1];
const uint8Array = new Uint8Array(
atob(raw)
.split('')
.map((c) => c.charCodeAt(0)),
);
data = fontkit.create(uint8Array, postscriptName);
} else if (BROWSER || isUrl(this.src)) {
const { headers, body, method = 'GET' } = this.options;
const buffer = await fetchFont(this.src, { method, body, headers });
data = fontkit.create(buffer, postscriptName);
} else if (!BROWSER) {
data = await fontkit.open(this.src, postscriptName);
}
if (data && 'fonts' in data) {
throw new Error('Font collection is not supported');
}
this.data = data;
}
async load() {
if (this.loadResultPromise === null) {
this.loadResultPromise = this._load();
}
return this.loadResultPromise;
}
}
export default FontSource;
================================================
FILE: packages/font/src/index.ts
================================================
import FontFamily from './font-family';
import {
BulkLoad,
EmojiSource,
FontDescriptor,
HyphenationCallback,
SingleLoad,
} from './types';
class FontStore {
fontFamilies: Record = {};
emojiSource: EmojiSource | null = null;
constructor() {
this.register({
family: 'Helvetica',
fonts: [
{ src: 'Helvetica', fontStyle: 'normal', fontWeight: 400 },
{ src: 'Helvetica-Bold', fontStyle: 'normal', fontWeight: 700 },
{ src: 'Helvetica-Oblique', fontStyle: 'italic', fontWeight: 400 },
{ src: 'Helvetica-BoldOblique', fontStyle: 'italic', fontWeight: 700 },
],
});
this.register({
family: 'Courier',
fonts: [
{ src: 'Courier', fontStyle: 'normal', fontWeight: 400 },
{ src: 'Courier-Bold', fontStyle: 'normal', fontWeight: 700 },
{ src: 'Courier-Oblique', fontStyle: 'italic', fontWeight: 400 },
{ src: 'Courier-BoldOblique', fontStyle: 'italic', fontWeight: 700 },
],
});
this.register({
family: 'Times-Roman',
fonts: [
{ src: 'Times-Roman', fontStyle: 'normal', fontWeight: 400 },
{ src: 'Times-Bold', fontStyle: 'normal', fontWeight: 700 },
{ src: 'Times-Italic', fontStyle: 'italic', fontWeight: 400 },
{ src: 'Times-BoldItalic', fontStyle: 'italic', fontWeight: 700 },
],
});
// For backwards compatibility
this.register({
family: 'Helvetica-Bold',
src: 'Helvetica-Bold',
});
this.register({
family: 'Helvetica-Oblique',
src: 'Helvetica-Oblique',
});
this.register({
family: 'Helvetica-BoldOblique',
src: 'Helvetica-BoldOblique',
});
this.register({
family: 'Courier-Bold',
src: 'Courier-Bold',
});
this.register({
family: 'Courier-Oblique',
src: 'Courier-Oblique',
});
this.register({
family: 'Courier-BoldOblique',
src: 'Courier-BoldOblique',
});
this.register({
family: 'Times-Bold',
src: 'Times-Bold',
});
this.register({
family: 'Times-Italic',
src: 'Times-Italic',
});
this.register({
family: 'Times-BoldItalic',
src: 'Times-BoldItalic',
});
// Load default fonts
this.load({
fontFamily: 'Helvetica',
fontStyle: 'normal',
fontWeight: 400,
});
this.load({
fontFamily: 'Helvetica',
fontStyle: 'normal',
fontWeight: 700,
});
this.load({
fontFamily: 'Helvetica',
fontStyle: 'italic',
fontWeight: 400,
});
this.load({
fontFamily: 'Helvetica',
fontStyle: 'italic',
fontWeight: 700,
});
}
hyphenationCallback: HyphenationCallback | null = null;
register = (data: SingleLoad | BulkLoad) => {
const { family } = data;
if (!this.fontFamilies[family]) {
this.fontFamilies[family] = FontFamily.create(family);
}
// Bulk loading
if ('fonts' in data) {
for (let i = 0; i < data.fonts.length; i += 1) {
const { src, fontStyle, fontWeight, ...options } = data.fonts[i];
this.fontFamilies[family].register({
src,
fontStyle,
fontWeight,
...options,
});
}
} else {
const { src, fontStyle, fontWeight, ...options } = data;
this.fontFamilies[family].register({
src,
fontStyle,
fontWeight,
...options,
});
}
};
registerEmojiSource = (emojiSource: EmojiSource) => {
this.emojiSource = emojiSource;
};
registerHyphenationCallback = (callback: HyphenationCallback) => {
this.hyphenationCallback = callback;
};
getFont = (descriptor: FontDescriptor) => {
const { fontFamily } = descriptor;
if (!this.fontFamilies[fontFamily]) {
throw new Error(
`Font family not registered: ${fontFamily}. Please register it calling Font.register() method.`,
);
}
return this.fontFamilies[fontFamily].resolve(descriptor);
};
load = async (descriptor: FontDescriptor) => {
const font = this.getFont(descriptor);
if (font) await font.load();
};
reset = () => {
const keys = Object.keys(this.fontFamilies);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
for (let j = 0; j < this.fontFamilies[key].sources.length; j++) {
const fontSource = this.fontFamilies[key].sources[j];
fontSource.data = null;
}
}
};
clear = () => {
this.fontFamilies = {};
this.emojiSource = null;
this.hyphenationCallback = null;
};
getRegisteredFonts = () => this.fontFamilies;
getEmojiSource = (): EmojiSource | null => this.emojiSource;
getHyphenationCallback = (): HyphenationCallback | null =>
this.hyphenationCallback;
getRegisteredFontFamilies = (): string[] => Object.keys(this.fontFamilies);
}
export type FontStoreType = FontStore;
export * from './types';
export default FontStore;
================================================
FILE: packages/font/src/standard-font.ts
================================================
// @ts-expect-error ts being silly
import { PDFFont } from '@react-pdf/pdfkit';
import * as fontkit from 'fontkit';
import { Font } from './types';
export const STANDARD_FONTS = [
'Courier',
'Courier-Bold',
'Courier-Oblique',
'Courier-BoldOblique',
'Helvetica',
'Helvetica-Bold',
'Helvetica-Oblique',
'Helvetica-BoldOblique',
'Times-Roman',
'Times-Bold',
'Times-Italic',
'Times-BoldItalic',
];
class StandardFont implements Font {
name: string;
src: any;
fullName: string;
familyName: string;
subfamilyName: string;
postscriptName: string;
copyright: string;
version: number;
underlinePosition: number;
underlineThickness: number;
italicAngle: number;
bbox: fontkit.BBOX;
'OS/2': fontkit.Os2Table;
hhea: fontkit.HHEA;
numGlyphs: number;
characterSet: number[];
availableFeatures: string[];
type: any;
constructor(src: string) {
this.name = src;
this.fullName = src;
this.familyName = src;
this.subfamilyName = src;
this.type = 'STANDARD';
this.postscriptName = src;
this.availableFeatures = [];
this.copyright = '';
this.version = 1;
this.underlinePosition = -100;
this.underlineThickness = 50;
this.italicAngle = 0;
this.bbox = {} as any;
this['OS/2'] = {} as any;
this.hhea = {} as any;
this.numGlyphs = 0;
this.characterSet = [];
this.src = PDFFont.open(null, src);
}
encode(str: string) {
return this.src.encode(str);
}
layout(str: string) {
const [encoded, positions] = this.encode(str);
const glyphs = encoded.map((g: any, i: any) => {
const glyph = this.getGlyph(parseInt(g, 16));
glyph.advanceWidth = positions[i].advanceWidth;
return glyph;
});
const advanceWidth = positions.reduce(
(acc: any, p: any) => acc + p.advanceWidth,
0,
);
return {
positions,
stringIndices: positions.map((_: any, i: any) => i),
glyphs,
script: 'latin',
language: 'dflt',
direction: 'ltr',
features: {},
advanceWidth,
advanceHeight: 0,
bbox: undefined as any,
};
}
glyphForCodePoint(codePoint: number) {
const glyph = this.getGlyph(codePoint);
glyph.advanceWidth = 400;
return glyph;
}
getGlyph(id: number): fontkit.Glyph {
return {
id,
codePoints: [id],
isLigature: false,
name: this.src.font.characterToGlyph(id),
_font: this.src,
// @ts-expect-error assign proper value
advanceWidth: undefined,
};
}
hasGlyphForCodePoint(codePoint: number) {
return this.src.font.characterToGlyph(codePoint) !== '.notdef';
}
// Based on empirical observation
get ascent() {
return 900;
}
// Based on empirical observation
get capHeight() {
switch (this.name) {
case 'Times-Roman':
case 'Times-Bold':
case 'Times-Italic':
case 'Times-BoldItalic':
return 650;
case 'Courier':
case 'Courier-Bold':
case 'Courier-Oblique':
case 'Courier-BoldOblique':
return 550;
default:
return 690;
}
}
// Based on empirical observation
get xHeight() {
switch (this.name) {
case 'Times-Roman':
case 'Times-Bold':
case 'Times-Italic':
case 'Times-BoldItalic':
return 440;
case 'Courier':
case 'Courier-Bold':
case 'Courier-Oblique':
case 'Courier-BoldOblique':
return 390;
default:
return 490;
}
}
// Based on empirical observation
get descent() {
switch (this.name) {
case 'Times-Roman':
case 'Times-Bold':
case 'Times-Italic':
case 'Times-BoldItalic':
return -220;
case 'Courier':
case 'Courier-Bold':
case 'Courier-Oblique':
case 'Courier-BoldOblique':
return -230;
default:
return -200;
}
}
get lineGap() {
return 0;
}
get unitsPerEm() {
return 1000;
}
stringsForGlyph(): string[] {
throw new Error('Method not implemented.');
}
glyphsForString(): fontkit.Glyph[] {
throw new Error('Method not implemented.');
}
widthOfGlyph(): number {
throw new Error('Method not implemented.');
}
getAvailableFeatures(): string[] {
throw new Error('Method not implemented.');
}
createSubset(): fontkit.Subset {
throw new Error('Method not implemented.');
}
getVariation(): any {
throw new Error('Method not implemented.');
}
getFont(): any {
throw new Error('Method not implemented.');
}
getName(): string | null {
throw new Error('Method not implemented.');
}
setDefaultLanguage(): void {
throw new Error('Method not implemented.');
}
}
export default StandardFont;
================================================
FILE: packages/font/src/types.ts
================================================
import * as fontkit from 'fontkit';
export type Font = Omit & {
type: 'TTF' | 'WOFF' | 'WOFF2' | 'STANDARD';
encode?: (string: string) => number[];
};
export type FontStyle = 'normal' | 'italic' | 'oblique';
export type FontWeight =
| number
| 'thin'
| 'hairline'
| 'ultralight'
| 'extralight'
| 'light'
| 'normal'
| 'medium'
| 'semibold'
| 'demibold'
| 'bold'
| 'ultrabold'
| 'extrabold'
| 'heavy'
| 'black';
export type FontDescriptor = {
fontFamily: string;
fontStyle?: FontStyle;
fontWeight?: FontWeight;
};
export type RemoteOptions = {
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
headers?: Record;
body?: any;
};
export type FontSourceOptions = {
postscriptName?: string;
} & RemoteOptions;
export type FontSource = {
src: string;
fontStyle?: FontStyle;
fontWeight?: FontWeight;
} & FontSourceOptions;
export type SingleLoad = {
family: string;
} & FontSource;
export type BulkLoad = {
family: string;
fonts: FontSource[];
};
interface EmojiSourceUrl {
url: string;
format?: string;
withVariationSelectors?: boolean;
}
interface EmojiSourceBuilder {
builder: (code: string) => string;
withVariationSelectors?: boolean;
}
export type EmojiSource = EmojiSourceUrl | EmojiSourceBuilder;
export type HyphenationCallback = (word: string) => string[];
================================================
FILE: packages/font/tests/fallback-weights.test.ts
================================================
import { describe, expect, it } from 'vitest';
import FontStore from '../src';
describe('fallback weights', () => {
it('should return exact match when available', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 400,
src: 'https://example.com/Roboto-normal-400.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 700,
src: 'https://example.com/Roboto-normal-700.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 400,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-400.ttf');
});
it('should resolve string weight names', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 'bold',
src: 'https://example.com/Roboto-bold.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 'thin',
src: 'https://example.com/Roboto-thin.ttf',
});
const bold = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 700,
});
const thin = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 100,
});
expect(bold?.src).toBe('https://example.com/Roboto-bold.ttf');
expect(thin?.src).toBe('https://example.com/Roboto-thin.ttf');
});
it('should filter by font style', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 400,
src: 'https://example.com/Roboto-normal.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'italic',
fontWeight: 400,
src: 'https://example.com/Roboto-italic.ttf',
});
const normal = fontStore.getFont({
fontFamily: 'Roboto',
fontStyle: 'normal',
});
const italic = fontStore.getFont({
fontFamily: 'Roboto',
fontStyle: 'italic',
});
expect(normal?.src).toBe('https://example.com/Roboto-normal.ttf');
expect(italic?.src).toBe('https://example.com/Roboto-italic.ttf');
});
it('should throw when no font can be resolved for style', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 400,
src: 'https://example.com/Roboto-normal.ttf',
});
expect(() =>
fontStore.getFont({
fontFamily: 'Roboto',
fontStyle: 'italic',
}),
).toThrow();
});
describe('if the target weight given is between 400 and 500 inclusive', () => {
it('look for available weights between the target and 500 in ascending order', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 200,
src: 'https://example.com/Roboto-normal-200.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 420,
src: 'https://example.com/Roboto-normal-420.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 470,
src: 'https://example.com/Roboto-normal-470.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 600,
src: 'https://example.com/Roboto-normal-600.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 450,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-470.ttf');
});
it('if no match is found, look for available weights less than the target, in descending order', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 100,
src: 'https://example.com/Roboto-normal-100.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 200,
src: 'https://example.com/Roboto-normal-200.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 600,
src: 'https://example.com/Roboto-normal-600.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 450,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-200.ttf');
});
it('if no match is found, look for available weights greater than 500, in ascending order.', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 600,
src: 'https://example.com/Roboto-normal-600.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 700,
src: 'https://example.com/Roboto-normal-700.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 450,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-600.ttf');
});
});
describe('if a weight less than 400 is given', () => {
it('look for available weights less than the target, in descending order.', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 100,
src: 'https://example.com/Roboto-normal-100.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 200,
src: 'https://example.com/Roboto-normal-200.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 500,
src: 'https://example.com/Roboto-normal-500.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 300,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-200.ttf');
});
it('if no match is found, look for available weights greater than the target, in ascending order', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 500,
src: 'https://example.com/Roboto-normal-500.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 600,
src: 'https://example.com/Roboto-normal-600.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 300,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-500.ttf');
});
});
describe('if a weight greater than 500 is given', () => {
it('look for available weights greater than the target, in ascending order', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 200,
src: 'https://example.com/Roboto-normal-200.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 700,
src: 'https://example.com/Roboto-normal-700.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 800,
src: 'https://example.com/Roboto-normal-800.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 600,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-700.ttf');
});
it('if no match is found, look for available weights less than the target, in descending order', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 100,
src: 'https://example.com/Roboto-normal-100.ttf',
});
fontStore.register({
family: 'Roboto',
fontStyle: 'normal',
fontWeight: 200,
src: 'https://example.com/Roboto-normal-200.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontWeight: 600,
});
expect(font?.src).toBe('https://example.com/Roboto-normal-200.ttf');
});
});
});
================================================
FILE: packages/font/tests/font-store.test.ts
================================================
import { describe, expect, it } from 'vitest';
import FontStore from '../src/index';
describe('font store', () => {
it('should create font store', () => {
const fontStore = new FontStore();
expect(fontStore).toBeTruthy();
});
it('should throw if font is not registered', () => {
const fontStore = new FontStore();
expect(() => fontStore.getFont({ fontFamily: 'Roboto' })).toThrow();
});
it('should register single font', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
src: 'https://example.com/Roboto-Regular.ttf',
});
const font = fontStore.getFont({ fontFamily: 'Roboto' });
expect(font).toBeTruthy();
});
it('should use default weight and style if not passed', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
src: 'https://example.com/Roboto-Regular.ttf',
});
const font = fontStore.getFont({ fontFamily: 'Roboto' });
expect(font?.fontWeight).toBe(400);
expect(font?.fontStyle).toBe('normal');
});
it('should register font with style and weight', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fontStyle: 'italic',
fontWeight: 700,
src: 'https://example.com/Roboto-BoldItalic.ttf',
});
const font = fontStore.getFont({
fontFamily: 'Roboto',
fontStyle: 'italic',
fontWeight: 700,
});
expect(font?.fontWeight).toBe(700);
expect(font?.fontStyle).toBe('italic');
expect(font?.src).toBe('https://example.com/Roboto-BoldItalic.ttf');
});
it('should register fonts in bulk', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
fonts: [
{
src: 'https://example.com/Roboto-Regular.ttf',
},
{
src: 'https://example.com/Roboto-Bold.ttf',
fontWeight: 700,
},
],
});
const regular = fontStore.getFont({ fontFamily: 'Roboto' });
const bold = fontStore.getFont({ fontFamily: 'Roboto', fontWeight: 700 });
expect(regular?.fontWeight).toBe(400);
expect(bold?.fontWeight).toBe(700);
});
it('should have standard fonts pre-registered', () => {
const fontStore = new FontStore();
expect(() => fontStore.getFont({ fontFamily: 'Helvetica' })).not.toThrow();
expect(() => fontStore.getFont({ fontFamily: 'Courier' })).not.toThrow();
expect(() =>
fontStore.getFont({ fontFamily: 'Times-Roman' }),
).not.toThrow();
});
it('should register and get emoji source', () => {
const fontStore = new FontStore();
const emojiSource = { url: 'https://example.com/emoji' };
expect(fontStore.getEmojiSource()).toBeNull();
fontStore.registerEmojiSource(emojiSource);
expect(fontStore.getEmojiSource()).toBe(emojiSource);
});
it('should register and get hyphenation callback', () => {
const fontStore = new FontStore();
const callback = (word: string) => [word];
expect(fontStore.getHyphenationCallback()).toBeNull();
fontStore.registerHyphenationCallback(callback);
expect(fontStore.getHyphenationCallback()).toBe(callback);
});
it('should get registered fonts', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
src: 'https://example.com/Roboto-Regular.ttf',
});
const fonts = fontStore.getRegisteredFonts();
expect(fonts.Roboto).toBeTruthy();
});
it('should get registered font families', () => {
const fontStore = new FontStore();
const families = fontStore.getRegisteredFontFamilies();
expect(families).toContain('Helvetica');
expect(families).toContain('Courier');
expect(families).toContain('Times-Roman');
});
it('should clear all registered fonts and callbacks', () => {
const fontStore = new FontStore();
fontStore.register({
family: 'Roboto',
src: 'https://example.com/Roboto-Regular.ttf',
});
fontStore.registerEmojiSource({ url: 'https://example.com/emoji' });
fontStore.registerHyphenationCallback((word) => [word]);
fontStore.clear();
expect(fontStore.getRegisteredFontFamilies()).toHaveLength(0);
expect(fontStore.getEmojiSource()).toBeNull();
expect(fontStore.getHyphenationCallback()).toBeNull();
});
});
================================================
FILE: packages/font/tests/standard-fonts.test.ts
================================================
import { describe, expect, it } from 'vitest';
import FontStore from '../src/index';
describe('standard fonts', () => {
it('should resolve courier', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Courier' });
expect(font.src).toBe('Courier');
});
it('should resolve bold courier', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Courier',
fontWeight: 700,
});
expect(font.src).toBe('Courier-Bold');
});
it('should resolve italic courier', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Courier',
fontStyle: 'italic',
});
expect(font.src).toBe('Courier-Oblique');
});
it('should resolve bold italic courier', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Courier',
fontWeight: 700,
fontStyle: 'italic',
});
expect(font.src).toBe('Courier-BoldOblique');
});
it('should resolve courier normal weight', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Courier',
fontWeight: 400,
});
expect(font.src).toBe('Courier');
});
it('should resolve courier missing font weight', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Courier',
fontWeight: 600,
});
expect(font.src).toBe('Courier-Bold');
});
it('should resolve times', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Times-Roman' });
expect(font.src).toBe('Times-Roman');
});
it('should resolve bold times', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Times-Roman',
fontWeight: 700,
});
expect(font.src).toBe('Times-Bold');
});
it('should resolve italic times', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Times-Roman',
fontStyle: 'italic',
});
expect(font.src).toBe('Times-Italic');
});
it('should resolve bold italic times', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Times-Roman',
fontWeight: 700,
fontStyle: 'italic',
});
expect(font.src).toBe('Times-BoldItalic');
});
it('should resolve times normal weight', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Times-Roman',
fontWeight: 400,
});
expect(font.src).toBe('Times-Roman');
});
it('should resolve times missing font weight', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Times-Roman',
fontWeight: 600,
});
expect(font.src).toBe('Times-Bold');
});
it('should resolve helvetica', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Helvetica' });
expect(font.src).toBe('Helvetica');
});
it('should resolve bold helvetica', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Helvetica',
fontWeight: 700,
});
expect(font.src).toBe('Helvetica-Bold');
});
it('should resolve italic helvetica', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Helvetica',
fontStyle: 'italic',
});
expect(font.src).toBe('Helvetica-Oblique');
});
it('should resolve bold italic helvetica', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Helvetica',
fontWeight: 700,
fontStyle: 'italic',
});
expect(font.src).toBe('Helvetica-BoldOblique');
});
it('should resolve helvetica normal weight', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Helvetica',
fontWeight: 400,
});
expect(font.src).toBe('Helvetica');
});
it('should resolve helvetica missing font weight', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({
fontFamily: 'Helvetica',
fontWeight: 600,
});
expect(font.src).toBe('Helvetica-Bold');
});
it('should resolve legacy courier bold', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Courier-Bold' });
expect(font.src).toBe('Courier-Bold');
});
it('should resolve legacy courier oblique', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Courier-Oblique' });
expect(font.src).toBe('Courier-Oblique');
});
it('should resolve legacy courier bold oblique', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Courier-BoldOblique' });
expect(font.src).toBe('Courier-BoldOblique');
});
it('should resolve legacy times bold', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Times-Bold' });
expect(font.src).toBe('Times-Bold');
});
it('should resolve legacy times italic', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Times-Italic' });
expect(font.src).toBe('Times-Italic');
});
it('should resolve legacy times bold italic', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Times-BoldItalic' });
expect(font.src).toBe('Times-BoldItalic');
});
it('should resolve legacy helvetica bold', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Helvetica-Bold' });
expect(font.src).toBe('Helvetica-Bold');
});
it('should resolve legacy helvetica oblique', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Helvetica-Oblique' });
expect(font.src).toBe('Helvetica-Oblique');
});
it('should resolve legacy helvetica bold oblique', () => {
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Helvetica-BoldOblique' });
expect(font.src).toBe('Helvetica-BoldOblique');
});
it('should resolve advanceWidth of soft hyphen to be zero', () => {
const SOFT_HYPHEN = '\u00AD';
const fontStore = new FontStore();
const font = fontStore.getFont({ fontFamily: 'Helvetica' });
expect(font.data!.encode!(SOFT_HYPHEN)[1][0].advanceWidth).toBe(0);
});
});
================================================
FILE: packages/font/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src", "**/*.d.ts"],
}
================================================
FILE: packages/image/.gitignore
================================================
lib
================================================
FILE: packages/image/CHANGELOG.md
================================================
# @react-pdf/image
## 3.0.4
### Patch Changes
- [#3183](https://github.com/diegomura/react-pdf/pull/3183) [`a5979c15`](https://github.com/diegomura/react-pdf/commit/a5979c1568761107076172e4c1843e66f62a08ab) Thanks [@thgh](https://github.com/thgh)! - Fix resolving images with special characters like space in filename
- [#3264](https://github.com/diegomura/react-pdf/pull/3264) [`04922fea`](https://github.com/diegomura/react-pdf/commit/04922fea2e60930ac550ec31beaeb7f20551cf63) Thanks [@diegomura](https://github.com/diegomura)! - feat(image): various improvements
## 3.0.3
### Patch Changes
- [#3094](https://github.com/diegomura/react-pdf/pull/3094) [`3fb01a90`](https://github.com/diegomura/react-pdf/commit/3fb01a90e590a31c097b3422fc911af61d65420a) Thanks [@diegomura](https://github.com/diegomura)! - refactor: image strict type checking
- [#3092](https://github.com/diegomura/react-pdf/pull/3092) [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert layout package to TS
## 3.0.2
### Patch Changes
- [#3078](https://github.com/diegomura/react-pdf/pull/3078) [`8d39fc46`](https://github.com/diegomura/react-pdf/commit/8d39fc4602730755ee63824ad4ed6ecd1bcd059f) Thanks [@diegomura](https://github.com/diegomura)! - fix: add types to image package.json
## 3.0.1
### Patch Changes
- [#2947](https://github.com/diegomura/react-pdf/pull/2947) [`ed562b9b`](https://github.com/diegomura/react-pdf/commit/ed562b9b7f14bc76a1cd83aaaf1dab966bd7540b) Thanks [@diegomura](https://github.com/diegomura)! - feat: remove cross-fetch
## 3.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Patch Changes
- [#2877](https://github.com/diegomura/react-pdf/pull/2877) [`fdcef566`](https://github.com/diegomura/react-pdf/commit/fdcef5666e4eeed542b625d394cdfe60d6346600) Thanks [@Friendseeker](https://github.com/Friendseeker)! - chore: bump jay-peg
- Updated dependencies [[`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/png-js@3.0.0
## 2.3.6
### Patch Changes
- [#2687](https://github.com/diegomura/react-pdf/pull/2687) [`68bfc57`](https://github.com/diegomura/react-pdf/commit/68bfc575adfb95302e320019715d1eec5398259f) Thanks [@diegomura](https://github.com/diegomura)! - chore: bump jay-peg
## 2.3.5
### Patch Changes
- [#2635](https://github.com/diegomura/react-pdf/pull/2635) [`da10a9b`](https://github.com/diegomura/react-pdf/commit/da10a9bb43dc4c4765687850444a24cbc4eb402a) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: bump jay-peg dependency to fix CJS module resolution error
## 2.3.4
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/png-js@2.3.1
## 2.3.3
### Patch Changes
- [#2573](https://github.com/diegomura/react-pdf/pull/2573) [`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235) Thanks [@davbrito](https://github.com/davbrito)! - feat: add support for resolving blob images
- [#2600](https://github.com/diegomura/react-pdf/pull/2600) [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7) Thanks [@diegomura](https://github.com/diegomura)! - feat: bidi support
## 2.3.2
### Patch Changes
- [`0590324`](https://github.com/diegomura/react-pdf/commit/0590324d7a6d75c0a49520b3f99cfb6594239390) Thanks [@diegomura](https://github.com/diegomura)! - fix: replace jpeg-exif with jay-peg
## 2.3.1
### Patch Changes
- [#2529](https://github.com/diegomura/react-pdf/pull/2529) [`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8) Thanks [@diegomura](https://github.com/diegomura)! - fix: jpeg exif orientation rendering
## 2.3.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
### Patch Changes
- Updated dependencies [[`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37)]:
- @react-pdf/png-js@2.3.0
## 2.2.3
### Patch Changes
- [#2479](https://github.com/diegomura/react-pdf/pull/2479) [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4) Thanks [@diegomura](https://github.com/diegomura)! - fix linting
## 2.2.2
### Patch Changes
- [#2130](https://github.com/diegomura/react-pdf/pull/2130) [`4a55c1b`](https://github.com/diegomura/react-pdf/commit/4a55c1b2ed19e460ccae6e749ed94c16729a23c4) Thanks [@PoornakumarRasiraju](https://github.com/PoornakumarRasiraju)! - fix: allow credentials option in Image
## 2.2.1
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
## 2.2.0
### Minor Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81), [`001a208`](https://github.com/diegomura/react-pdf/commit/001a20812fa039d09931b22eb97a8869e3b31cc5)]:
- @react-pdf/png-js@2.2.0
## 2.1.1
### Patch Changes
- [#1685](https://github.com/diegomura/react-pdf/pull/1685) [`90ab2f8`](https://github.com/diegomura/react-pdf/commit/90ab2f8c040afc3d42961404bdf2ae09fac599eb) Thanks [@jeetiss](https://github.com/jeetiss)! - updated cross-fetch
## 2.1.0
### Minor Changes
- [#1610](https://github.com/diegomura/react-pdf/pull/1610) [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e) Thanks [@jeetiss](https://github.com/jeetiss)! - updated rollup rollup-plugins and babel
* [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
- Updated dependencies [[`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e), [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca)]:
- @react-pdf/png-js@2.1.0
================================================
FILE: packages/image/README.md
================================================
# @react-pdf/image
Image parsing and resolution library for react-pdf. Handles PNG and JPEG images from various sources including local files, remote URLs, base64 data URIs, buffers, and blobs.
## Installation
```bash
yarn add @react-pdf/image
```
## Usage
```js
import resolveImage from '@react-pdf/image';
const image = await resolveImage({ uri: './path/to/image.png' });
console.log(image.width); // Image width in pixels
console.log(image.height); // Image height in pixels
console.log(image.format); // 'png' or 'jpeg'
console.log(image.data); // Buffer containing image data
```
## Image Sources
The library supports multiple image source types:
### Local File
```js
const image = await resolveImage({ uri: './image.png' });
// or
const image = await resolveImage({ uri: '/absolute/path/to/image.jpg' });
```
> **Note:** Local file resolution is only available in Node.js environments.
### Remote URL
```js
const image = await resolveImage({ uri: 'https://example.com/image.png' });
```
With custom request options:
```js
const image = await resolveImage({
uri: 'https://example.com/image.png',
method: 'GET',
headers: {
Authorization: 'Bearer token',
},
body: null,
credentials: 'include',
});
```
### Base64 Data URI
```js
const image = await resolveImage({
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==',
});
```
### Buffer
```js
import fs from 'fs';
const buffer = fs.readFileSync('./image.png');
const image = await resolveImage(buffer);
```
### Blob (Browser)
```js
const response = await fetch('https://example.com/image.png');
const blob = await response.blob();
const image = await resolveImage(blob);
```
### Data Object
```js
const image = await resolveImage({
data: imageBuffer,
format: 'png', // 'png', 'jpg', or 'jpeg'
});
```
## Caching
Images are cached by default to avoid redundant processing. You can disable caching for individual requests:
```js
const image = await resolveImage({ uri: './image.png' }, { cache: false });
```
The cache has a default limit of 30 entries and uses LRU (Least Recently Used) eviction.
## Types
### Image
The resolved image object:
```ts
interface Image {
width: number;
height: number;
data: Buffer;
format: 'jpeg' | 'png';
key?: string;
}
```
### ImageSrc
All supported image source types:
```ts
type ImageSrc =
| Blob
| Buffer
| DataImageSrc
| LocalImageSrc
| RemoteImageSrc
| Base64ImageSrc;
type DataImageSrc = {
data: Buffer;
format: 'jpg' | 'jpeg' | 'png';
};
type LocalImageSrc = {
uri: string;
format?: 'jpg' | 'jpeg' | 'png';
};
type RemoteImageSrc = {
uri: string;
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
headers?: Record;
format?: 'jpg' | 'jpeg' | 'png';
body?: any;
credentials?: 'omit' | 'same-origin' | 'include';
};
type Base64ImageSrc = {
uri: `data:image${string}`;
};
```
## Supported Formats
- **PNG** - Portable Network Graphics
- **JPEG/JPG** - Joint Photographic Experts Group
JPEG images with EXIF orientation data are automatically handled, with width and height adjusted accordingly.
## License
MIT
================================================
FILE: packages/image/declarations.d.ts
================================================
declare module 'jay-peg' {
export function decode(data: Buffer): any;
export default { decode };
}
declare module '@react-pdf/png-js' {
class PNG {
constructor(data: Buffer);
width: number;
height: number;
}
export default PNG;
}
================================================
FILE: packages/image/globals.d.ts
================================================
declare global {
const BROWSER: boolean;
}
export {};
================================================
FILE: packages/image/package.json
================================================
{
"name": "@react-pdf/image",
"version": "3.0.4",
"license": "MIT",
"description": "Parses the images in png or jpeg format for react-pdf document",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"browser": {
"./lib/index.js": "./lib/index.browser.js"
},
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/image"
},
"scripts": {
"test": "vitest",
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@react-pdf/png-js": "^3.0.0",
"jay-peg": "^1.1.1"
},
"files": [
"lib"
]
}
================================================
FILE: packages/image/rollup.config.js
================================================
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
import typescript from '@rollup/plugin-typescript';
import replace from '@rollup/plugin-replace';
import ignore from 'rollup-plugin-ignore';
import nodePolyfills from 'rollup-plugin-polyfill-node';
import pkg from './package.json' with { type: 'json' };
const input = './src/index.ts';
const getExternal = ({ browser }) => [
...Object.keys(pkg.dependencies),
...(browser ? [] : ['fs', 'path', 'url']),
];
const getPlugins = ({ browser }) => [
typescript(),
replace({
preventAssignment: true,
values: { BROWSER: JSON.stringify(browser) },
}),
...(browser
? [ignore(['fs', 'path', 'url']), nodePolyfills({ include: null })]
: []),
];
const serverConfig = {
input,
output: { format: 'es', file: 'lib/index.js' },
external: getExternal({ browser: false }),
plugins: getPlugins({ browser: false }),
};
const browserConfig = {
input,
output: { format: 'es', file: 'lib/index.browser.js' },
external: getExternal({ browser: true }),
plugins: getPlugins({ browser: true }),
};
const dtsConfig = {
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
};
export default [serverConfig, browserConfig, dtsConfig];
================================================
FILE: packages/image/src/cache.ts
================================================
const createCache = ({ limit = 100 } = {}) => {
let cache = new Map();
return {
get: (key: string | null): T | undefined | null =>
key ? cache.get(key) ?? undefined : null,
set: (key: string, value: T) => {
cache.delete(key);
if (cache.size >= limit) {
const firstKey = cache.keys().next().value as string;
cache.delete(firstKey);
}
cache.set(key, value);
},
reset: () => {
cache = new Map();
},
length: () => cache.size,
};
};
export default createCache;
================================================
FILE: packages/image/src/index.ts
================================================
import resolveImage from './resolve';
export type { Image, ImageSrc } from './types';
export default resolveImage;
================================================
FILE: packages/image/src/jpeg.ts
================================================
import _JPEG from 'jay-peg';
import { Image } from './types';
class JPEG implements Image {
data: Buffer;
width: number;
height: number;
format: 'jpeg';
constructor(data: Buffer) {
this.data = data;
this.format = 'jpeg';
this.width = 0;
this.height = 0;
if (data.readUInt16BE(0) !== 0xffd8) {
throw new Error('SOI not found in JPEG');
}
const markers = _JPEG.decode(this.data);
let orientation;
for (let i = 0; i < markers.length; i += 1) {
const marker = markers[i];
if (marker.name === 'EXIF' && marker.entries.orientation) {
orientation = marker.entries.orientation;
}
if (marker.name === 'SOF') {
this.width ||= marker.width;
this.height ||= marker.height;
}
}
if (orientation > 4) {
[this.width, this.height] = [this.height, this.width];
}
}
static isValid(data: Buffer) {
return data && Buffer.isBuffer(data) && data.readUInt16BE(0) === 0xffd8;
}
}
export default JPEG;
================================================
FILE: packages/image/src/png.ts
================================================
import _PNG from '@react-pdf/png-js';
import { Image } from './types';
class PNG implements Image {
data: Buffer;
width: number;
height: number;
format: 'png';
constructor(data: Buffer) {
const png = new _PNG(data);
this.data = data;
this.width = png.width;
this.height = png.height;
this.format = 'png';
}
static isValid(data: Buffer): boolean {
return (
data &&
Buffer.isBuffer(data) &&
data[0] === 137 &&
data[1] === 80 &&
data[2] === 78 &&
data[3] === 71 &&
data[4] === 13 &&
data[5] === 10 &&
data[6] === 26 &&
data[7] === 10
);
}
}
export default PNG;
================================================
FILE: packages/image/src/resolve.ts
================================================
import fs from 'fs';
import url from 'url';
import path from 'path';
import PNG from './png';
import JPEG from './jpeg';
import createCache from './cache.js';
import {
Base64ImageSrc,
DataImageSrc,
Image,
ImageFormat,
ImageSrc,
LocalImageSrc,
RemoteImageSrc,
} from './types';
export const IMAGE_CACHE = createCache>({ limit: 30 });
const isBuffer = Buffer.isBuffer;
const isBlob = (src: ImageSrc): src is Blob => {
return typeof Blob !== 'undefined' && src instanceof Blob;
};
const isDataImageSrc = (src: ImageSrc): src is DataImageSrc => {
return 'data' in src;
};
const isDataUri = (imageSrc: ImageSrc): imageSrc is Base64ImageSrc =>
'uri' in imageSrc && imageSrc.uri.startsWith('data:');
const getAbsoluteLocalPath = (src: string) => {
if (BROWSER) {
throw new Error('Cannot check local paths in client-side environment');
}
const {
protocol,
auth,
host,
port,
hostname,
path: pathname,
} = url.parse(src);
const absolutePath = pathname ? path.resolve(src) : undefined;
if ((protocol && protocol !== 'file:') || auth || host || port || hostname) {
return undefined;
}
return absolutePath;
};
const fetchLocalFile = (src: LocalImageSrc): Promise =>
new Promise((resolve, reject) => {
try {
if (BROWSER) {
reject(new Error('Cannot fetch local file in this environment'));
return;
}
const absolutePath = getAbsoluteLocalPath(src.uri);
if (!absolutePath) {
reject(new Error(`Cannot fetch non-local path: ${src.uri}`));
return;
}
fs.readFile(absolutePath, (err, data) =>
err ? reject(err) : resolve(data),
);
} catch (err) {
reject(err);
}
});
const fetchRemoteFile = async (src: RemoteImageSrc) => {
const { method = 'GET', headers, body, credentials } = src;
const response = await fetch(src.uri, {
method,
headers,
body,
credentials,
});
const buffer = await response.arrayBuffer();
return Buffer.from(buffer);
};
const isValidFormat = (format: string): format is ImageFormat => {
const lower = format.toLowerCase();
return lower === 'jpg' || lower === 'jpeg' || lower === 'png';
};
const getImageFormat = (buffer: Buffer) => {
let format;
if (JPEG.isValid(buffer)) {
format = 'jpg' as const;
} else if (PNG.isValid(buffer)) {
format = 'png' as const;
}
return format;
};
function getImage(body: Buffer, format: string): Image | null {
switch (format.toLowerCase()) {
case 'jpg':
case 'jpeg':
return new JPEG(body);
case 'png':
return new PNG(body);
default:
return null;
}
}
const resolveBase64Image = async ({ uri }: Base64ImageSrc) => {
const match = /^data:image\/([a-zA-Z]*);base64,([^"]*)/g.exec(uri);
if (!match) throw new Error(`Invalid base64 image: ${uri}`);
const format = match[1];
const data = match[2];
if (!isValidFormat(format))
throw new Error(`Base64 image invalid format: ${format}`);
return getImage(Buffer.from(data, 'base64'), format);
};
const resolveImageFromData = async (src: DataImageSrc) => {
if (src.data && src.format) {
return getImage(src.data, src.format);
}
throw new Error(`Invalid data given for local file: ${JSON.stringify(src)}`);
};
const resolveBufferImage = async (buffer: Buffer) => {
const format = getImageFormat(buffer);
if (format) {
return getImage(buffer, format);
}
return null;
};
const resolveBlobImage = async (blob: Blob) => {
const { type } = blob;
if (!type || type === 'application/octet-stream') {
const arrayBuffer = await blob.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
return resolveBufferImage(buffer);
}
if (!type.startsWith('image/')) {
throw new Error(`Invalid blob type: ${type}`);
}
const format = type.replace('image/', '');
if (!isValidFormat(format)) {
throw new Error(`Invalid blob type: ${type}`);
}
const buffer = await blob.arrayBuffer();
return getImage(Buffer.from(buffer), format);
};
const resolveImageFromUrl = async (src: LocalImageSrc | RemoteImageSrc) => {
const data =
!BROWSER && getAbsoluteLocalPath(src.uri)
? await fetchLocalFile(src)
: await fetchRemoteFile(src);
const format = getImageFormat(data);
if (!format) {
throw new Error('Not valid image extension');
}
return getImage(data, format);
};
const getCacheKey = (src: ImageSrc): string | null => {
if (isBlob(src) || isBuffer(src)) return null;
if (isDataImageSrc(src)) return src.data?.toString('base64') ?? null;
return src.uri;
};
const resolveImage = (src: ImageSrc, { cache = true } = {}) => {
let image: Promise;
const cacheKey = getCacheKey(src);
if (isBlob(src)) {
image = resolveBlobImage(src);
} else if (isBuffer(src)) {
image = resolveBufferImage(src);
} else if (cache && IMAGE_CACHE.get(cacheKey)) {
return IMAGE_CACHE.get(cacheKey);
} else if (isDataUri(src)) {
image = resolveBase64Image(src);
} else if (isDataImageSrc(src)) {
image = resolveImageFromData(src);
} else {
image = resolveImageFromUrl(src);
}
if (cache && cacheKey) {
IMAGE_CACHE.set(cacheKey, image);
}
return image;
};
export default resolveImage;
================================================
FILE: packages/image/src/types.ts
================================================
export interface Image {
width: number;
height: number;
data: Buffer;
format: 'jpeg' | 'png';
key?: string;
}
export type ImageFormat = 'jpg' | 'jpeg' | 'png';
export type DataImageSrc = {
data: Buffer;
format: ImageFormat;
};
export type LocalImageSrc = {
uri: string;
format?: ImageFormat;
};
export type RemoteImageSrc = {
uri: string;
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
headers?: Record;
format?: ImageFormat;
body?: any;
credentials?: 'omit' | 'same-origin' | 'include';
};
export type Base64ImageSrc = {
uri: `data:image${string}`;
};
export type ImageSrc =
| Blob
| Buffer
| DataImageSrc
| LocalImageSrc
| RemoteImageSrc
| Base64ImageSrc;
================================================
FILE: packages/image/tests/cache.test.ts
================================================
import { describe, expect, test } from 'vitest';
import createCache from '../src/cache.js';
describe('Background', () => {
test('should have length 0 by default', () => {
const cache = createCache();
expect(cache.length()).toBe(0);
});
test('should return undefined for invalid key', () => {
const cache = createCache();
expect(cache.get('somekey')).toBe(undefined);
});
test('should be able to set pair key-value', () => {
const cache = createCache();
expect(() => cache.set('somekey', 'somevalue')).not.toThrow();
});
test('should get key value', () => {
const cache = createCache();
cache.set('somekey', 'somevalue');
expect(cache.get('somekey')).toEqual('somevalue');
});
test('should reset cache', () => {
const cache = createCache();
cache.set('somekey', 'somevalue');
expect(cache.get('somekey')).toEqual('somevalue');
cache.reset();
expect(cache.length()).toBe(0);
expect(cache.get('somekey')).toBeFalsy();
});
test('remove elements FIFO if limit exceeded', () => {
const cache = createCache({ limit: 3 });
cache.set('1', '1');
cache.set('2', '2');
cache.set('3', '3');
cache.set('4', '4');
cache.set('5', '5');
expect(cache.length()).toBe(3);
expect(cache.get('1')).toBe(undefined);
expect(cache.get('2')).toBe(undefined);
expect(cache.get('3')).toBe('3');
expect(cache.get('4')).toBe('4');
expect(cache.get('5')).toBe('5');
});
test('should return null when getting with null key', () => {
const cache = createCache();
cache.set('somekey', 'somevalue');
expect(cache.get(null)).toBeNull();
});
test('should use default limit of 100', () => {
const cache = createCache();
for (let i = 0; i < 105; i++) {
cache.set(`key${i}`, `value${i}`);
}
expect(cache.length()).toBe(100);
expect(cache.get('key0')).toBe(undefined);
expect(cache.get('key4')).toBe(undefined);
expect(cache.get('key5')).toBe('value5');
expect(cache.get('key104')).toBe('value104');
});
test('should overwrite existing key without increasing length', () => {
const cache = createCache({ limit: 3 });
cache.set('key1', 'value1');
cache.set('key2', 'value2');
cache.set('key1', 'updatedValue1');
expect(cache.get('key1')).toBe('updatedValue1');
expect(cache.length()).toBe(2);
});
test('should handle limit of 1', () => {
const cache = createCache({ limit: 1 });
cache.set('key1', 'value1');
expect(cache.get('key1')).toBe('value1');
expect(cache.length()).toBe(1);
cache.set('key2', 'value2');
expect(cache.get('key1')).toBe(undefined);
expect(cache.get('key2')).toBe('value2');
expect(cache.length()).toBe(1);
});
});
================================================
FILE: packages/image/tests/resolve.test.ts
================================================
import { beforeEach, describe, expect, test } from 'vitest';
import fs from 'fs';
import path from 'path';
import url from 'url';
import './types';
import resolveImage, { IMAGE_CACHE } from '../src/resolve';
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
const jpgImageUrl = 'https://react-pdf.org/static/images/quijote1.jpg';
const pngImageUrl = 'https://react-pdf.org/static/images/quijote2.png';
const jpgLogalPath = path.join(__dirname, './assets/test.jpg');
const localJPGImage = fs.readFileSync(jpgLogalPath);
const pngLogalPath = path.join(__dirname, './assets/test.png');
const localPNGImage = fs.readFileSync(pngLogalPath);
describe('image resolveImage', () => {
beforeEach(() => {
fetchMock.resetMocks();
IMAGE_CACHE.reset();
});
test('Should fetch remote image using GET method by default', async () => {
fetchMock.once(localJPGImage);
await resolveImage({ uri: jpgImageUrl });
expect(fetchMock.mock.calls[0]?.[1]?.method).toBe('GET');
});
test('Should fetch remote image using passed method', async () => {
fetchMock.once(localJPGImage);
await resolveImage({ uri: jpgImageUrl, method: 'POST' });
expect(fetchMock.mock.calls[0]?.[1]?.method).toBe('POST');
});
test('Should fetch remote image using passed headers', async () => {
fetchMock.once(localJPGImage);
const headers = { Authorization: 'Bearer qwerty' };
await resolveImage({ uri: jpgImageUrl, headers });
expect(fetchMock.mock.calls[0]?.[1]?.headers).toEqual(headers);
});
test('Should fetch remote image using passed body', async () => {
fetchMock.once(localJPGImage);
const body = 'qwerty';
await resolveImage({ uri: jpgImageUrl, body, method: 'POST' });
expect(fetchMock.mock.calls[0]?.[1]?.body).toEqual(body);
});
test('Should fetch remote image using passed credentials', async () => {
fetchMock.once(localJPGImage);
const credentials = 'include';
await resolveImage({ uri: jpgImageUrl, credentials });
expect(fetchMock.mock.calls[0]?.[1]?.credentials).toBe(credentials);
});
test('Should not include credentials if not exist', async () => {
fetchMock.once(localJPGImage);
await resolveImage({ uri: jpgImageUrl });
expect(fetchMock.mock.calls[0]?.[1]?.credentials).toBeUndefined();
});
test('Should render a jpeg image over http', async () => {
fetchMock.once(localJPGImage);
const image = await resolveImage({ uri: jpgImageUrl });
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a png image over http', async () => {
fetchMock.once(localPNGImage);
const image = await resolveImage({ uri: pngImageUrl });
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a local image from absolute path', async () => {
const absolutePath = path.join(__dirname, './assets/test.jpg');
const image = await resolveImage({ uri: absolutePath });
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a local image from relative path', async () => {
const image = await resolveImage({
uri: 'packages/layout/tests/assets/test.jpg',
});
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a local image from src object', async () => {
const image = await resolveImage({
uri: './packages/layout/tests/assets/test.jpg',
});
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a local image with spaces in filename', async () => {
const image = await resolveImage({
uri: './packages/image/tests/assets/test with spaces.jpg',
});
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a local image with special characters in filename', async () => {
const image = await resolveImage({
uri: './packages/image/tests/assets/special_ _%20_@&é"\'(§è!çà)-^$ù`,;:=?.+%£¨*<>.jpg',
});
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a local image from data', async () => {
const image = await resolveImage({ data: localJPGImage, format: 'jpg' });
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a base64 image', async () => {
const image = await resolveImage({
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
});
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a buffer jpg image', async () => {
const image = await resolveImage(localJPGImage);
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a buffer png image', async () => {
const image = await resolveImage(localPNGImage);
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should not cache previously loaded remote images if flag false', async () => {
fetchMock.mockResponse(localJPGImage);
const image1 = await resolveImage({ uri: jpgImageUrl }, { cache: false });
const image2 = await resolveImage({ uri: jpgImageUrl }, { cache: false });
expect(image1).not.toBe(image2);
});
test('Should cache previously loaded local images by default', async () => {
fetchMock.mockResponse(localJPGImage);
const image1 = await resolveImage({ uri: jpgImageUrl });
const image2 = await resolveImage({ uri: jpgImageUrl });
expect(image1).toBe(image2);
});
test('Should not cache previously loaded local images if flag false', async () => {
fetchMock.mockResponse(localJPGImage);
const image1 = await resolveImage(localJPGImage, { cache: false });
const image2 = await resolveImage(localJPGImage, { cache: false });
expect(image1).not.toBe(image2);
});
test('Should render a blob image', async () => {
const blob = new Blob([localJPGImage], { type: 'image/jpeg' });
const image = await resolveImage(blob);
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a blob without type', async () => {
const blob = new Blob([localJPGImage]);
const image = await resolveImage(blob);
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should render a blob image with type application/octet-stream', async () => {
const blob = new Blob([localJPGImage], {
type: 'application/octet-stream',
});
const image = await resolveImage(blob);
expect(image?.data).toBeTruthy();
expect(image?.width).toBeGreaterThan(0);
expect(image?.height).toBeGreaterThan(0);
});
test('Should throw error for unsupported base64 format', async () => {
await expect(
resolveImage({
uri: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
}),
).rejects.toThrow('Base64 image invalid format: gif');
});
test('Should throw error for invalid base64 URI', async () => {
await expect(
resolveImage({ uri: 'data:image/pngbase64,invalid' } as any),
).rejects.toThrow('Invalid base64 image');
});
test('Should throw error for invalid blob type', async () => {
const blob = new Blob([localJPGImage], { type: 'text/plain' });
await expect(resolveImage(blob)).rejects.toThrow(
'Invalid blob type: text/plain',
);
});
test('Should throw error for unsupported blob image type', async () => {
const blob = new Blob([localJPGImage], { type: 'image/gif' });
await expect(resolveImage(blob)).rejects.toThrow(
'Invalid blob type: image/gif',
);
});
test('Should throw error for invalid data source', async () => {
await expect(
resolveImage({ data: undefined as any, format: 'jpg' }),
).rejects.toThrow('Invalid data given for local file');
});
test('Should throw error for non-existent local file', async () => {
await expect(
resolveImage({ uri: '/nonexistent/path/image.jpg' }),
).rejects.toThrow();
});
test('Should return null for invalid buffer', async () => {
const invalidBuffer = Buffer.from('not an image');
const image = await resolveImage(invalidBuffer);
expect(image).toBeNull();
});
test('Should throw on network fetch failure', async () => {
fetchMock.once(() => {
throw new Error('Network error');
});
await expect(resolveImage({ uri: jpgImageUrl })).rejects.toThrow(
'Network error',
);
});
test('Should throw for unsupported remote image format', async () => {
// GIF89a magic bytes - neither JPEG nor PNG
const gifBuffer = Buffer.from([0x47, 0x49, 0x46, 0x38, 0x39, 0x61]);
fetchMock.once(gifBuffer);
await expect(
resolveImage({ uri: 'https://example.com/image.gif' }),
).rejects.toThrow('Not valid image extension');
});
test('Should cache DataImageSrc images using base64 key', async () => {
const image1 = await resolveImage({ data: localJPGImage, format: 'jpg' });
const image2 = await resolveImage({ data: localJPGImage, format: 'jpg' });
expect(image1).toBe(image2);
});
test('Should return null when getting cache with null key', () => {
expect(IMAGE_CACHE.get(null)).toBeNull();
});
});
================================================
FILE: packages/image/tests/types.ts
================================================
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-namespace */
import Global = NodeJS.Global;
import type { Mock } from 'vitest';
declare global {
const fetchMock: FetchMock;
namespace NodeJS {
interface Global {
fetch: FetchMock;
}
}
}
export interface GlobalWithFetchMock extends Global {
fetchMock: FetchMock;
fetch: FetchMock;
}
export interface FetchMock
extends Mock<
[string | Request | undefined, RequestInit | undefined],
Promise
> {
(input: string | Request, init?: RequestInit): Promise;
/**
* Response mocking
*/
mockResponse(value: Buffer): FetchMock;
mockResponse(fn: MockResponseInitFunction): FetchMock;
mockResponse(response: string, responseInit?: MockParams): FetchMock;
/**
* alias for mockResponseOnce
*/
once(value: Buffer): FetchMock;
once(fn: MockResponseInitFunction): FetchMock;
once(url: string, responseInit?: MockParams): FetchMock;
/**
* Returns all the requests that have been made to the mocked fetch function.
* Does not include aborted requests.
*/
requests(): Request[];
resetMocks(): void;
enableMocks(): void;
disableMocks(): void;
}
export interface MockParams {
status?: number;
statusText?: string;
headers?: string[][] | { [key: string]: string }; // HeadersInit
url?: string;
/** Set >= 1 to have redirected return true. Only applicable to Node.js */
counter?: number;
}
export interface MockResponseInit extends MockParams {
body?: string;
init?: MockParams;
}
export type ErrorOrFunction = Error | ((...args: any[]) => Promise);
export type UrlOrPredicate = string | RegExp | ((input: Request) => boolean);
export type MockResponseInitFunction = (
request: Request,
) => MockResponseInit | string | Promise;
declare const fetchMock: FetchMock;
================================================
FILE: packages/image/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src", "**/*.d.ts"],
}
================================================
FILE: packages/image/vitest.config.js
================================================
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
setupFiles: ['vitest.setup.js'],
include: ['tests/*.{test,spec}.?(c|m)[jt]s?(x)'],
watch: false,
},
});
================================================
FILE: packages/image/vitest.setup.js
================================================
import { vi } from 'vitest';
import createFetchMock from 'vitest-fetch-mock';
const fetchMocker = createFetchMock(vi);
fetchMocker.enableMocks();
global.BROWSER = false;
================================================
FILE: packages/layout/.gitignore
================================================
lib
================================================
FILE: packages/layout/CHANGELOG.md
================================================
# @react-pdf/layout
## 4.4.2
### Patch Changes
- [#3254](https://github.com/diegomura/react-pdf/pull/3254) [`cc1aff24`](https://github.com/diegomura/react-pdf/commit/cc1aff2454263f64d1f79c9df051d21d74f8d7cf) Thanks [@rafw87](https://github.com/rafw87)! - fix duplicated bookmarks when View is spanning multiple pages
- Updated dependencies [[`a5979c15`](https://github.com/diegomura/react-pdf/commit/a5979c1568761107076172e4c1843e66f62a08ab), [`f034491b`](https://github.com/diegomura/react-pdf/commit/f034491b1f77ce6f18a5db88e70b10b9c502ca35), [`04922fea`](https://github.com/diegomura/react-pdf/commit/04922fea2e60930ac550ec31beaeb7f20551cf63)]:
- @react-pdf/image@3.0.4
- @react-pdf/textkit@6.1.0
- @react-pdf/types@2.9.2
- @react-pdf/stylesheet@6.1.2
## 4.4.1
### Patch Changes
- [#3152](https://github.com/diegomura/react-pdf/pull/3152) [`beaffd3d`](https://github.com/diegomura/react-pdf/commit/beaffd3d2bb5ac81033ef53421413662d6d71158) Thanks [@Namchee](https://github.com/Namchee)! - chore: replace emoji-regex with emoji-regex-xs
- [#3190](https://github.com/diegomura/react-pdf/pull/3190) [`a99d10fb`](https://github.com/diegomura/react-pdf/commit/a99d10fb2fbb6bfeb233ccb9bf0b703ed092e8d5) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - Fix yoga error Invalid array length at Array.push()
Fix infinite loop while wrapping pages
- [#3203](https://github.com/diegomura/react-pdf/pull/3203) [`ec063bec`](https://github.com/diegomura/react-pdf/commit/ec063bec8d6a56df42849a8e66521fad7719dc29) Thanks [@100Gyeon](https://github.com/100Gyeon)! - fix: prevent unhandled promise rejections when loading emoji images
- Updated dependencies []:
- @react-pdf/types@2.9.1
- @react-pdf/stylesheet@6.1.1
## 4.4.0
### Minor Changes
- [#3112](https://github.com/diegomura/react-pdf/pull/3112) [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a) Thanks [@diegomura](https://github.com/diegomura)! - feat: add xLinkHref, gradientTransform and gradientUnits support
### Patch Changes
- Updated dependencies [[`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/stylesheet@6.1.0
- @react-pdf/types@2.9.0
## 4.3.1
### Patch Changes
- [`e257f7ee`](https://github.com/diegomura/react-pdf/commit/e257f7ee18ff09f4895cd16c0b21b824678384c8) Thanks [@diegomura](https://github.com/diegomura)! - fix: font store types
- Updated dependencies []:
- @react-pdf/types@2.8.2
- @react-pdf/stylesheet@6.0.2
## 4.3.0
### Minor Changes
- [#3100](https://github.com/diegomura/react-pdf/pull/3100) [`a9ef6416`](https://github.com/diegomura/react-pdf/commit/a9ef6416473c86f6d8fe35c3d7231e642d6ae265) Thanks [@diegomura](https://github.com/diegomura)! - feat: support percentage gap
- [#3102](https://github.com/diegomura/react-pdf/pull/3102) [`24690f52`](https://github.com/diegomura/react-pdf/commit/24690f5238e4eacf28351cf9996856a7d196d29e) Thanks [@diegomura](https://github.com/diegomura)! - feat: handle standard fonts in fonts package
- [#3092](https://github.com/diegomura/react-pdf/pull/3092) [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert layout package to TS
- [#3103](https://github.com/diegomura/react-pdf/pull/3103) [`b06d3a0f`](https://github.com/diegomura/react-pdf/commit/b06d3a0f64593ac18097efd061334f1e5bd70095) Thanks [@diegomura](https://github.com/diegomura)! - refactor: unify font substitution engines
### Patch Changes
- [#3104](https://github.com/diegomura/react-pdf/pull/3104) [`ddfa3675`](https://github.com/diegomura/react-pdf/commit/ddfa367587618b313b4b0b3b57a9a7631e8e7604) Thanks [@diegomura](https://github.com/diegomura)! - feat(textkit): expect font array
- [#3098](https://github.com/diegomura/react-pdf/pull/3098) [`bfb51ec0`](https://github.com/diegomura/react-pdf/commit/bfb51ec09b851c52659ce16fed1286173e9516a9) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert render package to TS
- [#3101](https://github.com/diegomura/react-pdf/pull/3101) [`fce45ea5`](https://github.com/diegomura/react-pdf/commit/fce45ea5860038e7f3b227cabf0dd6212f4404b8) Thanks [@diegomura](https://github.com/diegomura)! - fix: layout package types
- Updated dependencies [[`2a4f1bfc`](https://github.com/diegomura/react-pdf/commit/2a4f1bfca6b84e6c6bbde683447ce8079a1febbe), [`7cd66e4f`](https://github.com/diegomura/react-pdf/commit/7cd66e4fc37cd1393adc6250a919fe2629812082), [`ddfa3675`](https://github.com/diegomura/react-pdf/commit/ddfa367587618b313b4b0b3b57a9a7631e8e7604), [`3fb01a90`](https://github.com/diegomura/react-pdf/commit/3fb01a90e590a31c097b3422fc911af61d65420a), [`c7b74963`](https://github.com/diegomura/react-pdf/commit/c7b749632f07db7808d58d99357dc830d4895da8), [`bfb51ec0`](https://github.com/diegomura/react-pdf/commit/bfb51ec09b851c52659ce16fed1286173e9516a9), [`24690f52`](https://github.com/diegomura/react-pdf/commit/24690f5238e4eacf28351cf9996856a7d196d29e), [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8), [`b06d3a0f`](https://github.com/diegomura/react-pdf/commit/b06d3a0f64593ac18097efd061334f1e5bd70095)]:
- @react-pdf/stylesheet@6.0.1
- @react-pdf/types@2.8.1
- @react-pdf/textkit@6.0.0
- @react-pdf/image@3.0.3
- @react-pdf/fns@3.1.2
## 4.2.3
### Patch Changes
- [#3082](https://github.com/diegomura/react-pdf/pull/3082) [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45) Thanks [@diegomura](https://github.com/diegomura)! - feat: rework and type stylesheet package
- [#3077](https://github.com/diegomura/react-pdf/pull/3077) [`442ce355`](https://github.com/diegomura/react-pdf/commit/442ce35534f916b9146a35fd03870387ed488d92) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert textkit package to TS
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6), [`96c2464d`](https://github.com/diegomura/react-pdf/commit/96c2464dfaa7294e0d79b7ed64743bfd7b1a8c72), [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45), [`700535c5`](https://github.com/diegomura/react-pdf/commit/700535c57ff1b105d923be70f4fc4bfdf4479f91), [`442ce355`](https://github.com/diegomura/react-pdf/commit/442ce35534f916b9146a35fd03870387ed488d92), [`8d39fc46`](https://github.com/diegomura/react-pdf/commit/8d39fc4602730755ee63824ad4ed6ecd1bcd059f), [`3007d34a`](https://github.com/diegomura/react-pdf/commit/3007d34ad3e10bf32ada3631938f5bb08e1c549f)]:
- @react-pdf/pdfkit@4.0.2
- @react-pdf/primitives@4.1.1
- @react-pdf/types@2.8.0
- @react-pdf/stylesheet@6.0.0
- @react-pdf/fns@3.1.1
- @react-pdf/textkit@5.0.3
- @react-pdf/image@3.0.2
## 4.2.2
### Patch Changes
- Updated dependencies [[`d36ace66`](https://github.com/diegomura/react-pdf/commit/d36ace66c77d57d845894e89772be7ae0cdd25ee)]:
- @react-pdf/fns@3.1.0
- @react-pdf/stylesheet@5.2.2
- @react-pdf/textkit@5.0.2
## 4.2.1
### Patch Changes
- [`fabecc56`](https://github.com/diegomura/react-pdf/commit/fabecc56727dfb6d590a3fa1e11f50250ecbbea1) Thanks [@diegomura](https://github.com/diegomura)! - chore: bump yoga-layout
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`01944231`](https://github.com/diegomura/react-pdf/commit/01944231a342d502b832aeecb4c313020b8360c8), [`6d875056`](https://github.com/diegomura/react-pdf/commit/6d875056a07e8479ef695416c1fed575491b6ff1), [`49daae8f`](https://github.com/diegomura/react-pdf/commit/49daae8fdfba672a3e828847232ee9b70bb51711), [`5cc47319`](https://github.com/diegomura/react-pdf/commit/5cc47319bb428f6d4bcad21cd6dba9afca5cdc17), [`aa0f6725`](https://github.com/diegomura/react-pdf/commit/aa0f672589683a66abc79f838291996ae9aaffb8)]:
- @react-pdf/primitives@4.1.0
- @react-pdf/types@2.7.1
- @react-pdf/pdfkit@4.0.1
- @react-pdf/stylesheet@5.2.1
## 4.2.0
### Minor Changes
- [#2773](https://github.com/diegomura/react-pdf/pull/2773) [`18834efa`](https://github.com/diegomura/react-pdf/commit/18834efac2787a636c378718fee40cbe74f01ab8) Thanks [@nikischin](https://github.com/nikischin)! - Changed unit behavior according to PDF spec. Please note that all unitless values are considered as user unit which is a 72dpi equality of the value. This is according to PDF spec and ensures a consistent layout independent of the dpi setting.
### Patch Changes
- Updated dependencies [[`18834efa`](https://github.com/diegomura/react-pdf/commit/18834efac2787a636c378718fee40cbe74f01ab8)]:
- @react-pdf/stylesheet@5.2.0
## 4.1.3
### Patch Changes
- Updated dependencies [[`00bfdc1e`](https://github.com/diegomura/react-pdf/commit/00bfdc1e5a6c673d2de7b3ab09d5020e932562fb)]:
- @react-pdf/textkit@5.0.1
## 4.1.2
### Patch Changes
- [#2955](https://github.com/diegomura/react-pdf/pull/2955) [`425f1183`](https://github.com/diegomura/react-pdf/commit/425f1183bba9a83fd5712a1371abb6cea2ed8fca) Thanks [@diegomura](https://github.com/diegomura)! - feat: support rem units
- [#2952](https://github.com/diegomura/react-pdf/pull/2952) [`2c3c887e`](https://github.com/diegomura/react-pdf/commit/2c3c887ea2d3aed2863f49bff375d08feaf975aa) Thanks [@diegomura](https://github.com/diegomura)! - feat: support multiple line-height units
- Updated dependencies [[`425f1183`](https://github.com/diegomura/react-pdf/commit/425f1183bba9a83fd5712a1371abb6cea2ed8fca), [`2c3c887e`](https://github.com/diegomura/react-pdf/commit/2c3c887ea2d3aed2863f49bff375d08feaf975aa)]:
- @react-pdf/stylesheet@5.1.0
## 4.1.1
### Patch Changes
- [#2947](https://github.com/diegomura/react-pdf/pull/2947) [`ed562b9b`](https://github.com/diegomura/react-pdf/commit/ed562b9b7f14bc76a1cd83aaaf1dab966bd7540b) Thanks [@diegomura](https://github.com/diegomura)! - feat: remove cross-fetch
- Updated dependencies [[`ed562b9b`](https://github.com/diegomura/react-pdf/commit/ed562b9b7f14bc76a1cd83aaaf1dab966bd7540b), [`77e480cd`](https://github.com/diegomura/react-pdf/commit/77e480cdd161270ac07453525dfaf993e2d3f17f)]:
- @react-pdf/image@3.0.1
- @react-pdf/stylesheet@5.0.1
## 4.1.0
### Minor Changes
- [#2736](https://github.com/diegomura/react-pdf/pull/2736) [`b242e59a`](https://github.com/diegomura/react-pdf/commit/b242e59a14a856e280c9fcbad81f707248819721) Thanks [@siketyan](https://github.com/siketyan)! - Use monochrome emojis contained in the font family if no emoji source available
## 4.0.1
### Patch Changes
- [#2878](https://github.com/diegomura/react-pdf/pull/2878) [`58f9a047`](https://github.com/diegomura/react-pdf/commit/58f9a04740ed1331ef1dfa9999fb43c0ee10fa5b) Thanks [@jmezzacappa](https://github.com/jmezzacappa)! - Prevent Yoga init from running more than once
## 4.0.0
### Major Changes
- [#2711](https://github.com/diegomura/react-pdf/pull/2711) [`42570321`](https://github.com/diegomura/react-pdf/commit/42570321af54bf331ca81f09a102664cd9f7c46a) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Update Yoga to 3.0
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Minor Changes
- [#2876](https://github.com/diegomura/react-pdf/pull/2876) [`afe4bcfe`](https://github.com/diegomura/react-pdf/commit/afe4bcfe6f4b991cf22341242fc27d169b758d47) Thanks [@diegomura](https://github.com/diegomura)! - feat: add gap percentage support
- [#2875](https://github.com/diegomura/react-pdf/pull/2875) [`46c3047d`](https://github.com/diegomura/react-pdf/commit/46c3047de56ae82f062b72c4910a4e6096eee99f) Thanks [@diegomura](https://github.com/diegomura)! - feat: add position: static support
- [#2874](https://github.com/diegomura/react-pdf/pull/2874) [`55973278`](https://github.com/diegomura/react-pdf/commit/55973278ac8bc8f703b63844f57d6f155ae8d86f) Thanks [@diegomura](https://github.com/diegomura)! - feat: add align-content: space-evenly support
### Patch Changes
- Updated dependencies [[`fdcef566`](https://github.com/diegomura/react-pdf/commit/fdcef5666e4eeed542b625d394cdfe60d6346600), [`46c3047d`](https://github.com/diegomura/react-pdf/commit/46c3047de56ae82f062b72c4910a4e6096eee99f), [`55973278`](https://github.com/diegomura/react-pdf/commit/55973278ac8bc8f703b63844f57d6f155ae8d86f), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/pdfkit@4.0.0
- @react-pdf/image@3.0.0
- @react-pdf/types@2.7.0
- @react-pdf/primitives@4.0.0
- @react-pdf/stylesheet@5.0.0
- @react-pdf/textkit@5.0.0
- @react-pdf/fns@3.0.0
## 3.13.0
### Minor Changes
- [#2771](https://github.com/diegomura/react-pdf/pull/2771) [`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2) Thanks [@nikischin](https://github.com/nikischin)! - fix: fix dpi
### Patch Changes
- [#2864](https://github.com/diegomura/react-pdf/pull/2864) [`e425ca4`](https://github.com/diegomura/react-pdf/commit/e425ca4add7eb353b6282a40fd1020aad0da36c4) Thanks [@nnaku](https://github.com/nnaku)! - Prevent loading yoga-layout wasm binaries more than once
- [#2822](https://github.com/diegomura/react-pdf/pull/2822) [`e42a79a`](https://github.com/diegomura/react-pdf/commit/e42a79a3857932a4ebc89feb6e4d2c891280d633) Thanks [@mantljosh](https://github.com/mantljosh)! - fix: prevent infinite loop while splitting pages
- [#2747](https://github.com/diegomura/react-pdf/pull/2747) [`5af35ec`](https://github.com/diegomura/react-pdf/commit/5af35ec9743cc0d7bf75f5ca789627517ff35816) Thanks [@andrew-spare](https://github.com/andrew-spare)! - fix: font selection regression
- Updated dependencies [[`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2), [`4bafab8`](https://github.com/diegomura/react-pdf/commit/4bafab8455c9003759f48bad20a720baf4ed189b)]:
- @react-pdf/pdfkit@3.2.0
- @react-pdf/stylesheet@4.3.0
- @react-pdf/types@2.6.0
## 3.12.1
### Patch Changes
- Updated dependencies [[`22a34a9`](https://github.com/diegomura/react-pdf/commit/22a34a91b16a201cd8288e0dbea9368b12ca73f5)]:
- @react-pdf/types@2.5.0
- @react-pdf/stylesheet@4.2.5
## 3.12.0
### Minor Changes
- [#2640](https://github.com/diegomura/react-pdf/pull/2640) [`67c265a`](https://github.com/diegomura/react-pdf/commit/67c265a7e39cc0baa319f49137219677904695e6) Thanks [@nikgraf](https://github.com/nikgraf)! - Add support for fontFamily fallbacks e.g. fontFamily: ['Roboto', 'NotoSansArabic']
### Patch Changes
- Updated dependencies [[`713690c`](https://github.com/diegomura/react-pdf/commit/713690cca266116bb7e80d13cf84bc843f9dfd52)]:
- @react-pdf/pdfkit@3.1.10
## 3.11.5
### Patch Changes
- Updated dependencies [[`e2d21a4`](https://github.com/diegomura/react-pdf/commit/e2d21a433b881bb96ea4d0b3a01a7297dd1f4a94)]:
- @react-pdf/pdfkit@3.1.9
## 3.11.4
### Patch Changes
- Updated dependencies [[`68bfc57`](https://github.com/diegomura/react-pdf/commit/68bfc575adfb95302e320019715d1eec5398259f)]:
- @react-pdf/pdfkit@3.1.8
- @react-pdf/image@2.3.6
## 3.11.3
### Patch Changes
- [#2629](https://github.com/diegomura/react-pdf/pull/2629) [`087ee22`](https://github.com/diegomura/react-pdf/commit/087ee22f63a922a2d3ee01bae3b0351f99cb9021) Thanks [@diegomura](https://github.com/diegomura)! - fix: resolve styles on dynamic elements
- Updated dependencies [[`da10a9b`](https://github.com/diegomura/react-pdf/commit/da10a9bb43dc4c4765687850444a24cbc4eb402a)]:
- @react-pdf/pdfkit@3.1.7
- @react-pdf/image@2.3.5
## 3.11.2
### Patch Changes
- Updated dependencies [[`dc54c13`](https://github.com/diegomura/react-pdf/commit/dc54c13625510482e93f80ed5cc07cf3a6a6d34c)]:
- @react-pdf/pdfkit@3.1.6
## 3.11.1
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/stylesheet@4.2.4
- @react-pdf/textkit@4.4.1
- @react-pdf/image@2.3.4
- @react-pdf/fns@2.2.1
- @react-pdf/pdfkit@3.1.5
## 3.11.0
### Minor Changes
- [#2600](https://github.com/diegomura/react-pdf/pull/2600) [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7) Thanks [@diegomura](https://github.com/diegomura)! - feat: bidi support
### Patch Changes
- [#2573](https://github.com/diegomura/react-pdf/pull/2573) [`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235) Thanks [@davbrito](https://github.com/davbrito)! - feat: add support for resolving blob images
- Updated dependencies [[`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235), [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7)]:
- @react-pdf/image@2.3.3
- @react-pdf/types@2.4.1
- @react-pdf/textkit@4.4.0
- @react-pdf/fns@2.2.0
- @react-pdf/pdfkit@3.1.4
- @react-pdf/stylesheet@4.2.3
## 3.10.4
### Patch Changes
- Updated dependencies [[`0590324`](https://github.com/diegomura/react-pdf/commit/0590324d7a6d75c0a49520b3f99cfb6594239390)]:
- @react-pdf/image@2.3.2
- @react-pdf/pdfkit@3.1.3
## 3.10.3
### Patch Changes
- Updated dependencies [[`44bd45b`](https://github.com/diegomura/react-pdf/commit/44bd45b1961ca8bae4a2f84cc77db945e5c43419)]:
- @react-pdf/pdfkit@3.1.2
## 3.10.2
### Patch Changes
- Updated dependencies [[`fb5273d`](https://github.com/diegomura/react-pdf/commit/fb5273d8d80d919f7b9c214e02d67b79ce23fa19)]:
- @react-pdf/types@2.4.0
- @react-pdf/stylesheet@4.2.2
## 3.10.1
### Patch Changes
- Updated dependencies [[`36c6ba3`](https://github.com/diegomura/react-pdf/commit/36c6ba30ae73a512f19fe5bc47ac8c304887c0da), [`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8)]:
- @react-pdf/pdfkit@3.1.1
- @react-pdf/image@2.3.1
## 3.10.0
### Minor Changes
- [#2505](https://github.com/diegomura/react-pdf/pull/2505) [`0f5c43f`](https://github.com/diegomura/react-pdf/commit/0f5c43fa6f3c0b53c067200cc1ac21e651504760) Thanks [@diegomura](https://github.com/diegomura)! - feat: wasm yoga
### Patch Changes
- Updated dependencies [[`9e5842b`](https://github.com/diegomura/react-pdf/commit/9e5842bbecca6e249af2c5fc50078bb7ddd5420f)]:
- @react-pdf/types@2.3.6
- @react-pdf/stylesheet@4.2.1
## 3.9.1
### Patch Changes
- Updated dependencies [[`42bbbda`](https://github.com/diegomura/react-pdf/commit/42bbbda48058acd2d36d7a92c812d133608c459e)]:
- @react-pdf/primitives@3.1.1
## 3.9.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
### Patch Changes
- [#2504](https://github.com/diegomura/react-pdf/pull/2504) [`e705d98`](https://github.com/diegomura/react-pdf/commit/e705d9862e3364fde00cbe6cdaf06d492bf58526) Thanks [@diegomura](https://github.com/diegomura)! - feat: nested text inherit background color
* [#2496](https://github.com/diegomura/react-pdf/pull/2496) [`c8fe2c8`](https://github.com/diegomura/react-pdf/commit/c8fe2c86639cb8e44f26f78e62fc67379a8e3ceb) Thanks [@diegomura](https://github.com/diegomura)! - fix: copyright and registered symbol rendering
- [#2502](https://github.com/diegomura/react-pdf/pull/2502) [`96ea576`](https://github.com/diegomura/react-pdf/commit/96ea5764cbe4e6e3869cd0fe6620e5216f94ffc0) Thanks [@DominikMeca](https://github.com/DominikMeca)! - feat: include text preceeding special case emojis, include ™ symbol in excluded emojis
- Updated dependencies [[`6bfe7e8`](https://github.com/diegomura/react-pdf/commit/6bfe7e8a30d96c04a1552800159992705f3605b1), [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37)]:
- @react-pdf/stylesheet@4.2.0
- @react-pdf/primitives@3.1.0
- @react-pdf/textkit@4.3.0
- @react-pdf/pdfkit@3.1.0
- @react-pdf/image@2.3.0
- @react-pdf/fns@2.1.0
## 3.8.0
### Minor Changes
- [#2400](https://github.com/diegomura/react-pdf/pull/2400) [`0538bd9`](https://github.com/diegomura/react-pdf/commit/0538bd900e5490a5ef81bcdbd1676fc9f9ae6acb) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - Rework minPresenceAhead detection and add tests
## 3.7.0
### Minor Changes
- [#2473](https://github.com/diegomura/react-pdf/pull/2473) [`b227e0e`](https://github.com/diegomura/react-pdf/commit/b227e0e303da8bca754910f55f5d27dd18f3a874) Thanks [@mskec](https://github.com/mskec)! - Upgraded yoga to v2 and dropped bundled yoga v1 package
### Patch Changes
- [#2479](https://github.com/diegomura/react-pdf/pull/2479) [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4) Thanks [@diegomura](https://github.com/diegomura)! - fix linting
* [#2467](https://github.com/diegomura/react-pdf/pull/2467) [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2) Thanks [@JaeSeoKim](https://github.com/JaeSeoKim)! - feat: add withVariationSelectors option to registerEmojiSource [#2466](https://github.com/diegomura/react-pdf/issues/2466)
* Updated dependencies [[`e5c8fde`](https://github.com/diegomura/react-pdf/commit/e5c8fde9379a9a85ecac7e3d6273953e39d65f8d), [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4), [`b457a0c`](https://github.com/diegomura/react-pdf/commit/b457a0cc1c1352325e6c633af3000a3c9241f7f7), [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2), [`4c40b14`](https://github.com/diegomura/react-pdf/commit/4c40b149cfed42f2513e1dd330a92ccc3363c04f)]:
- @react-pdf/types@2.3.5
- @react-pdf/textkit@4.2.1
- @react-pdf/pdfkit@3.0.4
- @react-pdf/image@2.2.3
- @react-pdf/stylesheet@4.1.9
## 3.6.4
### Patch Changes
- Updated dependencies [[`4cfb84d`](https://github.com/diegomura/react-pdf/commit/4cfb84d9f3d2301720b68b4c40a0257b9520c6e1)]:
- @react-pdf/pdfkit@3.0.3
## 3.6.3
### Patch Changes
- Updated dependencies [[`4a55c1b`](https://github.com/diegomura/react-pdf/commit/4a55c1b2ed19e460ccae6e749ed94c16729a23c4)]:
- @react-pdf/image@2.2.2
- @react-pdf/types@2.3.4
- @react-pdf/stylesheet@4.1.8
## 3.6.2
### Patch Changes
- Updated dependencies [[`1e1fbdc`](https://github.com/diegomura/react-pdf/commit/1e1fbdc3c33ced46d8c7ebba7a196733cb789d59), [`8636812`](https://github.com/diegomura/react-pdf/commit/86368122ed87621d19ae3bc248080e17703d9fcb)]:
- @react-pdf/types@2.3.3
- @react-pdf/stylesheet@4.1.7
## 3.6.1
### Patch Changes
- Updated dependencies [[`a25dbcb`](https://github.com/diegomura/react-pdf/commit/a25dbcb32b65c300f5b088e8b210bb0c1abca5c2)]:
- @react-pdf/types@2.3.2
- @react-pdf/stylesheet@4.1.6
## 3.6.0
### Minor Changes
- [#2254](https://github.com/diegomura/react-pdf/pull/2254) [`d48039c`](https://github.com/diegomura/react-pdf/commit/d48039c9e224346fd22395f48eb03ceffa5e3dd6) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - Enable more modern emoji (Unicode 13+)
## 3.5.1
### Patch Changes
- [#2252](https://github.com/diegomura/react-pdf/pull/2252) [`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59) Thanks [@jeetiss](https://github.com/jeetiss)! - implement function as emoji source to build more complex urls
- Updated dependencies [[`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59)]:
- @react-pdf/types@2.3.1
- @react-pdf/stylesheet@4.1.5
## 3.5.0
### Minor Changes
- [#2214](https://github.com/diegomura/react-pdf/pull/2214) [`2db67a3`](https://github.com/diegomura/react-pdf/commit/2db67a38b9be98b7816a2b5aa4733446b95e3724) Thanks [@KODIKAS-NL](https://github.com/KODIKAS-NL)! - added base support for verticalAlign "super" and "sub"
### Patch Changes
- Updated dependencies [[`2db67a3`](https://github.com/diegomura/react-pdf/commit/2db67a38b9be98b7816a2b5aa4733446b95e3724), [`eff1ff0`](https://github.com/diegomura/react-pdf/commit/eff1ff0fefcd710994e4654904ef55843af76a17), [`c5b21fc`](https://github.com/diegomura/react-pdf/commit/c5b21fc97b704b3616522b897847a9d3c9dc0052)]:
- @react-pdf/textkit@4.2.0
- @react-pdf/types@2.3.0
- @react-pdf/fns@2.0.1
- @react-pdf/yoga@4.1.2
- @react-pdf/stylesheet@4.1.4
## 3.4.1
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
- Updated dependencies [[`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905)]:
- @react-pdf/stylesheet@4.1.3
- @react-pdf/textkit@4.1.1
- @react-pdf/pdfkit@3.0.2
- @react-pdf/image@2.2.1
- @react-pdf/yoga@4.1.1
## 3.4.0
### Minor Changes
- [#2198](https://github.com/diegomura/react-pdf/pull/2198) [`c981784`](https://github.com/diegomura/react-pdf/commit/c981784b172e9a7631edb7a1fe41ce77bc6ccdee) Thanks [@Solpatium](https://github.com/Solpatium)! - Break on containers whose children can not fit on a page
## 3.3.1
### Patch Changes
- [#2186](https://github.com/diegomura/react-pdf/pull/2186) [`72435bd`](https://github.com/diegomura/react-pdf/commit/72435bd81afdada5b811a1d82af0c873cfb62fa0) Thanks [@jeetiss](https://github.com/jeetiss)! - update yoga-layout to support flexBasis auto
- Updated dependencies [[`72435bd`](https://github.com/diegomura/react-pdf/commit/72435bd81afdada5b811a1d82af0c873cfb62fa0)]:
- @react-pdf/stylesheet@4.1.1
- @react-pdf/yoga@4.1.0
## 3.3.0
### Minor Changes
- [#2160](https://github.com/diegomura/react-pdf/pull/2160) [`a743c90`](https://github.com/diegomura/react-pdf/commit/a743c905fb5d201d2382bc9175fa36b83cc47284) Thanks [@jeetiss](https://github.com/jeetiss)! - implement flex gap
### Patch Changes
- Updated dependencies [[`a743c90`](https://github.com/diegomura/react-pdf/commit/a743c905fb5d201d2382bc9175fa36b83cc47284), [`a14ca9e`](https://github.com/diegomura/react-pdf/commit/a14ca9e62c9edc37f239558f8dbae29212b0da4d)]:
- @react-pdf/stylesheet@4.1.0
- @react-pdf/types@2.2.0
- @react-pdf/yoga@4.0.0
## 3.2.2
### Patch Changes
- [#2141](https://github.com/diegomura/react-pdf/pull/2141) [`0000d34`](https://github.com/diegomura/react-pdf/commit/0000d347d5b2fec33ee213da4ba637f06be78fae) Thanks [@jeetiss](https://github.com/jeetiss)! - fix rendering freeze when `` is empty
## 3.2.1
### Patch Changes
- [#2056](https://github.com/diegomura/react-pdf/pull/2056) [`2ebba93`](https://github.com/diegomura/react-pdf/commit/2ebba93c43608a31655e99f226f1cf2d7006ac39) Thanks [@jasnross](https://github.com/jasnross)! - fix: TypeError when returning fragments or arrays from render prop
* [#2034](https://github.com/diegomura/react-pdf/pull/2034) [`992b91b`](https://github.com/diegomura/react-pdf/commit/992b91b3866e8e24efa014eef4d3eeec6a40f9a5) Thanks [@imatwork](https://github.com/imatwork)! - fix: page wrap=false not preventing page from breaking
## 3.2.0
### Minor Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- [#1911](https://github.com/diegomura/react-pdf/pull/1911) [`5fe9754`](https://github.com/diegomura/react-pdf/commit/5fe9754f21f103e17d1b70498ee7961cde779b22) Thanks [@diegomura](https://github.com/diegomura)! - refactor: yoga node prop name
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81), [`4bb97c3`](https://github.com/diegomura/react-pdf/commit/4bb97c3b92e82d7d7be2698c770f42560c6fcab6), [`001a208`](https://github.com/diegomura/react-pdf/commit/001a20812fa039d09931b22eb97a8869e3b31cc5), [`d1f3d5b`](https://github.com/diegomura/react-pdf/commit/d1f3d5b9b4103705e95e2160347ee253d842ed5d), [`9996158`](https://github.com/diegomura/react-pdf/commit/9996158636edf2118c4a6dcce08a00408b982993)]:
- @react-pdf/fns@2.0.0
- @react-pdf/pdfkit@3.0.0
- @react-pdf/stylesheet@4.0.0
- @react-pdf/yoga@3.0.0
- @react-pdf/image@2.2.0
- @react-pdf/textkit@4.1.0
## 3.1.2
### Patch Changes
- [#1910](https://github.com/diegomura/react-pdf/pull/1910) [`e94e50a`](https://github.com/diegomura/react-pdf/commit/e94e50a931df7347a8febc717ca76843502826c8) Thanks [@diegomura](https://github.com/diegomura)! - fix: media queries computing
* [#1906](https://github.com/diegomura/react-pdf/pull/1906) [`884695b`](https://github.com/diegomura/react-pdf/commit/884695b44feb974f155c83e0714e8e939b4f641b) Thanks [@diegomura](https://github.com/diegomura)! - feat: build textkit with rollup & define public api
* Updated dependencies [[`035d3f8`](https://github.com/diegomura/react-pdf/commit/035d3f8d24fa4f4af9f350950d81b51547858367), [`9527fe4`](https://github.com/diegomura/react-pdf/commit/9527fe4c9087818421eca4753172b06e3c0cb934), [`0fcc594`](https://github.com/diegomura/react-pdf/commit/0fcc594310d5af30ca1e752b3efc7a047e813dcb), [`37a9a74`](https://github.com/diegomura/react-pdf/commit/37a9a747f7677fa05e3ddf5669c0379aa65c1e39), [`884695b`](https://github.com/diegomura/react-pdf/commit/884695b44feb974f155c83e0714e8e939b4f641b)]:
- @react-pdf/pdfkit@2.4.0
- @react-pdf/stylesheet@3.2.0
- @react-pdf/textkit@4.0.0
## 3.1.1
### Patch Changes
- [#1874](https://github.com/diegomura/react-pdf/pull/1874) [`84d94a8`](https://github.com/diegomura/react-pdf/commit/84d94a885e5140c38e31fc843340b8f09682c923) Thanks [@jeetiss](https://github.com/jeetiss)! - fixed path to es module bundle
* [#1875](https://github.com/diegomura/react-pdf/pull/1875) [`03d80a7`](https://github.com/diegomura/react-pdf/commit/03d80a71b487007a49694e1f6cf3c1136b50a688) Thanks [@jeetiss](https://github.com/jeetiss)! - fixed overwriting for default link style
## 3.1.0
### Minor Changes
- [#1862](https://github.com/diegomura/react-pdf/pull/1862) [`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb) Thanks [@diegomura](https://github.com/diegomura)! - feat: bookmarks support
* [#1871](https://github.com/diegomura/react-pdf/pull/1871) [`22fb0f0`](https://github.com/diegomura/react-pdf/commit/22fb0f008ac2a2e251657e9cbd97ccedb4ff67db) Thanks [@jeetiss](https://github.com/jeetiss)! - added esm bundle
- [#1869](https://github.com/diegomura/react-pdf/pull/1869) [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57) Thanks [@diegomura](https://github.com/diegomura)! - feat: variable dpi
### Patch Changes
- [#1858](https://github.com/diegomura/react-pdf/pull/1858) [`70c3c9f`](https://github.com/diegomura/react-pdf/commit/70c3c9f52517dc2820765e657dd2bff6b47d1ef2) Thanks [@diegomura](https://github.com/diegomura)! - fix: line width computation
* [#1857](https://github.com/diegomura/react-pdf/pull/1857) [`d958b0a`](https://github.com/diegomura/react-pdf/commit/d958b0ae06a61c157b2581488a9121a0464222f4) Thanks [@diegomura](https://github.com/diegomura)! - feat: embed same image once in final document
* Updated dependencies [[`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb), [`4fadb48`](https://github.com/diegomura/react-pdf/commit/4fadb48983d7269452f89f80c7e341ece859aaee), [`d958b0a`](https://github.com/diegomura/react-pdf/commit/d958b0ae06a61c157b2581488a9121a0464222f4), [`24f5c77`](https://github.com/diegomura/react-pdf/commit/24f5c77706e12dbab45053cb704a2fe7cf60eb53), [`ce8762f`](https://github.com/diegomura/react-pdf/commit/ce8762f6de5c796e69ec5a225c7f3ff9c619a960), [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57)]:
- @react-pdf/pdfkit@2.3.0
- @react-pdf/types@2.1.0
- @react-pdf/stylesheet@3.1.0
## 3.0.0
### Major Changes
- [#1827](https://github.com/diegomura/react-pdf/pull/1827) [`7c1d373`](https://github.com/diegomura/react-pdf/commit/7c1d373a06b04369e762069be4b96d4e40371ecc) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from layout package
### Minor Changes
- [#1841](https://github.com/diegomura/react-pdf/pull/1841) [`25a80eb`](https://github.com/diegomura/react-pdf/commit/25a80ebd5f96ade7101883624010bad51474967c) Thanks [@diegomura](https://github.com/diegomura)! - feat: support bold-italic standard fonts
### Patch Changes
- [#1829](https://github.com/diegomura/react-pdf/pull/1829) [`5458a00`](https://github.com/diegomura/react-pdf/commit/5458a00979d883341c6df094243cae859344d2b9) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from stylesheet package
* [#1838](https://github.com/diegomura/react-pdf/pull/1838) [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de) Thanks [@diegomura](https://github.com/diegomura)! - feat: create fns package
- [#1830](https://github.com/diegomura/react-pdf/pull/1830) [`9a2b935`](https://github.com/diegomura/react-pdf/commit/9a2b935cfe173f80425ed87d9f474da271c050d2) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from textkit package
- Updated dependencies [[`e938df0`](https://github.com/diegomura/react-pdf/commit/e938df0857642707b10b7f65f17ed22dc394ac1b), [`5458a00`](https://github.com/diegomura/react-pdf/commit/5458a00979d883341c6df094243cae859344d2b9), [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de), [`fe0f214`](https://github.com/diegomura/react-pdf/commit/fe0f214dbbf2f632b852ebfe65f886ecc4dd6953), [`9a2b935`](https://github.com/diegomura/react-pdf/commit/9a2b935cfe173f80425ed87d9f474da271c050d2), [`25a80eb`](https://github.com/diegomura/react-pdf/commit/25a80ebd5f96ade7101883624010bad51474967c)]:
- @react-pdf/primitives@3.0.0
- @react-pdf/stylesheet@3.0.0
- @react-pdf/fns@1.0.0
- @react-pdf/textkit@3.0.0
- @react-pdf/types@2.0.9
- @react-pdf/pdfkit@2.2.0
## 2.1.1
### Patch Changes
- [#1685](https://github.com/diegomura/react-pdf/pull/1685) [`90ab2f8`](https://github.com/diegomura/react-pdf/commit/90ab2f8c040afc3d42961404bdf2ae09fac599eb) Thanks [@jeetiss](https://github.com/jeetiss)! - updated cross-fetch
- Updated dependencies [[`90ab2f8`](https://github.com/diegomura/react-pdf/commit/90ab2f8c040afc3d42961404bdf2ae09fac599eb)]:
- @react-pdf/image@2.1.1
## 2.1.0
### Minor Changes
- [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1659](https://github.com/diegomura/react-pdf/pull/1659) [`6f0e8d2`](https://github.com/diegomura/react-pdf/commit/6f0e8d2a130d39350cc4f61ff5c743b4b262c98a) Thanks [@jeetiss](https://github.com/jeetiss)! - use styles for forcing nodes height after split
* [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
* Updated dependencies [[`1f0eb6e`](https://github.com/diegomura/react-pdf/commit/1f0eb6e0d4e75480de6745a204924d5075859db7), [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e), [`d341ae6`](https://github.com/diegomura/react-pdf/commit/d341ae66e91774e95e82deb8d9162bf458688768), [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca), [`5d2d688`](https://github.com/diegomura/react-pdf/commit/5d2d688e18c830bb96c6e08446437d29f9f9c65f), [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b), [`a592e99`](https://github.com/diegomura/react-pdf/commit/a592e99f7df7481697582c2a12f31ce7f9559c66)]:
- @react-pdf/stylesheet@2.1.0
- @react-pdf/image@2.1.0
- @react-pdf/pdfkit@2.1.0
- @react-pdf/primitives@2.0.2
- @react-pdf/textkit@2.1.0
- @react-pdf/types@2.0.8
- @react-pdf/yoga@2.0.4
================================================
FILE: packages/layout/README.md
================================================
# @react-pdf/layout
================================================
FILE: packages/layout/globals.d.ts
================================================
declare module 'yoga-layout/load' {
export enum Align {
Auto = 0,
FlexStart = 1,
Center = 2,
FlexEnd = 3,
Stretch = 4,
Baseline = 5,
SpaceBetween = 6,
SpaceAround = 7,
SpaceEvenly = 8,
}
export enum BoxSizing {
BorderBox = 0,
ContentBox = 1,
}
export enum Dimension {
Width = 0,
Height = 1,
}
export enum Direction {
Inherit = 0,
LTR = 1,
RTL = 2,
}
export enum Display {
Flex = 0,
None = 1,
Contents = 2,
}
export enum Edge {
Left = 0,
Top = 1,
Right = 2,
Bottom = 3,
Start = 4,
End = 5,
Horizontal = 6,
Vertical = 7,
All = 8,
}
export enum Errata {
None = 0,
StretchFlexBasis = 1,
AbsolutePositionWithoutInsetsExcludesPadding = 2,
AbsolutePercentAgainstInnerSize = 4,
All = 2147483647,
Classic = 2147483646,
}
export enum ExperimentalFeature {
WebFlexBasis = 0,
}
export enum FlexDirection {
Column = 0,
ColumnReverse = 1,
Row = 2,
RowReverse = 3,
}
export enum Gutter {
Column = 0,
Row = 1,
All = 2,
}
export enum Justify {
FlexStart = 0,
Center = 1,
FlexEnd = 2,
SpaceBetween = 3,
SpaceAround = 4,
SpaceEvenly = 5,
}
export enum LogLevel {
Error = 0,
Warn = 1,
Info = 2,
Debug = 3,
Verbose = 4,
Fatal = 5,
}
export enum MeasureMode {
Undefined = 0,
Exactly = 1,
AtMost = 2,
}
export enum NodeType {
Default = 0,
Text = 1,
}
export enum Overflow {
Visible = 0,
Hidden = 1,
Scroll = 2,
}
export enum PositionType {
Static = 0,
Relative = 1,
Absolute = 2,
}
export enum Unit {
Undefined = 0,
Point = 1,
Percent = 2,
Auto = 3,
}
export enum Wrap {
NoWrap = 0,
Wrap = 1,
WrapReverse = 2,
}
export type MeasureFunction = (
width: number,
widthMeasureMode: MeasureMode,
height: number,
heightMeasureMode: MeasureMode,
) => {
width?: number | undefined;
height?: number | undefined;
} | null;
export interface YogaNode {
calculateLayout(
width?: number,
height?: number,
direction?: Direction,
): void;
copyStyle(node: YogaNode): void;
free(): void;
freeRecursive(): void;
getAlignContent(): Align;
getAlignItems(): Align;
getAlignSelf(): Align;
getAspectRatio(): number;
getBorder(edge: Edge): number;
getChild(index: number): YogaNode;
getChildCount(): number;
getComputedBorder(edge: Edge): number;
getComputedBottom(): number;
getComputedHeight(): number;
// getComputedLayout(): Layout;
getComputedLeft(): number;
getComputedMargin(edge: Edge): number;
getComputedPadding(edge: Edge): number;
getComputedRight(): number;
getComputedTop(): number;
getComputedWidth(): number;
getDisplay(): Display;
getFlexBasis(): number;
getFlexDirection(): FlexDirection;
getFlexGrow(): number;
getFlexShrink(): number;
getFlexWrap(): Wrap;
getHeight(): Value;
getJustifyContent(): Justify;
getOverflow(): Overflow;
getParent(): YogaNode | null;
getPositionType(): PositionType;
insertChild(child: YogaNode, index: number): void;
isDirty(): boolean;
markDirty(): void;
removeChild(child: YogaNode): void;
reset(): void;
setAlignContent(alignContent: Align): void;
setAlignItems(alignItems: Align): void;
setAlignSelf(alignSelf: Align): void;
setAspectRatio(aspectRatio: number): void;
setBorder(edge: Edge, borderWidth: number): void;
setDisplay(display: Display): void;
setFlex(flex: number): void;
setFlexBasis(flexBasis: number | string): void;
setFlexBasisPercent(flexBasis: number): void;
setFlexDirection(flexDirection: Direction): void;
setFlexGrow(flexGrow: number): void;
setFlexShrink(flexShrink: number): void;
setFlexWrap(flexWrap: Wrap): void;
setHeight(height: number | string): void;
setHeightAuto(): void;
setHeightPercent(height: number): void;
setJustifyContent(justifyContent: Justify): void;
setMargin(edge: Edge, margin: number | string): void;
setMarginAuto(edge: Edge): void;
setMarginPercent(edge: Edge, margin: number): void;
setMaxHeight(maxHeight: number | string): void;
setMaxHeightPercent(maxHeight: number): void;
setMaxWidth(maxWidth: number | string): void;
setMaxWidthPercent(maxWidth: number): void;
setGap(gap: Gutter, value: number): void;
setGapPercent(gap: Gutter, value: number): void;
setMeasureFunc(measureFunction: MeasureFunction): void;
setMinHeight(minHeight: number | string): void;
setMinHeightPercent(minHeight: number): void;
setMinWidth(minWidth: number | string): void;
setMinWidthPercent(minWidth: number): void;
setOverflow(overflow: Overflow): void;
setPadding(edge: Edge, padding: number | string): void;
setPaddingPercent(edge: Edge, padding: number): void;
setPosition(edge: Edge, position: number | string): void;
setPositionPercent(edge: Edge, position: number): void;
setPositionType(positionType: PositionType): void;
setWidth(width: number | string): void;
setWidthAuto(): void;
setWidthPercent(width: number): void;
unsetMeasureFunc(): void;
}
interface YogaConfig {
setPointScaleFactor(factor: number): void;
}
interface ConfigStatic {
create(): YogaConfig;
destroy(config: YogaConfig): any;
}
interface NodeStatic {
create(): YogaNode;
createDefault(): YogaNode;
createWithConfig(config: YogaConfig): YogaNode;
destroy(node: YogaNode): any;
}
export interface Yoga {
Node: NodeStatic;
Config: ConfigStatic;
getInstanceCount(): number;
}
export const loadYoga: () => Promise;
}
================================================
FILE: packages/layout/jest.config.js
================================================
export default {
automock: false,
testRegex: 'tests/.*?(test)\\.js$',
};
================================================
FILE: packages/layout/package.json
================================================
{
"name": "@react-pdf/layout",
"version": "4.4.2",
"license": "MIT",
"description": "Resolve document component's layout",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/layout"
},
"scripts": {
"test": "vitest",
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@react-pdf/fns": "3.1.2",
"@react-pdf/image": "^3.0.4",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/stylesheet": "^6.1.2",
"@react-pdf/textkit": "^6.1.0",
"@react-pdf/types": "^2.9.2",
"emoji-regex-xs": "^1.0.0",
"queue": "^6.0.1",
"yoga-layout": "^3.2.1"
},
"files": [
"lib"
]
}
================================================
FILE: packages/layout/rollup.config.js
================================================
import typescript from '@rollup/plugin-typescript';
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
import pkg from './package.json' with { type: 'json' };
const config = [
{
input: 'src/index.ts',
output: { format: 'es', dir: 'lib' },
external: Object.keys(pkg.dependencies).concat(/@react-pdf/),
plugins: [typescript(), del({ targets: 'lib' })],
},
{
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
},
];
export default config;
================================================
FILE: packages/layout/setupTests.js
================================================
import { vi } from 'vitest';
import createFetchMock from 'vitest-fetch-mock';
import '../../polyfills';
const fetchMocker = createFetchMock(vi);
fetchMocker.enableMocks();
global.BROWSER = false;
================================================
FILE: packages/layout/src/canvas/measureCanvas.ts
================================================
import { MeasureFunction } from 'yoga-layout/load';
import getMargin from '../node/getMargin';
import getPadding from '../node/getPadding';
import isHeightAuto from '../page/isHeightAuto';
import { SafePageNode } from '../types';
import { SafeCanvasNode } from '../types/canvas';
const SAFETY_HEIGHT = 10;
type Point = [number, number];
const getMax = (values: number[]) => Math.max(-Infinity, ...values);
/**
* Helper object to predict canvas size
* TODO: Implement remaining functions (as close as possible);
*/
const measureCtx = () => {
const ctx: any = {};
const points: Point[] = [];
const nil = () => ctx;
const addPoint = (x: number, y: number) => points.push([x, y]);
const moveTo = (x: number, y: number) => {
addPoint(x, y);
return ctx;
};
const rect = (x: number, y: number, w: number, h: number) => {
addPoint(x, y);
addPoint(x + w, y);
addPoint(x, y + h);
addPoint(x + w, y + h);
return ctx;
};
const ellipse = (x: number, y: number, rx: number, ry: number) => {
ry = ry || rx;
addPoint(x - rx, y - ry);
addPoint(x + rx, y - ry);
addPoint(x + rx, y + ry);
addPoint(x - rx, y + ry);
return ctx;
};
const polygon = (...pts: Point[]) => {
points.push(...pts);
return ctx;
};
// Change dimensions
ctx.rect = rect;
ctx.moveTo = moveTo;
ctx.lineTo = moveTo;
ctx.circle = ellipse;
ctx.polygon = polygon;
ctx.ellipse = ellipse;
ctx.roundedRect = rect;
// To be implemented
ctx.text = nil;
ctx.path = nil;
ctx.lineWidth = nil;
ctx.bezierCurveTo = nil;
ctx.quadraticCurveTo = nil;
ctx.scale = nil;
ctx.rotate = nil;
ctx.translate = nil;
// These don't change dimensions
ctx.dash = nil;
ctx.clip = nil;
ctx.save = nil;
ctx.fill = nil;
ctx.font = nil;
ctx.stroke = nil;
ctx.lineCap = nil;
ctx.opacity = nil;
ctx.restore = nil;
ctx.lineJoin = nil;
ctx.fontSize = nil;
ctx.fillColor = nil;
ctx.miterLimit = nil;
ctx.strokeColor = nil;
ctx.fillOpacity = nil;
ctx.strokeOpacity = nil;
ctx.linearGradient = nil;
ctx.radialGradient = nil;
ctx.getWidth = () => getMax(points.map((p) => p[0]));
ctx.getHeight = () => getMax(points.map((p) => p[1]));
return ctx;
};
/**
* @typedef {Function} MeasureCanvas
* @returns {{ width: number, height: number }} canvas width and height
*/
/**
* Yoga canvas measure function
*
* @param {Object} page
* @param {Object} node
* @returns {MeasureCanvas} measure canvas
*/
const measureCanvas =
(page: SafePageNode, node: SafeCanvasNode): MeasureFunction =>
() => {
const imageMargin = getMargin(node);
const pagePadding = getPadding(page);
// TODO: Check image percentage margins
const pageArea = isHeightAuto(page)
? Infinity
: (page.box?.height || 0) -
(pagePadding.paddingTop as number) -
(pagePadding.paddingBottom as number) -
(imageMargin.marginTop as number) -
(imageMargin.marginBottom as number) -
SAFETY_HEIGHT;
const ctx = measureCtx();
node.props.paint(ctx);
const width = ctx.getWidth();
const height = Math.min(pageArea, ctx.getHeight());
return { width, height };
};
export default measureCanvas;
================================================
FILE: packages/layout/src/image/fetchImage.ts
================================================
import resolveImage from '@react-pdf/image';
import getSource from './getSource';
import resolveSource from './resolveSource';
import { SafeImageNode } from '../types';
/**
* Fetches image and append data to node
* Ideally this fn should be immutable.
*
* @param node
*/
const fetchImage = async (node: SafeImageNode) => {
const src = getSource(node);
const { cache } = node.props;
if (!src) {
console.warn(false, 'Image should receive either a "src" or "source" prop');
return;
}
try {
const source = await resolveSource(src);
if (!source) {
throw new Error(`Image's "src" or "source" prop returned ${source}`);
}
node.image = await resolveImage(source, { cache });
if (Buffer.isBuffer(source) || source instanceof Blob) return;
node.image.key = 'data' in source ? source.data.toString() : source.uri;
} catch (e: any) {
console.warn(e.message);
}
};
export default fetchImage;
================================================
FILE: packages/layout/src/image/getRatio.ts
================================================
import { SafeImageNode } from '../types';
/**
* Get image ratio
*
* @param node - Image node
* @returns Image ratio
*/
const getRatio = (node: SafeImageNode) => {
return node.image?.data ? node.image.width / node.image.height : 1;
};
export default getRatio;
================================================
FILE: packages/layout/src/image/getSource.ts
================================================
import { SafeImageNode } from '../types';
/**
* Get image source
*
* @param node - Image node
* @returns Image src
*/
const getSource = (node: SafeImageNode) => {
if (node.props.src) return node.props.src;
if (node.props.source) return node.props.source;
};
export default getSource;
================================================
FILE: packages/layout/src/image/measureImage.ts
================================================
import * as Yoga from 'yoga-layout/load';
import getRatio from './getRatio';
import getMargin from '../node/getMargin';
import getPadding from '../node/getPadding';
import isHeightAuto from '../page/isHeightAuto';
import { SafeImageNode, SafePageNode } from '../types';
const SAFETY_HEIGHT = 10;
/**
* Yoga image measure function
*
* @param page - Page
* @param node - Node
* @returns Measure image
*/
const measureImage =
(page: SafePageNode, node: SafeImageNode): Yoga.MeasureFunction =>
(width, widthMode, height, heightMode) => {
const imageRatio = getRatio(node);
const imageMargin = getMargin(node);
const pagePadding = getPadding(page);
// TODO: Check image percentage margins
const pageArea = isHeightAuto(page)
? Infinity
: (page.box?.height || 0) -
(pagePadding.paddingTop as number) -
(pagePadding.paddingBottom as number) -
(imageMargin.marginTop as number) -
(imageMargin.marginBottom as number) -
SAFETY_HEIGHT;
// Skip measure if image data not present yet
if (!node.image) return { width: 0, height: 0 };
if (
widthMode === Yoga.MeasureMode.Exactly &&
heightMode === Yoga.MeasureMode.Undefined
) {
const scaledHeight = width / imageRatio;
return { height: Math.min(pageArea, scaledHeight) };
}
if (
heightMode === Yoga.MeasureMode.Exactly &&
(widthMode === Yoga.MeasureMode.AtMost ||
widthMode === Yoga.MeasureMode.Undefined)
) {
return { width: Math.min(height * imageRatio, width) };
}
if (
widthMode === Yoga.MeasureMode.Exactly &&
heightMode === Yoga.MeasureMode.AtMost
) {
const scaledHeight = width / imageRatio;
return { height: Math.min(height, pageArea, scaledHeight) };
}
if (
widthMode === Yoga.MeasureMode.AtMost &&
heightMode === Yoga.MeasureMode.AtMost
) {
if (imageRatio > 1) {
return {
width,
height: Math.min(width / imageRatio, height),
};
}
return {
height,
width: Math.min(height * imageRatio, width),
};
}
return { height, width };
};
export default measureImage;
================================================
FILE: packages/layout/src/image/resolveSource.ts
================================================
import { SourceObject } from '../types';
/**
* Resolves `src` to `@react-pdf/image` interface.
*
* Also it handles factories and async sources.
*
* @param src
* @returns Resolved src
*/
const resolveSource = async (src: SourceObject) => {
const source = typeof src === 'function' ? await src() : await src;
return typeof source === 'string' ? { uri: source } : source;
};
export default resolveSource;
================================================
FILE: packages/layout/src/index.ts
================================================
import { asyncCompose } from '@react-pdf/fns';
import resolveSvg from './steps/resolveSvg';
import resolveYoga from './steps/resolveYoga';
import resolveZIndex from './steps/resolveZIndex';
import resolveAssets from './steps/resolveAssets';
import resolveStyles from './steps/resolveStyles';
import resolveOrigins from './steps/resolveOrigins';
import resolveBookmarks from './steps/resolveBookmarks';
import resolvePageSizes from './steps/resolvePageSizes';
import resolvePagination from './steps/resolvePagination';
import resolveDimensions from './steps/resolveDimensions';
import resolveTextLayout from './steps/resolveTextLayout';
import resolveInheritance from './steps/resolveInheritance';
import resolvePagePaddings from './steps/resolvePagePaddings';
import resolvePercentRadius from './steps/resolvePercentRadius';
import resolvePercentHeight from './steps/resolvePercentHeight';
import resolveLinkSubstitution from './steps/resolveLinkSubstitution';
const layout = asyncCompose(
resolveZIndex,
resolveOrigins,
resolveAssets,
resolvePagination,
resolveTextLayout,
resolvePercentRadius,
resolveDimensions,
resolveSvg,
resolveAssets,
resolveInheritance,
resolvePercentHeight,
resolvePagePaddings,
resolveStyles,
resolveLinkSubstitution,
resolveBookmarks,
resolvePageSizes,
resolveYoga,
);
export * from './types';
export default layout;
================================================
FILE: packages/layout/src/node/createInstances.ts
================================================
import { castArray } from '@react-pdf/fns';
import * as P from '@react-pdf/primitives';
import React from 'react';
import { Node } from '../types';
const isString = (value: any): value is string => typeof value === 'string';
const isNumber = (value: any): value is number => typeof value === 'number';
const isBoolean = (value: any): value is boolean => typeof value === 'boolean';
const isFragment = (value: any): value is React.ReactFragment =>
value && value.type === Symbol.for('react.fragment');
/**
* Transforms a react element instance to internal element format.
*
* Can return multiple instances in the case of arrays or fragments.
*
* @param element - React element
* @returns Parsed React elements
*/
const createInstances = (element: React.ReactNode): Node[] => {
if (!element) return [];
if (Array.isArray(element)) {
return element.reduce((acc, el) => acc.concat(createInstances(el)), []);
}
if (isBoolean(element)) {
return [];
}
if (isString(element) || isNumber(element)) {
return [{ type: P.TextInstance, value: `${element}` }];
}
if (isFragment(element)) {
// @ts-expect-error figure out why this is complains
return createInstances(element.props.children);
}
if (!isString(element.type)) {
// @ts-expect-error figure out why this is complains
return createInstances(element.type(element.props));
}
const {
type,
props: { style = {}, children, ...props },
} = element;
const nextChildren = castArray(children).reduce(
(acc, child) => acc.concat(createInstances(child)),
[],
);
return [
{
type,
style,
props,
children: nextChildren,
},
] as Node[];
};
export default createInstances;
================================================
FILE: packages/layout/src/node/getBorderWidth.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
const getComputedBorder = (
yogaNode: Yoga.YogaNode | undefined,
edge: Yoga.Edge,
) => (yogaNode ? yogaNode.getComputedBorder(edge) : 0);
/**
* Get Yoga computed border width. Zero otherwise
*
* @param node
* @returns Border widths
*/
const getBorderWidth = (node: SafeNode) => {
const { yogaNode } = node;
return {
borderTopWidth: getComputedBorder(yogaNode, Yoga.Edge.Top),
borderRightWidth: getComputedBorder(yogaNode, Yoga.Edge.Right),
borderBottomWidth: getComputedBorder(yogaNode, Yoga.Edge.Bottom),
borderLeftWidth: getComputedBorder(yogaNode, Yoga.Edge.Left),
};
};
export default getBorderWidth;
================================================
FILE: packages/layout/src/node/getDimension.ts
================================================
import { SafeNode } from '../types';
const DEFAULT_DIMENSION = {
width: 0,
height: 0,
};
/**
* Get Yoga computed dimensions. Zero otherwise
*
* @param node
* @returns Dimensions
*/
const getDimension = (node: SafeNode) => {
const { yogaNode } = node;
if (!yogaNode) return DEFAULT_DIMENSION;
return {
width: yogaNode.getComputedWidth(),
height: yogaNode.getComputedHeight(),
};
};
export default getDimension;
================================================
FILE: packages/layout/src/node/getMargin.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
const getComputedMargin = (node: SafeNode, edge: Yoga.Edge) => {
const { yogaNode } = node;
return yogaNode ? yogaNode.getComputedMargin(edge) : null;
};
/**
* Get Yoga computed magins. Zero otherwise
*
* @param node
* @returns Margins
*/
const getMargin = (node: SafeNode) => {
const { style, box } = node;
const marginTop =
getComputedMargin(node, Yoga.Edge.Top) ||
box?.marginTop ||
style?.marginTop ||
0;
const marginRight =
getComputedMargin(node, Yoga.Edge.Right) ||
box?.marginRight ||
style?.marginRight ||
0;
const marginBottom =
getComputedMargin(node, Yoga.Edge.Bottom) ||
box?.marginBottom ||
style?.marginBottom ||
0;
const marginLeft =
getComputedMargin(node, Yoga.Edge.Left) ||
box?.marginLeft ||
style?.marginLeft ||
0;
return { marginTop, marginRight, marginBottom, marginLeft };
};
export default getMargin;
================================================
FILE: packages/layout/src/node/getOrigin.ts
================================================
import { isNil, matchPercent } from '@react-pdf/fns';
import { Origin, SafeNode } from '../types';
const getTransformStyle =
(s: 'transformOriginX' | 'transformOriginY') => (node: SafeNode) =>
isNil(node.style?.[s]) ? '50%' : node.style?.[s] ?? null;
/**
* Get node origin
*
* @param node
* @returns {{ left?: number, top?: number }} node origin
*/
const getOrigin = (node: SafeNode): Origin | null => {
if (!node.box) return null;
const { left, top, width, height } = node.box;
const transformOriginX = getTransformStyle('transformOriginX')(node);
const transformOriginY = getTransformStyle('transformOriginY')(node);
const percentX = matchPercent(transformOriginX);
const percentY = matchPercent(transformOriginY);
const offsetX = percentX ? width * percentX.percent : transformOriginX;
const offsetY = percentY ? height * percentY.percent : transformOriginY;
if (isNil(offsetX) || typeof offsetX === 'string')
throw new Error(`Invalid origin offsetX: ${offsetX}`);
if (isNil(offsetY) || typeof offsetY === 'string')
throw new Error(`Invalid origin offsetY: ${offsetY}`);
return { left: left + offsetX, top: top + offsetY };
};
export default getOrigin;
================================================
FILE: packages/layout/src/node/getPadding.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
const getComputedPadding = (node: SafeNode, edge: Yoga.Edge) => {
const { yogaNode } = node;
return yogaNode ? yogaNode.getComputedPadding(edge) : null;
};
/**
* Get Yoga computed paddings. Zero otherwise
*
* @param node
* @returns paddings
*/
const getPadding = (node: SafeNode) => {
const { style, box } = node;
const paddingTop =
getComputedPadding(node, Yoga.Edge.Top) ||
box?.paddingTop ||
style?.paddingTop ||
0;
const paddingRight =
getComputedPadding(node, Yoga.Edge.Right) ||
box?.paddingRight ||
style?.paddingRight ||
0;
const paddingBottom =
getComputedPadding(node, Yoga.Edge.Bottom) ||
box?.paddingBottom ||
style?.paddingBottom ||
0;
const paddingLeft =
getComputedPadding(node, Yoga.Edge.Left) ||
box?.paddingLeft ||
style?.paddingLeft ||
0;
return { paddingTop, paddingRight, paddingBottom, paddingLeft };
};
export default getPadding;
================================================
FILE: packages/layout/src/node/getPosition.ts
================================================
import { SafeNode } from '../types';
/**
* Get Yoga computed position. Zero otherwise
*
* @param node
* @returns Position
*/
const getPosition = (node: SafeNode) => {
const { yogaNode } = node;
return {
top: yogaNode?.getComputedTop() || 0,
right: yogaNode?.getComputedRight() || 0,
bottom: yogaNode?.getComputedBottom() || 0,
left: yogaNode?.getComputedLeft() || 0,
};
};
export default getPosition;
================================================
FILE: packages/layout/src/node/getWrap.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeNode } from '../types';
const NON_WRAP_TYPES = [P.Svg, P.Note, P.Image, P.Canvas];
const getWrap = (node: SafeNode) => {
if (NON_WRAP_TYPES.includes(node.type)) return false;
if (!node.props) return true;
return 'wrap' in node.props ? node.props.wrap : true;
};
export default getWrap;
================================================
FILE: packages/layout/src/node/isFixed.ts
================================================
import { SafeNode } from '../types';
const isFixed = (node: SafeNode) => {
if (!node.props) return false;
return 'fixed' in node.props ? node.props.fixed === true : false;
};
export default isFixed;
================================================
FILE: packages/layout/src/node/removePaddings.ts
================================================
import { omit } from '@react-pdf/fns';
import setPadding from './setPadding';
import { SafeNode } from '../types';
const PADDING_PROPS = [
'padding',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'paddingHorizontal',
'paddingVertical',
];
/**
* Removes padding on node
*
* @param node
* @returns Node without padding
*/
const removePaddings = (node: SafeNode) => {
const style = omit(PADDING_PROPS, node.style || {});
const newNode: SafeNode = Object.assign({}, node, { style });
setPadding(0)(newNode);
return newNode;
};
export default removePaddings;
================================================
FILE: packages/layout/src/node/setAlign.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { upperFirst } from '@react-pdf/fns';
import { SafeNode } from '../types';
const ALIGN = {
'flex-start': Yoga.Align.FlexStart,
center: Yoga.Align.Center,
'flex-end': Yoga.Align.FlexEnd,
stretch: Yoga.Align.Stretch,
baseline: Yoga.Align.Baseline,
'space-between': Yoga.Align.SpaceBetween,
'space-around': Yoga.Align.SpaceAround,
'space-evenly': Yoga.Align.SpaceEvenly,
};
/**
* Set generic align attribute to node's Yoga instance
*
* @param attr - Specific align property
* @param value - Specific align value
* @param node - Node
* @returns Node
*/
const setAlign = (attr: string) => (value: any) => (node: SafeNode) => {
const { yogaNode } = node;
const defaultValue = attr === 'items' ? Yoga.Align.Stretch : Yoga.Align.Auto;
if (yogaNode) {
const align = ALIGN[value] || defaultValue;
yogaNode[`setAlign${upperFirst(attr)}`](align);
}
return node;
};
export default setAlign;
================================================
FILE: packages/layout/src/node/setAlignContent.ts
================================================
import setAlign from './setAlign';
/**
* Set align content attribute to node's Yoga instance
*
* @param align - Value
* @param node - Instance
* @returns Node instance
*/
const setAlignContent = setAlign('content');
export default setAlignContent;
================================================
FILE: packages/layout/src/node/setAlignItems.ts
================================================
import setAlign from './setAlign';
/**
* Set align items attribute to node's Yoga instance
*
* @param align - Value
* @param node - Node instance
* @returns Node instance
*/
const setAlignItems = setAlign('items');
export default setAlignItems;
================================================
FILE: packages/layout/src/node/setAlignSelf.ts
================================================
import setAlign from './setAlign';
/**
* Set align self attribute to node's Yoga instance
*
* @param align - Value
* @param node - Node instance
* @returns Node instance
*/
const setAlignSelf = setAlign('self');
export default setAlignSelf;
================================================
FILE: packages/layout/src/node/setAspectRatio.ts
================================================
import { isNil } from '@react-pdf/fns';
import { SafeNode } from '../types';
/**
* Set aspect ratio attribute to node's Yoga instance
*
* @param value - Ratio
* @returns Node instance
*/
const setAspectRatio = (value?: number | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (!isNil(value) && yogaNode) {
yogaNode.setAspectRatio(value);
}
return node;
};
export default setAspectRatio;
================================================
FILE: packages/layout/src/node/setBorderWidth.ts
================================================
import * as Yoga from 'yoga-layout/load';
import setYogaValue from './setYogaValue';
import { SafeNode } from '../types';
/**
* Set border top attribute to node's Yoga instance
*
* @param border - Border top width
* @param node - Node instance
* @returns Node instance
*/
export const setBorderTop = setYogaValue('border', Yoga.Edge.Top);
/**
* Set border right attribute to node's Yoga instance
*
* @param border - Border right width
* @param node - Node instance
* @returns Node instance
*/
export const setBorderRight = setYogaValue('border', Yoga.Edge.Right);
/**
* Set border bottom attribute to node's Yoga instance
*
* @param border - Border bottom width
* @param node - Node instance
* @returns Node instance
*/
export const setBorderBottom = setYogaValue('border', Yoga.Edge.Bottom);
/**
* Set border left attribute to node's Yoga instance
*
* @param border - Border left width
* @param node - Node instance
* @returns Node instance
*/
export const setBorderLeft = setYogaValue('border', Yoga.Edge.Left);
/**
* Set all border widths at once
*
* @param width - Border width
* @returns Node instance wrapper
*/
export const setBorder = (width?: number | null) => (node: SafeNode) => {
setBorderTop(width)(node);
setBorderRight(width)(node);
setBorderBottom(width)(node);
setBorderLeft(width)(node);
return node;
};
export default setBorder;
================================================
FILE: packages/layout/src/node/setDimension.ts
================================================
import setYogaValue from './setYogaValue';
/**
* Set width to node's Yoga instance
*
* @param width - Width
* @param node - Node instance
* @returns Node instance
*/
export const setWidth = setYogaValue('width');
/**
* Set min width to node's Yoga instance
*
* @param min - Width
* @param node - Node instance
* @returns Node instance
*/
export const setMinWidth = setYogaValue('minWidth');
/**
* Set max width to node's Yoga instance
*
* @param max - Width
* @param node - Node instance
* @returns Node instance
*/
export const setMaxWidth = setYogaValue('maxWidth');
/**
* Set height to node's Yoga instance
*
* @param height - Height
* @param node - Node instance
* @returns Node instance
*/
export const setHeight = setYogaValue('height');
/**
* Set min height to node's Yoga instance
*
* @param min - Height
* @param node - Node instance
* @returns Node instance
*/
export const setMinHeight = setYogaValue('minHeight');
/**
* Set max height to node's Yoga instance
*
* @param max - Height
* @param node - Node instance
* @returns Node instance
*/
export const setMaxHeight = setYogaValue('maxHeight');
================================================
FILE: packages/layout/src/node/setDisplay.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
/**
* Set display attribute to node's Yoga instance
*
* @param value - Display
* @returns Node instance wrapper
*/
const setDisplay = (value?: string | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (yogaNode) {
yogaNode.setDisplay(
value === 'none' ? Yoga.Display.None : Yoga.Display.Flex,
);
}
return node;
};
export default setDisplay;
================================================
FILE: packages/layout/src/node/setFlexBasis.ts
================================================
import setYogaValue from './setYogaValue';
/**
* Set flex basis attribute to node's Yoga instance
*
* @param flex - Basis value
* @param node - Node instance
* @returns Node instance
*/
const setFlexBasis = setYogaValue('flexBasis');
export default setFlexBasis;
================================================
FILE: packages/layout/src/node/setFlexDirection.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
const FLEX_DIRECTIONS = {
row: Yoga.FlexDirection.Row,
'row-reverse': Yoga.FlexDirection.RowReverse,
'column-reverse': Yoga.FlexDirection.ColumnReverse,
};
/**
* Set flex direction attribute to node's Yoga instance
*
* @param value - Flex direction value
* @returns Node instance wrapper
*/
const setFlexDirection = (value?: string | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (yogaNode) {
const flexDirection = FLEX_DIRECTIONS[value] || Yoga.FlexDirection.Column;
yogaNode.setFlexDirection(flexDirection);
}
return node;
};
export default setFlexDirection;
================================================
FILE: packages/layout/src/node/setFlexGrow.ts
================================================
import { SafeNode } from '../types';
import setYogaValue from './setYogaValue';
/**
* Set flex grow attribute to node's Yoga instance
*
* @param value - Flex grow value
* @returns Node instance wrapper
*/
const setFlexGrow = (value?: number | null) => (node: SafeNode) => {
return setYogaValue('flexGrow')(value || 0)(node);
};
export default setFlexGrow;
================================================
FILE: packages/layout/src/node/setFlexShrink.ts
================================================
import { SafeNode } from '../types';
import setYogaValue from './setYogaValue';
/**
* Set flex shrink attribute to node's Yoga instance
*
* @param value - Flex shrink value
* @returns Node instance wrapper
*/
const setFlexShrink = (value?: string | number | null) => (node: SafeNode) => {
return setYogaValue('flexShrink')(value || 1)(node);
};
export default setFlexShrink;
================================================
FILE: packages/layout/src/node/setFlexWrap.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
const FLEX_WRAP = {
wrap: Yoga.Wrap.Wrap,
'wrap-reverse': Yoga.Wrap.WrapReverse,
};
/**
* Set flex wrap attribute to node's Yoga instance
*
* @param value - Flex wrap value
* @returns Node instance wrapper
*/
const setFlexWrap = (value?: string | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (yogaNode) {
const flexWrap: Yoga.Wrap = FLEX_WRAP[value] || Yoga.Wrap.NoWrap;
yogaNode.setFlexWrap(flexWrap);
}
return node;
};
export default setFlexWrap;
================================================
FILE: packages/layout/src/node/setGap.ts
================================================
import * as Yoga from 'yoga-layout/load';
import setYogaValue from './setYogaValue';
/**
* Set rowGap value to node's Yoga instance
*
* @param value - Gap value
* @returns Node instance wrapper
*/
export const setRowGap = setYogaValue('gap', Yoga.Gutter.Row);
/**
* Set columnGap value to node's Yoga instance
*
* @param value - Gap value
* @returns Node instance wrapper
*/
export const setColumnGap = setYogaValue('gap', Yoga.Gutter.Column);
================================================
FILE: packages/layout/src/node/setJustifyContent.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { isNil } from '@react-pdf/fns';
import { SafeNode } from '../types';
const JUSTIFY_CONTENT = {
center: Yoga.Justify.Center,
'flex-end': Yoga.Justify.FlexEnd,
'space-between': Yoga.Justify.SpaceBetween,
'space-around': Yoga.Justify.SpaceAround,
'space-evenly': Yoga.Justify.SpaceEvenly,
};
/**
* Set justify content attribute to node's Yoga instance
*
* @param value - Justify content value
* @returns Node instance wrapper
*/
const setJustifyContent = (value?: string | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (!isNil(value) && yogaNode) {
const justifyContent = JUSTIFY_CONTENT[value] || Yoga.Justify.FlexStart;
yogaNode.setJustifyContent(justifyContent);
}
return node;
};
export default setJustifyContent;
================================================
FILE: packages/layout/src/node/setMargin.ts
================================================
import * as Yoga from 'yoga-layout/load';
import setYogaValue from './setYogaValue';
import { SafeNode } from '../types';
/**
* Set margin top attribute to node's Yoga instance
*
* @param margin - Margin top
* @param node - Node instance
* @returns Node instance
*/
export const setMarginTop = setYogaValue('margin', Yoga.Edge.Top);
/**
* Set margin right attribute to node's Yoga instance
*
* @param margin - Margin right
* @param node - Node instance
* @returns Node instance
*/
export const setMarginRight = setYogaValue('margin', Yoga.Edge.Right);
/**
* Set margin bottom attribute to node's Yoga instance
*
* @param margin - Margin bottom
* @param node - Node instance
* @returns Node instance
*/
export const setMarginBottom = setYogaValue('margin', Yoga.Edge.Bottom);
/**
* Set margin left attribute to node's Yoga instance
*
* @param margin - Margin left
* @param node - Node instance
* @returns Node instance
*/
export const setMarginLeft = setYogaValue('margin', Yoga.Edge.Left);
/**
* Set all margins at once
*
* @param margin - Margin
* @returns Node instance wrapper
*/
export const setMargin =
(margin?: number | string | null) => (node: SafeNode) => {
setMarginTop(margin)(node);
setMarginRight(margin)(node);
setMarginBottom(margin)(node);
setMarginLeft(margin)(node);
return node;
};
export default setMargin;
================================================
FILE: packages/layout/src/node/setOverflow.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { isNil } from '@react-pdf/fns';
import { SafeNode } from '../types';
const OVERFLOW = {
hidden: Yoga.Overflow.Hidden,
scroll: Yoga.Overflow.Scroll,
};
/**
* Set overflow attribute to node's Yoga instance
*
* @param value - Overflow value
* @returns Node instance wrapper
*/
const setOverflow = (value?: string | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (!isNil(value) && yogaNode) {
const overflow = OVERFLOW[value] || Yoga.Overflow.Visible;
yogaNode.setOverflow(overflow);
}
return node;
};
export default setOverflow;
================================================
FILE: packages/layout/src/node/setPadding.ts
================================================
import * as Yoga from 'yoga-layout/load';
import setYogaValue from './setYogaValue';
import { SafeNode } from '../types';
/**
* Set padding top attribute to node's Yoga instance
*
* @param padding - Padding top
* @param node - Node instance
* @returns Node instance
*/
export const setPaddingTop = setYogaValue('padding', Yoga.Edge.Top);
/**
* Set padding right attribute to node's Yoga instance
*
* @param padding - Padding right
* @param node - Node instance
* @returns Node instance
*/
export const setPaddingRight = setYogaValue('padding', Yoga.Edge.Right);
/**
* Set padding bottom attribute to node's Yoga instance
*
* @param padding - Padding bottom
* @param node Node instance
* @returns Node instance
*/
export const setPaddingBottom = setYogaValue('padding', Yoga.Edge.Bottom);
/**
* Set padding left attribute to node's Yoga instance
*
* @param padding - Padding left
* @param node - Node instance
* @returns Node instance
*/
export const setPaddingLeft = setYogaValue('padding', Yoga.Edge.Left);
/**
* Set all paddings at once
*
* @param padding padding
* @returns Node instance
*/
export const setPadding =
(padding?: number | string | null) => (node: SafeNode) => {
setPaddingTop(padding)(node);
setPaddingRight(padding)(node);
setPaddingBottom(padding)(node);
setPaddingLeft(padding)(node);
return node;
};
export default setPadding;
================================================
FILE: packages/layout/src/node/setPosition.ts
================================================
import * as Yoga from 'yoga-layout/load';
import setYogaValue from './setYogaValue';
import { SafeNode } from '../types';
/**
* Set position top attribute to node's Yoga instance
*
* @param position - Position top
* @param node - Node instance
* @returns Node instance
*/
export const setPositionTop = setYogaValue('position', Yoga.Edge.Top);
/**
* Set position right attribute to node's Yoga instance
*
* @param position - Position right
* @param node - Node instance
* @returns Node instance
*/
export const setPositionRight = setYogaValue('position', Yoga.Edge.Right);
/**
* Set position bottom attribute to node's Yoga instance
*
* @param position - Position bottom
* @param node - Node instance
* @returns Node instance
*/
export const setPositionBottom = setYogaValue('position', Yoga.Edge.Bottom);
/**
* Set position left attribute to node's Yoga instance
*
* @param position - Position left
* @param node - Node instance
* @returns Node instance
*/
export const setPositionLeft = setYogaValue('position', Yoga.Edge.Left);
/**
* Set all positions at once
*
* @param position - Position
* @returns Node instance wrapper
*/
export const setPosition =
(position?: number | string | null) => (node: SafeNode) => {
setPositionTop(position)(node);
setPositionRight(position)(node);
setPositionBottom(position)(node);
setPositionLeft(position)(node);
return node;
};
export default setPosition;
================================================
FILE: packages/layout/src/node/setPositionType.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { isNil } from '@react-pdf/fns';
import { SafeNode } from '../types';
const POSITION = {
absolute: Yoga.PositionType.Absolute,
relative: Yoga.PositionType.Relative,
static: Yoga.PositionType.Static,
};
/**
* Set position type attribute to node's Yoga instance
*
* @param value - Position position type
* @returns Node instance
*/
const setPositionType = (value?: string | null) => (node: SafeNode) => {
const { yogaNode } = node;
if (!isNil(value) && yogaNode) {
yogaNode.setPositionType(POSITION[value]);
}
return node;
};
export default setPositionType;
================================================
FILE: packages/layout/src/node/setYogaValue.ts
================================================
import { isNil, upperFirst, matchPercent } from '@react-pdf/fns';
import * as Yoga from 'yoga-layout/load';
import { SafeNode } from '../types';
/**
* Set generic yoga attribute to node's Yoga instance, handing `auto`, edges and percentage cases
*
* @param attr - Property
* @param edge - Edge
* @returns Node instance wrapper
*/
const setYogaValue =
(attr: string, edge?: Yoga.Edge | Yoga.Gutter) =>
(value?: string | number | null) =>
(node: SafeNode) => {
const { yogaNode } = node;
if (!isNil(value) && yogaNode) {
const hasEdge = !isNil(edge);
const fixedMethod = `set${upperFirst(attr)}`;
const autoMethod = `${fixedMethod}Auto`;
const percentMethod = `${fixedMethod}Percent`;
const percent = matchPercent(value);
if (percent && !yogaNode[percentMethod]) {
throw new Error(`You can't pass percentage values to ${attr} property`);
}
if (percent) {
if (hasEdge) {
yogaNode[percentMethod]?.(edge, percent.value);
} else {
yogaNode[percentMethod]?.(percent.value);
}
} else if (value === 'auto') {
if (hasEdge) {
yogaNode[autoMethod]?.(edge);
} else {
yogaNode[autoMethod]?.();
}
} else if (hasEdge) {
yogaNode[fixedMethod]?.(edge, value);
} else {
yogaNode[fixedMethod]?.(value);
}
}
return node;
};
export default setYogaValue;
================================================
FILE: packages/layout/src/node/shouldBreak.ts
================================================
import { SafeNode } from '../types';
import getWrap from './getWrap';
import isFixed from './isFixed';
const getBreak = (node: SafeNode) =>
'break' in node.props ? node.props.break : false;
const getMinPresenceAhead = (node: SafeNode) =>
'minPresenceAhead' in node.props ? node.props.minPresenceAhead : 0;
const getFurthestEnd = (elements: SafeNode[]) =>
Math.max(...elements.map((node) => node.box.top + node.box.height));
const getEndOfMinPresenceAhead = (child: SafeNode) => {
return (
child.box.top +
child.box.height +
child.box.marginBottom +
getMinPresenceAhead(child)
);
};
const getEndOfPresence = (child: SafeNode, futureElements: SafeNode[]) => {
const afterMinPresenceAhead = getEndOfMinPresenceAhead(child);
const endOfFurthestFutureElement = getFurthestEnd(
futureElements.filter((node) => !('fixed' in node.props)),
);
return Math.min(afterMinPresenceAhead, endOfFurthestFutureElement);
};
const shouldBreak = (
child: SafeNode,
futureElements: SafeNode[],
height: number,
previousElements: SafeNode[],
) => {
if ('fixed' in child.props) return false;
const shouldSplit = height < child.box.top + child.box.height;
const canWrap = getWrap(child);
// Calculate the y coordinate where the desired presence of the child ends
const endOfPresence = getEndOfPresence(child, futureElements);
// If the child is already at the top of the page, breaking won't improve its presence
// (as long as react-pdf does not support breaking into differently sized containers)
const breakingImprovesPresence =
previousElements.filter((node: SafeNode) => !isFixed(node)).length > 0;
return (
getBreak(child) ||
(shouldSplit && !canWrap) ||
(!shouldSplit && endOfPresence > height && breakingImprovesPresence)
);
};
export default shouldBreak;
================================================
FILE: packages/layout/src/node/splitNode.ts
================================================
import { isNil } from '@react-pdf/fns';
import { SafeNode } from '../types';
const getTop = (node: SafeNode) => node.box?.top || 0;
const hasFixedHeight = (node: SafeNode) => !isNil(node.style?.height);
const splitNode = (node: SafeNode, height: number) => {
if (!node) return [null, null];
const nodeTop = getTop(node);
const current: SafeNode = Object.assign({}, node, {
box: {
...node.box,
borderBottomWidth: 0,
},
style: {
...node.style,
marginBottom: 0,
paddingBottom: 0,
borderBottomWidth: 0,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
},
});
current.style.height = height - nodeTop;
const nextHeight = hasFixedHeight(node)
? node.box.height - (height - nodeTop)
: null;
const next: SafeNode = Object.assign({}, node, {
box: {
...node.box,
top: 0,
borderTopWidth: 0,
},
style: {
...node.style,
marginTop: 0,
paddingTop: 0,
borderTopWidth: 0,
borderTopLeftRadius: 0,
borderTopRightRadius: 0,
},
props: {
...node.props,
bookmark: null,
},
});
if (nextHeight) {
next.style.height = nextHeight;
}
return [current, next];
};
export default splitNode;
================================================
FILE: packages/layout/src/page/getContentArea.ts
================================================
import getPadding from '../node/getPadding';
import { SafePageNode } from '../types';
const getContentArea = (page: SafePageNode) => {
const height = page.style?.height as number;
const { paddingTop, paddingBottom } = getPadding(page as any);
return height - (paddingBottom as number) - (paddingTop as number);
};
export default getContentArea;
================================================
FILE: packages/layout/src/page/getOrientation.ts
================================================
import { PageNode } from '../types';
const VALID_ORIENTATIONS = ['portrait', 'landscape'];
/**
* Get page orientation. Defaults to portrait
*
* @param page - Page object
* @returns Page orientation
*/
const getOrientation = (page: PageNode) => {
const value = page.props?.orientation || 'portrait';
return VALID_ORIENTATIONS.includes(value) ? value : 'portrait';
};
export default getOrientation;
================================================
FILE: packages/layout/src/page/getSize.ts
================================================
import isLandscape from './isLandscape';
import { PageNode } from '../types';
type UnitSize = { width: string | number; height?: string | number };
type Size = { width: number; height: number };
// Page sizes for 72dpi. 72dpi is used internally by pdfkit.
const PAGE_SIZES = {
'4A0': [4767.87, 6740.79],
'2A0': [3370.39, 4767.87],
A0: [2383.94, 3370.39],
A1: [1683.78, 2383.94],
A2: [1190.55, 1683.78],
A3: [841.89, 1190.55],
A4: [595.28, 841.89],
A5: [419.53, 595.28],
A6: [297.64, 419.53],
A7: [209.76, 297.64],
A8: [147.4, 209.76],
A9: [104.88, 147.4],
A10: [73.7, 104.88],
B0: [2834.65, 4008.19],
B1: [2004.09, 2834.65],
B2: [1417.32, 2004.09],
B3: [1000.63, 1417.32],
B4: [708.66, 1000.63],
B5: [498.9, 708.66],
B6: [354.33, 498.9],
B7: [249.45, 354.33],
B8: [175.75, 249.45],
B9: [124.72, 175.75],
B10: [87.87, 124.72],
C0: [2599.37, 3676.54],
C1: [1836.85, 2599.37],
C2: [1298.27, 1836.85],
C3: [918.43, 1298.27],
C4: [649.13, 918.43],
C5: [459.21, 649.13],
C6: [323.15, 459.21],
C7: [229.61, 323.15],
C8: [161.57, 229.61],
C9: [113.39, 161.57],
C10: [79.37, 113.39],
RA0: [2437.8, 3458.27],
RA1: [1729.13, 2437.8],
RA2: [1218.9, 1729.13],
RA3: [864.57, 1218.9],
RA4: [609.45, 864.57],
SRA0: [2551.18, 3628.35],
SRA1: [1814.17, 2551.18],
SRA2: [1275.59, 1814.17],
SRA3: [907.09, 1275.59],
SRA4: [637.8, 907.09],
EXECUTIVE: [521.86, 756.0],
FOLIO: [612.0, 936.0],
LEGAL: [612.0, 1008.0],
LETTER: [612.0, 792.0],
TABLOID: [792.0, 1224.0],
ID1: [153, 243],
};
/**
* Parses scalar value in value and unit pairs
*
* @param value - Scalar value
* @returns Parsed value
*/
const parseValue = (value: string | number) => {
if (typeof value === 'number') return { value, unit: undefined };
const match = /^(-?\d*\.?\d+)(in|mm|cm|pt|px)?$/g.exec(value);
return match
? { value: parseFloat(match[1]), unit: match[2] || 'pt' }
: { value, unit: undefined };
};
/**
* Transform given scalar value to 72dpi equivalent of size
*
* @param value - Styles value
* @param inputDpi - User defined dpi
* @returns Transformed value
*/
const transformUnit = (
value: string | number | undefined,
inputDpi: number,
) => {
if (!value) return 0;
const scalar = parseValue(value);
const outputDpi = 72;
const mmFactor = (1 / 25.4) * outputDpi;
const cmFactor = (1 / 2.54) * outputDpi;
if (typeof scalar.value === 'string')
throw new Error(`Invalid page size: ${value}`);
switch (scalar.unit) {
case 'in':
return scalar.value * outputDpi;
case 'mm':
return scalar.value * mmFactor;
case 'cm':
return scalar.value * cmFactor;
case 'px':
return Math.round(scalar.value * (outputDpi / inputDpi));
default:
return scalar.value;
}
};
const transformUnits = ({ width, height }: UnitSize, dpi: number): Size => ({
width: transformUnit(width, dpi),
height: transformUnit(height, dpi),
});
/**
* Transforms array into size object
*
* @param v - Values array
* @returns Size object with width and height
*/
const toSizeObject = (v: (number | string)[]) => ({
width: v[0],
height: v[1],
});
/**
* Flip size object
*
* @param v - Size object
* @returns Flipped size object
*/
const flipSizeObject = (v: Size): Size => ({
width: v.height,
height: v.width,
});
/**
* Returns size object from a given string
*
* @param v - Page size string
* @returns Size object with width and height
*/
const getStringSize = (v: string) => {
return toSizeObject(PAGE_SIZES[v.toUpperCase()]) as Size;
};
/**
* Returns size object from a single number
*
* @param n - Page size number
* @returns Size object with width and height
*/
const getNumberSize = (n: number) => toSizeObject([n, n]);
/**
* Return page size in an object { width, height }
*
* @param page - Page node
* @returns Size object with width and height
*/
const getSize = (page: PageNode) => {
const value = page.props?.size || 'A4';
const dpi = page.props?.dpi || 72;
let size: Size;
if (typeof value === 'string') {
size = getStringSize(value);
} else if (Array.isArray(value)) {
size = transformUnits(toSizeObject(value), dpi);
} else if (typeof value === 'number') {
size = transformUnits(getNumberSize(value), dpi);
} else {
size = transformUnits(value, dpi);
}
return isLandscape(page) ? flipSizeObject(size) : size;
};
export default getSize;
================================================
FILE: packages/layout/src/page/getWrapArea.ts
================================================
import getPadding from '../node/getPadding';
import { SafePageNode } from '../types';
const getWrapArea = (page: SafePageNode) => {
const height = page.style?.height as number;
const { paddingBottom } = getPadding(page);
return height - (paddingBottom as number);
};
export default getWrapArea;
================================================
FILE: packages/layout/src/page/isHeightAuto.ts
================================================
import { isNil } from '@react-pdf/fns';
import { SafePageNode } from '../types';
/**
* Checks if page has auto height
*
* @param page
* @returns Is page height auto
*/
const isHeightAuto = (page: SafePageNode) => isNil(page.box?.height);
export default isHeightAuto;
================================================
FILE: packages/layout/src/page/isLandscape.ts
================================================
import { PageNode } from '../types';
import getOrientation from './getOrientation';
/**
* Return true if page is landscape
*
* @param page - Page instance
* @returns Is page landscape
*/
const isLandscape = (page: PageNode) => getOrientation(page) === 'landscape';
export default isLandscape;
================================================
FILE: packages/layout/src/page/isPortrait.ts
================================================
import getOrientation from './getOrientation';
import { PageNode } from '../types';
/**
* Return true if page is portrait
*
* @param page - Page node
* @returns Is page portrait
*/
const isPortrait = (page: PageNode) => getOrientation(page) === 'portrait';
export default isPortrait;
================================================
FILE: packages/layout/src/steps/resolveAssets.ts
================================================
import * as P from '@react-pdf/primitives';
import FontStore from '@react-pdf/font';
import { castArray } from '@react-pdf/fns';
import fetchEmojis from '../text/emoji';
import fetchImage from '../image/fetchImage';
import { SafeImageNode, SafeNode } from '../types';
const isImage = (node: SafeNode): node is SafeImageNode =>
node.type === P.Image;
/**
* Get all asset promises that need to be resolved
*
* @param fontStore - Font store
* @param node - Root node
* @returns Asset promises
*/
const fetchAssets = (fontStore: FontStore, node: SafeNode) => {
const promises: Promise[] = [];
const listToExplore = node.children?.slice(0) || [];
const emojiSource = fontStore ? fontStore.getEmojiSource() : null;
while (listToExplore.length > 0) {
const n = listToExplore.shift();
if (isImage(n)) {
promises.push(fetchImage(n));
}
if (fontStore && n.style?.fontFamily) {
const fontFamilies = castArray(n.style.fontFamily);
promises.push(
...fontFamilies.map((fontFamily) =>
fontStore.load({
fontFamily,
fontStyle: n.style.fontStyle,
fontWeight: n.style.fontWeight,
}),
),
);
}
if (typeof n === 'string') {
promises.push(...fetchEmojis(n, emojiSource));
}
if ('value' in n && typeof n.value === 'string') {
promises.push(...fetchEmojis(n.value, emojiSource));
}
if (n.children) {
n.children.forEach((childNode) => {
listToExplore.push(childNode);
});
}
}
return promises;
};
/**
* Fetch image, font and emoji assets in parallel.
* Layout process will not be resumed until promise resolves.
*
* @param node root node
* @param fontStore font store
* @returns Root node
*/
const resolveAssets = async (node: SafeNode, fontStore: FontStore) => {
const promises = fetchAssets(fontStore, node);
await Promise.all(promises);
return node;
};
export default resolveAssets;
================================================
FILE: packages/layout/src/steps/resolveBookmarks.ts
================================================
import { Bookmark, DocumentNode, Node } from '../types';
const getBookmarkValue = (bookmark: Bookmark) => {
return typeof bookmark === 'string'
? { title: bookmark, fit: false, expanded: false }
: bookmark;
};
type Parent = Bookmark & { ref: number; parent: number | null };
type Item = {
value: Node;
parent: Parent | null;
};
const resolveBookmarks = (node: DocumentNode) => {
let refs = 0;
const children = (node.children || []).slice(0);
const listToExplore: Item[] = children.map((value) => ({
value,
parent: null,
}));
while (listToExplore.length > 0) {
const element = listToExplore.shift();
if (!element) break;
const child = element.value;
let parent = element.parent;
if (child.props && 'bookmark' in child.props && child.props.bookmark) {
const bookmark = getBookmarkValue(child.props.bookmark);
const ref = refs++;
const newHierarchy = { ref, parent: parent?.ref, ...bookmark };
child.props.bookmark = newHierarchy;
parent = newHierarchy;
}
if (child.children) {
child.children.forEach((childNode) => {
listToExplore.push({ value: childNode, parent });
});
}
}
return node;
};
export default resolveBookmarks;
================================================
FILE: packages/layout/src/steps/resolveDimensions.ts
================================================
import * as P from '@react-pdf/primitives';
import { isNil, compose } from '@react-pdf/fns';
import FontStore from '@react-pdf/font';
import getMargin from '../node/getMargin';
import getPadding from '../node/getPadding';
import getPosition from '../node/getPosition';
import getDimension from '../node/getDimension';
import getBorderWidth from '../node/getBorderWidth';
import setDisplay from '../node/setDisplay';
import setOverflow from '../node/setOverflow';
import setFlexWrap from '../node/setFlexWrap';
import setFlexGrow from '../node/setFlexGrow';
import setFlexBasis from '../node/setFlexBasis';
import setAlignSelf from '../node/setAlignSelf';
import setAlignItems from '../node/setAlignItems';
import setFlexShrink from '../node/setFlexShrink';
import setAspectRatio from '../node/setAspectRatio';
import setAlignContent from '../node/setAlignContent';
import setPositionType from '../node/setPositionType';
import setFlexDirection from '../node/setFlexDirection';
import setJustifyContent from '../node/setJustifyContent';
import {
setMarginTop,
setMarginRight,
setMarginBottom,
setMarginLeft,
} from '../node/setMargin';
import {
setPaddingTop,
setPaddingRight,
setPaddingBottom,
setPaddingLeft,
} from '../node/setPadding';
import {
setBorderTop,
setBorderRight,
setBorderBottom,
setBorderLeft,
} from '../node/setBorderWidth';
import {
setPositionTop,
setPositionRight,
setPositionBottom,
setPositionLeft,
} from '../node/setPosition';
import {
setWidth,
setHeight,
setMinWidth,
setMaxWidth,
setMinHeight,
setMaxHeight,
} from '../node/setDimension';
import { setRowGap, setColumnGap } from '../node/setGap';
import measureSvg from '../svg/measureSvg';
import measureText from '../text/measureText';
import measureImage from '../image/measureImage';
import measureCanvas from '../canvas/measureCanvas';
import {
Box,
SafeDocumentNode,
SafeNode,
SafePageNode,
YogaInstance,
} from '../types';
const isType = (type) => (node) => node.type === type;
const isSvg = isType(P.Svg);
const isText = isType(P.Text);
const isNote = isType(P.Note);
const isPage = isType(P.Page);
const isImage = isType(P.Image);
const isCanvas = isType(P.Canvas);
const isTextInstance = isType(P.TextInstance);
const setNodeHeight = (node: SafeNode) => {
const value = isPage(node) ? node.box?.height : node.style?.height;
return setHeight(value);
};
/**
* Set styles valeus into yoga node before layout calculation
*
* @param node
*/
const setYogaValues = (node: SafeNode) => {
compose(
setNodeHeight(node),
setWidth(node.style.width),
setMinWidth(node.style.minWidth),
setMaxWidth(node.style.maxWidth),
setMinHeight(node.style.minHeight),
setMaxHeight(node.style.maxHeight),
setMarginTop(node.style.marginTop),
setMarginRight(node.style.marginRight),
setMarginBottom(node.style.marginBottom),
setMarginLeft(node.style.marginLeft),
setPaddingTop(node.style.paddingTop),
setPaddingRight(node.style.paddingRight),
setPaddingBottom(node.style.paddingBottom),
setPaddingLeft(node.style.paddingLeft),
setPositionType(node.style.position),
setPositionTop(node.style.top),
setPositionRight(node.style.right),
setPositionBottom(node.style.bottom),
setPositionLeft(node.style.left),
setBorderTop(node.style.borderTopWidth),
setBorderRight(node.style.borderRightWidth),
setBorderBottom(node.style.borderBottomWidth),
setBorderLeft(node.style.borderLeftWidth),
setDisplay(node.style.display),
setFlexDirection(node.style.flexDirection),
setAlignSelf(node.style.alignSelf),
setAlignContent(node.style.alignContent),
setAlignItems(node.style.alignItems),
setJustifyContent(node.style.justifyContent),
setFlexWrap(node.style.flexWrap),
setOverflow(node.style.overflow),
setAspectRatio(node.style.aspectRatio),
setFlexBasis(node.style.flexBasis),
setFlexGrow(node.style.flexGrow),
setFlexShrink(node.style.flexShrink),
setRowGap(node.style.rowGap),
setColumnGap(node.style.columnGap),
)(node);
};
/**
* Inserts child into parent' yoga node
*
* @param parent parent
* @returns Insert yoga nodes
*/
const insertYogaNodes = (parent) => (child) => {
parent.insertChild(child.yogaNode, parent.getChildCount());
return child;
};
const setMeasureFunc = (node, page, fontStore) => {
const { yogaNode } = node;
if (isText(node)) {
yogaNode.setMeasureFunc(measureText(page, node, fontStore));
}
if (isImage(node)) {
yogaNode.setMeasureFunc(measureImage(page, node));
}
if (isCanvas(node)) {
yogaNode.setMeasureFunc(measureCanvas(page, node));
}
if (isSvg(node)) {
yogaNode.setMeasureFunc(measureSvg(page, node));
}
return node;
};
const isLayoutElement = (node) =>
!isText(node) && !isNote(node) && !isSvg(node);
/**
* @typedef {Function} CreateYogaNodes
* @param {Object} node
* @returns {Object} node with appended yoga node
*/
/**
* Creates and add yoga node to document tree
* Handles measure function for text and image nodes
*
* @returns Create yoga nodes
*/
const createYogaNodes =
(page: SafePageNode, fontStore: FontStore, yoga: YogaInstance) =>
(node: SafeNode) => {
const yogaNode = yoga.node.create();
const result = Object.assign({}, node, { yogaNode });
setYogaValues(result);
if (isLayoutElement(node) && node.children) {
const resolveChild = compose(
insertYogaNodes(yogaNode),
createYogaNodes(page, fontStore, yoga),
);
result.children = node.children.map(resolveChild);
}
setMeasureFunc(result, page, fontStore);
return result;
};
/**
* Performs yoga calculation
*
* @param page - Page node
* @returns Page node
*/
const calculateLayout = (page: SafePageNode) => {
page.yogaNode.calculateLayout();
return page;
};
/**
* Saves Yoga layout result into 'box' attribute of node
*
* @param node
* @returns Node with box data
*/
const persistDimensions = (node: SafeNode) => {
if (isTextInstance(node)) return node;
const box: Box = Object.assign(
getPadding(node),
getMargin(node),
getBorderWidth(node),
getPosition(node),
getDimension(node),
);
const newNode = Object.assign({}, node, { box });
if (!node.children) return newNode;
const children = node.children.map(persistDimensions);
return Object.assign({}, newNode, { children });
};
/**
* Removes yoga node from document tree
*
* @param node
* @returns Node without yoga node
*/
const destroyYogaNodes = (node: SafeNode): SafeNode => {
const newNode = Object.assign({}, node);
delete newNode.yogaNode;
if (!node.children) return newNode;
const children = node.children.map(destroyYogaNodes);
return Object.assign({}, newNode, { children });
};
/**
* Free yoga node from document tree
*
* @param node
* @returns Node without yoga node
*/
const freeYogaNodes = (node: SafeNode) => {
if (node.yogaNode) node.yogaNode.freeRecursive();
return node;
};
/**
* Calculates page object layout using Yoga.
* Takes node values from 'box' and 'style' attributes, and persist them back into 'box'
* Destroy yoga values at the end.
*
* @param page - Object
* @returns Page object with correct 'box' layout attributes
*/
export const resolvePageDimensions = (
page: SafePageNode,
fontStore: FontStore,
yoga: YogaInstance,
) => {
if (isNil(page)) return null;
return compose(
destroyYogaNodes,
freeYogaNodes,
persistDimensions,
calculateLayout,
createYogaNodes(page, fontStore, yoga),
)(page);
};
/**
* Calculates root object layout using Yoga.
*
* @param node - Root object
* @param fontStore - Font store
* @returns Root object with correct 'box' layout attributes
*/
const resolveDimensions = (node: SafeDocumentNode, fontStore: FontStore) => {
if (!node.children) return node;
const resolveChild = (child: SafePageNode) =>
resolvePageDimensions(child, fontStore, node.yoga);
const children = node.children.map(resolveChild);
return Object.assign({}, node, { children });
};
export default resolveDimensions;
================================================
FILE: packages/layout/src/steps/resolveInheritance.ts
================================================
import * as P from '@react-pdf/primitives';
import { pick, compose } from '@react-pdf/fns';
import { SafeStyle } from '@react-pdf/stylesheet';
import { SafeNode } from '../types';
type StyleKey = keyof SafeStyle;
const BASE_INHERITABLE_PROPERTIES = [
'color',
'fontFamily',
'fontSize',
'fontStyle',
'fontWeight',
'letterSpacing',
'opacity',
'textDecoration',
'textTransform',
'lineHeight',
'textAlign',
'visibility',
'wordSpacing',
];
const TEXT_INHERITABLE_PROPERTIES = [
...BASE_INHERITABLE_PROPERTIES,
'backgroundColor',
];
const isType = (type: string) => (node: SafeNode) => node.type === type;
const isSvg = isType(P.Svg);
const isText = isType(P.Text);
// Merge style values
const mergeValues = (
styleName: K,
value: SafeStyle[K],
inheritedValue: SafeStyle[K],
) => {
switch (styleName) {
case 'textDecoration': {
// merge not none and not false textDecoration values to one rule
return [inheritedValue, value].filter((v) => v && v !== 'none').join(' ');
}
default:
return value;
}
};
// Merge inherited and node styles
const merge = (inheritedStyles: SafeStyle, style: SafeStyle): SafeStyle => {
const mergedStyles = { ...inheritedStyles };
Object.entries(style).forEach(([styleName, value]) => {
mergedStyles[styleName] = mergeValues(
styleName as StyleKey,
value,
inheritedStyles[styleName],
);
});
return mergedStyles;
};
/**
* Merges styles with node
*
* @param inheritedStyles - Style object
* @returns Merge styles function
*/
const mergeStyles =
(inheritedStyles: SafeStyle) =>
(node: SafeNode): SafeNode => {
const style = merge(inheritedStyles, node.style || {});
return Object.assign({}, node, { style });
};
/**
* Inherit style values from the root to the leafs
*
* @param node - Document root
* @returns Document root with inheritance
*
*/
const resolveInheritance = (node: SafeNode) => {
if (isSvg(node)) return node;
if (!('children' in node)) return node;
const inheritableProperties = isText(node)
? TEXT_INHERITABLE_PROPERTIES
: BASE_INHERITABLE_PROPERTIES;
const inheritStyles = pick(inheritableProperties, node.style || {});
const resolveChild = compose(resolveInheritance, mergeStyles(inheritStyles));
const children = node.children.map(resolveChild);
return Object.assign({}, node, { children });
};
export default resolveInheritance;
================================================
FILE: packages/layout/src/steps/resolveLinkSubstitution.ts
================================================
import * as P from '@react-pdf/primitives';
import { compose } from '@react-pdf/fns';
import { Node } from '../types';
const isType = (type: string) => (node: Node) => node.type === type;
const isLink = isType(P.Link);
const isText = isType(P.Text);
const isTextInstance = isType(P.TextInstance);
/**
* Checks if node has render prop
*
* @param node
* @returns Has render prop?
*/
const hasRenderProp = (node: Node) => 'render' in node.props;
/**
* Checks if node is text type (Text or TextInstance)
*
* @param node
* @returns Are all children text instances?
*/
const isTextType = (node: Node) => isText(node) || isTextInstance(node);
/**
* Checks if is tet link that needs to be wrapped in Text
*
* @param node
* @returns Are all children text instances?
*/
const isTextLink = (node: Node) => {
const children = node.children || [];
// Text string inside a Link
if (children.every(isTextInstance)) return true;
// Text node inside a Link
if (children.every(isText)) return false;
return children.every(isTextType);
};
/**
* Wraps node children inside Text node
*
* @param node
* @returns Node with intermediate Text child
*/
const wrapText = (node) => {
const textElement = {
type: P.Text,
props: {},
style: {},
box: {},
children: node.children,
};
return Object.assign({}, node, { children: [textElement] });
};
const transformLink = (node: Node) => {
if (!isLink(node)) return node;
// If has render prop substitute the instance by a Text, that will
// ultimately render the inline Link via the textkit PDF renderer.
if (hasRenderProp(node)) return Object.assign({}, node, { type: P.Text });
// If is a text link (either contains Text or TextInstance), wrap it
// inside a Text element so styles are applied correctly
if (isTextLink(node)) return wrapText(node);
return node;
};
/**
* Transforms Link layout to correctly render text and dynamic rendered links
*
* @param node
* @returns Node with link substitution
*/
const resolveLinkSubstitution = (node: Node): Node => {
if (!node.children) return node;
const resolveChild = compose(transformLink, resolveLinkSubstitution);
const children = node.children.map(resolveChild);
return Object.assign({}, node, { children });
};
export default resolveLinkSubstitution;
================================================
FILE: packages/layout/src/steps/resolveOrigins.ts
================================================
import getOrigin from '../node/getOrigin';
import { SafeDocumentNode, SafeNode } from '../types';
/**
* Resolve node origin
*
* @param node
* @returns Node with origin attribute
*/
const resolveNodeOrigin = (node: SafeNode): SafeNode => {
const origin = getOrigin(node);
const newNode = Object.assign({}, node, { origin });
if (!node.children) return newNode;
const children = node.children.map(resolveNodeOrigin);
return Object.assign({}, newNode, { children });
};
/**
* Resolve document origins
*
* @param root - Document root
* @returns Document root
*/
const resolveOrigin = (root: SafeDocumentNode) => {
if (!root.children) return root;
const children = root.children.map(resolveNodeOrigin);
return Object.assign({}, root, { children });
};
export default resolveOrigin;
================================================
FILE: packages/layout/src/steps/resolvePagePaddings.ts
================================================
import { evolve, matchPercent } from '@react-pdf/fns';
import { SafeStyle } from '@react-pdf/stylesheet';
import { SafeDocumentNode, SafePageNode } from '../types';
/**
* Translates page percentage horizontal paddings in fixed ones
*
* @param container - Page container
* @returns Resolve page horizontal padding
*/
const resolvePageHorizontalPadding =
(container: SafeStyle) => (value: number) => {
const match = matchPercent(value);
const width = container.width as number;
return match ? match.percent * width : value;
};
/**
* Translates page percentage vertical paddings in fixed ones
*
* @param container - Page container
* @returns Resolve page vertical padding
*/
const resolvePageVerticalPadding =
(container: SafeStyle) => (value: number) => {
const match = matchPercent(value);
const height = container.height as number;
return match ? match.percent * height : value;
};
/**
* Translates page percentage paddings in fixed ones
*
* @param page
* @returns Page with fixed paddings
*/
const resolvePagePaddings = (page: SafePageNode): SafePageNode => {
const container = page.style;
const style = evolve(
{
paddingTop: resolvePageVerticalPadding(container),
paddingLeft: resolvePageHorizontalPadding(container),
paddingRight: resolvePageHorizontalPadding(container),
paddingBottom: resolvePageVerticalPadding(container),
},
page.style,
);
return Object.assign({}, page, { style });
};
/**
* Translates all pages percentage paddings in fixed ones
* This has to be computed from pages calculated size and not by Yoga
* because at this point we didn't performed pagination yet.
*
* @param root - Document root
* @returns Document root with translated page paddings
*/
const resolvePagesPaddings = (root: SafeDocumentNode) => {
if (!root.children) return root;
const children = root.children.map(resolvePagePaddings);
return Object.assign({}, root, { children });
};
export default resolvePagesPaddings;
================================================
FILE: packages/layout/src/steps/resolvePageSizes.ts
================================================
import { flatten } from '@react-pdf/stylesheet';
import getPageSize from '../page/getSize';
import { DocumentNode, PageNode } from '../types';
/**
* Resolves page size
*
* @param page
* @returns Page with resolved size in style attribute
*/
export const resolvePageSize = (page: PageNode): PageNode => {
const size = getPageSize(page);
const style = flatten(page.style || {});
return { ...page, style: { ...style, ...size } };
};
/**
* Resolves page sizes
*
* @param root -Document root
* @returns Document root with resolved page sizes
*/
const resolvePageSizes = (root: DocumentNode) => {
if (!root.children) return root;
const children = root.children.map(resolvePageSize);
return Object.assign({}, root, { children });
};
export default resolvePageSizes;
================================================
FILE: packages/layout/src/steps/resolvePagination.ts
================================================
import * as P from '@react-pdf/primitives';
import { omit, compose } from '@react-pdf/fns';
import FontStore from '@react-pdf/font';
import isFixed from '../node/isFixed';
import splitText from '../text/splitText';
import splitNode from '../node/splitNode';
import canNodeWrap from '../node/getWrap';
import getWrapArea from '../page/getWrapArea';
import getContentArea from '../page/getContentArea';
import createInstances from '../node/createInstances';
import shouldNodeBreak from '../node/shouldBreak';
import resolveTextLayout from './resolveTextLayout';
import resolveInheritance from './resolveInheritance';
import { resolvePageDimensions } from './resolveDimensions';
import { resolvePageStyles } from './resolveStyles';
import {
DynamicPageProps,
SafeDocumentNode,
SafeLinkNode,
SafeNode,
SafePageNode,
SafeTextNode,
SafeViewNode,
YogaInstance,
} from '../types';
const isText = (node: SafeNode): node is SafeTextNode => node.type === P.Text;
// Prevent splitting elements by low decimal numbers
const SAFETY_THRESHOLD = 0.001;
const assingChildren = (children: SafeNode[], node: T): T =>
Object.assign({}, node, { children });
const getTop = (node: SafeNode) => node.box?.top || 0;
const allFixed = (nodes: SafeNode[]) => nodes.every(isFixed);
const isDynamic = (
node: SafeNode,
): node is SafeLinkNode | SafeTextNode | SafeViewNode =>
node.props && 'render' in node.props;
const relayoutPage = compose(
resolveTextLayout,
resolvePageDimensions,
resolveInheritance,
resolvePageStyles,
);
const warnUnavailableSpace = (node: SafeNode) => {
console.warn(
`Node of type ${node.type} can't wrap between pages and it's bigger than available page height`,
);
};
const splitNodes = (height: number, contentArea: number, nodes: SafeNode[]) => {
const currentChildren: SafeNode[] = [];
const nextChildren: SafeNode[] = [];
for (let i = 0; i < nodes.length; i += 1) {
const child = nodes[i];
const futureNodes = nodes.slice(i + 1);
const futureFixedNodes = futureNodes.filter(isFixed);
const nodeTop = getTop(child);
const nodeHeight = child.box.height;
const isOutside = height <= nodeTop;
const shouldBreak = shouldNodeBreak(
child,
futureNodes,
height,
currentChildren,
);
const shouldSplit = height + SAFETY_THRESHOLD < nodeTop + nodeHeight;
const canWrap = canNodeWrap(child);
const fitsInsidePage = nodeHeight <= contentArea;
if (isFixed(child)) {
nextChildren.push(child);
currentChildren.push(child);
continue;
}
if (isOutside) {
const box = Object.assign({}, child.box, { top: child.box.top - height });
const next = Object.assign({}, child, { box });
nextChildren.push(next);
continue;
}
if (!fitsInsidePage && !canWrap) {
currentChildren.push(child);
nextChildren.push(...futureNodes);
warnUnavailableSpace(child);
break;
}
if (shouldBreak) {
const box = Object.assign({}, child.box, { top: child.box.top - height });
const props = Object.assign({}, child.props, {
wrap: true,
break: false,
});
const next = Object.assign({}, child, { box, props });
currentChildren.push(...futureFixedNodes);
nextChildren.push(next, ...futureNodes);
break;
}
if (shouldSplit) {
const [currentChild, nextChild] = split(child, height, contentArea);
// All children are moved to the next page, it doesn't make sense to show the parent on the current page
if (child.children.length > 0 && currentChild.children.length === 0) {
// But if the current page is empty then we can just include the parent on the current page
if (currentChildren.length === 0) {
currentChildren.push(child, ...futureFixedNodes);
nextChildren.push(...futureNodes);
} else {
const box = Object.assign({}, child.box, {
top: child.box.top - height,
});
const next = Object.assign({}, child, { box });
currentChildren.push(...futureFixedNodes);
nextChildren.push(next, ...futureNodes);
}
break;
}
if (currentChild) currentChildren.push(currentChild);
if (nextChild) nextChildren.push(nextChild);
continue;
}
currentChildren.push(child);
}
return [currentChildren, nextChildren];
};
const splitChildren = (height: number, contentArea: number, node: SafeNode) => {
const children = node.children || [];
const availableHeight = height - getTop(node);
return splitNodes(availableHeight, contentArea, children);
};
const splitView = (node: SafeNode, height: number, contentArea: number) => {
const [currentNode, nextNode] = splitNode(node, height);
const [currentChilds, nextChildren] = splitChildren(
height,
contentArea,
node,
);
return [
assingChildren(currentChilds, currentNode),
assingChildren(nextChildren, nextNode),
];
};
const split = (node: SafeNode, height: number, contentArea: number) =>
isText(node) ? splitText(node, height) : splitView(node, height, contentArea);
const shouldResolveDynamicNodes = (node: SafeNode) => {
const children = node.children || [];
return isDynamic(node) || children.some(shouldResolveDynamicNodes);
};
const resolveDynamicNodes = (props: DynamicPageProps, node: SafeNode) => {
const isNodeDynamic = isDynamic(node);
// Call render prop on dynamic nodes and append result to children
const resolveChildren = (children = []) => {
if (isNodeDynamic) {
const res = node.props.render(props);
return (
createInstances(res)
.filter(Boolean)
// @ts-expect-error rework dynamic nodes. conflicting types
.map((n) => resolveDynamicNodes(props, n))
);
}
return children.map((c) => resolveDynamicNodes(props, c));
};
// We reset dynamic text box so it can be computed again later on
const resetHeight = isNodeDynamic && isText(node);
const box = resetHeight ? { ...node.box, height: 0 } : node.box;
const children = resolveChildren(node.children);
// @ts-expect-error handle text here specifically
const lines = isNodeDynamic ? null : node.lines;
return Object.assign({}, node, { box, lines, children });
};
const resolveDynamicPage = (
props: DynamicPageProps,
page: SafePageNode,
fontStore: FontStore,
yoga: YogaInstance,
) => {
if (shouldResolveDynamicNodes(page)) {
const resolvedPage = resolveDynamicNodes(props, page);
return relayoutPage(resolvedPage, fontStore, yoga);
}
return page;
};
const splitPage = (
page: SafePageNode,
pageNumber: number,
fontStore: FontStore,
yoga: YogaInstance,
): SafePageNode[] => {
const wrapArea = getWrapArea(page);
const contentArea = getContentArea(page);
const dynamicPage = resolveDynamicPage({ pageNumber }, page, fontStore, yoga);
const height = page.style.height;
const [currentChilds, nextChilds] = splitNodes(
wrapArea,
contentArea,
dynamicPage.children,
);
const relayout = (node: SafePageNode): SafePageNode =>
// @ts-expect-error rework pagination
relayoutPage(node, fontStore, yoga) as SafePageNode;
const currentBox = { ...page.box, height };
const currentPage = relayout(
Object.assign({}, page, { box: currentBox, children: currentChilds }),
);
if (nextChilds.length === 0 || allFixed(nextChilds))
return [currentPage, null];
const nextBox = omit('height', page.box);
const nextProps = omit('bookmark', page.props);
const nextPage = relayout(
Object.assign({}, page, {
props: nextProps,
box: nextBox,
children: nextChilds,
}),
);
return [currentPage, nextPage];
};
const resolvePageIndices = (fontStore, yoga, page, pageNumber, pages) => {
const totalPages = pages.length;
const props = {
totalPages,
pageNumber: pageNumber + 1,
subPageNumber: page.subPageNumber + 1,
subPageTotalPages: page.subPageTotalPages,
};
return resolveDynamicPage(props, page, fontStore, yoga);
};
const assocSubPageData = (subpages) => {
return subpages.map((page, i) => ({
...page,
subPageNumber: i,
subPageTotalPages: subpages.length,
}));
};
const dissocSubPageData = (page) => {
return omit(['subPageNumber', 'subPageTotalPages'], page);
};
const paginate = (
page: SafePageNode,
pageNumber: number,
fontStore: FontStore,
yoga: YogaInstance,
) => {
if (!page) return [];
if (page.props?.wrap === false) return [page];
let splittedPage = splitPage(page, pageNumber, fontStore, yoga);
const pages = [splittedPage[0]];
let nextPage = splittedPage[1];
while (nextPage !== null) {
splittedPage = splitPage(
nextPage,
pageNumber + pages.length,
fontStore,
yoga,
);
pages.push(splittedPage[0]);
nextPage = splittedPage[1];
}
return pages;
};
/**
* Performs pagination. This is the step responsible of breaking the whole document
* into pages following pagiation rules, such as `fixed`, `break` and dynamic nodes.
*
* @param root - Document node
* @param fontStore - Font store
* @returns Layout node
*/
const resolvePagination = (
root: SafeDocumentNode,
fontStore: FontStore,
): SafeDocumentNode => {
let pages = [];
let pageNumber = 1;
for (let i = 0; i < root.children.length; i += 1) {
const page = root.children[i];
let subpages = paginate(page, pageNumber, fontStore, root.yoga);
subpages = assocSubPageData(subpages);
pageNumber += subpages.length;
pages = pages.concat(subpages);
}
pages = pages.map((...args) =>
dissocSubPageData(resolvePageIndices(fontStore, root.yoga, ...args)),
);
return assingChildren(pages, root);
};
export default resolvePagination;
================================================
FILE: packages/layout/src/steps/resolvePercentHeight.ts
================================================
import { isNil, matchPercent } from '@react-pdf/fns';
import { SafeDocumentNode, SafeNode, SafePageNode } from '../types';
/**
* Transform percent height into fixed
*
* @param height
* @returns Height
*/
const transformHeight = (pageArea: number, height: number | string) => {
const match = matchPercent(height);
return match ? match.percent * pageArea : height;
};
/**
* Get page area (height minus paddings)
*
* @param page
* @returns Page area
*/
const getPageArea = (page: SafePageNode) => {
const pageHeight = page.style.height as number;
const pagePaddingTop = (page.style?.paddingTop || 0) as number;
const pagePaddingBottom = (page.style?.paddingBottom || 0) as number;
return pageHeight - pagePaddingTop - pagePaddingBottom;
};
/**
* Transform node percent height to fixed
*
* @param page
* @param node
* @returns Transformed node
*/
const resolveNodePercentHeight = (
page: SafePageNode,
node: SafeNode,
): SafeNode => {
if (isNil(page.style?.height)) return node;
if (isNil(node.style?.height)) return node;
const pageArea = getPageArea(page);
const height = transformHeight(pageArea, node.style.height);
const style = Object.assign({}, node.style, { height });
return Object.assign({}, node, { style });
};
/**
* Transform page immediate children with percent height to fixed
*
* @param page
* @returns Transformed page
*/
const resolvePagePercentHeight = (page: SafePageNode) => {
if (!page.children) return page;
const resolveChild = (child: SafeNode) =>
resolveNodePercentHeight(page, child);
const children = page.children.map(resolveChild);
return Object.assign({}, page, { children });
};
/**
* Transform all page immediate children with percent height to fixed.
* This is needed for computing correct dimensions on pre-pagination layout.
*
* @param root - Document root
* @returns Transformed document root
*/
const resolvePercentHeight = (root: SafeDocumentNode) => {
if (!root.children) return root;
const children = root.children.map(resolvePagePercentHeight);
return Object.assign({}, root, { children });
};
export default resolvePercentHeight;
================================================
FILE: packages/layout/src/steps/resolvePercentRadius.ts
================================================
import { evolve, matchPercent } from '@react-pdf/fns';
import { Box, SafeNode } from '../types';
const resolveRadius = (box: Box) => (value: number | `${string}%`) => {
if (!value) return undefined;
const match = matchPercent(value);
return match ? match.percent * Math.min(box.width, box.height) : value;
};
/**
* Transforms percent border radius into fixed values
*
* @param node
* @returns Node
*/
const resolvePercentRadius = (node: SafeNode): SafeNode => {
const style = evolve(
{
borderTopLeftRadius: resolveRadius(node.box),
borderTopRightRadius: resolveRadius(node.box),
borderBottomRightRadius: resolveRadius(node.box),
borderBottomLeftRadius: resolveRadius(node.box),
},
node.style || {},
);
const newNode = Object.assign({}, node, { style });
if (!node.children) return newNode;
const children = node.children.map(resolvePercentRadius);
return Object.assign({}, newNode, { children });
};
export default resolvePercentRadius;
================================================
FILE: packages/layout/src/steps/resolveStyles.ts
================================================
import * as P from '@react-pdf/primitives';
import stylesheet, { Container, Style } from '@react-pdf/stylesheet';
import {
DocumentNode,
Node,
PageNode,
SafeDocumentNode,
SafeNode,
} from '../types';
const isLink = (node: Node) => node.type === P.Link;
const DEFAULT_LINK_STYLES: Style = {
color: 'blue',
textDecoration: 'underline',
};
/**
* Computes styles using stylesheet
*
* @param container
* @param node - Document node
* @returns Computed styles
*/
const computeStyle = (container: Container, node: Node) => {
let baseStyle: Style[] = [node.style as Style];
if (isLink(node)) {
baseStyle = Array.isArray(node.style)
? [DEFAULT_LINK_STYLES, ...node.style]
: [DEFAULT_LINK_STYLES, node.style];
}
return stylesheet(container, baseStyle);
};
/**
* Resolves node styles
*
* @param container
* @returns Resolve node styles
*/
const resolveNodeStyles =
(container: Container) =>
(node: Node): SafeNode => {
const style = computeStyle(container, node);
if (!node.children) return Object.assign({}, node, { style }) as SafeNode;
const children = node.children.map(resolveNodeStyles(container));
return Object.assign({}, node, { style, children }) as SafeNode;
};
/**
* Resolves page styles
*
* @param page Document page
* @returns Document page with resolved styles
*/
export const resolvePageStyles = (page: PageNode) => {
const dpi = page.props?.dpi || 72;
const style = page.style as Style;
const width = page.box?.width || style.width;
const height = page.box?.height || style.height;
const orientation = page.props?.orientation || 'portrait';
const remBase = style?.fontSize || 18;
const container = { width, height, orientation, dpi, remBase } as Container;
return resolveNodeStyles(container)(page);
};
/**
* Resolves document styles
*
* @param root - Document root
* @returns Document root with resolved styles
*/
const resolveStyles = (root: DocumentNode): SafeDocumentNode => {
if (!root.children) return root as SafeDocumentNode;
const children = root.children.map(resolvePageStyles);
return Object.assign({}, root, { children }) as SafeDocumentNode;
};
export default resolveStyles;
================================================
FILE: packages/layout/src/steps/resolveSvg.ts
================================================
import * as P from '@react-pdf/primitives';
import FontStore from '@react-pdf/font';
import resolveStyle, { transformColor } from '@react-pdf/stylesheet';
import {
pick,
evolve,
compose,
mapValues,
matchPercent,
parseFloat,
} from '@react-pdf/fns';
import layoutText from '../svg/layoutText';
import replaceDefs from '../svg/replaceDefs';
import getContainer from '../svg/getContainer';
import parseViewbox from '../svg/parseViewbox';
import inheritProps from '../svg/inheritProps';
import parseAspectRatio from '../svg/parseAspectRatio';
import {
SafeNode,
SafeSvgNode,
SafeTextInstanceNode,
SafeTextNode,
SafeTspanNode,
} from '../types';
type Container = { width: number; height: number };
const STYLE_PROPS = [
'width',
'height',
'color',
'stroke',
'strokeWidth',
'opacity',
'fillOpacity',
'strokeOpacity',
'fill',
'fillRule',
'clipPath',
'offset',
'transform',
'strokeLinejoin',
'strokeLinecap',
'strokeDasharray',
'gradientUnits',
'gradientTransform',
];
const VERTICAL_PROPS = ['y', 'y1', 'y2', 'height', 'cy', 'ry'];
const HORIZONTAL_PROPS = ['x', 'x1', 'x2', 'width', 'cx', 'rx'];
const isSvg = (node: SafeNode): node is SafeSvgNode => node.type === P.Svg;
const isText = (node: SafeNode): node is SafeTextNode => node.type === P.Text;
const isTextInstance = (node: SafeNode): node is SafeTextInstanceNode =>
node.type === P.TextInstance;
const transformPercent = (container: Container) => (props) =>
mapValues(props, (value, key) => {
const match = matchPercent(value);
if (match && VERTICAL_PROPS.includes(key)) {
return match.percent * container.height;
}
if (match && HORIZONTAL_PROPS.includes(key)) {
return match.percent * container.width;
}
return value;
});
const parsePercent = (value) => {
const match = matchPercent(value);
return match ? match.percent : parseFloat(value);
};
const parseTransform = (container: Container) => (value) => {
return resolveStyle(container, { transform: value }).transform;
};
const parseProps =
(container: Container) =>
(node: SafeNode): SafeNode => {
let props = transformPercent(container)(node.props);
props = evolve(
{
x: parseFloat,
x1: parseFloat,
x2: parseFloat,
y: parseFloat,
y1: parseFloat,
y2: parseFloat,
r: parseFloat,
rx: parseFloat,
ry: parseFloat,
cx: parseFloat,
cy: parseFloat,
width: parseFloat,
height: parseFloat,
offset: parsePercent,
fill: transformColor,
opacity: parsePercent,
stroke: transformColor,
stopOpacity: parsePercent,
stopColor: transformColor,
transform: parseTransform(container),
gradientTransform: parseTransform(container),
},
props,
);
return Object.assign({}, node, { props });
};
const mergeStyles = (node: SafeNode): SafeNode => {
const style = node.style || {};
const props = Object.assign({}, style, node.props);
return Object.assign({}, node, { props });
};
const removeNoneValues = (node: SafeNode): SafeNode => {
const removeNone = (value) => (value === 'none' ? null : value);
const props = mapValues(node.props, removeNone);
return Object.assign({}, node, { props });
};
const pickStyleProps = (node: SafeNode): SafeNode => {
const props = node.props || {};
const styleProps = pick(STYLE_PROPS, props);
const style = Object.assign({}, styleProps, node.style || {});
return Object.assign({}, node, { style });
};
const parseSvgProps = (node: SafeSvgNode) => {
const props = evolve(
{
width: parseFloat,
height: parseFloat,
viewBox: parseViewbox,
preserveAspectRatio: parseAspectRatio,
},
node.props,
);
return Object.assign({}, node, { props });
};
const wrapBetweenTspan = (node: SafeTextInstanceNode): SafeTspanNode => ({
type: P.Tspan,
props: {},
style: {},
children: [node],
});
const addMissingTspan = (node: SafeNode): SafeNode => {
if (!isText(node)) return node;
if (!node.children) return node;
const resolveChild = (child) =>
isTextInstance(child) ? wrapBetweenTspan(child) : child;
const children = node.children.map(resolveChild);
return Object.assign({}, node, { children });
};
const parseText =
(fontStore: FontStore) =>
(node: SafeNode): SafeNode => {
if (isText(node)) return layoutText(fontStore, node);
if (!node.children) return node;
const children = node.children.map(parseText(fontStore));
return Object.assign({}, node, { children });
};
const resolveSvgNode = (container: Container) =>
compose(
parseProps(container),
addMissingTspan,
removeNoneValues,
mergeStyles,
);
const resolveChildren =
(container: Container) =>
(node: SafeNode): SafeNode => {
if (!node.children) return node;
const resolveChild = compose(
resolveChildren(container),
resolveSvgNode(container),
);
const children = node.children.map(resolveChild);
return Object.assign({}, node, { children });
};
const buildXLinksIndex = (node: SafeSvgNode) => {
const idIndex: Record = {};
const listToExplore: SafeNode[] = node.children?.slice(0) || [];
while (listToExplore.length > 0) {
const child = listToExplore.shift();
if (child.props && 'id' in child.props) {
idIndex[child.props.id] = child;
}
if (child.children) listToExplore.push(...child.children);
}
return idIndex;
};
const replaceXLinks = (node: SafeNode, idIndex: Record) => {
if (node.props && 'xlinkHref' in node.props) {
const linkedNode = idIndex[node.props.xlinkHref.replace(/^#/, '')];
// No node to extend from
if (!linkedNode) return node;
const newProps = Object.assign({}, linkedNode.props, node.props);
delete newProps.xlinkHref;
return Object.assign({}, linkedNode, { props: newProps });
}
const children = node.children?.map((child) => replaceXLinks(child, idIndex));
return Object.assign({}, node, { children });
};
export const resolveXLinks = (node: SafeSvgNode): SafeSvgNode => {
const idIndex = buildXLinksIndex(node);
return replaceXLinks(node, idIndex);
};
const resolveSvgRoot = (node: SafeSvgNode, fontStore: FontStore) => {
const container = getContainer(node);
return compose(
replaceDefs,
parseText(fontStore),
parseSvgProps,
pickStyleProps,
inheritProps,
resolveChildren(container),
resolveXLinks,
)(node);
};
/**
* Pre-process SVG nodes so they can be rendered in the next steps
*
* @param node - Root node
* @param fontStore - Font store
* @returns Root node
*/
const resolveSvg = (node: SafeNode, fontStore: FontStore) => {
if (!('children' in node)) return node;
const resolveChild = (child) => resolveSvg(child, fontStore);
const root = isSvg(node) ? resolveSvgRoot(node, fontStore) : node;
const children = root.children?.map(resolveChild);
return Object.assign({}, root, { children });
};
export default resolveSvg;
================================================
FILE: packages/layout/src/steps/resolveTextLayout.ts
================================================
import * as P from '@react-pdf/primitives';
import FontStore from '@react-pdf/font';
import layoutText from '../text/layoutText';
import { SafeNode, SafeSvgNode, SafeTextNode } from '../types';
const isSvg = (node: SafeNode): node is SafeSvgNode => node.type === P.Svg;
const isText = (node: SafeNode): node is SafeTextNode => node.type === P.Text;
const shouldIterate = (node: SafeNode) => !isSvg(node) && !isText(node);
const shouldLayoutText = (node: SafeNode): node is SafeTextNode =>
isText(node) && !node.lines;
/**
* Performs text layout on text node if wasn't calculated before.
* Text layout is usually performed on Yoga's layout process (via setMeasureFunc),
* but we need to layout those nodes with fixed width and height.
*
* @param node
* @returns Layout node
*/
const resolveTextLayout = (node: SafeNode, fontStore: FontStore): SafeNode => {
if (shouldLayoutText(node)) {
const width =
node.box.width - (node.box.paddingRight + node.box.paddingLeft);
const height =
node.box.height - (node.box.paddingTop + node.box.paddingBottom);
node.lines = layoutText(node, width, height, fontStore);
}
if (shouldIterate(node)) {
if (!node.children) return node;
const mapChild = (child: SafeNode) => resolveTextLayout(child, fontStore);
const children = node.children.map(mapChild);
return Object.assign({}, node, { children });
}
return node;
};
export default resolveTextLayout;
================================================
FILE: packages/layout/src/steps/resolveYoga.ts
================================================
import { loadYoga } from '../yoga/index';
import { DocumentNode } from '../types';
const resolveYoga = async (root: DocumentNode): Promise => {
const yoga = await loadYoga();
return Object.assign({}, root, { yoga });
};
export default resolveYoga;
================================================
FILE: packages/layout/src/steps/resolveZIndex.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeDocumentNode, SafeNode } from '../types';
const getZIndex = (node: SafeNode) => node.style.zIndex;
const shouldSort = (node: SafeNode) =>
node.type !== P.Document && node.type !== P.Svg;
const sortZIndex = (a: SafeNode, b: SafeNode) => {
const za = getZIndex(a);
const zb = getZIndex(b);
if (!za && !zb) return 0;
if (!za) return 1;
if (!zb) return -1;
return zb - za;
};
/**
* Sort children by zIndex value
*
* @param node
* @returns Node
*/
const resolveNodeZIndex = (node: T): T => {
if (!node.children) return node;
const sortedChildren = shouldSort(node)
? node.children.sort(sortZIndex)
: node.children;
const children = sortedChildren.map(resolveNodeZIndex);
return Object.assign({}, node, { children });
};
/**
* Sort children by zIndex value
*
* @param node
* @returns Node
*/
const resolveZIndex = (root: SafeDocumentNode) => resolveNodeZIndex(root);
export default resolveZIndex;
================================================
FILE: packages/layout/src/svg/getContainer.ts
================================================
import { parseFloat } from '@react-pdf/fns';
import parseViewBox from './parseViewbox';
import { SafeSvgNode } from '../types';
const getContainer = (node: SafeSvgNode) => {
const viewbox = parseViewBox(node.props.viewBox);
if (viewbox) {
return { width: viewbox.maxX, height: viewbox.maxY };
}
if (node.props.width && node.props.height) {
return {
width: parseFloat(node.props.width),
height: parseFloat(node.props.height),
};
}
return { width: 0, height: 0 };
};
export default getContainer;
================================================
FILE: packages/layout/src/svg/getDefs.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeDefs, SafeDefsNode, SafeNode, SafeSvgNode } from '../types';
const isDefs = (node: SafeNode): node is SafeDefsNode => node.type === P.Defs;
const getDefs = (node: SafeSvgNode) => {
const children = node.children || [];
const defs = children.find(isDefs);
const values = defs?.children || [];
return values.reduce((acc: SafeDefs, value) => {
const id = value.props?.id;
if (id) acc[id] = value;
return acc;
}, {});
};
export default getDefs;
================================================
FILE: packages/layout/src/svg/inheritProps.ts
================================================
import * as P from '@react-pdf/primitives';
import { pick, without } from '@react-pdf/fns';
import { SafeNode } from '../types';
const BASE_SVG_INHERITED_PROPS = [
'x',
'y',
'clipPath',
'clipRule',
'opacity',
'fill',
'fillOpacity',
'fillRule',
'stroke',
'strokeLinecap',
'strokeLinejoin',
'strokeOpacity',
'strokeWidth',
'textAnchor',
'dominantBaseline',
'color',
'fontFamily',
'fontSize',
'fontStyle',
'fontWeight',
'letterSpacing',
'opacity',
'textDecoration',
'lineHeight',
'textAlign',
'visibility',
'wordSpacing',
];
// Do not inherit "x" for elements from parent
const TEXT_SVG_INHERITED_PROPS = without(['x'], BASE_SVG_INHERITED_PROPS);
const SVG_INHERITED_PROPS = {
[P.Text]: TEXT_SVG_INHERITED_PROPS,
};
const getInheritProps = (node) => {
const props = node.props || {};
const svgInheritedProps =
SVG_INHERITED_PROPS[node.type] ?? BASE_SVG_INHERITED_PROPS;
return pick(svgInheritedProps, props);
};
const inheritProps = (node: SafeNode) => {
if (!node.children) return node;
const inheritedProps = getInheritProps(node);
const children = node.children.map((child) => {
const props = Object.assign({}, inheritedProps, child.props || {});
const newChild = Object.assign({}, child, { props });
return inheritProps(newChild);
});
return Object.assign({}, node, { children });
};
export default inheritProps;
================================================
FILE: packages/layout/src/svg/layoutText.ts
================================================
import * as P from '@react-pdf/primitives';
import FontStore from '@react-pdf/font';
import layoutEngine, {
bidi,
linebreaker,
justification,
scriptItemizer,
wordHyphenation,
fontSubstitution,
textDecoration,
fromFragments,
Fragment,
} from '@react-pdf/textkit';
import transformText from '../text/transformText';
import {
SafeNode,
SafeTextNode,
SafeTspanNode,
SafeTextInstanceNode,
} from '../types';
const isTspan = (node: SafeNode): node is SafeTspanNode =>
node.type === P.Tspan;
const isTextInstance = (node: SafeNode): node is SafeTextInstanceNode =>
node.type === P.TextInstance;
const engines = {
bidi,
linebreaker,
justification,
textDecoration,
scriptItemizer,
wordHyphenation,
fontSubstitution,
};
const engine = layoutEngine(engines);
const getFragments = (fontStore: FontStore, instance) => {
if (!instance) return [{ string: '' }];
const fragments: Fragment[] = [];
const {
fill = 'black',
fontFamily = 'Helvetica',
fontWeight,
fontStyle,
fontSize = 18,
textDecorationColor,
textDecorationStyle,
textTransform,
opacity,
} = instance.props;
const _textDecoration = instance.props.textDecoration;
const fontFamilies =
typeof fontFamily === 'string' ? [fontFamily] : [...(fontFamily || [])];
// Fallback font
fontFamilies.push('Helvetica');
const font = fontFamilies.map((fontFamilyName) => {
const opts = { fontFamily: fontFamilyName, fontWeight, fontStyle };
const obj = fontStore.getFont(opts);
return obj?.data;
});
const attributes = {
font,
opacity,
fontSize,
color: fill,
underlineStyle: textDecorationStyle,
underline:
_textDecoration === 'underline' ||
_textDecoration === 'underline line-through' ||
_textDecoration === 'line-through underline',
underlineColor: textDecorationColor || fill,
strike:
_textDecoration === 'line-through' ||
_textDecoration === 'underline line-through' ||
_textDecoration === 'line-through underline',
strikeStyle: textDecorationStyle,
strikeColor: textDecorationColor || fill,
};
for (let i = 0; i < instance.children.length; i += 1) {
const child = instance.children[i];
if (isTextInstance(child)) {
fragments.push({
string: transformText(child.value, textTransform),
attributes,
});
} else if (child) {
fragments.push(...getFragments(fontStore, child));
}
}
return fragments;
};
const getAttributedString = (fontStore: FontStore, instance) =>
fromFragments(getFragments(fontStore, instance));
const AlmostInfinity = 999999999999;
const shrinkWhitespaceFactor = { before: -0.5, after: -0.5 };
const layoutTspan = (fontStore: FontStore) => (node, xOffset) => {
const attributedString = getAttributedString(fontStore, node);
const x = node.props.x === undefined ? xOffset : node.props.x;
const y = node.props?.y || 0;
const container = { x, y, width: AlmostInfinity, height: AlmostInfinity };
const hyphenationCallback =
node.props.hyphenationCallback ||
fontStore?.getHyphenationCallback() ||
null;
const layoutOptions = { hyphenationCallback, shrinkWhitespaceFactor };
const lines = engine(attributedString, container, layoutOptions).flat();
return Object.assign({}, node, { lines });
};
// Consecutive TSpan elements should be joined with a space
const joinTSpanLines = (node: SafeTextNode) => {
const children = node.children.map((child, index) => {
if (!isTspan(child)) return child;
const textInstance = child.children[0];
if (
child.props.x === undefined &&
index < node.children.length - 1 &&
textInstance?.value
) {
return Object.assign({}, child, {
children: [{ ...textInstance, value: `${textInstance.value} ` }],
});
}
return child;
}, []);
return Object.assign({}, node, { children });
};
const layoutText = (fontStore: FontStore, node: SafeTextNode) => {
if (!node.children) return node;
let currentXOffset = node.props?.x || 0;
const layoutFn = layoutTspan(fontStore);
const joinedNode = joinTSpanLines(node);
const children = joinedNode.children.map((child) => {
const childWithLayout = layoutFn(child, currentXOffset);
currentXOffset += childWithLayout.lines[0].xAdvance;
return childWithLayout;
});
return Object.assign({}, node, { children });
};
export default layoutText;
================================================
FILE: packages/layout/src/svg/measureSvg.ts
================================================
import * as Yoga from 'yoga-layout/load';
import { SafePageNode, SafeSvgNode, Viewbox } from '../types';
const getAspectRatio = (viewbox: string | Viewbox) => {
if (!viewbox) return null;
if (typeof viewbox === 'string') return null;
return (viewbox.maxX - viewbox.minX) / (viewbox.maxY - viewbox.minY);
};
/**
* Yoga svg measure function
*
* @param page
* @param node
* @returns Measure svg
*/
const measureCanvas =
(page: SafePageNode, node: SafeSvgNode): Yoga.MeasureFunction =>
(width, widthMode, height, heightMode) => {
const aspectRatio = getAspectRatio(node.props.viewBox) || 1;
if (
widthMode === Yoga.MeasureMode.Exactly ||
widthMode === Yoga.MeasureMode.AtMost
) {
return { width, height: width / aspectRatio };
}
if (heightMode === Yoga.MeasureMode.Exactly) {
return { width: height * aspectRatio };
}
return {};
};
export default measureCanvas;
================================================
FILE: packages/layout/src/svg/parseAspectRatio.ts
================================================
import { PreserveAspectRatio } from '../types';
const parseAspectRatio = (value: string | PreserveAspectRatio) => {
if (typeof value !== 'string') return value;
const match = value
.replace(/[\s\r\t\n]+/gm, ' ')
.replace(/^defer\s/, '')
.split(' ');
const align = (match[0] || 'xMidYMid') as PreserveAspectRatio['align'];
const meetOrSlice = (match[1] ||
'meet') as PreserveAspectRatio['meetOrSlice'];
return { align, meetOrSlice };
};
export default parseAspectRatio;
================================================
FILE: packages/layout/src/svg/parseViewbox.ts
================================================
import { parseFloat } from '@react-pdf/fns';
import { Viewbox } from '../types';
const parseViewbox = (value?: string | Viewbox) => {
if (!value) return null;
if (typeof value !== 'string') return value;
const values = value.split(/[,\s]+/).map(parseFloat);
if (values.length !== 4) return null;
return { minX: values[0], minY: values[1], maxX: values[2], maxY: values[3] };
};
export default parseViewbox;
================================================
FILE: packages/layout/src/svg/replaceDefs.ts
================================================
import * as P from '@react-pdf/primitives';
import getDefs from './getDefs';
import { SafeDefs, SafeNode, SafeSvgNode } from '../types';
const isNotDefs = (node: SafeNode) => node.type !== P.Defs;
const detachDefs = (node: SafeSvgNode) => {
if (!node.children) return node;
const children = node.children.filter(isNotDefs);
return Object.assign({}, node, { children });
};
const URL_REGEX = /url\(['"]?#([^'"]+)['"]?\)/;
const replaceDef = (defs: SafeDefs, value: string) => {
if (!value) return undefined;
if (!URL_REGEX.test(value)) return value;
const match = value.match(URL_REGEX);
return defs[match[1]];
};
const parseNodeDefs =
(defs: SafeDefs) =>
(node: SafeNode): SafeNode => {
const props = node.props;
const fill =
`fill` in props ? replaceDef(defs, props?.fill as any) : undefined;
const clipPath =
`clipPath` in props
? replaceDef(defs, props?.clipPath as any)
: undefined;
const newProps = Object.assign({}, node.props, { fill, clipPath });
const children = node.children
? node.children.map(parseNodeDefs(defs))
: undefined;
return Object.assign({}, node, { props: newProps, children });
};
const parseDefs = (root: SafeSvgNode) => {
if (!root.children) return root;
const defs = getDefs(root);
const children = root.children.map(parseNodeDefs(defs));
return Object.assign({}, root, { children });
};
const replaceDefs = (node: SafeSvgNode) => {
return detachDefs(parseDefs(node));
};
export default replaceDefs;
================================================
FILE: packages/layout/src/text/emoji.ts
================================================
/* eslint-disable no-console */
import emojiRegex from 'emoji-regex-xs';
import resolveImage from '@react-pdf/image';
import { Fragment } from '@react-pdf/textkit';
import { EmojiSource } from '../../../types';
// Caches emoji images data
const emojis = {};
const regex = emojiRegex();
/**
* When an emoji as no variations, it might still have 2 parts,
* the canonical emoji and an empty string.
* ex.
* (no color) Array.from('❤️') => ["❤", "️"]
* (w/ color) Array.from('👍🏿') => ["👍", "🏿"]
*
* The empty string needs to be removed otherwise the generated
* url will be incorect.
*/
const removeVariationSelectors = (x: string) => x !== '️';
const getCodePoints = (
string: string,
withVariationSelectors: boolean = false,
) =>
Array.from(string)
.filter(withVariationSelectors ? () => true : removeVariationSelectors)
.map((char) => char.codePointAt(0).toString(16))
.join('-');
const buildEmojiUrl = (emoji: string, source: EmojiSource) => {
if ('builder' in source) {
return source.builder(getCodePoints(emoji, source.withVariationSelectors));
}
const { url, format = 'png', withVariationSelectors } = source;
return `${url}${getCodePoints(emoji, withVariationSelectors)}.${format}`;
};
export const fetchEmojis = (string: string, source?: EmojiSource) => {
if (!source) return [];
const promises = [];
Array.from(string.matchAll(regex)).forEach((match) => {
const emoji = match[0];
if (!emojis[emoji] || emojis[emoji].loading) {
const emojiUrl = buildEmojiUrl(emoji, source);
emojis[emoji] = { loading: true };
promises.push(
resolveImage({ uri: emojiUrl })
.then((image) => {
emojis[emoji].loading = false;
emojis[emoji].data = image.data;
})
.catch((e) => {
console.warn(e, 'Failed to load emoji image');
emojis[emoji].loading = false;
}),
);
}
});
return promises;
};
export const embedEmojis = (fragments: Fragment[]) => {
const result: Fragment[] = [];
for (let i = 0; i < fragments.length; i += 1) {
const fragment = fragments[i];
let lastIndex = 0;
Array.from(fragment.string.matchAll(regex)).forEach((match) => {
const { index } = match;
const emoji = match[0];
const emojiSize = fragment.attributes.fontSize;
const chunk = fragment.string.slice(lastIndex, index + match[0].length);
// If emoji image was found, we create a new fragment with the
// correct attachment and object substitution character;
if (emojis[emoji] && emojis[emoji].data) {
result.push({
string: chunk.replace(match[0], String.fromCharCode(0xfffc)),
attributes: {
...fragment.attributes,
attachment: {
width: emojiSize,
height: emojiSize,
yOffset: Math.floor(emojiSize * 0.1),
image: emojis[emoji].data,
},
},
});
} else {
// If no emoji data, we try to use emojis in the font
result.push({
string: chunk,
attributes: fragment.attributes,
});
}
lastIndex = index + emoji.length;
});
if (lastIndex < fragment.string.length) {
result.push({
string: fragment.string.slice(lastIndex),
attributes: fragment.attributes,
});
}
}
return result;
};
export default fetchEmojis;
================================================
FILE: packages/layout/src/text/getAttributedString.ts
================================================
import * as P from '@react-pdf/primitives';
import { Fragment, fromFragments } from '@react-pdf/textkit';
import FontStore from '@react-pdf/font';
import { embedEmojis } from './emoji';
import ignoreChars from './ignoreChars';
import transformText from './transformText';
import {
SafeNode,
SafeTextNode,
SafeImageNode,
SafeTextInstanceNode,
SafeTspanNode,
} from '../types';
const PREPROCESSORS = [ignoreChars, embedEmojis];
const isImage = (node: SafeNode): node is SafeImageNode =>
node.type === P.Image;
const isTextInstance = (node: SafeNode): node is SafeTextInstanceNode =>
node.type === P.TextInstance;
/**
* Get textkit fragments of given node object
*
* @param fontStore - Font store
* @param instance - Node
* @param parentLink - Parent link
* @param level - Fragment level
* @returns Text fragments
*/
const getFragments = (
fontStore: FontStore,
instance: SafeTextNode | SafeTspanNode,
parentLink = null,
level = 0,
) => {
if (!instance) return [{ string: '' }];
let fragments: Fragment[] = [];
const {
color = 'black',
direction = 'ltr',
fontFamily = 'Helvetica',
fontWeight,
fontStyle,
fontSize = 18,
textAlign,
lineHeight,
textDecoration,
textDecorationColor,
textDecorationStyle,
textTransform,
letterSpacing,
textIndent,
opacity,
verticalAlign,
} = instance.style;
const fontFamilies =
typeof fontFamily === 'string' ? [fontFamily] : [...(fontFamily || [])];
// Fallback font
fontFamilies.push('Helvetica');
const font = fontFamilies.map((fontFamilyName) => {
const opts = { fontFamily: fontFamilyName, fontWeight, fontStyle };
const obj = fontStore.getFont(opts);
return obj?.data;
});
// Don't pass main background color to textkit. Will be rendered by the render package instead
const backgroundColor = level === 0 ? null : instance.style.backgroundColor;
const attributes = {
font,
color,
opacity,
fontSize,
lineHeight,
direction,
verticalAlign,
backgroundColor,
indent: textIndent,
characterSpacing: letterSpacing,
strikeStyle: textDecorationStyle,
underlineStyle: textDecorationStyle,
underline:
textDecoration === 'underline' ||
textDecoration === 'underline line-through' ||
textDecoration === 'line-through underline',
strike:
textDecoration === 'line-through' ||
textDecoration === 'underline line-through' ||
textDecoration === 'line-through underline',
strikeColor: textDecorationColor || color,
underlineColor: textDecorationColor || color,
// @ts-expect-error allow this props access
link: parentLink || instance.props?.src || instance.props?.href,
align: textAlign || (direction === 'rtl' ? 'right' : 'left'),
};
for (let i = 0; i < instance.children.length; i += 1) {
const child = instance.children[i];
if (isImage(child)) {
fragments.push({
string: String.fromCharCode(0xfffc),
attributes: {
...attributes,
attachment: {
width: (child.style.width || fontSize) as number,
height: (child.style.height || fontSize) as number,
image: child.image.data,
},
},
});
} else if (isTextInstance(child)) {
fragments.push({
string: transformText(child.value, textTransform),
attributes,
});
} else if (child) {
fragments.push(
...getFragments(fontStore, child, attributes.link, level + 1),
);
}
}
for (let i = 0; i < PREPROCESSORS.length; i += 1) {
const preprocessor = PREPROCESSORS[i];
fragments = preprocessor(fragments);
}
return fragments;
};
/**
* Get textkit attributed string from text node
*
* @param fontStore - Font store
* @param instance Node
* @returns Attributed string
*/
const getAttributedString = (fontStore: FontStore, instance: SafeTextNode) => {
const fragments = getFragments(fontStore, instance);
return fromFragments(fragments);
};
export default getAttributedString;
================================================
FILE: packages/layout/src/text/heightAtLineIndex.ts
================================================
import { SafeTextNode } from '../types';
/**
* Get height for given text line index
*
* @param node
* @param index
*/
const heightAtLineIndex = (node: SafeTextNode, index: number) => {
let counter = 0;
if (!node.lines) return counter;
for (let i = 0; i < index; i += 1) {
const line = node.lines[i];
if (!line) break;
counter += line.box.height;
}
return counter;
};
export default heightAtLineIndex;
================================================
FILE: packages/layout/src/text/ignoreChars.ts
================================================
import { Font, Fragment } from '@react-pdf/textkit';
const IGNORABLE_CODEPOINTS = [
8232, // LINE_SEPARATOR
8233, // PARAGRAPH_SEPARATOR
];
const buildSubsetForFont = (font: Font) =>
IGNORABLE_CODEPOINTS.reduce((acc, codePoint) => {
if (
font &&
font.hasGlyphForCodePoint &&
font.hasGlyphForCodePoint(codePoint)
) {
return acc;
}
return [...acc, String.fromCharCode(codePoint)];
}, []);
const ignoreChars = (fragments: Fragment[]): Fragment[] =>
fragments.map((fragment) => {
const charSubset = buildSubsetForFont(fragment.attributes.font[0]);
const subsetRegex = new RegExp(charSubset.join('|'));
return {
string: fragment.string.replace(subsetRegex, ''),
attributes: fragment.attributes,
};
});
export default ignoreChars;
================================================
FILE: packages/layout/src/text/layoutText.ts
================================================
import layoutEngine, {
bidi,
linebreaker,
justification,
scriptItemizer,
wordHyphenation,
textDecoration,
fontSubstitution,
} from '@react-pdf/textkit';
import FontStore from '@react-pdf/font';
import getAttributedString from './getAttributedString';
import { SafeTextNode } from '../types';
const engines = {
bidi,
linebreaker,
justification,
textDecoration,
scriptItemizer,
wordHyphenation,
fontSubstitution,
};
const engine = layoutEngine(engines);
const getMaxLines = (node) => node.style?.maxLines;
const getTextOverflow = (node) => node.style?.textOverflow;
/**
* Get layout container for specific text node
*
* @param {number} width
* @param {number} height
* @param {Object} node
* @returns {Object} layout container
*/
const getContainer = (width, height, node) => {
const maxLines = getMaxLines(node);
const textOverflow = getTextOverflow(node);
return {
x: 0,
y: 0,
width,
maxLines,
height: height || Infinity,
truncateMode: textOverflow,
};
};
/**
* Get text layout options for specific text node
*
* @param {Object} node instance
* @returns {Object} layout options
*/
const getLayoutOptions = (fontStore, node) => ({
hyphenationPenalty: node.props.hyphenationPenalty,
shrinkWhitespaceFactor: { before: -0.5, after: -0.5 },
hyphenationCallback:
node.props.hyphenationCallback ||
fontStore?.getHyphenationCallback() ||
null,
});
/**
* Get text lines for given node
*
* @param node - Node
* @param width - Container width
* @param height - Container height
* @param fontStore - Font store
* @returns Layout lines
*/
const layoutText = (
node: SafeTextNode,
width: number,
height: number,
fontStore: FontStore,
) => {
const attributedString = getAttributedString(fontStore, node);
const container = getContainer(width, height, node);
const options = getLayoutOptions(fontStore, node);
const lines = engine(attributedString, container, options);
return lines.reduce((acc, line) => [...acc, ...line], []);
};
export default layoutText;
================================================
FILE: packages/layout/src/text/lineIndexAtHeight.ts
================================================
import { SafeTextNode } from '../types';
/**
* Get line index at given height
*
* @param node
* @param height
*/
const lineIndexAtHeight = (node: SafeTextNode, height: number) => {
let y = 0;
if (!node.lines) return 0;
for (let i = 0; i < node.lines.length; i += 1) {
const line = node.lines[i];
if (y + line.box.height > height) return i;
y += line.box.height;
}
return node.lines.length;
};
export default lineIndexAtHeight;
================================================
FILE: packages/layout/src/text/linesHeight.ts
================================================
import { SafeTextNode } from '../types';
/**
* Get lines height (if any)
*
* @param node
* @returns Lines height
*/
const linesHeight = (node: SafeTextNode) => {
if (!node.lines) return -1;
return node.lines.reduce((acc, line) => acc + line.box.height, 0);
};
export default linesHeight;
================================================
FILE: packages/layout/src/text/linesWidth.ts
================================================
import { SafeTextNode } from '../types';
/**
* Get lines width (if any)
*
* @param node
* @returns Lines width
*/
const linesWidth = (node: SafeTextNode) => {
if (!node.lines) return 0;
return Math.max(0, ...node.lines.map((line) => line.xAdvance));
};
export default linesWidth;
================================================
FILE: packages/layout/src/text/measureText.ts
================================================
import * as Yoga from 'yoga-layout/load';
import FontStore from '@react-pdf/font';
import layoutText from './layoutText';
import linesWidth from './linesWidth';
import linesHeight from './linesHeight';
import { SafePageNode, SafeTextNode } from '../types';
const ALIGNMENT_FACTORS = { center: 0.5, right: 1 };
/**
* Yoga text measure function
*
* @param page
* @param node
* @param fontStore
* @returns {MeasureText} measure text function
*/
const measureText =
(
page: SafePageNode,
node: SafeTextNode,
fontStore: FontStore,
): Yoga.MeasureFunction =>
(width, widthMode, height) => {
if (widthMode === Yoga.MeasureMode.Exactly) {
if (!node.lines) node.lines = layoutText(node, width, height, fontStore);
return { height: linesHeight(node), width };
}
if (widthMode === Yoga.MeasureMode.AtMost) {
const alignFactor = ALIGNMENT_FACTORS[node.style?.textAlign] || 0;
if (!node.lines) {
node.lines = layoutText(node, width, height, fontStore);
node.alignOffset = (width - linesWidth(node)) * alignFactor; // Compensate align in variable width containers
}
return {
height: linesHeight(node),
width: Math.min(width, linesWidth(node)),
};
}
return {};
};
export default measureText;
================================================
FILE: packages/layout/src/text/splitText.ts
================================================
import lineIndexAtHeight from './lineIndexAtHeight';
import heightAtLineIndex from './heightAtLineIndex';
import { SafeTextNode } from '../types';
const getLineBreak = (node: SafeTextNode, height: number) => {
const top = node.box?.top || 0;
const widows = node.props.widows || 2;
const orphans = node.props.orphans || 2;
const linesQuantity = node.lines.length;
const slicedLine = lineIndexAtHeight(node, height - top);
if (slicedLine === 0) {
return 0;
}
if (linesQuantity < orphans) {
return linesQuantity;
}
if (slicedLine < orphans || linesQuantity < orphans + widows) {
return 0;
}
if (linesQuantity === orphans + widows) {
return orphans;
}
if (linesQuantity - slicedLine < widows) {
return linesQuantity - widows;
}
return slicedLine;
};
// Also receives contentArea in case it's needed
const splitText = (node: SafeTextNode, height: number) => {
const slicedLineIndex = getLineBreak(node, height);
const currentHeight = heightAtLineIndex(node, slicedLineIndex);
const nextHeight = node.box.height - currentHeight;
const current: SafeTextNode = Object.assign({}, node, {
box: {
...node.box,
height: currentHeight,
borderBottomWidth: 0,
},
style: {
...node.style,
marginBottom: 0,
paddingBottom: 0,
borderBottomWidth: 0,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0,
},
lines: node.lines.slice(0, slicedLineIndex),
});
const next: SafeTextNode = Object.assign({}, node, {
box: {
...node.box,
top: 0,
height: nextHeight,
borderTopWidth: 0,
},
style: {
...node.style,
marginTop: 0,
paddingTop: 0,
borderTopWidth: 0,
borderTopLeftRadius: 0,
borderTopRightRadius: 0,
},
lines: node.lines.slice(slicedLineIndex),
});
return [current, next];
};
export default splitText;
================================================
FILE: packages/layout/src/text/transformText.ts
================================================
import { capitalize, upperFirst } from '@react-pdf/fns';
import { SafeStyle } from '@react-pdf/stylesheet';
/**
* Apply transformation to text string
*
* @param {string} text
* @param {string} transformation type
* @returns {string} transformed text
*/
const transformText = (
text: string,
transformation: SafeStyle['textTransform'],
) => {
switch (transformation) {
case 'uppercase':
return text.toUpperCase();
case 'lowercase':
return text.toLowerCase();
case 'capitalize':
return capitalize(text);
case 'upperfirst':
return upperFirst(text);
default:
return text;
}
};
export default transformText;
================================================
FILE: packages/layout/src/types/base.ts
================================================
import { Transform } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import * as React from 'react';
import { SafeClipPathNode } from './clip-path';
import { SafeLinearGradientNode } from './linear-gradient';
import { SafeRadialGradientNode } from './radial-gradient';
export type YogaInstance = {
node: { create: () => YogaNode };
};
export type Box = {
width: number;
height: number;
top: number;
left: number;
right: number;
bottom: number;
// TODO: should be optional?
marginTop?: number;
marginRight?: number;
marginBottom?: number;
marginLeft?: number;
paddingTop?: number;
paddingRight?: number;
paddingBottom?: number;
paddingLeft?: number;
borderTopWidth?: number;
borderRightWidth?: number;
borderBottomWidth?: number;
borderLeftWidth?: number;
};
export type Origin = {
left: number;
top: number;
};
export interface Bookmark {
title: string;
top?: number;
left?: number;
zoom?: number;
fit?: true | false;
expanded?: true | false;
parent?: number;
ref?: number;
}
export type DynamicPageProps = {
pageNumber: number;
totalPages?: number;
subPageNumber?: number;
subPageTotalPages?: number;
};
export type RenderProp = (
props: DynamicPageProps,
) => React.ReactNode | null | undefined;
export type NodeProps = {
id?: string;
/**
* Render component in all wrapped pages.
* @see https://react-pdf.org/advanced#fixed-components
*/
fixed?: boolean;
/**
* Force the wrapping algorithm to start a new page when rendering the
* element.
* @see https://react-pdf.org/advanced#page-breaks
*/
break?: boolean;
/**
* Hint that no page wrapping should occur between all sibling elements following the element within n points
* @see https://react-pdf.org/advanced#orphan-&-widow-protection
*/
minPresenceAhead?: number;
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
bookmark?: Bookmark;
};
export type FillRule = 'nonzero' | 'evenodd';
export type TextAnchor = 'start' | 'middle' | 'end';
export type StrokeLinecap = 'butt' | 'round' | 'square';
export type StrokeLinejoin = 'butt' | 'round' | 'square' | 'miter' | 'bevel';
export type Visibility = 'visible' | 'hidden' | 'collapse';
export type DominantBaseline =
| 'auto'
| 'middle'
| 'central'
| 'hanging'
| 'mathematical'
| 'text-after-edge'
| 'text-before-edge';
export type SVGPresentationAttributes = {
fill?: string;
color?: string;
stroke?: string;
transform?: string;
strokeDasharray?: string;
opacity?: string | number;
strokeWidth?: string | number;
fillOpacity?: string | number;
fillRule?: FillRule;
strokeOpacity?: string | number;
textAnchor?: TextAnchor;
strokeLinecap?: StrokeLinecap;
strokeLinejoin?: StrokeLinejoin;
visibility?: Visibility;
clipPath?: string;
dominantBaseline?: DominantBaseline;
};
export type SafeSVGPresentationAttributes = {
fill?: string | SafeLinearGradientNode | SafeRadialGradientNode;
color?: string;
stroke?: string;
transform?: Transform[];
strokeDasharray?: string;
opacity?: number;
strokeWidth?: number;
fillOpacity?: number;
fillRule?: FillRule;
strokeOpacity?: number;
textAnchor?: TextAnchor;
strokeLinecap?: StrokeLinecap;
strokeLinejoin?: StrokeLinejoin;
visibility?: Visibility;
clipPath?: SafeClipPathNode;
dominantBaseline?: DominantBaseline;
};
export interface FormCommonProps extends NodeProps {
name?: string;
required?: boolean;
noExport?: boolean;
readOnly?: boolean;
value?: number | string;
defaultValue?: number | string;
}
================================================
FILE: packages/layout/src/types/canvas.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import { Box, NodeProps, Origin } from './base';
interface CanvasProps extends NodeProps {
paint: (
painter: any,
availableWidth?: number,
availableHeight?: number,
) => null;
}
export type CanvasNode = {
type: typeof P.Canvas;
props: CanvasProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: never[];
};
export type SafeCanvasNode = Omit & {
style: SafeStyle;
};
================================================
FILE: packages/layout/src/types/checkbox.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import { Box, FormCommonProps, Origin } from './base';
interface CheckboxProps extends FormCommonProps {
backgroundColor?: string;
borderColor?: string;
checked?: boolean;
onState?: string;
offState?: string;
xMark?: boolean;
}
export type CheckboxNode = {
type: typeof P.Checkbox;
props: CheckboxProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: never[];
};
export type SafeCheckboxNode = Omit & {
style: SafeStyle;
};
================================================
FILE: packages/layout/src/types/circle.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
Origin,
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
interface CircleProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
cx?: string | number;
cy?: string | number;
r: string | number;
}
interface SafeCircleProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
cx?: number;
cy?: number;
r: number;
}
export type CircleNode = {
type: typeof P.Circle;
props: CircleProps;
style?: Style | Style[];
box?: never;
origin?: Origin;
yogaNode?: never;
children?: never[];
};
export type SafeCircleNode = Omit & {
style: SafeStyle;
props: SafeCircleProps;
};
================================================
FILE: packages/layout/src/types/clip-path.ts
================================================
import * as P from '@react-pdf/primitives';
import { LineNode, SafeLineNode } from './line';
import { PolylineNode, SafePolylineNode } from './polyline';
import { PolygonNode, SafePolygonNode } from './polygon';
import { PathNode, SafePathNode } from './path';
import { RectNode, SafeRectNode } from './rect';
import { CircleNode, SafeCircleNode } from './circle';
import { EllipseNode, SafeEllipseNode } from './ellipse';
interface ClipPathProps {
id?: string;
}
export type ClipPathNode = {
type: typeof P.ClipPath;
props: ClipPathProps;
style: never;
box?: never;
origin?: never;
yogaNode?: never;
children?: (
| LineNode
| PolylineNode
| PolygonNode
| PathNode
| RectNode
| CircleNode
| EllipseNode
)[];
};
export type SafeClipPathNode = Omit & {
children?: (
| SafeLineNode
| SafePolylineNode
| SafePolygonNode
| SafePathNode
| SafeRectNode
| SafeCircleNode
| SafeEllipseNode
)[];
};
================================================
FILE: packages/layout/src/types/defs.ts
================================================
import * as P from '@react-pdf/primitives';
import { ClipPathNode, SafeClipPathNode } from './clip-path';
import { LinearGradientNode, SafeLinearGradientNode } from './linear-gradient';
import { RadialGradientNode, SafeRadialGradientNode } from './radial-gradient';
export type DefsNode = {
type: typeof P.Defs;
props?: never;
style?: never;
box?: never;
origin?: never;
yogaNode?: never;
children?: (ClipPathNode | LinearGradientNode | RadialGradientNode)[];
};
export type Defs = Record;
export type SafeDefsNode = Omit & {
children?: (
| SafeClipPathNode
| SafeLinearGradientNode
| SafeRadialGradientNode
)[];
};
export type SafeDefs = Record;
================================================
FILE: packages/layout/src/types/document.ts
================================================
import * as P from '@react-pdf/primitives';
import { PageNode, SafePageNode } from './page';
import { YogaInstance } from './base';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
export type PDFVersion = '1.3' | '1.4' | '1.5' | '1.6' | '1.7' | '1.7ext3';
export type PageLayout =
| 'singlePage'
| 'oneColumn'
| 'twoColumnLeft'
| 'twoColumnRight'
| 'twoPageLeft'
| 'twoPageRight';
export type PageMode =
| 'useNone'
| 'useOutlines'
| 'useThumbs'
| 'fullScreen'
| 'useOC'
| 'useAttachments';
export interface OnRenderProps {
blob?: Blob;
}
export type DocumentProps = {
bookmark?: never;
title?: string;
author?: string;
subject?: string;
creator?: string;
keywords?: string;
producer?: string;
language?: string;
creationDate?: Date;
modificationDate?: Date;
pdfVersion?: PDFVersion;
pageMode?: PageMode;
pageLayout?: PageLayout;
onRender?: (props: OnRenderProps) => any;
};
export type DocumentNode = {
type: typeof P.Document;
props: DocumentProps;
box?: never;
origin?: never;
style?: Style | Style[];
yoga?: YogaInstance;
yogaNode?: never;
children: PageNode[];
};
export type SafeDocumentNode = Omit & {
style: SafeStyle;
children: SafePageNode[];
};
================================================
FILE: packages/layout/src/types/ellipse.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
SafeSVGPresentationAttributes,
SVGPresentationAttributes,
} from './base';
interface EllipseProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
cx?: string | number;
cy?: string | number;
rx: string | number;
ry: string | number;
}
interface SafeEllipseProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
cx?: number;
cy?: number;
rx: number;
ry: number;
}
export type EllipseNode = {
type: typeof P.Ellipse;
props: EllipseProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafeEllipseNode = Omit & {
style: SafeStyle;
props: SafeEllipseProps;
};
================================================
FILE: packages/layout/src/types/field-set.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import { Box, NodeProps, Origin } from './base';
import { SafeTextNode, TextNode } from './text';
import { SafeViewNode, ViewNode } from './view';
import { SafeTextInputNode, TextInputNode } from './text-input';
interface FieldSetProps extends NodeProps {
name: string;
}
export type FieldSetNode = {
type: typeof P.FieldSet;
props: FieldSetProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: (TextNode | ViewNode | TextInputNode)[];
};
export type SafeFieldSetNode = Omit & {
style: SafeStyle;
children?: (SafeTextNode | SafeViewNode | SafeTextInputNode)[];
};
================================================
FILE: packages/layout/src/types/g.ts
================================================
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import * as P from '@react-pdf/primitives';
import { LineNode, SafeLineNode } from './line';
import { PolylineNode, SafePolylineNode } from './polyline';
import { PolygonNode, SafePolygonNode } from './polygon';
import { PathNode, SafePathNode } from './path';
import { RectNode, SafeRectNode } from './rect';
import { CircleNode, SafeCircleNode } from './circle';
import { EllipseNode, SafeEllipseNode } from './ellipse';
import { SafeTspanNode, TspanNode } from './tspan';
import { ImageNode, SafeImageNode } from './image';
import { SafeTextNode, TextNode } from './text';
import {
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
interface GProps extends SVGPresentationAttributes {
style?: Style | Style[];
}
interface SafeGProps extends SafeSVGPresentationAttributes {
style?: Style;
}
export type GNode = {
type: typeof P.G;
props: GProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: (
| LineNode
| PolylineNode
| PolygonNode
| PathNode
| RectNode
| CircleNode
| EllipseNode
| ImageNode
| TextNode
| TspanNode
| GNode
)[];
};
export type SafeGNode = Omit & {
style: SafeStyle;
props: SafeGProps;
children?: (
| SafeLineNode
| SafePolylineNode
| SafePolygonNode
| SafePathNode
| SafeRectNode
| SafeCircleNode
| SafeEllipseNode
| SafeImageNode
| SafeTextNode
| SafeTspanNode
| SafeGNode
)[];
};
================================================
FILE: packages/layout/src/types/image.ts
================================================
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import * as P from '@react-pdf/primitives';
import { YogaNode } from 'yoga-layout/load';
import { Box, NodeProps, Origin } from './base';
import { Image } from '@react-pdf/image';
type HTTPMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
type SourceURL = string;
type SourceBuffer = Buffer;
type SourceBlob = Blob;
type SourceDataBuffer = { data: Buffer; format: 'png' | 'jpg' };
type SourceURLObject = {
uri: string;
method?: HTTPMethod;
body?: any;
headers?: any;
credentials?: 'omit' | 'same-origin' | 'include';
};
type Source =
| SourceURL
| SourceBuffer
| SourceBlob
| SourceDataBuffer
| SourceURLObject
| undefined;
type SourceFactory = () => Source;
type SourceAsync = Promise;
type SourceAsyncFactory = () => Promise;
export type SourceObject =
| Source
| SourceFactory
| SourceAsync
| SourceAsyncFactory;
interface BaseImageProps extends NodeProps {
cache?: boolean;
x?: number;
y?: number;
}
interface ImageWithSrcProp extends BaseImageProps {
src: SourceObject;
source?: never;
}
interface ImageWithSourceProp extends BaseImageProps {
source: SourceObject;
src?: never;
}
export type ImageProps = ImageWithSrcProp | ImageWithSourceProp;
export type ImageNode = {
type: typeof P.Image;
props: ImageProps;
image?: Image;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: never[];
};
export type SafeImageNode = Omit & {
style: SafeStyle;
};
================================================
FILE: packages/layout/src/types/index.ts
================================================
export * from './base';
export * from './canvas';
export * from './circle';
export * from './checkbox';
export * from './clip-path';
export * from './defs';
export * from './document';
export * from './ellipse';
export * from './field-set';
export * from './g';
export * from './image';
export * from './line';
export * from './linear-gradient';
export * from './link';
export * from './node';
export * from './note';
export * from './page';
export * from './path';
export * from './polygon';
export * from './polyline';
export * from './radial-gradient';
export * from './rect';
export * from './select';
export * from './stop';
export * from './svg';
export * from './text-instance';
export * from './text-input';
export * from './text';
export * from './tspan';
export * from './view';
================================================
FILE: packages/layout/src/types/line.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
interface LineProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
x1: string | number;
x2: string | number;
y1: string | number;
y2: string | number;
}
interface SafeLineProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
x1: number;
x2: number;
y1: number;
y2: number;
}
export type LineNode = {
type: typeof P.Line;
props: LineProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafeLineNode = Omit & {
style: SafeStyle;
props: SafeLineProps;
};
================================================
FILE: packages/layout/src/types/linear-gradient.ts
================================================
import * as P from '@react-pdf/primitives';
import { Transform } from '@react-pdf/stylesheet';
import { SafeStopNode, StopNode } from './stop';
interface LinearGradientProps {
id: string;
x1?: string | number;
x2?: string | number;
y1?: string | number;
y2?: string | number;
xlinkHref?: string;
gradientTransform?: string;
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
}
interface SafeLinearGradientProps {
id: string;
x1?: number;
x2?: number;
y1?: number;
y2?: number;
xlinkHref?: string;
gradientTransform?: Transform[];
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
}
export type LinearGradientNode = {
type: typeof P.LinearGradient;
props: LinearGradientProps;
style?: never;
box?: never;
origin?: never;
yogaNode?: never;
children?: StopNode[];
};
export type SafeLinearGradientNode = Omit<
LinearGradientNode,
'props' | 'children'
> & {
props: SafeLinearGradientProps;
children?: SafeStopNode[];
};
================================================
FILE: packages/layout/src/types/link.ts
================================================
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import * as P from '@react-pdf/primitives';
import { YogaNode } from 'yoga-layout/load';
import { Box, NodeProps, Origin, RenderProp } from './base';
import { ImageNode, SafeImageNode } from './image';
import { SafeTextNode, TextNode } from './text';
import { SafeTextInstanceNode, TextInstanceNode } from './text-instance';
import { SafeViewNode, ViewNode } from './view';
interface LinkProps extends NodeProps {
/**
* Enable/disable page wrapping for element.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
href?: string;
src?: string;
render?: RenderProp;
}
export type LinkNode = {
type: typeof P.Link;
props: LinkProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: (ViewNode | ImageNode | TextNode | TextInstanceNode)[];
};
export type SafeLinkNode = Omit & {
style: SafeStyle;
children?: (
| SafeViewNode
| SafeImageNode
| SafeTextNode
| SafeTextInstanceNode
)[];
};
================================================
FILE: packages/layout/src/types/node.ts
================================================
import { CanvasNode, SafeCanvasNode } from './canvas';
import { CheckboxNode, SafeCheckboxNode } from './checkbox';
import { CircleNode, SafeCircleNode } from './circle';
import { ClipPathNode, SafeClipPathNode } from './clip-path';
import { DefsNode, SafeDefsNode } from './defs';
import { DocumentNode, SafeDocumentNode } from './document';
import { EllipseNode, SafeEllipseNode } from './ellipse';
import { FieldSetNode, SafeFieldSetNode } from './field-set';
import { GNode, SafeGNode } from './g';
import { ImageNode, SafeImageNode } from './image';
import { LineNode, SafeLineNode } from './line';
import { LinearGradientNode, SafeLinearGradientNode } from './linear-gradient';
import { LinkNode, SafeLinkNode } from './link';
import { NoteNode, SafeNoteNode } from './note';
import { PageNode, SafePageNode } from './page';
import { PathNode, SafePathNode } from './path';
import { PolygonNode, SafePolygonNode } from './polygon';
import { PolylineNode, SafePolylineNode } from './polyline';
import { RadialGradientNode, SafeRadialGradientNode } from './radial-gradient';
import { RectNode, SafeRectNode } from './rect';
import { ListNode, SafeListNode, SafeSelectNode, SelectNode } from './select';
import { SafeStopNode, StopNode } from './stop';
import { SafeSvgNode, SvgNode } from './svg';
import { SafeTextNode, TextNode } from './text';
import { SafeTextInputNode, TextInputNode } from './text-input';
import { SafeTextInstanceNode, TextInstanceNode } from './text-instance';
import { SafeTspanNode, TspanNode } from './tspan';
import { SafeViewNode, ViewNode } from './view';
export type Node =
| DocumentNode
| PageNode
| ImageNode
| SvgNode
| CircleNode
| ClipPathNode
| DefsNode
| EllipseNode
| GNode
| LineNode
| LinearGradientNode
| PathNode
| PolygonNode
| PolylineNode
| RadialGradientNode
| RectNode
| StopNode
| TspanNode
| ViewNode
| LinkNode
| TextNode
| TextInstanceNode
| NoteNode
| CanvasNode
| FieldSetNode
| TextInputNode
| SelectNode
| ListNode
| CheckboxNode;
export type SafeNode =
| SafeDocumentNode
| SafePageNode
| SafeImageNode
| SafeSvgNode
| SafeCircleNode
| SafeClipPathNode
| SafeDefsNode
| SafeEllipseNode
| SafeGNode
| SafeLineNode
| SafeLinearGradientNode
| SafePathNode
| SafePolygonNode
| SafePolylineNode
| SafeRadialGradientNode
| SafeRectNode
| SafeStopNode
| SafeTspanNode
| SafeViewNode
| SafeLinkNode
| SafeTextNode
| SafeTextInstanceNode
| SafeNoteNode
| SafeCanvasNode
| SafeFieldSetNode
| SafeTextInputNode
| SafeSelectNode
| SafeListNode
| SafeCheckboxNode;
================================================
FILE: packages/layout/src/types/note.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { NodeProps } from './base';
import { SafeTextInstanceNode, TextInstanceNode } from './text-instance';
export type NoteNode = {
type: typeof P.Note;
props: NodeProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: TextInstanceNode[];
};
export type SafeNoteNode = Omit & {
style: SafeStyle;
children?: SafeTextInstanceNode[];
};
================================================
FILE: packages/layout/src/types/page.ts
================================================
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import * as P from '@react-pdf/primitives';
import { YogaNode } from 'yoga-layout/load';
import type { Box, NodeProps, Origin } from './base';
import { ImageNode, SafeImageNode } from './image';
import { SafeViewNode, ViewNode } from './view';
import { SafeTextNode, TextNode } from './text';
import { LinkNode, SafeLinkNode } from './link';
import { CanvasNode, SafeCanvasNode } from './canvas';
import { FieldSetNode, SafeFieldSetNode } from './field-set';
import { SafeTextInputNode, TextInputNode } from './text-input';
import { ListNode, SafeListNode, SafeSelectNode, SelectNode } from './select';
import { CheckboxNode, SafeCheckboxNode } from './checkbox';
import { NoteNode, SafeNoteNode } from './note';
export type Orientation = 'portrait' | 'landscape';
export type StandardPageSize =
| '4A0'
| '2A0'
| 'A0'
| 'A1'
| 'A2'
| 'A3'
| 'A4'
| 'A5'
| 'A6'
| 'A7'
| 'A8'
| 'A9'
| 'A10'
| 'B0'
| 'B1'
| 'B2'
| 'B3'
| 'B4'
| 'B5'
| 'B6'
| 'B7'
| 'B8'
| 'B9'
| 'B10'
| 'C0'
| 'C1'
| 'C2'
| 'C3'
| 'C4'
| 'C5'
| 'C6'
| 'C7'
| 'C8'
| 'C9'
| 'C10'
| 'RA0'
| 'RA1'
| 'RA2'
| 'RA3'
| 'RA4'
| 'SRA0'
| 'SRA1'
| 'SRA2'
| 'SRA3'
| 'SRA4'
| 'EXECUTIVE'
| 'FOLIO'
| 'LEGAL'
| 'LETTER'
| 'TABLOID'
| 'ID1';
type StaticSize = number | string;
export type PageSize =
| number
| StandardPageSize
| [StaticSize]
| [StaticSize, StaticSize]
| { width: StaticSize; height?: StaticSize };
interface PageProps extends NodeProps {
/**
* Enable page wrapping for this page.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
size?: PageSize;
orientation?: Orientation;
dpi?: number;
}
export type PageNode = {
type: typeof P.Page;
props: PageProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: (
| ViewNode
| ImageNode
| TextNode
| LinkNode
| CanvasNode
| FieldSetNode
| TextInputNode
| SelectNode
| ListNode
| CheckboxNode
| NoteNode
)[];
};
export type SafePageNode = Omit & {
style: SafeStyle;
children?: (
| SafeViewNode
| SafeImageNode
| SafeTextNode
| SafeLinkNode
| SafeCanvasNode
| SafeFieldSetNode
| SafeTextInputNode
| SafeSelectNode
| SafeListNode
| SafeCheckboxNode
| SafeNoteNode
)[];
};
================================================
FILE: packages/layout/src/types/path.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
interface PathProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
d: string;
}
interface SafePathProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
d: string;
}
export type PathNode = {
type: typeof P.Path;
props: PathProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafePathNode = Omit & {
style: SafeStyle;
props: SafePathProps;
};
================================================
FILE: packages/layout/src/types/polygon.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
SafeSVGPresentationAttributes,
SVGPresentationAttributes,
} from './base';
interface PolygonProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
points: string;
}
interface SafePolygonProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
points: string;
}
export type PolygonNode = {
type: typeof P.Polygon;
props: PolygonProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafePolygonNode = Omit & {
style: SafeStyle;
props: SafePolygonProps;
};
================================================
FILE: packages/layout/src/types/polyline.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
interface PolylineProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
points: string;
}
interface SafePolylineProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
points: string;
}
export type PolylineNode = {
type: typeof P.Polyline;
props: PolylineProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafePolylineNode = Omit & {
style: SafeStyle;
props: SafePolylineProps;
};
================================================
FILE: packages/layout/src/types/radial-gradient.ts
================================================
import * as P from '@react-pdf/primitives';
import { Transform } from '@react-pdf/stylesheet';
import { SafeStopNode, StopNode } from './stop';
interface RadialGradientProps {
id: string;
cx?: string | number;
cy?: string | number;
fr?: string | number;
fx?: string | number;
fy?: string | number;
r?: string | number;
xlinkHref?: string;
gradientTransform?: string;
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
}
interface SafeRadialGradientProps {
id: string;
cx?: number;
cy?: number;
fr?: number;
fx?: number;
fy?: number;
r?: number;
xlinkHref?: string;
gradientTransform?: Transform[];
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
}
export type RadialGradientNode = {
type: typeof P.RadialGradient;
props: RadialGradientProps;
style?: never;
box?: never;
origin?: never;
yogaNode?: never;
children?: StopNode[];
};
export type SafeRadialGradientNode = Omit<
RadialGradientNode,
'props' | 'children'
> & {
props: SafeRadialGradientProps;
children?: SafeStopNode[];
};
================================================
FILE: packages/layout/src/types/rect.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import {
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
interface RectProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
x?: string | number;
y?: string | number;
width: string | number;
height: string | number;
rx?: string | number;
ry?: string | number;
}
interface SafeRectProps extends SafeSVGPresentationAttributes {
style?: SafeSVGPresentationAttributes;
x?: number;
y?: number;
width: number;
height: number;
rx?: number;
ry?: number;
}
export type RectNode = {
type: typeof P.Rect;
props: RectProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafeRectNode = Omit & {
style: SafeStyle;
props: SafeRectProps;
};
================================================
FILE: packages/layout/src/types/select.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import { Box, FormCommonProps, Origin } from './base';
interface SelectAndListProps extends FormCommonProps {
sort?: boolean;
edit?: boolean;
multiSelect?: boolean;
noSpell?: boolean;
select?: string[];
}
export type SelectNode = {
type: typeof P.Select;
props: SelectAndListProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: never;
children?: never[];
};
export type SafeSelectNode = Omit & {
style: SafeStyle;
};
export type ListNode = {
type: typeof P.List;
props: SelectAndListProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: never[];
};
export type SafeListNode = Omit & {
style: SafeStyle;
};
================================================
FILE: packages/layout/src/types/stop.ts
================================================
import * as P from '@react-pdf/primitives';
interface StopProps {
offset: string | number;
stopColor: string;
stopOpacity?: string | number;
}
interface StopSafeProps {
offset: number;
stopColor: string;
stopOpacity?: number;
}
export type StopNode = {
type: typeof P.Stop;
props: StopProps;
style?: never;
box?: never;
origin?: never;
yogaNode?: never;
children?: never[];
};
export type SafeStopNode = Omit & {
props: StopSafeProps;
};
================================================
FILE: packages/layout/src/types/svg.ts
================================================
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import * as P from '@react-pdf/primitives';
import { YogaNode } from 'yoga-layout/load';
import {
Box,
Origin,
NodeProps,
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
import { LineNode, SafeLineNode } from './line';
import { PolylineNode, SafePolylineNode } from './polyline';
import { PolygonNode, SafePolygonNode } from './polygon';
import { PathNode, SafePathNode } from './path';
import { RectNode, SafeRectNode } from './rect';
import { CircleNode, SafeCircleNode } from './circle';
import { EllipseNode, SafeEllipseNode } from './ellipse';
import { SafeTspanNode, TspanNode } from './tspan';
import { GNode, SafeGNode } from './g';
import { DefsNode, SafeDefsNode } from './defs';
import { SafeTextNode, TextNode } from './text';
import { ImageNode, SafeImageNode } from './image';
export type Viewbox = {
minX: number;
minY: number;
maxX: number;
maxY: number;
};
export type PreserveAspectRatio = {
align:
| 'none'
| 'xMinYMin'
| 'xMidYMin'
| 'xMaxYMin'
| 'xMinYMid'
| 'xMidYMid'
| 'xMaxYMid'
| 'xMinYMax'
| 'xMidYMax'
| 'xMaxYMax';
meetOrSlice: 'meet' | 'slice';
};
interface SvgProps extends NodeProps, SVGPresentationAttributes {
width?: string | number;
height?: string | number;
viewBox?: string | Viewbox;
preserveAspectRatio?: string;
}
interface SvgSafeProps extends NodeProps, SafeSVGPresentationAttributes {
width?: string | number;
height?: string | number;
viewBox?: Viewbox;
preserveAspectRatio?: PreserveAspectRatio;
}
export type SvgNode = {
type: typeof P.Svg;
props: SvgProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: (
| LineNode
| PolylineNode
| PolygonNode
| PathNode
| RectNode
| CircleNode
| EllipseNode
| ImageNode
| TextNode
| TspanNode
| GNode
| DefsNode
)[];
};
export type SafeSvgNode = Omit & {
style: SafeStyle;
props: SvgSafeProps;
children?: (
| SafeLineNode
| SafePolylineNode
| SafePolygonNode
| SafePathNode
| SafeRectNode
| SafeCircleNode
| SafeEllipseNode
| SafeImageNode
| SafeTextNode
| SafeTspanNode
| SafeGNode
| SafeDefsNode
)[];
};
================================================
FILE: packages/layout/src/types/text-input.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import { Box, FormCommonProps, Origin } from './base';
// see http://pdfkit.org/docs/forms.html#text_field_formatting
interface TextInputFormatting {
type:
| 'date'
| 'time'
| 'percent'
| 'number'
| 'zip'
| 'zipPlus4'
| 'phone'
| 'ssn';
param?: string;
nDec?: number;
sepComma?: boolean;
negStyle?: 'MinusBlack' | 'Red' | 'ParensBlack' | 'ParensRed';
currency?: string;
currencyPrepend?: boolean;
}
// see http://pdfkit.org/docs/forms.html#text_field_formatting
interface TextInputProps extends FormCommonProps {
align?: 'left' | 'center' | 'right';
multiline?: boolean;
/**
* The text will be masked (e.g. with asterisks).
*/
password?: boolean;
/**
* If set, text entered in the field is not spell-checked
*/
noSpell?: boolean;
format?: TextInputFormatting;
/**
* Sets the fontSize (default or 0 means auto sizing)
*/
fontSize?: number;
/**
* Sets the maximum length (characters) of the text in the field
*/
maxLength?: number;
}
export type TextInputNode = {
type: typeof P.TextInput;
props: TextInputProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: never[];
};
export type SafeTextInputNode = Omit & {
style: SafeStyle;
};
================================================
FILE: packages/layout/src/types/text-instance.ts
================================================
import * as P from '@react-pdf/primitives';
export type TextInstanceNode = {
type: typeof P.TextInstance;
props?: never;
style?: never;
box?: never;
origin?: never;
children?: never[];
yogaNode?: never;
value: string;
};
export type SafeTextInstanceNode = TextInstanceNode;
================================================
FILE: packages/layout/src/types/text.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { HyphenationCallback } from '@react-pdf/font';
import { YogaNode } from 'yoga-layout/load';
import { Paragraph } from '@react-pdf/textkit';
import { Box, NodeProps, Origin, RenderProp } from './base';
import { SafeTextInstanceNode, TextInstanceNode } from './text-instance';
import { ImageNode, SafeImageNode } from './image';
import { SafeTspanNode, TspanNode } from './tspan';
interface TextProps extends NodeProps {
/**
* Enable/disable page wrapping for element.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
render?: RenderProp;
/**
* Override the default hyphenation-callback
* @see https://react-pdf.org/fonts#registerhyphenationcallback
*/
hyphenationCallback?: HyphenationCallback;
/**
* Specifies the minimum number of lines in a text element that must be shown at the bottom of a page or its container.
* @see https://react-pdf.org/advanced#orphan-&-widow-protection
*/
orphans?: number;
/**
* Specifies the minimum number of lines in a text element that must be shown at the top of a page or its container..
* @see https://react-pdf.org/advanced#orphan-&-widow-protection
*/
widows?: number;
// Svg props
x?: number;
y?: number;
}
export type TextNode = {
type: typeof P.Text;
props: TextProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
lines?: Paragraph;
alignOffset?: number; // TODO: Remove this
children?: (TextNode | TextInstanceNode | ImageNode | TspanNode)[];
};
export type SafeTextNode = Omit & {
style: SafeStyle;
children?: (
| SafeTextNode
| SafeTextInstanceNode
| SafeImageNode
| SafeTspanNode
)[];
};
================================================
FILE: packages/layout/src/types/tspan.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { Paragraph } from '@react-pdf/textkit';
import {
SVGPresentationAttributes,
SafeSVGPresentationAttributes,
} from './base';
import { SafeTextInstanceNode, TextInstanceNode } from './text-instance';
interface TspanProps extends SVGPresentationAttributes {
x?: string | number;
y?: string | number;
}
interface SafeTspanProps extends SafeSVGPresentationAttributes {
x?: number;
y?: number;
}
export type TspanNode = {
type: typeof P.Tspan;
props: TspanProps;
style?: Style | Style[];
box?: never;
origin?: never;
yogaNode?: never;
lines?: Paragraph;
children?: TextInstanceNode[];
};
export type SafeTspanNode = Omit & {
style: SafeStyle;
props: SafeTspanProps;
children?: SafeTextInstanceNode[];
};
================================================
FILE: packages/layout/src/types/view.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeStyle, Style } from '@react-pdf/stylesheet';
import { YogaNode } from 'yoga-layout/load';
import { Box, NodeProps, Origin, RenderProp } from './base';
import { ImageNode, SafeImageNode } from './image';
import { SafeTextNode, TextNode } from './text';
import { LinkNode, SafeLinkNode } from './link';
import { CanvasNode, SafeCanvasNode } from './canvas';
import { FieldSetNode, SafeFieldSetNode } from './field-set';
import { SafeTextInputNode, TextInputNode } from './text-input';
import { ListNode, SafeListNode, SafeSelectNode, SelectNode } from './select';
import { CheckboxNode } from './checkbox';
import { NoteNode, SafeNoteNode } from './note';
interface ViewProps extends NodeProps {
id?: string;
/**
* Enable/disable page wrapping for element.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
render?: RenderProp;
}
export type ViewNode = {
type: typeof P.View;
props: ViewProps;
style?: Style | Style[];
box?: Box;
origin?: Origin;
yogaNode?: YogaNode;
children?: (
| ViewNode
| ImageNode
| TextNode
| LinkNode
| CanvasNode
| FieldSetNode
| TextInputNode
| SelectNode
| ListNode
| CheckboxNode
| NoteNode
)[];
};
export type SafeViewNode = Omit & {
style: SafeStyle;
children?: (
| SafeViewNode
| SafeImageNode
| SafeTextNode
| SafeLinkNode
| SafeCanvasNode
| SafeFieldSetNode
| SafeTextInputNode
| SafeSelectNode
| SafeListNode
| SafeCanvasNode
| SafeNoteNode
)[];
};
================================================
FILE: packages/layout/src/yoga/index.ts
================================================
import { type Yoga, loadYoga as yogaLoadYoga } from 'yoga-layout/load';
let instancePromise: Promise;
export const loadYoga = async () => {
// Yoga WASM binaries must be asynchronously compiled and loaded
// to prevent Event emitter memory leak warnings, Yoga must be loaded only once
const instance = await (instancePromise ??= yogaLoadYoga());
const config = instance.Config.create();
config.setPointScaleFactor(0);
const node = { create: () => instance.Node.createWithConfig(config) };
return { node };
};
================================================
FILE: packages/layout/tests/image/getSource.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getSource from '../../src/image/getSource';
const VALUE = 'gotcha';
describe('image getSource', () => {
test('Should get src', () => {
expect(
getSource({ type: 'IMAGE', style: {}, props: { src: VALUE } }),
).toEqual(VALUE);
});
test('Should get source', () => {
expect(
getSource({ type: 'IMAGE', style: {}, props: { source: VALUE } }),
).toEqual(VALUE);
});
test('Should get undefined if either present', () => {
expect(getSource({ type: 'IMAGE', style: {}, props: {} as any })).toEqual(
undefined,
);
});
});
================================================
FILE: packages/layout/tests/image/resolveSource.test.ts
================================================
import { describe, expect, it } from 'vitest';
import resolveSource from '../../src/image/resolveSource';
const SOURCE_URL = 'gotcha';
const SOURCE_URL_OBJECT = { uri: 'gotcha', method: 'GET' };
const SOURCE_BUFFER = Buffer.from('gotcha');
const SOURCE_DATA_BUFFER = { data: Buffer.from('gotcha'), format: 'png' };
const SOURCE_BLOB = new Blob([SOURCE_BUFFER], { type: 'image/png' });
describe('image resolveSource', () => {
describe('source', () => {
it('resolves url', async () => {
await expect(resolveSource(SOURCE_URL)).resolves.toEqual({
uri: SOURCE_URL,
});
});
it('resolves url object', async () => {
await expect(resolveSource(SOURCE_URL_OBJECT)).resolves.toBe(
SOURCE_URL_OBJECT,
);
});
it('resolves buffer', async () => {
await expect(resolveSource(SOURCE_BUFFER)).resolves.toBe(SOURCE_BUFFER);
});
it('resolves data buffer', async () => {
await expect(resolveSource(SOURCE_DATA_BUFFER)).resolves.toBe(
SOURCE_DATA_BUFFER,
);
});
it('resolves blob', async () => {
await expect(resolveSource(SOURCE_BLOB)).resolves.toBe(SOURCE_BLOB);
});
});
describe('async', () => {
it('resolves url', async () => {
await expect(resolveSource(Promise.resolve(SOURCE_URL))).resolves.toEqual(
{
uri: SOURCE_URL,
},
);
});
it('resolves url object', async () => {
await expect(
resolveSource(Promise.resolve(SOURCE_URL_OBJECT)),
).resolves.toBe(SOURCE_URL_OBJECT);
});
it('resolves buffer', async () => {
await expect(resolveSource(Promise.resolve(SOURCE_BUFFER))).resolves.toBe(
SOURCE_BUFFER,
);
});
it('resolves data buffer', async () => {
await expect(
resolveSource(Promise.resolve(SOURCE_DATA_BUFFER)),
).resolves.toBe(SOURCE_DATA_BUFFER);
});
it('resolves blob', async () => {
await expect(resolveSource(Promise.resolve(SOURCE_BLOB))).resolves.toBe(
SOURCE_BLOB,
);
});
});
describe('factory', () => {
it('resolves url', async () => {
await expect(resolveSource(() => SOURCE_URL)).resolves.toEqual({
uri: SOURCE_URL,
});
});
it('resolves url object', async () => {
await expect(resolveSource(() => SOURCE_URL_OBJECT)).resolves.toBe(
SOURCE_URL_OBJECT,
);
});
it('resolves buffer', async () => {
await expect(resolveSource(() => SOURCE_BUFFER)).resolves.toBe(
SOURCE_BUFFER,
);
});
it('resolves data buffer', async () => {
await expect(resolveSource(() => SOURCE_DATA_BUFFER)).resolves.toBe(
SOURCE_DATA_BUFFER,
);
});
it('resolves undefined', async () => {
await expect(resolveSource(() => undefined)).resolves.toBe(undefined);
});
it('resolves blob', async () => {
await expect(resolveSource(() => SOURCE_BLOB)).resolves.toBe(SOURCE_BLOB);
});
});
describe('async factory', () => {
it('resolves url', async () => {
await expect(resolveSource(async () => SOURCE_URL)).resolves.toEqual({
uri: SOURCE_URL,
});
});
it('resolves url object', async () => {
await expect(resolveSource(async () => SOURCE_URL_OBJECT)).resolves.toBe(
SOURCE_URL_OBJECT,
);
});
it('resolves buffer', async () => {
await expect(resolveSource(async () => SOURCE_BUFFER)).resolves.toBe(
SOURCE_BUFFER,
);
});
it('resolves data buffer', async () => {
await expect(resolveSource(async () => SOURCE_DATA_BUFFER)).resolves.toBe(
SOURCE_DATA_BUFFER,
);
});
it('resolves undefined', async () => {
await expect(resolveSource(async () => undefined)).resolves.toBe(
undefined,
);
});
it('resolves blob', async () => {
await expect(resolveSource(async () => SOURCE_BLOB)).resolves.toBe(
SOURCE_BLOB,
);
});
});
});
================================================
FILE: packages/layout/tests/node/getBorderWidth.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import getBorderWidth from '../../src/node/getBorderWidth';
const getComputedBorder = (value) => {
if (value === Yoga.Edge.Top) return 1;
if (value === Yoga.Edge.Right) return 2;
if (value === Yoga.Edge.Bottom) return 3;
return 4;
};
describe('node getBorderWidth', () => {
test('Should return 0 by default if no yoga node available', () => {
const result = getBorderWidth({
type: 'VIEW',
props: {},
style: {},
children: [],
});
expect(result).toHaveProperty('borderTopWidth', 0);
expect(result).toHaveProperty('borderRightWidth', 0);
expect(result).toHaveProperty('borderBottomWidth', 0);
expect(result).toHaveProperty('borderLeftWidth', 0);
});
test('Should return yoga values if node available', () => {
const yogaNode = { getComputedBorder };
const result = getBorderWidth({
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode,
});
expect(result).toHaveProperty('borderTopWidth', 1);
expect(result).toHaveProperty('borderRightWidth', 2);
expect(result).toHaveProperty('borderBottomWidth', 3);
expect(result).toHaveProperty('borderLeftWidth', 4);
});
});
================================================
FILE: packages/layout/tests/node/getDimension.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getDimension from '../../src/node/getDimension';
const getComputedWidth = () => 10;
const getComputedHeight = () => 20;
describe('node getDimension', () => {
test('Should return 0 by default if no yoga node available', () => {
const result = getDimension({
type: 'VIEW',
props: {},
style: {},
children: [],
});
expect(result).toHaveProperty('width', 0);
expect(result).toHaveProperty('height', 0);
});
test('Should return yoga values if node available', () => {
const yogaNode = { getComputedWidth, getComputedHeight };
const result = getDimension({
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode,
});
expect(result).toHaveProperty('width', 10);
expect(result).toHaveProperty('height', 20);
});
});
================================================
FILE: packages/layout/tests/node/getMargin.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import getMargin from '../../src/node/getMargin';
const getComputedMargin = (value) => {
if (value === Yoga.Edge.Top) return 1;
if (value === Yoga.Edge.Right) return 2;
if (value === Yoga.Edge.Bottom) return 3;
return 4;
};
describe('node getMargin', () => {
test('Should return 0 by default if no yoga node available', () => {
const result = getMargin({
type: 'VIEW',
props: {},
style: {},
children: [],
});
expect(result).toHaveProperty('marginTop', 0);
expect(result).toHaveProperty('marginRight', 0);
expect(result).toHaveProperty('marginBottom', 0);
expect(result).toHaveProperty('marginLeft', 0);
});
test('Should return yoga values if node available', () => {
const yogaNode = { getComputedMargin };
const result = getMargin({
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode,
});
expect(result).toHaveProperty('marginTop', 1);
expect(result).toHaveProperty('marginRight', 2);
expect(result).toHaveProperty('marginBottom', 3);
expect(result).toHaveProperty('marginLeft', 4);
});
test('Should return box specific values if available', () => {
const result = getMargin({
type: 'VIEW',
props: {},
style: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
marginTop: 1,
marginRight: 2,
marginBottom: 3,
marginLeft: 4,
},
children: [],
});
expect(result).toHaveProperty('marginTop', 1);
expect(result).toHaveProperty('marginRight', 2);
expect(result).toHaveProperty('marginBottom', 3);
expect(result).toHaveProperty('marginLeft', 4);
});
test('Should return style specific values if available', () => {
const result = getMargin({
type: 'VIEW',
props: {},
style: {
marginTop: 1,
marginRight: 2,
marginBottom: 3,
marginLeft: 4,
},
children: [],
});
expect(result).toHaveProperty('marginTop', 1);
expect(result).toHaveProperty('marginRight', 2);
expect(result).toHaveProperty('marginBottom', 3);
expect(result).toHaveProperty('marginLeft', 4);
});
});
================================================
FILE: packages/layout/tests/node/getOrigin.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getOrigin from '../../src/node/getOrigin';
describe('node getOrigin', () => {
test('Should return null for node without box', () => {
const result = getOrigin({
type: 'VIEW',
props: {},
style: {},
children: [],
});
expect(result).toEqual(null);
});
test('Should return centered origin by default', () => {
const result = getOrigin({
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 50, left: 100, bottom: 0, right: 0, width: 300, height: 400 },
});
expect(result).toHaveProperty('left', 250);
expect(result).toHaveProperty('left', 250);
});
test('Should return origin adjusted by fixed values', () => {
const result = getOrigin({
type: 'VIEW',
props: {},
children: [],
style: { transformOriginX: 100, transformOriginY: 50 },
box: { top: 50, left: 100, bottom: 0, right: 0, width: 300, height: 400 },
});
expect(result).toHaveProperty('left', 200);
expect(result).toHaveProperty('top', 100);
});
test('Should return origin adjusted by percent values', () => {
const result = getOrigin({
type: 'VIEW',
props: {},
children: [],
style: { transformOriginX: '20%', transformOriginY: '70%' },
box: { top: 50, left: 100, bottom: 0, right: 0, width: 300, height: 400 },
});
expect(result).toHaveProperty('left', 160);
expect(result).toHaveProperty('top', 330);
});
});
================================================
FILE: packages/layout/tests/node/getPadding.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import getPadding from '../../src/node/getPadding';
const getComputedPadding = (value) => {
if (value === Yoga.Edge.Top) return 1;
if (value === Yoga.Edge.Right) return 2;
if (value === Yoga.Edge.Bottom) return 3;
return 4;
};
describe('node getPadding', () => {
test('Should return 0 by default if no yoga node available', () => {
const result = getPadding({
type: 'VIEW',
props: {},
style: {},
children: [],
});
expect(result).toHaveProperty('paddingTop', 0);
expect(result).toHaveProperty('paddingRight', 0);
expect(result).toHaveProperty('paddingBottom', 0);
expect(result).toHaveProperty('paddingLeft', 0);
});
test('Should return yoga values if node available', () => {
const yogaNode = { getComputedPadding };
const result = getPadding({
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode,
});
expect(result).toHaveProperty('paddingTop', 1);
expect(result).toHaveProperty('paddingRight', 2);
expect(result).toHaveProperty('paddingBottom', 3);
expect(result).toHaveProperty('paddingLeft', 4);
});
test('Should return box specific values if available', () => {
const result = getPadding({
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 100,
paddingTop: 1,
paddingRight: 2,
paddingBottom: 3,
paddingLeft: 4,
},
});
expect(result).toHaveProperty('paddingTop', 1);
expect(result).toHaveProperty('paddingRight', 2);
expect(result).toHaveProperty('paddingBottom', 3);
expect(result).toHaveProperty('paddingLeft', 4);
});
test('Should return style specific values if available', () => {
const result = getPadding({
type: 'VIEW',
props: {},
children: [],
style: {
paddingTop: 1,
paddingRight: 2,
paddingBottom: 3,
paddingLeft: 4,
},
});
expect(result).toHaveProperty('paddingTop', 1);
expect(result).toHaveProperty('paddingRight', 2);
expect(result).toHaveProperty('paddingBottom', 3);
expect(result).toHaveProperty('paddingLeft', 4);
});
});
================================================
FILE: packages/layout/tests/node/getPosition.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getPosition from '../../src/node/getPosition';
const getComputedTop = () => 10;
const getComputedRight = () => 20;
const getComputedBottom = () => 30;
const getComputedLeft = () => 40;
describe('node getPosition', () => {
test('Should return 0 by default if no yoga node available', () => {
const result = getPosition({
type: 'VIEW',
props: {},
style: {},
children: [],
});
expect(result).toHaveProperty('top', 0);
expect(result).toHaveProperty('right', 0);
expect(result).toHaveProperty('bottom', 0);
expect(result).toHaveProperty('left', 0);
});
test('Should return yoga values if node available', () => {
const yogaNode = {
getComputedTop,
getComputedRight,
getComputedBottom,
getComputedLeft,
};
const result = getPosition({
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode,
});
expect(result).toHaveProperty('top', 10);
expect(result).toHaveProperty('right', 20);
expect(result).toHaveProperty('bottom', 30);
expect(result).toHaveProperty('left', 40);
});
});
================================================
FILE: packages/layout/tests/node/removePaddings.test.ts
================================================
import { describe, expect, test } from 'vitest';
import removePaddings from '../../src/node/removePaddings';
describe('node removePaddings', () => {
test('Should keep other styles untouched', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { color: 'red' },
});
expect(result.style).toHaveProperty('color', 'red');
});
test('Should remove paddingTop', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { paddingTop: 10 },
});
expect(result.style).not.toHaveProperty('paddingTop');
});
test('Should remove paddingRight', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { paddingRight: 10 },
});
expect(result.style).not.toHaveProperty('paddingRight');
});
test('Should remove paddingBottom', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { paddingBottom: 10 },
});
expect(result.style).not.toHaveProperty('paddingBottom');
});
test('Should remove paddingLeft', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { paddingLeft: 10 },
});
expect(result.style).not.toHaveProperty('paddingLeft');
});
test('Should remove padding shorthand', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { padding: 10 } as any,
});
expect(result.style).not.toHaveProperty('padding');
});
test('Should remove paddingHorizontal shorthand', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { paddingHorizontal: 10 } as any,
});
expect(result.style).not.toHaveProperty('paddingHorizontal');
});
test('Should remove paddingVertical shorthand', () => {
const result = removePaddings({
type: 'VIEW',
props: {},
children: [],
style: { paddingVertical: 10 } as any,
});
expect(result.style).not.toHaveProperty('paddingVertical');
});
});
================================================
FILE: packages/layout/tests/node/setAlignContent.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setAlignContent from '../../src/node/setAlignContent';
import { SafeNode } from '../../src/types';
describe('node setAlignContent', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setAlignContent: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setAlignContent(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set align auto by default', () => {
const result = setAlignContent(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Auto);
expect(result).toBe(node);
});
test('Should set flex-start', () => {
const result = setAlignContent('flex-start')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.FlexStart);
expect(result).toBe(node);
});
test('Should set center', () => {
const result = setAlignContent('center')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Center);
expect(result).toBe(node);
});
test('Should set flex-end', () => {
const result = setAlignContent('flex-end')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.FlexEnd);
expect(result).toBe(node);
});
test('Should set stretch', () => {
const result = setAlignContent('stretch')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Stretch);
expect(result).toBe(node);
});
test('Should set baseline', () => {
const result = setAlignContent('baseline')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Baseline);
expect(result).toBe(node);
});
test('Should set space-between', () => {
const result = setAlignContent('space-between')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceBetween);
expect(result).toBe(node);
});
test('Should set space-around', () => {
const result = setAlignContent('space-around')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceAround);
expect(result).toBe(node);
});
test('Should set space-evenly', () => {
const result = setAlignContent('space-evenly')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceEvenly);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setAlignItems.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setAlignItems from '../../src/node/setAlignItems';
import { SafeNode } from '../../src/types';
describe('node setAlignItems', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setAlignItems: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, left: 0, bottom: 0, width: 10, height: 20 },
} as SafeNode;
const result = setAlignItems(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set align auto by stretch', () => {
const result = setAlignItems(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Stretch);
expect(result).toBe(node);
});
test('Should set flex-start', () => {
const result = setAlignItems('flex-start')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.FlexStart);
expect(result).toBe(node);
});
test('Should set center', () => {
const result = setAlignItems('center')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Center);
expect(result).toBe(node);
});
test('Should set flex-end', () => {
const result = setAlignItems('flex-end')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.FlexEnd);
expect(result).toBe(node);
});
test('Should set stretch', () => {
const result = setAlignItems('stretch')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Stretch);
expect(result).toBe(node);
});
test('Should set baseline', () => {
const result = setAlignItems('baseline')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Baseline);
expect(result).toBe(node);
});
test('Should set space-between', () => {
const result = setAlignItems('space-between')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceBetween);
expect(result).toBe(node);
});
test('Should set space-around', () => {
const result = setAlignItems('space-around')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceAround);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setAlignSelf.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setAlignSelf from '../../src/node/setAlignSelf';
import { SafeNode } from '../../src/types';
describe('node setAlignSelf', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setAlignSelf: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, left: 0, bottom: 0, width: 10, height: 20 },
} as SafeNode;
const result = setAlignSelf(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set align auto by default', () => {
const result = setAlignSelf(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Auto);
expect(result).toBe(node);
});
test('Should set flex-start', () => {
const result = setAlignSelf('flex-start')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.FlexStart);
expect(result).toBe(node);
});
test('Should set center', () => {
const result = setAlignSelf('center')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Center);
expect(result).toBe(node);
});
test('Should set flex-end', () => {
const result = setAlignSelf('flex-end')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.FlexEnd);
expect(result).toBe(node);
});
test('Should set stretch', () => {
const result = setAlignSelf('stretch')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Stretch);
expect(result).toBe(node);
});
test('Should set baseline', () => {
const result = setAlignSelf('baseline')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.Baseline);
expect(result).toBe(node);
});
test('Should set space-between', () => {
const result = setAlignSelf('space-between')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceBetween);
expect(result).toBe(node);
});
test('Should set space-around', () => {
const result = setAlignSelf('space-around')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Align.SpaceAround);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setAspectRatio.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import setAspectRatio from '../../src/node/setAspectRatio';
import { SafeNode } from '../../src/types';
describe('node setAspectRatio', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setAspectRatio: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, left: 0, bottom: 0, width: 10, height: 20 },
} as SafeNode;
const result = setAspectRatio(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call yoga node setter if provided', () => {
const result = setAspectRatio(3)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(3);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setBorderWidth.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setBorder, {
setBorderTop,
setBorderRight,
setBorderBottom,
setBorderLeft,
} from '../../src/node/setBorderWidth';
import { SafeNode } from '../../src/types';
describe('node setBorderWidth', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setBorder: mock },
} as SafeNode;
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, left: 0, bottom: 0, width: 10, height: 20 },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
describe('setBorderTop', () => {
test('should return node if no yoga node available', () => {
const result = setBorderTop(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setBorderTop(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setBorderTop('50%')(node)).toThrow();
});
});
describe('setBorderRight', () => {
test('should return node if no yoga node available', () => {
const result = setBorderRight(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setBorderRight(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setBorderRight('50%')(node)).toThrow();
});
});
describe('setBorderBottom', () => {
test('should return node if no yoga node available', () => {
const result = setBorderBottom(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setBorderBottom(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setBorderBottom('50%')(node)).toThrow();
});
});
describe('setBorderLeft', () => {
test('should return node if no yoga node available', () => {
const result = setBorderLeft(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setBorderLeft(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setBorderLeft('50%')(node)).toThrow();
});
});
describe('setBorder', () => {
test('should return node if no yoga node available', () => {
const result = setBorder(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setBorder(50)(node);
expect(mock.mock.calls).toHaveLength(4);
expect(mock.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mock.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mock.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mock.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setBorder('50%' as any)(node)).toThrow();
});
});
});
================================================
FILE: packages/layout/tests/node/setDimension.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import {
setWidth,
setMinWidth,
setMaxWidth,
setHeight,
setMinHeight,
setMaxHeight,
} from '../../src/node/setDimension';
import { SafeNode } from '../../src/types';
describe('node setDimension', () => {
const mockSetWidth = vi.fn();
const mockSetWidthPercent = vi.fn();
const mockSetMinWidth = vi.fn();
const mockSetMaxWidth = vi.fn();
const mockSetHeight = vi.fn();
const mockSetHeightPercent = vi.fn();
const mockSetMinHeight = vi.fn();
const mockSetMaxHeight = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: {
setWidth: mockSetWidth,
setWidthPercent: mockSetWidthPercent,
setMinWidth: mockSetMinWidth,
setMaxWidth: mockSetMaxWidth,
setHeight: mockSetHeight,
setHeightPercent: mockSetHeightPercent,
setMinHeight: mockSetMinHeight,
setMaxHeight: mockSetMaxHeight,
},
} as SafeNode;
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
beforeEach(() => {
mockSetWidth.mockReset();
mockSetWidthPercent.mockReset();
mockSetMinWidth.mockReset();
mockSetMaxWidth.mockReset();
mockSetHeight.mockReset();
mockSetHeightPercent.mockReset();
mockSetMinHeight.mockReset();
mockSetMaxHeight.mockReset();
});
describe('setWidth', () => {
test('should return node if no yoga node available', () => {
const result = setWidth(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setWidth(50)(node);
expect(mockSetWidth.mock.calls).toHaveLength(1);
expect(mockSetWidthPercent.mock.calls).toHaveLength(0);
expect(mockSetWidth.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setWidth('50%')(node);
expect(mockSetWidth.mock.calls).toHaveLength(0);
expect(mockSetWidthPercent.mock.calls).toHaveLength(1);
expect(mockSetWidthPercent.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
});
describe('setMinWidth', () => {
test('should return node if no yoga node available', () => {
const result = setMinWidth(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMinWidth(50)(node);
expect(mockSetMaxWidth.mock.calls).toHaveLength(0);
expect(mockSetMinWidth.mock.calls).toHaveLength(1);
expect(mockSetMinWidth.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setMinWidth('50%')(node)).toThrow();
});
});
describe('setMaxWidth', () => {
test('should return node if no yoga node available', () => {
const result = setMaxWidth(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMaxWidth(50)(node);
expect(mockSetMinWidth.mock.calls).toHaveLength(0);
expect(mockSetMaxWidth.mock.calls).toHaveLength(1);
expect(mockSetMaxWidth.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setMaxWidth('50%')(node)).toThrow();
});
});
describe('setHeight', () => {
test('should return node if no yoga node available', () => {
const result = setHeight(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setHeight(50)(node);
expect(mockSetHeight.mock.calls).toHaveLength(1);
expect(mockSetHeightPercent.mock.calls).toHaveLength(0);
expect(mockSetHeight.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setHeight('50%')(node);
expect(mockSetHeight.mock.calls).toHaveLength(0);
expect(mockSetHeightPercent.mock.calls).toHaveLength(1);
expect(mockSetHeightPercent.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
});
describe('setMinHeight', () => {
test('should return node if no yoga node available', () => {
const result = setMinWidth(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMinHeight(50)(node);
expect(mockSetMaxHeight.mock.calls).toHaveLength(0);
expect(mockSetMinHeight.mock.calls).toHaveLength(1);
expect(mockSetMinHeight.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setMinHeight('50%')(node)).toThrow();
});
});
describe('setMaxHeight', () => {
test('should return node if no yoga node available', () => {
const result = setMaxHeight(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMaxHeight(50)(node);
expect(mockSetMinHeight.mock.calls).toHaveLength(0);
expect(mockSetMaxHeight.mock.calls).toHaveLength(1);
expect(mockSetMaxHeight.mock.calls[0][0]).toBe(50);
expect(result).toBe(node);
});
test('Should throw error for percent values', () => {
expect(() => setMaxHeight('50%')(node)).toThrow();
});
});
});
================================================
FILE: packages/layout/tests/node/setDisplay.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setDisplay from '../../src/node/setDisplay';
import { SafeNode } from '../../src/types';
describe('node setDisplay', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setDisplay: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setDisplay(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set flex by default', () => {
const result = setDisplay(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Display.Flex);
expect(result).toBe(node);
});
test('Should set flex', () => {
const result = setDisplay('flex')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Display.Flex);
expect(result).toBe(node);
});
test('Should set none', () => {
const result = setDisplay('none')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Display.None);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setFlexBasis.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import setFlexBasis from '../../src/node/setFlexBasis';
import { SafeNode } from '../../src/types';
describe('node setFlexBasis', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setFlexBasis: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setFlexBasis(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set provided value', () => {
const result = setFlexBasis(2)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(2);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setFlexDirection.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setFlexDirection from '../../src/node/setFlexDirection';
import { SafeNode } from '../../src/types';
describe('node setFlexDirection', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setFlexDirection: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setFlexDirection(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set column by default', () => {
const result = setFlexDirection(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.FlexDirection.Column);
expect(result).toBe(node);
});
test('Should set column', () => {
const result = setFlexDirection('column')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.FlexDirection.Column);
expect(result).toBe(node);
});
test('Should set row', () => {
const result = setFlexDirection('row')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.FlexDirection.Row);
expect(result).toBe(node);
});
test('Should set row-reverse', () => {
const result = setFlexDirection('row-reverse')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.FlexDirection.RowReverse);
expect(result).toBe(node);
});
test('Should set column-reverse', () => {
const result = setFlexDirection('column-reverse')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.FlexDirection.ColumnReverse);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setFlexGrow.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import setFlexGrow from '../../src/node/setFlexGrow';
import { SafeNode } from '../../src/types';
describe('node setFlexGrow', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setFlexGrow: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setFlexGrow(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set zero by default', () => {
const result = setFlexGrow(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(0);
expect(result).toBe(node);
});
test('Should set provided value', () => {
const result = setFlexGrow(2)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(2);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setFlexShrink.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import setFlexShrink from '../../src/node/setFlexShrink';
import { SafeNode } from '../../src/types';
describe('node setFlexShrink', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setFlexShrink: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setFlexShrink(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set one by default', () => {
const result = setFlexShrink(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(1);
expect(result).toBe(node);
});
test('Should set provided value', () => {
const result = setFlexShrink(2)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(2);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setFlexWrap.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setFlexWrap from '../../src/node/setFlexWrap';
import { SafeNode } from '../../src/types';
describe('node setFlexWrap', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setFlexWrap: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setFlexWrap(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set no-wrap by default', () => {
const result = setFlexWrap(null)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Wrap.NoWrap);
expect(result).toBe(node);
});
test('Should set no-wrap', () => {
const result = setFlexWrap('no-wrap')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Wrap.NoWrap);
expect(result).toBe(node);
});
test('Should set wrap', () => {
const result = setFlexWrap('wrap')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Wrap.Wrap);
expect(result).toBe(node);
});
test('Should set wrap-reverse', () => {
const result = setFlexWrap('wrap-reverse')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Wrap.WrapReverse);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setGap.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import { setRowGap, setColumnGap } from '../../src/node/setGap';
import { SafeNode } from '../../src/types';
describe('node setGap', () => {
const mock = vi.fn();
const mockPercent = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: {
setGap: mock,
setGapPercent: mockPercent,
},
} as SafeNode;
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
mockPercent.mockReset();
});
describe('setRowGap', () => {
test('should return node if no yoga node available', () => {
const result = setRowGap(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('should call appropiate yoga node method for numeric values', () => {
const result = setRowGap(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Gutter.Row);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('should call appropiate yoga node method for percent values', () => {
const result = setRowGap('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Gutter.Row);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setColumnGap', () => {
test('should return node if no yoga node available', () => {
const result = setColumnGap(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('should call appropiate yoga node method for numeric values', () => {
const result = setColumnGap(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Gutter.Column);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('should call appropiate yoga node method for percent values', () => {
const result = setColumnGap('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Gutter.Column);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
});
================================================
FILE: packages/layout/tests/node/setJustifyContent.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setJustifyContent from '../../src/node/setJustifyContent';
import { SafeNode } from '../../src/types';
describe('node setJustifyContent', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setJustifyContent: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setJustifyContent(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set center', () => {
const result = setJustifyContent('center')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Justify.Center);
expect(result).toBe(node);
});
test('Should set flex-end', () => {
const result = setJustifyContent('flex-end')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Justify.FlexEnd);
expect(result).toBe(node);
});
test('Should set flex-start', () => {
const result = setJustifyContent('flex-start')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Justify.FlexStart);
expect(result).toBe(node);
});
test('Should set space-between', () => {
const result = setJustifyContent('space-between')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Justify.SpaceBetween);
expect(result).toBe(node);
});
test('Should set space-around', () => {
const result = setJustifyContent('space-around')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Justify.SpaceAround);
expect(result).toBe(node);
});
test('Should set space-evenly', () => {
const result = setJustifyContent('space-evenly')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Justify.SpaceEvenly);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setMargin.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setMargin, {
setMarginTop,
setMarginRight,
setMarginBottom,
setMarginLeft,
} from '../../src/node/setMargin';
import { SafeNode } from '../../src/types';
describe('node setMargin', () => {
const mock = vi.fn();
const mockAuto = vi.fn();
const mockPercent = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: {
setMargin: mock,
setMarginAuto: mockAuto,
setMarginPercent: mockPercent,
},
} as SafeNode;
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
mockAuto.mockReset();
mockPercent.mockReset();
});
describe('setMarginTop', () => {
test('should return node if no yoga node available', () => {
const result = setMarginTop(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for auto value', () => {
const result = setMarginTop('auto')(node);
expect(mockAuto.mock.calls).toHaveLength(1);
expect(mockAuto.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMarginTop(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setMarginTop('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setMarginRight', () => {
test('should return node if no yoga node available', () => {
const result = setMarginRight(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for auto value', () => {
const result = setMarginRight('auto')(node);
expect(mockAuto.mock.calls).toHaveLength(1);
expect(mockAuto.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMarginRight(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setMarginRight('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setMarginBottom', () => {
test('should return node if no yoga node available', () => {
const result = setMarginBottom(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for auto value', () => {
const result = setMarginBottom('auto')(node);
expect(mockAuto.mock.calls).toHaveLength(1);
expect(mockAuto.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMarginBottom(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setMarginBottom('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setMarginLeft', () => {
test('should return node if no yoga node available', () => {
const result = setMarginLeft(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for auto value', () => {
const result = setMarginLeft('auto')(node);
expect(mockAuto.mock.calls).toHaveLength(1);
expect(mockAuto.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMarginLeft(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setMarginLeft('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setMargin', () => {
test('should return node if no yoga node available', () => {
const result = setMargin(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for auto value', () => {
const result = setMargin('auto')(node);
expect(mockAuto.mock.calls).toHaveLength(4);
expect(mockAuto.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mockAuto.mock.calls[1][0]).toBe(Yoga.Edge.Right);
expect(mockAuto.mock.calls[2][0]).toBe(Yoga.Edge.Bottom);
expect(mockAuto.mock.calls[3][0]).toBe(Yoga.Edge.Left);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setMargin(50)(node);
expect(mock.mock.calls).toHaveLength(4);
expect(mock.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mock.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mock.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mock.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setMargin('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(4);
expect(mockPercent.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mockPercent.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mockPercent.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mockPercent.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
});
});
================================================
FILE: packages/layout/tests/node/setOverflow.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setOverflow from '../../src/node/setOverflow';
import { SafeNode } from '../../src/types';
describe('node setOverflow', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setOverflow: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setOverflow(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set visible', () => {
const result = setOverflow('visible')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Overflow.Visible);
expect(result).toBe(node);
});
test('Should set scroll', () => {
const result = setOverflow('scroll')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Overflow.Scroll);
expect(result).toBe(node);
});
test('Should set hidden', () => {
const result = setOverflow('hidden')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Overflow.Hidden);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/setPadding.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setPadding, {
setPaddingTop,
setPaddingRight,
setPaddingBottom,
setPaddingLeft,
} from '../../src/node/setPadding';
import { SafeNode } from '../../src/types';
describe('node setPadding', () => {
const mock = vi.fn();
const mockPercent = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setPadding: mock, setPaddingPercent: mockPercent },
} as SafeNode;
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
mockPercent.mockReset();
});
describe('setPaddingTop', () => {
test('should return node if no yoga node available', () => {
const result = setPaddingTop(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPaddingTop(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPaddingTop('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPaddingRight', () => {
test('should return node if no yoga node available', () => {
const result = setPaddingRight(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPaddingRight(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPaddingRight('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPaddingBottom', () => {
test('should return node if no yoga node available', () => {
const result = setPaddingBottom(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPaddingBottom(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPaddingBottom('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPaddingLeft', () => {
test('should return node if no yoga node available', () => {
const result = setPaddingLeft(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPaddingLeft(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPaddingLeft('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPadding', () => {
test('should return node if no yoga node available', () => {
const result = setPadding(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPadding(50)(node);
expect(mock.mock.calls).toHaveLength(4);
expect(mock.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mock.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mock.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mock.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPadding('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(4);
expect(mockPercent.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mockPercent.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mockPercent.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mockPercent.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
});
});
================================================
FILE: packages/layout/tests/node/setPosition.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setPosition, {
setPositionTop,
setPositionRight,
setPositionBottom,
setPositionLeft,
} from '../../src/node/setPosition';
import { SafeNode } from '../../src/types';
describe('node setPosition', () => {
const mock = vi.fn();
const mockPercent = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setPosition: mock, setPositionPercent: mockPercent },
} as SafeNode;
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
mockPercent.mockReset();
});
describe('setPositionTop', () => {
test('should return node if no yoga node available', () => {
const result = setPositionTop(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPositionTop(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPositionTop('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Top);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPositionRight', () => {
test('should return node if no yoga node available', () => {
const result = setPositionRight(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPositionRight(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPositionRight('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Right);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPositionBottom', () => {
test('should return node if no yoga node available', () => {
const result = setPositionBottom(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPositionBottom(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPositionBottom('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Bottom);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPositionLeft', () => {
test('should return node if no yoga node available', () => {
const result = setPositionLeft(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPositionLeft(50)(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mock.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPositionLeft('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(1);
expect(mockPercent.mock.calls[0][0]).toBe(Yoga.Edge.Left);
expect(mockPercent.mock.calls[0][1]).toBe(50);
expect(result).toBe(node);
});
});
describe('setPosition', () => {
test('should return node if no yoga node available', () => {
const result = setPosition(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should call appropiate yoga node method for numeric values', () => {
const result = setPosition(50)(node);
expect(mock.mock.calls).toHaveLength(4);
expect(mock.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mock.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mock.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mock.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
test('Should call appropiate yoga node method for percent values', () => {
const result = setPosition('50%')(node);
expect(mockPercent.mock.calls).toHaveLength(4);
expect(mockPercent.mock.calls[0]).toEqual([Yoga.Edge.Top, 50]);
expect(mockPercent.mock.calls[1]).toEqual([Yoga.Edge.Right, 50]);
expect(mockPercent.mock.calls[2]).toEqual([Yoga.Edge.Bottom, 50]);
expect(mockPercent.mock.calls[3]).toEqual([Yoga.Edge.Left, 50]);
expect(result).toBe(node);
});
});
});
================================================
FILE: packages/layout/tests/node/setPositionType.test.ts
================================================
import { beforeEach, describe, expect, test, vi } from 'vitest';
import * as Yoga from 'yoga-layout/load';
import setPositionType from '../../src/node/setPositionType';
import { SafeNode } from '../../src/types';
describe('node setPositionType', () => {
const mock = vi.fn();
const node = {
type: 'VIEW',
props: {},
style: {},
children: [],
yogaNode: { setPositionType: mock },
} as SafeNode;
beforeEach(() => {
mock.mockReset();
});
test('should return node if no yoga node available', () => {
const emptyNode = {
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 0, right: 0, bottom: 0, left: 0, width: 10, height: 20 },
} as SafeNode;
const result = setPositionType(null)(emptyNode);
expect(result).toBe(emptyNode);
});
test('Should set relative', () => {
const result = setPositionType('relative')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.PositionType.Relative);
expect(result).toBe(node);
});
test('Should set absolute', () => {
const result = setPositionType('absolute')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.PositionType.Absolute);
expect(result).toBe(node);
});
test('Should set static', () => {
const result = setPositionType('static')(node);
expect(mock.mock.calls).toHaveLength(1);
expect(mock.mock.calls[0][0]).toBe(Yoga.PositionType.Static);
expect(result).toBe(node);
});
});
================================================
FILE: packages/layout/tests/node/shouldBreak.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import shouldBreak from '../../src/node/shouldBreak';
describe('node shouldBreak', () => {
test('should not break when the child has enough space on the page', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: { top: 50, right: 0, bottom: 0, left: 0, height: 400, width: 200 },
},
[],
1000,
[],
);
expect(result).toEqual(false);
});
test('should break when the child has enough space on the page', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { break: true },
style: {},
children: [],
box: { top: 50, right: 0, bottom: 0, left: 0, height: 400, width: 200 },
},
[],
1000,
[],
);
expect(result).toEqual(true);
});
test('should not break when the child can be wrapped', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { wrap: true },
style: {},
children: [],
box: {
top: 50,
right: 0,
bottom: 0,
left: 0,
height: 1400,
width: 200,
},
},
[],
1000,
[],
);
expect(result).toEqual(false);
});
test('should break when the child is an unwrappable node', () => {
const result = shouldBreak(
{
type: P.Image,
props: { wrap: true } as any,
style: {},
children: [],
box: {
top: 50,
right: 0,
bottom: 0,
left: 0,
height: 1400,
width: 200,
},
},
[],
1000,
[],
);
expect(result).toEqual(true);
});
test('should break when the child has wrapping disabled', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { wrap: false },
style: {},
children: [],
box: {
top: 50,
right: 0,
bottom: 0,
left: 0,
height: 1400,
width: 200,
},
},
[],
1000,
[],
);
expect(result).toEqual(true);
});
test('should break when minPresenceAhead is large enough and there are overflowing siblings after the child', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
);
expect(result).toEqual(true);
});
test('should break when minPresenceAhead is large enough and there are overflowing siblings due to margins after the child', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 1100,
right: 0,
bottom: 0,
left: 0,
height: 0,
width: 200,
marginTop: 200,
marginBottom: 0,
},
},
],
1000,
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
);
expect(result).toEqual(true);
});
test('should not break when minPresenceAhead is not past the page end', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 100 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test('should not break when the siblings after the child do not overflow past the page end', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 100,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test('should not break when the siblings after the child do not overflow past the page end, with margins', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 1000,
right: 0,
bottom: 0,
left: 0,
height: 0,
width: 200,
marginTop: 100,
marginBottom: 0,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test("should not break when only the last sibling's bottom margin overflows past the page end", () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 100,
width: 200,
marginTop: 0,
marginBottom: 100,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test('should not break due to minPresenceAhead when breaking does not improve presence because the node is already the first non-fixed node on the page, to avoid infinite loops', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 500,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test('should not break due to minPresenceAhead even when there are some previous fixed nodes on the page, to avoid infinite loops', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400 },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 500,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[
{
type: 'VIEW',
props: {
fixed: true,
},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
);
expect(result).toEqual(false);
});
test('should never break fixed child', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400, fixed: true },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test('should ignore fixed elements after child', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 400, fixed: true },
style: {},
children: [],
box: {
top: 500,
right: 0,
bottom: 0,
left: 0,
height: 400,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: { fixed: true },
style: {},
children: [],
box: {
top: 900,
right: 0,
bottom: 0,
left: 0,
height: 200,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
],
1000,
[],
);
expect(result).toEqual(false);
});
test('should work with trivial minimal reproduction example', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 100 },
style: {},
children: [],
box: {
top: 30,
right: 0,
bottom: 0,
left: 0,
height: 0,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 30,
right: 0,
bottom: 0,
left: 0,
height: 70,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 130,
right: 0,
bottom: 0,
left: 0,
height: 0,
width: 200,
marginTop: 30,
marginBottom: 0,
},
},
],
811.89,
[],
);
expect(result).toEqual(false);
});
test('should work with minimal infinite loop reproduction example', () => {
const result = shouldBreak(
{
type: 'VIEW',
props: { minPresenceAhead: 100 },
style: {},
children: [],
box: {
top: 30,
right: 0,
bottom: 0,
left: 0,
height: 0,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
[
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 30,
right: 0,
bottom: 0,
left: 0,
height: 71,
width: 200,
marginTop: 0,
marginBottom: 0,
},
},
{
type: 'VIEW',
props: {},
style: {},
children: [],
box: {
top: 131,
right: 0,
bottom: 0,
left: 0,
height: 0,
width: 200,
marginTop: 30,
marginBottom: 0,
},
},
],
811.89,
[],
);
expect(result).toEqual(false);
});
test('should work with reproduction from #2303', () => {
const result = shouldBreak(
{
type: 'TEXT',
box: {
paddingTop: 0,
paddingRight: 0,
paddingBottom: 0,
paddingLeft: 0,
marginTop: 12,
marginRight: 12,
marginBottom: 12,
marginLeft: 12,
borderTopWidth: 0,
borderRightWidth: 0,
borderBottomWidth: 0,
borderLeftWidth: 0,
top: 541.7999877929688,
right: 12,
bottom: 12,
left: 72,
width: 451.280029296875,
height: 250.8800048828125,
},
style: {
marginTop: 12,
marginRight: 12,
marginBottom: 12,
marginLeft: 12,
fontSize: 14,
textAlign: 'justify',
fontFamily: 'Times-Roman',
},
props: {
minPresenceAhead: 4,
},
children: [
{
type: 'TEXT_INSTANCE',
value:
'En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que carnero, salpicón las más noches, duelos y quebrantos los sábados, lentejas los viernes, algún palomino de añadidura los domingos, consumían las tres partes de su hacienda. El resto della concluían sayo de velarte, calzas de velludo para las fiestas con sus pantuflos de lo mismo, los días de entre semana se honraba con su vellori de lo más fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que así ensillaba el rocín como tomaba la podadera. Frisaba la edad de nuestro hidalgo con los cincuenta años, era de complexión recia, seco de carnes, enjuto de rostro; gran madrugador y amigo de la caza. Quieren decir que tenía el sobrenombre de Quijada o Quesada (que en esto hay alguna diferencia en los autores que deste caso escriben), aunque por conjeturas verosímiles se deja entender que se llama Quijana; pero esto importa poco a nuestro cuento; basta que en la narración dél no se salga un punto de la verdad',
},
],
},
[
{
type: 'TEXT',
box: {
paddingTop: 0,
paddingRight: 0,
paddingBottom: 0,
paddingLeft: 0,
marginTop: 550,
marginRight: 0,
marginBottom: 0,
marginLeft: 0,
borderTopWidth: 0,
borderRightWidth: 0,
borderBottomWidth: 0,
borderLeftWidth: 0,
top: 1354.679931640625,
right: 0,
bottom: 0,
left: 60,
width: 475.280029296875,
height: 19.799999237060547,
},
style: {
marginTop: 550,
},
props: {},
children: [
{
type: 'TEXT_INSTANCE',
value: 'Orphans example. Try changing prop value',
},
],
},
{
type: 'TEXT',
box: {
paddingTop: 0,
paddingRight: 0,
paddingBottom: 0,
paddingLeft: 0,
marginTop: 12,
marginRight: 12,
marginBottom: 12,
marginLeft: 12,
borderTopWidth: 0,
borderRightWidth: 0,
borderBottomWidth: 0,
borderLeftWidth: 0,
top: 1386.47998046875,
right: 12,
bottom: 12,
left: 72,
width: 451.280029296875,
height: 250.8800048828125,
},
style: {
marginTop: 12,
marginRight: 12,
marginBottom: 12,
marginLeft: 12,
fontSize: 14,
textAlign: 'justify',
fontFamily: 'Times-Roman',
},
props: {
orphans: 4,
},
children: [
{
type: 'TEXT_INSTANCE',
value:
'En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que carnero, salpicón las más noches, duelos y quebrantos los sábados, lentejas los viernes, algún palomino de añadidura los domingos, consumían las tres partes de su hacienda. El resto della concluían sayo de velarte, calzas de velludo para las fiestas con sus pantuflos de lo mismo, los días de entre semana se honraba con su vellori de lo más fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo de campo y plaza, que así ensillaba el rocín como tomaba la podadera. Frisaba la edad de nuestro hidalgo con los cincuenta años, era de complexión recia, seco de carnes, enjuto de rostro; gran madrugador y amigo de la caza. Quieren decir que tenía el sobrenombre de Quijada o Quesada (que en esto hay alguna diferencia en los autores que deste caso escriben), aunque por conjeturas verosímiles se deja entender que se llama Quijana; pero esto importa poco a nuestro cuento; basta que en la narración dél no se salga un punto de la verdad',
},
],
},
],
781.89,
[],
);
expect(result).toEqual(false);
});
test('should not break when the child can wrap', () => {
const result = shouldBreak(
{
type: 'TEXT',
props: {},
style: {},
children: [],
box: {
top: 425.23779296875,
right: 0,
bottom: 0,
left: 0,
height: 419.439453125,
width: 200,
marginTop: 12,
marginBottom: 12,
},
},
[
{
type: 'TEXT',
props: {},
style: {},
children: [],
box: {
top: 868.67724609375,
right: 0,
bottom: 0,
left: 0,
height: 247.8505859375,
width: 200,
marginTop: 12,
marginBottom: 12,
},
},
],
776.89,
[],
);
expect(result).toEqual(false);
});
});
================================================
FILE: packages/layout/tests/page/getOrientation.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getOrientation from '../../src/page/getOrientation';
describe('page getOrientation', () => {
test('Should return portrait if no orientation provided', () => {
const orientation = getOrientation({ type: 'PAGE', props: {} });
expect(orientation).toBe('portrait');
});
test('Should return landscape if landscape', () => {
const orientation = getOrientation({
type: 'PAGE',
props: { orientation: 'landscape' },
});
expect(orientation).toBe('landscape');
});
test('Should return portrait if portait', () => {
const orientation = getOrientation({
type: 'PAGE',
props: { orientation: 'portrait' },
});
expect(orientation).toBe('portrait');
});
test('Should return portrait if anything else', () => {
const orientation = getOrientation({
type: 'PAGE',
props: { orientation: 'boo' as any },
});
expect(orientation).toBe('portrait');
});
});
================================================
FILE: packages/layout/tests/page/getSize.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getSize from '../../src/page/getSize';
describe('page getSize', () => {
test('should default to A4', () => {
const size = getSize({ type: 'PAGE', props: {} });
expect(size).toHaveProperty('width', 595.28);
expect(size).toHaveProperty('height', 841.89);
});
test('should default to portrait A4', () => {
const size = getSize({
type: 'PAGE',
props: { orientation: 'portrait' },
});
expect(size).toHaveProperty('width', 595.28);
expect(size).toHaveProperty('height', 841.89);
});
test('should accept size string', () => {
const size = getSize({ type: 'PAGE', props: { size: 'A2' } });
expect(size).toHaveProperty('width', 1190.55);
expect(size).toHaveProperty('height', 1683.78);
});
test('should accept size string in landscape mode', () => {
const size = getSize({
type: 'PAGE',
props: { size: 'A2', orientation: 'landscape' },
});
expect(size).toHaveProperty('width', 1683.78);
expect(size).toHaveProperty('height', 1190.55);
});
test('should accept size number array', () => {
const size = getSize({ type: 'PAGE', props: { size: [100, 200] } });
expect(size).toHaveProperty('width', 100);
expect(size).toHaveProperty('height', 200);
});
test('should accept size string array', () => {
const size = getSize({ type: 'PAGE', props: { size: ['50px', '1in'] } });
expect(size).toHaveProperty('width', 50);
expect(size).toHaveProperty('height', 72);
});
test('should accept size number array in landscape mode', () => {
const size = getSize({
type: 'PAGE',
props: { size: [100, 200], orientation: 'landscape' },
});
expect(size).toHaveProperty('width', 200);
expect(size).toHaveProperty('height', 100);
});
test('should accept size string array in landscape mode', () => {
const size = getSize({
type: 'PAGE',
props: { size: ['50px', '1in'], orientation: 'landscape' },
});
expect(size).toHaveProperty('width', 72);
expect(size).toHaveProperty('height', 50);
});
test('should accept number size object', () => {
const size = getSize({
type: 'PAGE',
props: { size: { width: 100, height: 200 } },
});
expect(size).toHaveProperty('width', 100);
expect(size).toHaveProperty('height', 200);
});
test('should accept string size object', () => {
const size = getSize({
type: 'PAGE',
props: { size: { width: '50px', height: '1in' } },
});
expect(size).toHaveProperty('width', 50);
expect(size).toHaveProperty('height', 72);
});
test('should accept size object in landscape mode', () => {
const size = getSize({
type: 'PAGE',
props: { size: { width: 100, height: 200 }, orientation: 'landscape' },
});
expect(size).toHaveProperty('width', 200);
expect(size).toHaveProperty('height', 100);
});
test('should accept string size object in landscape mode', () => {
const size = getSize({
type: 'PAGE',
props: {
size: { width: '50px', height: '1in' },
orientation: 'landscape',
},
});
expect(size).toHaveProperty('width', 72);
expect(size).toHaveProperty('height', 50);
});
test('should accept size number', () => {
const size = getSize({ type: 'PAGE', props: { size: 100 } });
expect(size).toHaveProperty('width', 100);
expect(size).toHaveProperty('height', 100);
});
test('should accept size number in landscape mode', () => {
const size = getSize({
type: 'PAGE',
props: { size: 100, orientation: 'landscape' },
});
expect(size).toHaveProperty('width', 100);
expect(size).toHaveProperty('height', 100);
});
});
================================================
FILE: packages/layout/tests/page/isHeightAuto.test.ts
================================================
import { describe, expect, test } from 'vitest';
import isHeightAuto from '../../src/page/isHeightAuto';
describe('page isHeightAuto', () => {
test('Should return false if height present', () => {
const result = isHeightAuto({
type: 'PAGE',
props: {},
box: { width: 100, height: 10 },
});
expect(result).toBeFalsy();
});
test('Should return false if height is zero', () => {
const result = isHeightAuto({
type: 'PAGE',
props: {},
box: { width: 100, height: 0 },
});
expect(result).toBeFalsy();
});
test('Should return false if height not present', () => {
const result = isHeightAuto({
type: 'PAGE',
props: {},
box: { width: 100 },
});
expect(result).toBeTruthy();
});
test('Should return false if height is null', () => {
const result = isHeightAuto({
type: 'PAGE',
props: {},
box: { width: 100, height: null as any },
});
expect(result).toBeTruthy();
});
test('Should return false if height is undefined', () => {
const result = isHeightAuto({
type: 'PAGE',
props: {},
box: { width: 100, height: undefined },
});
expect(result).toBeTruthy();
});
});
================================================
FILE: packages/layout/tests/page/isLandscape.test.ts
================================================
import { describe, expect, test } from 'vitest';
import isLandscape from '../../src/page/isLandscape';
describe('page isLandscape', () => {
test('Should return false if no orientation provided', () => {
const result = isLandscape({ type: 'PAGE', props: {} });
expect(result).toBeFalsy();
});
test('Should return true if landscape', () => {
const result = isLandscape({
type: 'PAGE',
props: { orientation: 'landscape' },
});
expect(result).toBeTruthy();
});
test('Should return false if portait', () => {
const result = isLandscape({
type: 'PAGE',
props: { orientation: 'portrait' },
});
expect(result).toBeFalsy();
});
});
================================================
FILE: packages/layout/tests/page/isPortrait.test.ts
================================================
import { describe, expect, test } from 'vitest';
import isPortrait from '../../src/page/isPortrait';
describe('page isPortrait', () => {
test('Should return true if no orientation provided', () => {
const result = isPortrait({ type: 'PAGE', props: {} });
expect(result).toBeTruthy();
});
test('Should return false if landscape', () => {
const result = isPortrait({
type: 'PAGE',
props: { orientation: 'landscape' },
});
expect(result).toBeFalsy();
});
test('Should return true if portait', () => {
const result = isPortrait({
type: 'PAGE',
props: { orientation: 'portrait' },
});
expect(result).toBeTruthy();
});
});
================================================
FILE: packages/layout/tests/steps/__snapshots__/resolveLinkSubstitution.test.ts.snap
================================================
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`layout resolve link substitution > Should leave link with text children as it is 1`] = `
{
"children": [
{
"children": [
{
"children": [
{
"props": {},
"type": "TEXT",
},
],
"props": {
"src": "url",
},
"type": "LINK",
},
],
"props": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolve link substitution > Should replace link with only many text instances as children 1`] = `
{
"children": [
{
"children": [
{
"children": [
{
"box": {},
"children": [
{
"type": "TEXT_INSTANCE",
"value": "1",
},
{
"type": "TEXT_INSTANCE",
"value": "2",
},
{
"type": "TEXT_INSTANCE",
"value": "3",
},
{
"type": "TEXT_INSTANCE",
"value": "4",
},
],
"props": {},
"style": {},
"type": "TEXT",
},
],
"props": {
"src": "url",
},
"type": "LINK",
},
],
"props": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolve link substitution > Should replace link with only one text instance as children 1`] = `
{
"children": [
{
"children": [
{
"children": [
{
"box": {},
"children": [
{
"type": "TEXT_INSTANCE",
"value": "1",
},
],
"props": {},
"style": {},
"type": "TEXT",
},
],
"props": {
"src": "url",
},
"type": "LINK",
},
],
"props": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolve link substitution > Should replace link with render prop 1`] = `
{
"children": [
{
"children": [
{
"props": {
"render": [Function],
},
"type": "TEXT",
},
],
"props": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
================================================
FILE: packages/layout/tests/steps/__snapshots__/resolveOrigins.test.ts.snap
================================================
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`layout resolveOrigins > should not resolve for node without box 1`] = `
{
"children": [
{
"children": [
{
"origin": null,
"props": {},
"style": {},
"type": "VIEW",
},
],
"origin": null,
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveOrigins > should resolve centered origin by default 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 400,
"left": 100,
"right": 0,
"top": 50,
"width": 300,
},
"origin": {
"left": 250,
"top": 250,
},
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveOrigins > should resolve origin adjusted by fixed values 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 400,
"left": 100,
"right": 0,
"top": 50,
"width": 300,
},
"origin": {
"left": 200,
"top": 100,
},
"props": {},
"style": {
"transformOriginX": 100,
"transformOriginY": 50,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveOrigins > should resolve origin adjusted by percent values 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 400,
"left": 100,
"right": 0,
"top": 50,
"width": 300,
},
"origin": {
"left": 160,
"top": 330,
},
"props": {},
"style": {
"transformOriginX": "20%",
"transformOriginY": "70%",
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveOrigins > should resolve origins for nested elements 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 400,
"left": 100,
"right": 0,
"top": 50,
"width": 300,
},
"children": [
{
"box": {
"bottom": 0,
"height": 80,
"left": 10,
"right": 0,
"top": 0,
"width": 50,
},
"origin": {
"left": 35,
"top": 40,
},
"props": {},
"style": {},
"type": "VIEW",
},
],
"origin": {
"left": 250,
"top": 250,
},
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
================================================
FILE: packages/layout/tests/steps/__snapshots__/resolvePagePaddings.test.ts.snap
================================================
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`layout resolvePagePaddings > Should keep other styles untouched 1`] = `
{
"children": [
{
"props": {},
"style": {
"color": "red",
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should leave numeric paddingBottom as it is 1`] = `
{
"children": [
{
"props": {},
"style": {
"paddingBottom": 50,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should leave numeric paddingLeft as it is 1`] = `
{
"children": [
{
"props": {},
"style": {
"paddingLeft": 50,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should leave numeric paddingRight as it is 1`] = `
{
"children": [
{
"props": {},
"style": {
"paddingRight": 50,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should leave numeric paddingTop as it is 1`] = `
{
"children": [
{
"props": {},
"style": {
"paddingTop": 50,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should resolve percent paddingBottom 1`] = `
{
"children": [
{
"props": {},
"style": {
"height": 200,
"paddingBottom": 20,
"width": 100,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should resolve percent paddingLeft 1`] = `
{
"children": [
{
"props": {},
"style": {
"height": 200,
"paddingLeft": 10,
"width": 100,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should resolve percent paddingRight 1`] = `
{
"children": [
{
"props": {},
"style": {
"height": 200,
"paddingRight": 10,
"width": 100,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should resolve percent paddingTop 1`] = `
{
"children": [
{
"props": {},
"style": {
"height": 200,
"paddingTop": 20,
"width": 100,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePagePaddings > Should resolve several pages 1`] = `
{
"children": [
{
"props": {},
"style": {
"height": 200,
"paddingTop": 10,
"width": 100,
},
"type": "PAGE",
},
{
"props": {},
"style": {
"height": 200,
"paddingBottom": 20,
"width": 100,
},
"type": "PAGE",
},
{
"props": {},
"style": {
"height": 200,
"paddingLeft": 10,
"paddingRight": 10,
"width": 100,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
================================================
FILE: packages/layout/tests/steps/__snapshots__/resolvePercentHeight.test.ts.snap
================================================
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`layout resolvePercentHeight > Should keep empty document untouched 1`] = `
{
"children": [],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePercentHeight > Should keep empty page untouched 1`] = `
{
"children": [
{
"children": [],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePercentHeight > Should not resolve children if page dont have height 1`] = `
{
"children": [
{
"children": [
{
"props": {},
"style": {
"height": "80%",
"width": "60%",
},
"type": "VIEW",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolvePercentHeight > Should resolve children percent dimensions if page have height 1`] = `
{
"children": [
{
"children": [
{
"props": {},
"style": {
"height": 800,
},
"type": "VIEW",
},
],
"props": {},
"style": {
"height": 1000,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
================================================
FILE: packages/layout/tests/steps/__snapshots__/resolveStyles.test.ts.snap
================================================
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`layout resolveStyles > Should overide default link styles 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 200,
"left": 0,
"right": 0,
"top": 0,
"width": 100,
},
"children": [
{
"props": {},
"style": {
"color": "wheat",
"textDecoration": "none",
},
"type": "LINK",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should overide default link styles with array 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 200,
"left": 0,
"right": 0,
"top": 0,
"width": 100,
},
"children": [
{
"props": {},
"style": {
"color": "wheat",
"textDecoration": "none",
},
"type": "LINK",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve default link styles 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 200,
"left": 0,
"right": 0,
"top": 0,
"width": 100,
},
"children": [
{
"props": {},
"style": {
"color": "blue",
"textDecoration": "underline",
},
"type": "LINK",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve nested node styles 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 200,
"left": 0,
"right": 0,
"top": 0,
"width": 100,
},
"children": [
{
"props": {},
"style": {
"backgroundColor": "red",
"borderBottomColor": "green",
"borderBottomStyle": "dotted",
"borderBottomWidth": 28.346456692913385,
"borderLeftColor": "green",
"borderLeftStyle": "dotted",
"borderLeftWidth": 28.346456692913385,
"borderRightColor": "green",
"borderRightStyle": "dotted",
"borderRightWidth": 28.346456692913385,
"borderTopColor": "green",
"borderTopStyle": "dotted",
"borderTopWidth": 28.346456692913385,
"paddingBottom": 28.34645669291339,
"paddingLeft": 720,
"paddingRight": 720,
"paddingTop": 28.34645669291339,
},
"type": "VIEW",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve nested node styles array 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 200,
"left": 0,
"right": 0,
"top": 0,
"width": 100,
},
"children": [
{
"props": {},
"style": {
"backgroundColor": "red",
"borderBottomColor": "green",
"borderBottomStyle": "dotted",
"borderBottomWidth": 28.346456692913385,
"borderLeftColor": "green",
"borderLeftStyle": "dotted",
"borderLeftWidth": 28.346456692913385,
"borderRightColor": "green",
"borderRightStyle": "dotted",
"borderRightWidth": 28.346456692913385,
"borderTopColor": "green",
"borderTopStyle": "dotted",
"borderTopWidth": 28.346456692913385,
"paddingBottom": 28.34645669291339,
"paddingLeft": 720,
"paddingRight": 720,
"paddingTop": 28.34645669291339,
},
"type": "VIEW",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve nested node styles media queries 1`] = `
{
"children": [
{
"box": {
"bottom": 0,
"height": 200,
"left": 0,
"right": 0,
"top": 0,
"width": 100,
},
"children": [
{
"props": {},
"style": {
"backgroundColor": "green",
},
"type": "VIEW",
},
{
"props": {},
"style": {
"backgroundColor": "red",
},
"type": "VIEW",
},
],
"props": {},
"style": {},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve nested node styles media queries with page style 1`] = `
{
"children": [
{
"children": [
{
"props": {},
"style": {
"backgroundColor": "green",
},
"type": "VIEW",
},
{
"props": {},
"style": {
"backgroundColor": "red",
},
"type": "VIEW",
},
],
"props": {},
"style": {
"height": 200,
"width": 100,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve page styles 1`] = `
{
"children": [
{
"props": {},
"style": {
"backgroundColor": "red",
"borderBottomColor": "green",
"borderBottomStyle": "dotted",
"borderBottomWidth": 28.346456692913385,
"borderLeftColor": "green",
"borderLeftStyle": "dotted",
"borderLeftWidth": 28.346456692913385,
"borderRightColor": "green",
"borderRightStyle": "dotted",
"borderRightWidth": 28.346456692913385,
"borderTopColor": "green",
"borderTopStyle": "dotted",
"borderTopWidth": 28.346456692913385,
"paddingBottom": 28.34645669291339,
"paddingLeft": 720,
"paddingRight": 720,
"paddingTop": 28.34645669291339,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve page styles array 1`] = `
{
"children": [
{
"props": {},
"style": {
"backgroundColor": "red",
"borderBottomColor": "green",
"borderBottomStyle": "dotted",
"borderBottomWidth": 28.346456692913385,
"borderLeftColor": "green",
"borderLeftStyle": "dotted",
"borderLeftWidth": 28.346456692913385,
"borderRightColor": "green",
"borderRightStyle": "dotted",
"borderRightWidth": 28.346456692913385,
"borderTopColor": "green",
"borderTopStyle": "dotted",
"borderTopWidth": 28.346456692913385,
"paddingBottom": 28.34645669291339,
"paddingLeft": 720,
"paddingRight": 720,
"paddingTop": 28.34645669291339,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
exports[`layout resolveStyles > Should resolve several pages styles 1`] = `
{
"children": [
{
"props": {},
"style": {
"borderTopColor": "#FF00000",
"borderTopStyle": "solid",
"borderTopWidth": 4,
"paddingBottom": 28.34645669291339,
"paddingLeft": 720,
"paddingRight": 720,
"paddingTop": 28.34645669291339,
},
"type": "PAGE",
},
{
"props": {},
"style": {
"backgroundColor": "red",
"borderBottomColor": "green",
"borderBottomStyle": "dotted",
"borderBottomWidth": 28.346456692913385,
"borderLeftColor": "green",
"borderLeftStyle": "dotted",
"borderLeftWidth": 28.346456692913385,
"borderRightColor": "green",
"borderRightStyle": "dotted",
"borderRightWidth": 28.346456692913385,
"borderTopColor": "green",
"borderTopStyle": "dotted",
"borderTopWidth": 28.346456692913385,
"fontWeight": 700,
},
"type": "PAGE",
},
],
"props": {},
"type": "DOCUMENT",
}
`;
================================================
FILE: packages/layout/tests/steps/resolveBookmarks.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolveBookmarks from '../../src/steps/resolveBookmarks';
import { DocumentNode } from '../../src/types';
describe('layout resolveBookmarks', () => {
test('should keep nodes the same if no bookmark passed', () => {
const root = {
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
children: [{ type: 'VIEW', props: {} }],
},
],
} as DocumentNode;
const result = resolveBookmarks(root);
expect(result).toEqual({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
children: [{ type: 'VIEW', props: {} }],
},
],
});
});
test('should keep nodes the same if an undefined bookmark passed', () => {
const root = {
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { bookmark: undefined },
children: [{ type: 'VIEW', props: {} }],
},
],
} as DocumentNode;
const result = resolveBookmarks(root);
expect(result).toEqual({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { bookmark: undefined },
children: [{ type: 'VIEW', props: {} }],
},
],
});
});
test('should keep nodes the same if a null bookmark passed', () => {
const root = {
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { bookmark: null },
children: [{ type: 'VIEW', props: {} }],
},
],
} as DocumentNode;
const result = resolveBookmarks(root);
expect(result).toEqual({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { bookmark: null },
children: [{ type: 'VIEW', props: {} }],
},
],
});
});
test('should resolve bookmark in page node', () => {
const result = resolveBookmarks({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { bookmark: 'page' },
children: [{ type: 'VIEW', props: {} }],
},
],
});
expect(result.children?.[0]?.props?.bookmark).toEqual({
ref: 0,
title: 'page',
fit: false,
expanded: false,
});
});
test('should resolve bookmark hierarchy', () => {
const result = resolveBookmarks({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { bookmark: 'page' },
children: [
{
type: 'VIEW',
children: [
{
type: 'VIEW',
children: [
{
type: 'VIEW',
props: {
bookmark: 'sub chapter',
},
},
],
props: {
bookmark: 'chapter 1',
},
},
],
props: {},
},
{
type: 'VIEW',
props: {
bookmark: 'chapter 2',
},
},
],
},
],
});
const page = result.children[0];
const view = page.children![1];
const nestedView = page.children![0].children![0];
const subNestedView = nestedView!.children![0];
expect(page.props.bookmark).toEqual({
ref: 0,
title: 'page',
fit: false,
expanded: false,
});
expect(view.props.bookmark).toEqual({
ref: 1,
parent: 0,
title: 'chapter 2',
fit: false,
expanded: false,
});
expect(nestedView.props!.bookmark).toEqual({
ref: 2,
parent: 0,
title: 'chapter 1',
fit: false,
expanded: false,
});
expect(subNestedView!.props!.bookmark).toEqual({
ref: 3,
parent: 2,
title: 'sub chapter',
fit: false,
expanded: false,
});
});
test('should resolve bookmark object prop', () => {
const result = resolveBookmarks({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {
bookmark: {
title: 'page',
top: 20,
left: 10,
zoom: 5,
expanded: true,
},
},
children: [{ type: 'VIEW', props: {} }],
},
],
});
expect(result.children[0].props.bookmark).toEqual({
ref: 0,
title: 'page',
expanded: true,
top: 20,
left: 10,
zoom: 5,
});
});
});
================================================
FILE: packages/layout/tests/steps/resolveInhritance.test.ts
================================================
/* eslint-disable vitest/expect-expect */
import { describe, expect, test } from 'vitest';
import resolveInheritance from '../../src/steps/resolveInheritance';
describe('layout resolveInheritance', () => {
const shouldInherit = (prop) => () => {
const result = resolveInheritance({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { [prop]: 'value' },
children: [{ type: 'VIEW', props: {}, style: {} }],
},
],
});
const view = result.children[0].children[0];
expect(view.style).toHaveProperty(prop, 'value');
};
test('Should not inherit invalid property', () => {
const result = resolveInheritance({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { backgroundColor: 'value' },
children: [{ type: 'VIEW', props: {}, style: {} }],
},
],
});
const view = result.children[0].children[0];
expect(view.style).not.toHaveProperty('backgroundColor');
});
test('Should not override descendents styles', () => {
const result = resolveInheritance({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { color: 'red' },
children: [{ type: 'VIEW', props: {}, style: { color: 'green' } }],
},
],
});
const view = result.children[0].children[0];
expect(view.style).toHaveProperty('color', 'green');
});
test('Should only inherit node descendents', () => {
const result = resolveInheritance({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
style: {},
props: {},
children: [
{ type: 'VIEW', props: {}, style: {} },
{
type: 'VIEW',
props: {},
style: { color: 'green' },
children: [{ type: 'VIEW', props: {}, style: {} }],
},
],
},
],
});
const view1 = result.children[0].children[0];
const view2 = result.children[0].children[1];
const subview = view2.children[0];
expect(view1.style).not.toHaveProperty('color');
expect(view2.style).toHaveProperty('color', 'green');
expect(subview.style).toHaveProperty('color', 'green');
});
test('Should inherit multiple textDecoration properly', () => {
const result = resolveInheritance({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {},
children: [
{
type: 'TEXT',
props: {},
style: { textDecoration: 'line-through' },
children: [
{
type: 'TEXT',
props: {},
style: { textDecoration: 'underline' },
},
],
},
],
},
],
});
const text1 = result.children[0].children[0];
const text2 = text1.children[0];
expect(text1.style).toHaveProperty('textDecoration', 'line-through');
expect(text2.style).toHaveProperty(
'textDecoration',
'line-through underline',
);
});
test('Should inherit background color for text childs', () => {
const result = resolveInheritance({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {},
children: [
{
type: 'TEXT',
props: {},
style: { backgroundColor: 'red' },
children: [
{
type: 'TEXT',
props: {},
style: {},
children: [{ type: 'TEXT_INSTANCE', value: 'Hello' }],
},
],
},
],
},
],
});
const text1 = result.children[0].children[0];
const text2 = text1.children[0];
expect(text1.style).toHaveProperty('backgroundColor', 'red');
expect(text2.style).toHaveProperty('backgroundColor', 'red');
});
test('Should inherit color value', shouldInherit('color'));
test('Should inherit fontFamily value', shouldInherit('fontFamily'));
test('Should inherit fontSize value', shouldInherit('fontSize'));
test('Should inherit fontStyle value', shouldInherit('fontStyle'));
test('Should inherit fontWeight value', shouldInherit('fontWeight'));
test('Should inherit letterSpacing value', shouldInherit('letterSpacing'));
test('Should inherit opacity value', shouldInherit('opacity'));
test('Should inherit textDecoration value', shouldInherit('textDecoration'));
test('Should inherit textTransform value', shouldInherit('textTransform'));
test('Should inherit lineHeight value', shouldInherit('lineHeight'));
test('Should inherit textAlign value', shouldInherit('textAlign'));
test('Should inherit visibility value', shouldInherit('visibility'));
test('Should inherit wordSpacing value', shouldInherit('wordSpacing'));
});
================================================
FILE: packages/layout/tests/steps/resolveLinkSubstitution.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolveLinkSubstitution from '../../src/steps/resolveLinkSubstitution';
describe('layout resolve link substitution', () => {
test('Should leave link with text children as it is', () => {
const result = resolveLinkSubstitution({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
children: [
{
type: 'LINK',
props: { src: 'url' },
children: [
{
type: 'TEXT',
props: {},
},
],
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should replace link with only one text instance as children', () => {
const result = resolveLinkSubstitution({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
children: [
{
type: 'LINK',
props: { src: 'url' },
children: [{ type: 'TEXT_INSTANCE', value: '1' }],
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should replace link with only many text instances as children', () => {
const result = resolveLinkSubstitution({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
children: [
{
type: 'LINK',
props: { src: 'url' },
children: [
{ type: 'TEXT_INSTANCE', value: '1' },
{ type: 'TEXT_INSTANCE', value: '2' },
{ type: 'TEXT_INSTANCE', value: '3' },
{ type: 'TEXT_INSTANCE', value: '4' },
],
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should replace link with render prop', () => {
const result = resolveLinkSubstitution({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
children: [
{
type: 'LINK',
props: {
render: () => null,
},
},
],
},
],
});
expect(result).toMatchSnapshot();
});
});
================================================
FILE: packages/layout/tests/steps/resolveOrigins.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolveOrigins from '../../src/steps/resolveOrigins';
describe('layout resolveOrigins', () => {
test('should not resolve for node without box', () => {
const result = resolveOrigins({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
style: {},
props: {},
children: [{ type: 'VIEW', props: {}, style: {} }],
},
],
});
expect(result).toMatchSnapshot();
});
test('should resolve centered origin by default', () => {
const result = resolveOrigins({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
style: {},
props: {},
box: {
top: 50,
left: 100,
bottom: 0,
right: 0,
width: 300,
height: 400,
},
},
],
});
expect(result).toMatchSnapshot();
});
test('should resolve origin adjusted by fixed values', () => {
const result = resolveOrigins({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 50,
left: 100,
bottom: 0,
right: 0,
width: 300,
height: 400,
},
style: { transformOriginX: 100, transformOriginY: 50 },
},
],
});
expect(result).toMatchSnapshot();
});
test('should resolve origin adjusted by percent values', () => {
const result = resolveOrigins({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 50,
left: 100,
bottom: 0,
right: 0,
width: 300,
height: 400,
},
style: { transformOriginX: '20%', transformOriginY: '70%' },
},
],
});
expect(result).toMatchSnapshot();
});
test('should resolve origins for nested elements', () => {
const result = resolveOrigins({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
style: {},
props: {},
box: {
top: 50,
left: 100,
bottom: 0,
right: 0,
width: 300,
height: 400,
},
children: [
{
type: 'VIEW',
style: {},
props: {},
box: {
top: 0,
left: 10,
bottom: 0,
right: 0,
width: 50,
height: 80,
},
},
],
},
],
});
expect(result).toMatchSnapshot();
});
});
================================================
FILE: packages/layout/tests/steps/resolvePagePaddings.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolvePagePaddings from '../../src/steps/resolvePagePaddings';
describe('layout resolvePagePaddings', () => {
test('Should keep other styles untouched', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {}, style: { color: 'red' } }],
});
expect(result).toMatchSnapshot();
});
test('Should leave numeric paddingTop as it is', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {}, style: { paddingTop: 50 } }],
});
expect(result).toMatchSnapshot();
});
test('Should leave numeric paddingRight as it is', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {}, style: { paddingRight: 50 } }],
});
expect(result).toMatchSnapshot();
});
test('Should leave numeric paddingBottom as it is', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {}, style: { paddingBottom: 50 } }],
});
expect(result).toMatchSnapshot();
});
test('Should leave numeric paddingLeft as it is', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {}, style: { paddingLeft: 50 } }],
});
expect(result).toMatchSnapshot();
});
test('Should resolve percent paddingTop', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { paddingTop: '10%' as any, width: 100, height: 200 },
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve percent paddingRight', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { paddingRight: '10%' as any, width: 100, height: 200 },
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve percent paddingBottom', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { paddingBottom: '10%' as any, width: 100, height: 200 },
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve percent paddingLeft', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { paddingLeft: '10%' as any, width: 100, height: 200 },
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve several pages', () => {
const result = resolvePagePaddings({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { paddingTop: 10, width: 100, height: 200 },
},
{
type: 'PAGE',
props: {},
style: { paddingBottom: '10%' as any, width: 100, height: 200 },
},
{
type: 'PAGE',
props: {},
style: {
paddingRight: 10,
paddingLeft: '10%' as any,
width: 100,
height: 200,
},
},
],
});
expect(result).toMatchSnapshot();
});
});
================================================
FILE: packages/layout/tests/steps/resolvePageSizes.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolvePageSizes from '../../src/steps/resolvePageSizes';
describe('layout resolvePageSizes', () => {
test('Should default to A4', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {} }],
});
expect(result.children[0].style).toHaveProperty('width', 595.28);
expect(result.children[0].style).toHaveProperty('height', 841.89);
});
test('Should default to portrait A4', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: { orientation: 'portrait' } }],
});
expect(result.children[0].style).toHaveProperty('width', 595.28);
expect(result.children[0].style).toHaveProperty('height', 841.89);
});
test('Should accept size string', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: { size: 'A2' } }],
});
expect(result.children[0].style).toHaveProperty('width', 1190.55);
expect(result.children[0].style).toHaveProperty('height', 1683.78);
});
test('Should accept size string in landscape mode', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{ type: 'PAGE', props: { size: 'A2', orientation: 'landscape' } },
],
});
expect(result.children[0].style).toHaveProperty('width', 1683.78);
expect(result.children[0].style).toHaveProperty('height', 1190.55);
});
test('Should accept size array', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: { size: [100, 200] } }],
});
expect(result.children[0].style).toHaveProperty('width', 100);
expect(result.children[0].style).toHaveProperty('height', 200);
});
test('Should accept size array in landscape mode', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { size: [100, 200], orientation: 'landscape' },
},
],
});
expect(result.children[0].style).toHaveProperty('width', 200);
expect(result.children[0].style).toHaveProperty('height', 100);
});
test('Should accept size object', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{ type: 'PAGE', props: { size: { width: 100, height: 200 } } },
],
});
expect(result.children[0].style).toHaveProperty('width', 100);
expect(result.children[0].style).toHaveProperty('height', 200);
});
test('Should accept size object in landscape mode', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {
size: { width: 100, height: 200 },
orientation: 'landscape',
},
},
],
});
expect(result.children[0].style).toHaveProperty('width', 200);
expect(result.children[0].style).toHaveProperty('height', 100);
});
test('Should accept size number', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: { size: 100 } }],
});
expect(result.children[0].style).toHaveProperty('width', 100);
expect(result.children[0].style).toHaveProperty('height', 100);
});
test('Should accept size number in landscape mode', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{ type: 'PAGE', props: { size: 100, orientation: 'landscape' } },
],
});
expect(result.children[0].style).toHaveProperty('width', 100);
expect(result.children[0].style).toHaveProperty('height', 100);
});
test('Should resolve several pages', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{ type: 'PAGE', props: {} },
{ type: 'PAGE', props: { size: 'A5' } },
{ type: 'PAGE', props: { size: { width: 100, height: 200 } } },
],
});
expect(result.children[0].style).toHaveProperty('width', 595.28);
expect(result.children[0].style).toHaveProperty('height', 841.89);
expect(result.children[1].style).toHaveProperty('width', 419.53);
expect(result.children[1].style).toHaveProperty('height', 595.28);
expect(result.children[2].style).toHaveProperty('width', 100);
expect(result.children[2].style).toHaveProperty('height', 200);
});
test('Should flatten page styles', () => {
const result = resolvePageSizes({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: { size: 'A4' },
style: [{ backgroundColor: 'red' }],
},
],
});
expect(result.children[0].style).toHaveProperty('width', 595.28);
expect(result.children[0].style).toHaveProperty('height', 841.89);
expect(result.children[0].style).toHaveProperty('backgroundColor', 'red');
});
});
================================================
FILE: packages/layout/tests/steps/resolvePagination.test.ts
================================================
import { describe, expect, test } from 'vitest';
import FontStore from '@react-pdf/font';
import { loadYoga } from '../../src/yoga';
import resolvePagination from '../../src/steps/resolvePagination';
import resolveDimensions from '../../src/steps/resolveDimensions';
import { SafeDocumentNode } from '../../src/types';
const fontStore = new FontStore();
// dimensions is required by pagination step and them are calculated here
const calcLayout = (node: SafeDocumentNode) =>
resolvePagination(resolveDimensions(node, fontStore), fontStore);
describe('pagination step', () => {
test('should stretch absolute block to full page size', async () => {
const yoga = await loadYoga();
const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
width: 100,
height: 100,
},
children: [
{
type: 'VIEW',
style: {
position: 'absolute',
width: '50%',
top: 0,
bottom: 0,
},
props: {},
children: [],
},
{
type: 'TEXT',
style: {},
props: {},
children: [
{
type: 'TEXT_INSTANCE',
value: 'hello world',
},
],
},
],
},
],
});
const page = layout.children[0];
const view = layout.children[0]!.children![0];
expect(page.box!.height).toBe(100);
expect(view.box!.height).toBe(100);
});
test('should force new height for split nodes', async () => {
const yoga = await loadYoga();
const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
width: 15,
height: 60,
},
children: [
{
type: 'VIEW',
style: {},
props: {},
children: [
{
type: 'TEXT',
style: {},
props: {},
children: [
{
type: 'TEXT_INSTANCE',
value: 'a a a a',
},
],
},
],
},
],
},
],
});
const view1 = layout.children[0].children![0];
const view2 = layout.children[1].children![0];
expect(view1.box!.height).toBe(60);
expect(view2.box!.height).not.toBe(60);
});
test('should force new height for split nodes with fixed height', async () => {
const yoga = await loadYoga();
const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
width: 5,
height: 60,
},
children: [
{
type: 'VIEW',
style: { height: 130 },
props: {},
children: [],
},
],
},
],
});
const view1 = layout.children[0].children![0];
const view2 = layout.children[1].children![0];
const view3 = layout.children[2].children![0];
expect(view1.box!.height).toBe(60);
expect(view2.box!.height).toBe(60);
expect(view3.box!.height).toBe(10);
});
test('should not wrap page with false wrap prop', async () => {
const yoga = await loadYoga();
const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
children: [
{
type: 'PAGE',
style: {
width: 5,
height: 60,
},
props: {
wrap: false,
},
children: [
{
type: 'VIEW',
style: { height: 130 },
props: {},
children: [],
},
],
},
],
});
expect(layout.children.length).toBe(1);
});
test('should break on a container whose children can not fit on a page', async () => {
const yoga = await loadYoga();
const layout = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
width: 5,
height: 60,
},
children: [
{
type: 'VIEW',
style: {
width: 5,
height: 40,
},
props: {},
children: [],
},
{
type: 'VIEW',
style: {
width: 5,
},
props: {},
children: [
{
type: 'VIEW',
style: {
height: 40,
},
props: {
wrap: false,
},
children: [],
},
],
},
],
},
],
});
const page1 = layout.children[0];
const page2 = layout.children[1];
// Only the first view is displayed on the first page
expect(page1.children!.length).toBe(1);
// The second page displays the second wrapper, with its full height
expect(page2.children!.length).toBe(1);
expect(page2.children![0].box!.height).toBe(40);
});
test('should not infinitely loop when splitting pages', async () => {
const yoga = await loadYoga();
calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
height: 400,
},
children: [
{
type: 'VIEW',
style: { height: 401 },
props: {},
children: [
{
type: 'VIEW',
style: {
height: 400,
},
props: { wrap: false, break: true },
},
],
},
],
},
],
});
// If calcLayout returns then we did not hit an infinite loop
expect(true).toBe(true);
});
test('should take padding into account when splitting pages', async () => {
const yoga = await loadYoga();
const root = {
type: 'DOCUMENT' as const,
yoga,
props: {},
style: {},
children: [
{
type: 'PAGE' as const,
box: {
width: 612,
height: 792,
top: 0,
left: 0,
right: 612,
bottom: 792,
},
style: {
paddingTop: 30,
width: 612,
height: 792,
},
props: { wrap: true },
children: [
{
type: 'VIEW' as const,
box: {
width: 612,
height: 761,
top: 0,
left: 0,
right: 612,
bottom: 761,
},
style: { height: 761, marginBottom: 24 },
props: { wrap: true, break: false },
},
{
type: 'VIEW' as const,
box: {
width: 612,
height: 80,
top: 761,
left: 0,
right: 612,
bottom: 841,
},
style: { height: 80 },
props: { wrap: true, break: false },
},
],
},
],
};
calcLayout(root);
// If calcLayout returns then we did not hit an infinite loop
expect(true).toBe(true);
});
test('should not duplicate bookmarks', async () => {
const yoga = await loadYoga();
const bookmarkChapter1 = {
ref: 0,
title: 'chapter 1',
fit: false,
expanded: false,
};
const bookmarkChapter2 = {
ref: 1,
title: 'chapter 2',
fit: false,
expanded: false,
};
const bookmarkSubChapter1 = {
ref: 2,
parent: 1,
title: 'sub chapter 2',
fit: false,
expanded: false,
};
const bookmarkSubChapter2 = {
ref: 3,
parent: 1,
title: 'sub chapter 2',
fit: false,
expanded: false,
};
const bookmarkSubChapter3 = {
ref: 4,
parent: 1,
title: 'sub chapter 2',
fit: false,
expanded: false,
};
const result = calcLayout({
type: 'DOCUMENT',
yoga,
props: {},
style: {},
children: [
{
type: 'PAGE',
props: {},
style: { width: 5, height: 60 },
children: [
{
type: 'VIEW',
props: { bookmark: bookmarkChapter1 },
style: {
height: 30,
},
},
{
type: 'VIEW',
props: { bookmark: bookmarkChapter2 },
style: {},
children: [
{
type: 'VIEW',
props: {
bookmark: bookmarkSubChapter1,
},
style: {
height: 20,
},
children: [],
},
{
type: 'VIEW',
props: {
bookmark: bookmarkSubChapter2,
},
style: {
height: 20,
},
children: [],
},
{
type: 'VIEW',
props: {
bookmark: bookmarkSubChapter3,
},
style: {
height: 20,
},
children: [],
},
],
},
],
},
],
});
const page1 = result.children[0];
const page2 = result.children[1];
const chapter1 = page1.children![0];
const chapter2page1 = page1.children![1];
const chapter2page2 = page2.children![0];
const subChapter1 = chapter2page1.children![0];
const subChapter2page1 = chapter2page1.children![1];
const subChapter2page2 = chapter2page2.children![0];
const subChapter3 = chapter2page2.children![1];
expect(chapter1.props.bookmark).toEqual(bookmarkChapter1);
expect(chapter2page1.props.bookmark).toEqual(bookmarkChapter2);
expect(chapter2page2.props.bookmark).toEqual(null);
expect(subChapter1.props!.bookmark).toEqual(bookmarkSubChapter1);
expect(subChapter2page1.props!.bookmark).toEqual(bookmarkSubChapter2);
expect(subChapter2page2.props!.bookmark).toEqual(null);
expect(subChapter3.props!.bookmark).toEqual(bookmarkSubChapter3);
});
});
================================================
FILE: packages/layout/tests/steps/resolvePercentHeight.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolvePercentHeight from '../../src/steps/resolvePercentHeight';
describe('layout resolvePercentHeight', () => {
test('Should keep empty document untouched', () => {
const result = resolvePercentHeight({
type: 'DOCUMENT',
props: {},
children: [],
});
expect(result).toMatchSnapshot();
});
test('Should keep empty page untouched', () => {
const result = resolvePercentHeight({
type: 'DOCUMENT',
props: {},
children: [{ type: 'PAGE', props: {}, style: {}, children: [] }],
});
expect(result).toMatchSnapshot();
});
test('Should not resolve children if page dont have height', () => {
const result = resolvePercentHeight({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {},
children: [
{ type: 'VIEW', props: {}, style: { width: '60%', height: '80%' } },
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve children percent dimensions if page have height', () => {
const result = resolvePercentHeight({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { height: 1000 },
children: [{ type: 'VIEW', props: {}, style: { height: '80%' } }],
},
],
});
expect(result).toMatchSnapshot();
});
});
================================================
FILE: packages/layout/tests/steps/resolveStyles.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolveStyles from '../../src/steps/resolveStyles';
describe('layout resolveStyles', () => {
test('Should resolve page styles', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
paddingHorizontal: '10in',
paddingVertical: '10mm',
backgroundColor: 'red',
border: '1cm dotted green',
},
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve several pages styles', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: {
paddingHorizontal: '10in',
paddingVertical: '10mm',
borderTop: '4 solid #FF00000',
},
},
{
type: 'PAGE',
props: {},
style: {
backgroundColor: 'red',
border: '1cm dotted green',
fontWeight: 'bold',
},
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve page styles array', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: [
{
paddingHorizontal: '10in',
paddingVertical: '10mm',
},
{
backgroundColor: 'red',
border: '1cm dotted green',
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve nested node styles', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
},
children: [
{
type: 'VIEW',
props: {},
style: {
paddingHorizontal: '10in',
paddingVertical: '10mm',
backgroundColor: 'red',
border: '1cm dotted green',
},
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve nested node styles media queries', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
},
children: [
{
type: 'VIEW',
props: {},
style: {
backgroundColor: 'red',
'@media max-width: 500': {
backgroundColor: 'green',
},
},
},
{
type: 'VIEW',
props: {},
style: {
backgroundColor: 'red',
'@media min-width: 500': {
backgroundColor: 'green',
},
},
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve nested node styles media queries with page style', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
style: { width: 100, height: 200 },
children: [
{
type: 'VIEW',
props: {},
style: {
backgroundColor: 'red',
'@media max-width: 500': {
backgroundColor: 'green',
},
},
},
{
type: 'VIEW',
props: {},
style: {
backgroundColor: 'red',
'@media min-width: 500': {
backgroundColor: 'green',
},
},
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve nested node styles array', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
},
children: [
{
type: 'VIEW',
props: {},
style: [
{
paddingHorizontal: '10in',
paddingVertical: '10mm',
},
{
backgroundColor: 'red',
border: '1cm dotted green',
},
],
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should resolve default link styles', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
},
children: [
{
type: 'LINK',
props: {},
style: {},
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should overide default link styles', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
},
children: [
{
type: 'LINK',
props: {},
style: { color: 'wheat', textDecoration: 'none' },
},
],
},
],
});
expect(result).toMatchSnapshot();
});
test('Should overide default link styles with array', () => {
const result = resolveStyles({
type: 'DOCUMENT',
props: {},
children: [
{
type: 'PAGE',
props: {},
box: {
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 100,
height: 200,
},
children: [
{
type: 'LINK',
props: {},
style: [{ color: 'wheat', textDecoration: 'none' }],
},
],
},
],
});
expect(result).toMatchSnapshot();
});
});
================================================
FILE: packages/layout/tests/steps/resolveSvg.test.ts
================================================
import { describe, expect, test } from 'vitest';
import { resolveXLinks } from '../../src/steps/resolveSvg';
import { SafeSvgNode } from '../../src/types';
describe('layout resolveSvg', () => {
describe('resolve xlinks', () => {
test('should replace xlinkHref with the correct node', () => {
const node: SafeSvgNode = {
type: 'SVG',
props: {},
style: {},
children: [
{
type: 'DEFS',
children: [
{
type: 'LINEAR_GRADIENT',
props: { id: 'lg1' },
children: [
{
type: 'STOP',
props: { offset: 0, stopColor: 'red' },
},
{
type: 'STOP',
props: { offset: 100, stopColor: 'blue' },
},
],
},
{
type: 'LINEAR_GRADIENT',
props: { id: 'lg2', x1: 10, xlinkHref: '#lg1' },
},
],
},
],
};
const result = resolveXLinks(node);
expect(result.children![0].type).toBe('DEFS');
expect(result.children![0].children).toHaveLength(2);
expect(result.children![0].children![1].props).toEqual({
id: 'lg2',
x1: 10,
});
expect(result.children![0].children![1].children).toHaveLength(2);
});
test('should not replace xlinkHref if node does not exist', () => {
const node: SafeSvgNode = {
type: 'SVG',
props: {},
style: {},
children: [
{
type: 'DEFS',
children: [
{
type: 'LINEAR_GRADIENT',
props: { id: 'lg2', x1: 10, xlinkHref: '#lg1' },
},
],
},
],
};
const result = resolveXLinks(node);
expect(result.children![0].type).toBe('DEFS');
expect(result.children![0].children).toHaveLength(1);
expect(result.children![0].children![0].children).toBeFalsy();
});
});
});
================================================
FILE: packages/layout/tests/steps/resolveTextLayout.test.ts
================================================
import { describe, expect, test } from 'vitest';
import FontStore from '@react-pdf/font';
import { loadYoga } from '../../src/yoga';
import resolveTextLayout from '../../src/steps/resolveTextLayout';
import resolveDimensions from '../../src/steps/resolveDimensions';
import { SafeDocumentNode } from '../../src/types';
const fontStore = new FontStore();
const getRoot = async (
text = 'hello world',
styles = {},
): Promise => ({
type: 'DOCUMENT',
props: {},
yoga: await loadYoga(),
children: [
{
type: 'PAGE',
props: {},
style: {
width: 100,
height: 100,
},
children: [
{
type: 'TEXT',
style: styles,
props: {},
children: [
{
type: 'TEXT_INSTANCE',
value: text,
},
],
},
],
},
],
});
describe('text layout step', () => {
const getText = (root) => root.children[0].children[0];
test('should calculate lines for text while resolve dimensions', async () => {
const root = await getRoot('text text text');
const dimensions = resolveDimensions(root, fontStore);
expect(getText(dimensions).lines).toBeDefined();
});
test('should calculate lines for text width defined height', async () => {
const root = await getRoot('text text text', { height: 50 });
const dimensions = resolveDimensions(root, fontStore);
expect(getText(dimensions).lines).not.toBeDefined();
const textLayout = resolveTextLayout(dimensions, fontStore);
expect(getText(textLayout).lines).toBeDefined();
});
test('should calculate lines for empty text', async () => {
const root = await getRoot('');
const dimensions = resolveDimensions(root, fontStore);
expect(getText(dimensions).lines).toBeDefined();
});
});
================================================
FILE: packages/layout/tests/text/heightAtLineIndex.test.ts
================================================
import { describe, expect, test } from 'vitest';
import heightAtLineIndex from '../../src/text/heightAtLineIndex';
import { SafeTextNode } from '../../src/types';
const TEST_LINE = { box: { height: 25 } };
const TEST_LINES = Array(10).fill(TEST_LINE);
describe('text heightAtLineIndex', () => {
test('Should return 0 if no lines present', () => {
const node: SafeTextNode = { type: 'TEXT', props: {}, style: {} };
const result = heightAtLineIndex(node, 5);
expect(result).toBe(0);
});
test('Should return correct height for first line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = heightAtLineIndex(node, 1);
expect(result).toBe(25);
});
test('Should return correct height for intermediate line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = heightAtLineIndex(node, 5);
expect(result).toBe(125);
});
test('Should return correct height for last line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = heightAtLineIndex(node, 10);
expect(result).toBe(250);
});
test('Should return correct height for overflow line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = heightAtLineIndex(node, 12);
expect(result).toBe(250);
});
});
================================================
FILE: packages/layout/tests/text/layoutText.test.ts
================================================
import { describe, expect, test, vi } from 'vitest';
import * as P from '@react-pdf/primitives';
import FontStore from '@react-pdf/font';
import layoutText from '../../src/text/layoutText';
import { SafeTextNode } from '../../src/types';
const TEXT =
'Life can be much broader once you discover one simple fact: Everything around you that you call life was made up by people that were no smarter than you';
const fontStore = new FontStore();
const createTextNode = (
value: string,
style = {},
props = {},
): SafeTextNode => ({
style,
props,
type: P.Text,
children: [{ type: P.TextInstance, value }],
});
describe('text layoutText', () => {
test('Should render empty text', async () => {
const node = createTextNode('');
const lines = layoutText(node, 1500, 200, fontStore);
expect(lines).toHaveLength(0);
});
test('Should render aligned left text by default', async () => {
const node = createTextNode(TEXT);
const lines = layoutText(node, 1500, 30, fontStore);
expect(lines[0].box!.x).toBe(0);
});
test('Should render aligned left text', async () => {
const node = createTextNode(TEXT, { textAlign: 'left' });
const lines = layoutText(node, 1500, 30, fontStore);
expect(lines[0].box!.x).toBe(0);
});
test('Should render aligned right text', async () => {
const node = createTextNode(TEXT, { textAlign: 'right' });
const lines = layoutText(node, 1500, 30, fontStore);
const textWidth = lines[0].runs[0].xAdvance!;
expect(lines[0].box!.x).toBe(1500 - textWidth);
});
test('Should render aligned center text', async () => {
const node = createTextNode(TEXT, { textAlign: 'center' });
const lines = layoutText(node, 1500, 30, fontStore);
const textWidth = lines[0].runs[0].xAdvance!;
expect(lines[0].box!.x).toBe((1500 - textWidth) / 2);
});
test('Should render single line justified text aligned to the left', async () => {
const node = createTextNode(TEXT, { textAlign: 'justify' });
const lines = layoutText(node, 1500, 30, fontStore);
expect(lines[0].box!.x).toBe(0);
});
test('Should render multiline justified text correctly aligned', async () => {
const containerWidth = 800;
const node = createTextNode(TEXT, { textAlign: 'justify' });
const lines = layoutText(node, containerWidth, 100, fontStore);
const { positions } = lines[0].runs[0];
const spaceWidth = positions![positions!.length - 1].xAdvance;
// First line justified. Last line aligned to the left
expect(lines[0].box!.width).toBe(containerWidth + spaceWidth);
expect(lines[1].box!.width).not.toBe(containerWidth + spaceWidth);
});
test('Should render maxLines', async () => {
const node = createTextNode(TEXT, { maxLines: 2 });
const lines = layoutText(node, 300, 100, fontStore);
expect(lines.length).toEqual(2);
});
test('should allow hyphenation callback to be overriden', async () => {
const text = 'reallylongtext';
const hyphens = ['really', 'long', 'text'];
const hyphenationCallback = vi.fn().mockReturnValue(hyphens);
const node = createTextNode(text, {}, { hyphenationCallback });
const lines = layoutText(node, 50, 100, fontStore);
expect(lines[0].string).toEqual('really-');
expect(lines[1].string).toEqual('long-');
expect(lines[2].string).toEqual('text');
expect(hyphenationCallback).toHaveBeenCalledWith(
'reallylongtext',
expect.any(Function),
);
});
});
================================================
FILE: packages/layout/tests/text/lineIndexAtHeight.test.ts
================================================
import { describe, expect, test } from 'vitest';
import lineIndexAtHeight from '../../src/text/lineIndexAtHeight';
import { SafeTextNode } from '../../src/types';
const TEST_LINE = { box: { height: 25 } };
const TEST_LINES = Array(10).fill(TEST_LINE);
describe('text lineIndexAtHeight', () => {
test('Should return 0 if no lines present', () => {
const node: SafeTextNode = { type: 'TEXT', props: {}, style: {} };
const result = lineIndexAtHeight(node, 5);
expect(result).toBe(0);
});
test('Should return 0 for height lower than first line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = lineIndexAtHeight(node, 10);
expect(result).toBe(0);
});
test('Should return 1 for height higher than first line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = lineIndexAtHeight(node, 30);
expect(result).toBe(1);
});
test('Should return correct line index for intermediate line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = lineIndexAtHeight(node, 85);
expect(result).toBe(3);
});
test('Should return penultimate line index for height lower than last line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = lineIndexAtHeight(node, 230);
expect(result).toBe(9);
});
test('Should return correct line index for last line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = lineIndexAtHeight(node, 250);
expect(result).toBe(10);
});
test('Should return correct line index for height higher than last line', () => {
const node: SafeTextNode = {
type: 'TEXT',
props: {},
style: {},
lines: TEST_LINES,
};
const result = lineIndexAtHeight(node, 300);
expect(result).toBe(10);
});
});
================================================
FILE: packages/layout/tests/text/measureText.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import FontStore from '@react-pdf/font';
import { SafeTextNode } from '../../src';
import measureText from '../../src/text/measureText';
const TEXT =
'Life can be much broader once you discover one simple fact: Everything around you that you call life was made up by people that were no smarter than you';
const fontStore = new FontStore();
const createTextNode = (
value: string,
style = {},
props = {},
): SafeTextNode => ({
style,
props,
type: P.Text,
children: [{ type: P.TextInstance, value }],
});
describe('measureText', () => {
describe('widthMode Exactly', () => {
test('should return width and height', async () => {
const page = {
type: 'PAGE' as const,
props: {},
style: {},
};
const node = createTextNode(TEXT);
const measureFunc = measureText(page, node, fontStore);
const dimensions = measureFunc(100, 1 /*Yoga.MeasureMode.Exactly*/, 50);
expect(dimensions.width).toStrictEqual(100);
expect(dimensions.height).toBe(39.599999999999994);
});
});
describe('widthMode AtMost', () => {
test('should return width and height', async () => {
const page = {
type: 'PAGE' as const,
props: {},
style: {},
};
const node = createTextNode(TEXT);
const measureFunc = measureText(page, node, fontStore);
const dimensions = measureFunc(100, 2 /*Yoga.MeasureMode.AtMost*/, 50);
expect(dimensions.width).toStrictEqual(100);
expect(dimensions.height).toBe(39.599999999999994);
});
});
});
================================================
FILE: packages/layout/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src", "globals.d.ts"],
}
================================================
FILE: packages/pdfkit/.gitignore
================================================
src/font/data/*.json
lib
node_modules
================================================
FILE: packages/pdfkit/.prettierrc
================================================
{
"singleQuote": true,
"trailingComma": "none"
}
================================================
FILE: packages/pdfkit/CHANGELOG.md
================================================
# @react-pdf/pdfkit
## 4.1.0
### Minor Changes
- [#3188](https://github.com/diegomura/react-pdf/pull/3188) [`f034491b`](https://github.com/diegomura/react-pdf/commit/f034491b1f77ce6f18a5db88e70b10b9c502ca35) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - Fix and rework the hyphenation algorithm, and allow custom word hyphenation algorithms to specify whether a hyphen should be inserted in case the word is wrapped.
**Caution**: If you have been using a custom hyphenation callback - which hasn't been working properly since at least version 2.0.21 - then you will need to change your implementation to leave a soft hyphen character (`'\u00AD'`) at the end of syllables where you want react-pdf to insert a hyphen when wrapping lines. Syllables without a final soft hyphen character will still be able to break, but will not produce a hyphen character at the end of the line.
This allows you to break correctly on normal hyphens or other special characters in your text. For example, to use the default english-language syllable breaking built into react-pdf, but also break after hyphens naturally occurring in your text (such as is often present in hyperlinks), you could use the following hyphenation callback:
```js
import { Font } from "@react-pdf/renderer";
Font.registerHyphenationCallback((word, originalHyphenationCallback) => {
return originalHyphenationCallback(word).flatMap((w) => w.split(/(?<=-)/));
});
```
(`flatMap` requires at least ES2019)
## 4.0.4
### Patch Changes
- [#2715](https://github.com/diegomura/react-pdf/pull/2715) [`5cbe2fb0`](https://github.com/diegomura/react-pdf/commit/5cbe2fb0bde45c44eb68dde01f20feea245908c6) Thanks [@mgmolisani](https://github.com/mgmolisani)! - Add back functionality for bookmark props
## 4.0.3
### Patch Changes
- [#3118](https://github.com/diegomura/react-pdf/pull/3118) [`106699e8`](https://github.com/diegomura/react-pdf/commit/106699e850dad2285e6999d59975111f217e8a81) Thanks [@diegomura](https://github.com/diegomura)! - feat: compile nullish coalescing operator
## 4.0.2
### Patch Changes
- [#3065](https://github.com/diegomura/react-pdf/pull/3065) [`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6) Thanks [@diegomura](https://github.com/diegomura)! - refactor: partially unify pdfkit
## 4.0.1
### Patch Changes
- [#3061](https://github.com/diegomura/react-pdf/pull/3061) [`6d875056`](https://github.com/diegomura/react-pdf/commit/6d875056a07e8479ef695416c1fed575491b6ff1) Thanks [@diegomura](https://github.com/diegomura)! - feat: pdfkit upstream changes
- [#3060](https://github.com/diegomura/react-pdf/pull/3060) [`49daae8f`](https://github.com/diegomura/react-pdf/commit/49daae8fdfba672a3e828847232ee9b70bb51711) Thanks [@diegomura](https://github.com/diegomura)! - feat: enable pdfkit markings mixin
- [#3062](https://github.com/diegomura/react-pdf/pull/3062) [`5cc47319`](https://github.com/diegomura/react-pdf/commit/5cc47319bb428f6d4bcad21cd6dba9afca5cdc17) Thanks [@diegomura](https://github.com/diegomura)! - refactor: unify pdfkit image mixin
- [#3059](https://github.com/diegomura/react-pdf/pull/3059) [`aa0f6725`](https://github.com/diegomura/react-pdf/commit/aa0f672589683a66abc79f838291996ae9aaffb8) Thanks [@diegomura](https://github.com/diegomura)! - feat: add pdfkit subsets mixin
## 4.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Patch Changes
- [#2877](https://github.com/diegomura/react-pdf/pull/2877) [`fdcef566`](https://github.com/diegomura/react-pdf/commit/fdcef5666e4eeed542b625d394cdfe60d6346600) Thanks [@Friendseeker](https://github.com/Friendseeker)! - chore: bump jay-peg
- Updated dependencies [[`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/png-js@3.0.0
## 3.2.0
### Minor Changes
- [#2771](https://github.com/diegomura/react-pdf/pull/2771) [`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2) Thanks [@nikischin](https://github.com/nikischin)! - fix: fix dpi
## 3.1.10
### Patch Changes
- [#2721](https://github.com/diegomura/react-pdf/pull/2721) [`713690c`](https://github.com/diegomura/react-pdf/commit/713690cca266116bb7e80d13cf84bc843f9dfd52) Thanks [@cfhull](https://github.com/cfhull)! - fix: support values of `0` in stroke-dasharray
## 3.1.9
### Patch Changes
- [#2689](https://github.com/diegomura/react-pdf/pull/2689) [`e2d21a4`](https://github.com/diegomura/react-pdf/commit/e2d21a433b881bb96ea4d0b3a01a7297dd1f4a94) Thanks [@joelybahh](https://github.com/joelybahh)! - fix: jpeg precision metadata
## 3.1.8
### Patch Changes
- [#2687](https://github.com/diegomura/react-pdf/pull/2687) [`68bfc57`](https://github.com/diegomura/react-pdf/commit/68bfc575adfb95302e320019715d1eec5398259f) Thanks [@diegomura](https://github.com/diegomura)! - chore: bump jay-peg
## 3.1.7
### Patch Changes
- [#2635](https://github.com/diegomura/react-pdf/pull/2635) [`da10a9b`](https://github.com/diegomura/react-pdf/commit/da10a9bb43dc4c4765687850444a24cbc4eb402a) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: bump jay-peg dependency to fix CJS module resolution error
## 3.1.6
### Patch Changes
- [#2610](https://github.com/diegomura/react-pdf/pull/2610) [`dc54c13`](https://github.com/diegomura/react-pdf/commit/dc54c13625510482e93f80ed5cc07cf3a6a6d34c) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
## 3.1.5
### Patch Changes
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/png-js@2.3.1
## 3.1.4
### Patch Changes
- [#2600](https://github.com/diegomura/react-pdf/pull/2600) [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7) Thanks [@diegomura](https://github.com/diegomura)! - feat: bidi support
## 3.1.3
### Patch Changes
- [`0590324`](https://github.com/diegomura/react-pdf/commit/0590324d7a6d75c0a49520b3f99cfb6594239390) Thanks [@diegomura](https://github.com/diegomura)! - fix: replace jpeg-exif with jay-peg
## 3.1.2
### Patch Changes
- [#2549](https://github.com/diegomura/react-pdf/pull/2549) [`44bd45b`](https://github.com/diegomura/react-pdf/commit/44bd45b1961ca8bae4a2f84cc77db945e5c43419) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - Fix named destinations (id attribute with string value)
## 3.1.1
### Patch Changes
- [#2532](https://github.com/diegomura/react-pdf/pull/2532) [`36c6ba3`](https://github.com/diegomura/react-pdf/commit/36c6ba30ae73a512f19fe5bc47ac8c304887c0da) Thanks [@diegomura](https://github.com/diegomura)! - refactor: converge pdfkit
* [#2529](https://github.com/diegomura/react-pdf/pull/2529) [`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8) Thanks [@diegomura](https://github.com/diegomura)! - fix: jpeg exif orientation rendering
## 3.1.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
### Patch Changes
- Updated dependencies [[`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37)]:
- @react-pdf/png-js@2.3.0
## 3.0.4
### Patch Changes
- [#2479](https://github.com/diegomura/react-pdf/pull/2479) [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4) Thanks [@diegomura](https://github.com/diegomura)! - fix linting
* [#2488](https://github.com/diegomura/react-pdf/pull/2488) [`b457a0c`](https://github.com/diegomura/react-pdf/commit/b457a0cc1c1352325e6c633af3000a3c9241f7f7) Thanks [@diegomura](https://github.com/diegomura)! - fix: copy-paste for registered font
## 3.0.3
### Patch Changes
- [#2450](https://github.com/diegomura/react-pdf/pull/2450) [`4cfb84d`](https://github.com/diegomura/react-pdf/commit/4cfb84d9f3d2301720b68b4c40a0257b9520c6e1) Thanks [@strazto](https://github.com/strazto)! - build: update crypto-js from 4.0.0 -> 4.2.0 (CVE-2023-46233)
## 3.0.2
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
## 3.0.1
### Patch Changes
- [#2121](https://github.com/diegomura/react-pdf/pull/2121) [`8536f10`](https://github.com/diegomura/react-pdf/commit/8536f103830a9ed00211fc4c821b221377885a07) Thanks [@jeetiss](https://github.com/jeetiss)! - fix `attachments` mixin
## 3.0.0
### Major Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- [#1941](https://github.com/diegomura/react-pdf/pull/1941) [`001a208`](https://github.com/diegomura/react-pdf/commit/001a20812fa039d09931b22eb97a8869e3b31cc5) Thanks [@PhilippMeissner](https://github.com/PhilippMeissner)! - chore: adds missing licenses to package.json
* [#1908](https://github.com/diegomura/react-pdf/pull/1908) [`d1f3d5b`](https://github.com/diegomura/react-pdf/commit/d1f3d5b9b4103705e95e2160347ee253d842ed5d) Thanks [@diegomura](https://github.com/diegomura)! - chore: use fontkit mainline repo + drop node 12
- [#1929](https://github.com/diegomura/react-pdf/pull/1929) [`9996158`](https://github.com/diegomura/react-pdf/commit/9996158636edf2118c4a6dcce08a00408b982993) Thanks [@diegomura](https://github.com/diegomura)! - feat: remove blob stream dependency
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81), [`001a208`](https://github.com/diegomura/react-pdf/commit/001a20812fa039d09931b22eb97a8869e3b31cc5)]:
- @react-pdf/png-js@2.2.0
## 2.4.0
### Minor Changes
- [#1892](https://github.com/diegomura/react-pdf/pull/1892) [`035d3f8`](https://github.com/diegomura/react-pdf/commit/035d3f8d24fa4f4af9f350950d81b51547858367) Thanks [@diegomura](https://github.com/diegomura)! - feat: add skew transformation support
### Patch Changes
- [#1894](https://github.com/diegomura/react-pdf/pull/1894) [`9527fe4`](https://github.com/diegomura/react-pdf/commit/9527fe4c9087818421eca4753172b06e3c0cb934) Thanks [@diegomura](https://github.com/diegomura)! - feat: generate document ID
- Updated dependencies [[`0fcc594`](https://github.com/diegomura/react-pdf/commit/0fcc594310d5af30ca1e752b3efc7a047e813dcb)]:
- @react-pdf/fontkit@2.1.2
## 2.3.0
### Minor Changes
- [#1862](https://github.com/diegomura/react-pdf/pull/1862) [`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb) Thanks [@diegomura](https://github.com/diegomura)! - feat: bookmarks support
* [#1867](https://github.com/diegomura/react-pdf/pull/1867) [`4fadb48`](https://github.com/diegomura/react-pdf/commit/4fadb48983d7269452f89f80c7e341ece859aaee) Thanks [@diegomura](https://github.com/diegomura)! - feat: add page layout support
- [#1857](https://github.com/diegomura/react-pdf/pull/1857) [`d958b0a`](https://github.com/diegomura/react-pdf/commit/d958b0ae06a61c157b2581488a9121a0464222f4) Thanks [@diegomura](https://github.com/diegomura)! - feat: embed same image once in final document
* [#1868](https://github.com/diegomura/react-pdf/pull/1868) [`ce8762f`](https://github.com/diegomura/react-pdf/commit/ce8762f6de5c796e69ec5a225c7f3ff9c619a960) Thanks [@diegomura](https://github.com/diegomura)! - feat: add page mode support
- [#1869](https://github.com/diegomura/react-pdf/pull/1869) [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57) Thanks [@diegomura](https://github.com/diegomura)! - feat: variable dpi
### Patch Changes
- [#1865](https://github.com/diegomura/react-pdf/pull/1865) [`24f5c77`](https://github.com/diegomura/react-pdf/commit/24f5c77706e12dbab45053cb704a2fe7cf60eb53) Thanks [@diegomura](https://github.com/diegomura)! - feat: add background color and border with Note support
- Updated dependencies [[`89b8059`](https://github.com/diegomura/react-pdf/commit/89b8059185f917531a56b3424223e8656ffed8f7)]:
- @react-pdf/fontkit@2.1.1
## 2.2.0
### Minor Changes
- [#1841](https://github.com/diegomura/react-pdf/pull/1841) [`25a80eb`](https://github.com/diegomura/react-pdf/commit/25a80ebd5f96ade7101883624010bad51474967c) Thanks [@diegomura](https://github.com/diegomura)! - feat: support bold-italic standard fonts
## 2.1.0
### Minor Changes
- [#1610](https://github.com/diegomura/react-pdf/pull/1610) [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e) Thanks [@jeetiss](https://github.com/jeetiss)! - updated rollup rollup-plugins and babel
* [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1673](https://github.com/diegomura/react-pdf/pull/1673) [`d341ae6`](https://github.com/diegomura/react-pdf/commit/d341ae66e91774e95e82deb8d9162bf458688768) Thanks [@jeetiss](https://github.com/jeetiss)! - ingore fs package in browser bundle
* [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
- [#1607](https://github.com/diegomura/react-pdf/pull/1607) [`a592e99`](https://github.com/diegomura/react-pdf/commit/a592e99f7df7481697582c2a12f31ce7f9559c66) Thanks [@jeetiss](https://github.com/jeetiss)! - replaced `crypto-js` with `crypto-js/md5` to reduce bundle size
- Updated dependencies [[`3217a89`](https://github.com/diegomura/react-pdf/commit/3217a892e92ff98e92b6c7ea6e3244d403f679b6), [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e), [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca), [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b)]:
- @react-pdf/fontkit@2.1.0
- @react-pdf/png-js@2.1.0
================================================
FILE: packages/pdfkit/LICENSE
================================================
MIT LICENSE
Copyright (c) 2014 Devon Govett
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: packages/pdfkit/README.md
================================================
# @react-pdf/pdfkit
A JavaScript PDF generation library for Node and the browser.
## Acknowledges
This project is a fork of [pdfkit](https://github.com/foliojs/pdfkit) by @devongovett and continued under the scope of this project since it has react-pdf specific features. Any recongnition should go to him and the original project mantainers.
## Description
PDFKit is a PDF document generation library for Node and the browser that makes creating complex, multi-page, printable documents easy.
It's written in CoffeeScript, but you can choose to use the API in plain 'ol JavaScript if you like. The API embraces
chainability, and includes both low level functions as well as abstractions for higher level functionality. The PDFKit API
is designed to be simple, so generating complex documents is often as simple as a few function calls.
Check out some of the [documentation and examples](http://pdfkit.org/docs/getting_started.html) to see for yourself!
You can also read the guide as a [self-generated PDF](http://pdfkit.org/docs/guide.pdf) with example output displayed inline.
If you'd like to see how it was generated, check out the README in the [docs](https://github.com/devongovett/pdfkit/tree/master/docs)
folder.
You can also try out an interactive in-browser demo of PDFKit [here](http://pdfkit.org/demo/browser.html).
## Installation
Installation uses the [npm](http://npmjs.org/) package manager. Just type the following command after installing npm.
npm install @react-pdf/pdfkit
## Features
- Vector graphics
- HTML5 canvas-like API
- Path operations
- SVG path parser for easy path creation
- Transformations
- Linear and radial gradients
- Text
- Line wrapping
- Text alignments
- Bulleted lists
- Font embedding
- Supports TrueType (.ttf), OpenType (.otf), WOFF, WOFF2, TrueType Collections (.ttc), and Datafork TrueType (.dfont) fonts
- Font subsetting
- See [fontkit](http://github.com/devongovett/fontkit) for more details on advanced glyph layout support.
- Image embedding
- Supports JPEG and PNG files (including indexed PNGs, and PNGs with transparency)
- Annotations
- Links
- Notes
- Highlights
- Underlines
- etc.
## Coming soon!
- Patterns fills
- Outlines
- PDF Security
- Higher level APIs for creating tables and laying out content
- More performance optimizations
- Even more awesomeness, perhaps written by you! Please fork this repository and send me pull requests.
## Documentation
For complete API documentation and more examples, see the [PDFKit website](http://pdfkit.org/).
## License
PDFKit is available under the MIT license.
================================================
FILE: packages/pdfkit/babel.config.js
================================================
export default { extends: '../../babel.config.js', plugins: ['@babel/plugin-transform-nullish-coalescing-operator'] };
================================================
FILE: packages/pdfkit/package.json
================================================
{
"name": "@react-pdf/pdfkit",
"version": "4.1.0",
"license": "MIT",
"description": "A PDF generation library for Node.js",
"type": "module",
"main": "./lib/pdfkit.js",
"browser": {
"./lib/pdfkit.js": "./lib/pdfkit.browser.js"
},
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/pdfkit"
},
"author": {
"name": "Devon Govett",
"email": "devongovett@gmail.com",
"url": "http://badassjs.com/"
},
"scripts": {
"test": "vitest",
"clear": "rimraf ./lib ./src/font/data/*.json",
"parse:afm": "node ./src/font/data/compressData.js",
"build": "npm run clear && npm run parse:afm && rollup -c ",
"watch": "npm run clear && npm run parse:afm && rollup -c -w"
},
"files": [
"lib"
],
"dependencies": {
"@babel/runtime": "^7.20.13",
"@react-pdf/png-js": "^3.0.0",
"browserify-zlib": "^0.2.0",
"crypto-js": "^4.2.0",
"fontkit": "^2.0.2",
"jay-peg": "^1.1.1",
"linebreak": "^1.1.0",
"vite-compatible-readable-stream": "^3.6.1"
},
"devDependencies": {
"iconv-lite": "^0.4.13"
}
}
================================================
FILE: packages/pdfkit/rollup.config.js
================================================
import babel from '@rollup/plugin-babel';
import json from '@rollup/plugin-json';
import replace from '@rollup/plugin-replace';
import nodeResolve from '@rollup/plugin-node-resolve';
import ignore from 'rollup-plugin-ignore';
import alias from '@rollup/plugin-alias';
import nodePolyfills from 'rollup-plugin-polyfill-node';
import commonjs from '@rollup/plugin-commonjs';
import pkg from './package.json' with { type: 'json' };
const input = 'src/index.js';
const babelConfig = () => ({
babelrc: true,
exclude: 'node_modules/**',
babelHelpers: 'runtime'
});
const getExternal = ({ browser }) => [
...Object.keys(pkg.dependencies).filter(
(dep) =>
!browser ||
!['vite-compatible-readable-stream', 'browserify-zlib'].includes(dep)
),
/\/node_modules\/pako\//,
/crypto-js/,
/@babel\/runtime/,
...(browser ? [] : ['fs'])
];
const getPlugins = ({ browser }) => [
json(),
...(browser
? [
ignore(['fs']),
alias({
entries: [
// See https://github.com/browserify/browserify-zlib/pull/45
{
find: 'pako/lib/zlib/zstream',
replacement: 'pako/lib/zlib/zstream.js'
},
{
find: 'pako/lib/zlib/constants',
replacement: 'pako/lib/zlib/constants.js'
},
{ find: 'stream', replacement: 'vite-compatible-readable-stream' },
{ find: 'zlib', replacement: 'browserify-zlib' }
]
}),
commonjs(),
nodeResolve({ browser, preferBuiltins: !browser }),
nodePolyfills({
include: [/node_modules\/.+\.js/, /pdfkit\/src\/.*\.js/]
})
]
: [nodeResolve({ browser, preferBuiltins: !browser })]),
replace({
preventAssignment: true,
values: {
BROWSER: JSON.stringify(browser)
}
}),
babel(babelConfig()),
];
const serverConfig = {
input,
output: { format: 'es', file: 'lib/pdfkit.js' },
external: getExternal({ browser: false }),
plugins: getPlugins({ browser: false })
};
const browserConfig = {
input,
output: { format: 'es', file: 'lib/pdfkit.browser.js' },
external: getExternal({ browser: true }),
plugins: getPlugins({ browser: true })
};
export default [
serverConfig,
browserConfig,
];
================================================
FILE: packages/pdfkit/src/abstract_reference.js
================================================
/*
PDFAbstractReference - abstract class for PDF reference
*/
class PDFAbstractReference {
toString() {
throw new Error('Must be implemented by subclasses');
}
}
export default PDFAbstractReference;
================================================
FILE: packages/pdfkit/src/data.js
================================================
class Data {
constructor(data = []) {
this.data = data;
this.pos = 0;
this.length = this.data.length;
}
readByte() {
return this.data[this.pos++];
}
writeByte(byte) {
return (this.data[this.pos++] = byte);
}
byteAt(index) {
return this.data[index];
}
readBool() {
return !!this.readByte();
}
writeBool(val) {
return this.writeByte(val ? 1 : 0);
}
readUInt32() {
const b1 = this.readByte() * 0x1000000;
const b2 = this.readByte() << 16;
const b3 = this.readByte() << 8;
const b4 = this.readByte();
return b1 + b2 + b3 + b4;
}
writeUInt32(val) {
this.writeByte((val >>> 24) & 0xff);
this.writeByte((val >> 16) & 0xff);
this.writeByte((val >> 8) & 0xff);
return this.writeByte(val & 0xff);
}
readInt32() {
const int = this.readUInt32();
if (int >= 0x80000000) {
return int - 0x100000000;
} else {
return int;
}
}
writeInt32(val) {
if (val < 0) {
val += 0x100000000;
}
return this.writeUInt32(val);
}
readUInt16() {
const b1 = this.readByte() << 8;
const b2 = this.readByte();
return b1 | b2;
}
writeUInt16(val) {
this.writeByte((val >> 8) & 0xff);
return this.writeByte(val & 0xff);
}
readInt16() {
const int = this.readUInt16();
if (int >= 0x8000) {
return int - 0x10000;
} else {
return int;
}
}
writeInt16(val) {
if (val < 0) {
val += 0x10000;
}
return this.writeUInt16(val);
}
readString(length) {
const ret = [];
for (let i = 0; i < length; i++) {
ret[i] = String.fromCharCode(this.readByte());
}
return ret.join('');
}
writeString(val) {
// todo: remove returning data. Seems not used
const result = [];
for (let i = 0; i <= val.length; i++) {
result.push(this.writeByte(val.charCodeAt(i)));
}
return result;
}
stringAt(pos, length) {
this.pos = pos;
return this.readString(length);
}
readShort() {
return this.readInt16();
}
writeShort(val) {
return this.writeInt16(val);
}
readLongLong() {
const b1 = this.readByte();
const b2 = this.readByte();
const b3 = this.readByte();
const b4 = this.readByte();
const b5 = this.readByte();
const b6 = this.readByte();
const b7 = this.readByte();
const b8 = this.readByte();
if (b1 & 0x80) {
// sign -> avoid overflow
return (
((b1 ^ 0xff) * 0x100000000000000 +
(b2 ^ 0xff) * 0x1000000000000 +
(b3 ^ 0xff) * 0x10000000000 +
(b4 ^ 0xff) * 0x100000000 +
(b5 ^ 0xff) * 0x1000000 +
(b6 ^ 0xff) * 0x10000 +
(b7 ^ 0xff) * 0x100 +
(b8 ^ 0xff) +
1) *
-1
);
}
return (
b1 * 0x100000000000000 +
b2 * 0x1000000000000 +
b3 * 0x10000000000 +
b4 * 0x100000000 +
b5 * 0x1000000 +
b6 * 0x10000 +
b7 * 0x100 +
b8
);
}
writeLongLong(val) {
const high = Math.floor(val / 0x100000000);
const low = val & 0xffffffff;
this.writeByte((high >> 24) & 0xff);
this.writeByte((high >> 16) & 0xff);
this.writeByte((high >> 8) & 0xff);
this.writeByte(high & 0xff);
this.writeByte((low >> 24) & 0xff);
this.writeByte((low >> 16) & 0xff);
this.writeByte((low >> 8) & 0xff);
return this.writeByte(low & 0xff);
}
readInt() {
return this.readInt32();
}
writeInt(val) {
return this.writeInt32(val);
}
slice(start, end) {
return this.data.slice(start, end);
}
read(bytes) {
const buf = [];
for (let i = 0; i < bytes; i++) {
buf.push(this.readByte());
}
return buf;
}
write(bytes) {
return bytes.map((byte) => this.writeByte(byte));
}
}
export default Data;
================================================
FILE: packages/pdfkit/src/document.js
================================================
/*
PDFDocument - represents an entire PDF document
By Devon Govett
*/
import stream from 'stream';
import PDFObject from './object';
import PDFReference from './reference';
import PDFPage from './page';
import PDFNameTree from './name_tree';
import PDFSecurity from './security';
import ColorMixin from './mixins/color';
import VectorMixin from './mixins/vector';
import FontsMixin from './mixins/fonts';
import TextMixin from './mixins/text';
import ImagesMixin from './mixins/images';
import AnnotationsMixin from './mixins/annotations';
import OutlineMixin from './mixins/outline';
import MarkingsMixin from './mixins/markings';
import AcroFormMixin from './mixins/acroform';
import AttachmentsMixin from './mixins/attachments';
import LineWrapper from './line_wrapper';
import SubsetMixin from './mixins/subsets';
import MetadataMixin from './mixins/metadata';
class PDFDocument extends stream.Readable {
constructor(options = {}) {
super(options);
this.options = options;
// PDF version
switch (options.pdfVersion) {
case '1.4':
this.version = 1.4;
break;
case '1.5':
this.version = 1.5;
break;
case '1.6':
this.version = 1.6;
break;
case '1.7':
case '1.7ext3':
this.version = 1.7;
break;
default:
this.version = 1.3;
break;
}
// Whether streams should be compressed
this.compress =
this.options.compress != null ? this.options.compress : true;
this._pageBuffer = [];
this._pageBufferStart = 0;
// The PDF object store
this._offsets = [];
this._waiting = 0;
this._ended = false;
this._offset = 0;
const Pages = this.ref({
Type: 'Pages',
Count: 0,
Kids: []
});
const Names = this.ref({
Dests: new PDFNameTree()
});
this._root = this.ref({
Type: 'Catalog',
Pages,
Names
});
if (this.options.lang) {
this._root.data.Lang = new String(this.options.lang);
}
// The current page
this.page = null;
// Initialize mixins
this.initMetadata();
this.initColor();
this.initVector();
this.initFonts(options.font);
this.initText();
this.initImages();
this.initOutline();
this.initMarkings(options);
this.initSubset(options);
// Initialize the metadata
this.info = {
Producer: 'PDFKit',
Creator: 'PDFKit',
CreationDate: new Date()
};
if (this.options.info) {
for (let key in this.options.info) {
const val = this.options.info[key];
this.info[key] = val;
}
}
if (this.options.displayTitle) {
this._root.data.ViewerPreferences = this.ref({
DisplayDocTitle: true
});
}
// Generate file ID
this._id = PDFSecurity.generateFileID(this.info);
// Initialize security settings
// this._security = PDFSecurity.create(this, options);
// Write the header
// PDF version
this._write(`%PDF-${this.version}`);
// 4 binary chars, as recommended by the spec
this._write('%\xFF\xFF\xFF\xFF');
// Add the first page
if (this.options.autoFirstPage !== false) {
this.addPage();
}
}
addPage(options) {
if (options == null) {
({ options } = this);
}
// end the current page if needed
if (!this.options.bufferPages) {
this.flushPages();
}
// create a page object
this.page = new PDFPage(this, options);
this._pageBuffer.push(this.page);
// add the page to the object store
const pages = this._root.data.Pages.data;
pages.Kids.push(this.page.dictionary);
pages.Count++;
// reset x and y coordinates
this.x = this.page.margins.left;
this.y = this.page.margins.top;
// flip PDF coordinate system so that the origin is in
// the top left rather than the bottom left
this._ctm = [1, 0, 0, 1, 0, 0];
this.transform(1, 0, 0, -1, 0, this.page.height);
this.emit('pageAdded');
return this;
}
continueOnNewPage(options) {
const pageMarkings = this.endPageMarkings(this.page);
this.addPage(options ?? this.page._options);
this.initPageMarkings(pageMarkings);
return this;
}
bufferedPageRange() {
return { start: this._pageBufferStart, count: this._pageBuffer.length };
}
switchToPage(n) {
let page;
if (!(page = this._pageBuffer[n - this._pageBufferStart])) {
throw new Error(
`switchToPage(${n}) out of bounds, current buffer covers pages ${
this._pageBufferStart
} to ${this._pageBufferStart + this._pageBuffer.length - 1}`
);
}
return (this.page = page);
}
flushPages() {
// this local variable exists so we're future-proof against
// reentrant calls to flushPages.
const pages = this._pageBuffer;
this._pageBuffer = [];
this._pageBufferStart += pages.length;
for (let page of pages) {
this.endPageMarkings(page);
page.end();
}
}
addNamedDestination(name, ...args) {
if (args.length === 0) {
args = ['XYZ', null, null, null];
}
if (args[0] === 'XYZ' && args[2] !== null) {
args[2] = this.page.height - args[2];
}
args.unshift(this.page.dictionary);
this._root.data.Names.data.Dests.add(name, args);
}
addNamedEmbeddedFile(name, ref) {
if (!this._root.data.Names.data.EmbeddedFiles) {
// disabling /Limits for this tree fixes attachments not showing in Adobe Reader
this._root.data.Names.data.EmbeddedFiles = new PDFNameTree({
limits: false
});
}
// add filespec to EmbeddedFiles
this._root.data.Names.data.EmbeddedFiles.add(name, ref);
}
addNamedJavaScript(name, js) {
if (!this._root.data.Names.data.JavaScript) {
this._root.data.Names.data.JavaScript = new PDFNameTree();
}
let data = {
JS: new String(js),
S: 'JavaScript'
};
this._root.data.Names.data.JavaScript.add(name, data);
}
ref(data) {
const ref = new PDFReference(this, this._offsets.length + 1, data);
this._offsets.push(null); // placeholder for this object's offset once it is finalized
this._waiting++;
return ref;
}
_read() {}
// do nothing, but this method is required by node
_write(data) {
if (!Buffer.isBuffer(data)) {
data = Buffer.from(data + '\n', 'binary');
}
this.push(data);
return (this._offset += data.length);
}
addContent(data) {
this.page.write(data);
return this;
}
_refEnd(ref) {
this._offsets[ref.id - 1] = ref.offset;
if (--this._waiting === 0 && this._ended) {
this._finalize();
return (this._ended = false);
}
}
end() {
this.flushPages();
this._info = this.ref();
for (let key in this.info) {
let val = this.info[key];
if (typeof val === 'string') {
val = new String(val);
}
let entry = this.ref(val);
entry.end();
this._info.data[key] = entry;
}
this._info.end();
for (let name in this._fontFamilies) {
const font = this._fontFamilies[name];
font.finalize();
}
this.endOutline();
this.endMarkings();
if (this.subset) {
this.endSubset();
}
this.endMetadata();
this._root.end();
this._root.data.Pages.end();
this._root.data.Names.end();
this.endAcroForm();
if (this._root.data.ViewerPreferences) {
this._root.data.ViewerPreferences.end();
}
if (this._security) {
this._security.end();
}
if (this._waiting === 0) {
return this._finalize();
} else {
return (this._ended = true);
}
}
_finalize() {
// generate xref
const xRefOffset = this._offset;
this._write('xref');
this._write(`0 ${this._offsets.length + 1}`);
this._write('0000000000 65535 f ');
for (let offset of this._offsets) {
offset = `0000000000${offset}`.slice(-10);
this._write(offset + ' 00000 n ');
}
// trailer
const trailer = {
Size: this._offsets.length + 1,
Root: this._root,
Info: this._info,
ID: [this._id, this._id]
};
if (this._security) {
trailer.Encrypt = this._security.dictionary;
}
this._write('trailer');
this._write(PDFObject.convert(trailer));
this._write('startxref');
this._write(`${xRefOffset}`);
this._write('%%EOF');
// end the stream
return this.push(null);
}
toString() {
return '[object PDFDocument]';
}
}
const mixin = (methods) => {
Object.assign(PDFDocument.prototype, methods);
};
mixin(MetadataMixin);
mixin(ColorMixin);
mixin(VectorMixin);
mixin(FontsMixin);
mixin(TextMixin);
mixin(ImagesMixin);
mixin(AnnotationsMixin);
mixin(OutlineMixin);
mixin(MarkingsMixin);
mixin(AcroFormMixin);
mixin(AttachmentsMixin);
mixin(SubsetMixin);
PDFDocument.LineWrapper = LineWrapper;
export default PDFDocument;
================================================
FILE: packages/pdfkit/src/font/afm.js
================================================
import fs from 'fs';
import range from '../utils/range.js';
const WIN_ANSI_MAP = {
402: 131,
8211: 150,
8212: 151,
8216: 145,
8217: 146,
8218: 130,
8220: 147,
8221: 148,
8222: 132,
8224: 134,
8225: 135,
8226: 149,
8230: 133,
8364: 128,
8240: 137,
8249: 139,
8250: 155,
710: 136,
8482: 153,
338: 140,
339: 156,
732: 152,
352: 138,
353: 154,
376: 159,
381: 142,
382: 158
};
const characters = `\
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
.notdef .notdef .notdef .notdef
space exclam quotedbl numbersign
dollar percent ampersand quotesingle
parenleft parenright asterisk plus
comma hyphen period slash
zero one two three
four five six seven
eight nine colon semicolon
less equal greater question
at A B C
D E F G
H I J K
L M N O
P Q R S
T U V W
X Y Z bracketleft
backslash bracketright asciicircum underscore
grave a b c
d e f g
h i j k
l m n o
p q r s
t u v w
x y z braceleft
bar braceright asciitilde .notdef
Euro .notdef quotesinglbase florin
quotedblbase ellipsis dagger daggerdbl
circumflex perthousand Scaron guilsinglleft
OE .notdef Zcaron .notdef
.notdef quoteleft quoteright quotedblleft
quotedblright bullet endash emdash
tilde trademark scaron guilsinglright
oe .notdef zcaron ydieresis
space exclamdown cent sterling
currency yen brokenbar section
dieresis copyright ordfeminine guillemotleft
logicalnot softhyphen registered macron
degree plusminus twosuperior threesuperior
acute mu paragraph periodcentered
cedilla onesuperior ordmasculine guillemotright
onequarter onehalf threequarters questiondown
Agrave Aacute Acircumflex Atilde
Adieresis Aring AE Ccedilla
Egrave Eacute Ecircumflex Edieresis
Igrave Iacute Icircumflex Idieresis
Eth Ntilde Ograve Oacute
Ocircumflex Otilde Odieresis multiply
Oslash Ugrave Uacute Ucircumflex
Udieresis Yacute Thorn germandbls
agrave aacute acircumflex atilde
adieresis aring ae ccedilla
egrave eacute ecircumflex edieresis
igrave iacute icircumflex idieresis
eth ntilde ograve oacute
ocircumflex otilde odieresis divide
oslash ugrave uacute ucircumflex
udieresis yacute thorn ydieresis\
`.split(/\s+/);
function parse(contents) {
const obj = {
attributes: {},
glyphWidths: {},
kernPairs: {}
};
let section = '';
for (let line of contents.split('\n')) {
var match;
var a;
if ((match = line.match(/^Start(\w+)/))) {
section = match[1];
continue;
} else if ((match = line.match(/^End(\w+)/))) {
section = '';
continue;
}
switch (section) {
case 'FontMetrics':
match = line.match(/(^\w+)\s+(.*)/);
var key = match[1];
var value = match[2];
if ((a = obj.attributes[key])) {
if (!Array.isArray(a)) {
a = obj.attributes[key] = [a];
}
a.push(value);
} else {
obj.attributes[key] = value;
}
break;
case 'CharMetrics':
if (!/^CH?\s/.test(line)) {
continue;
}
var name = line.match(/\bN\s+(\.?\w+)\s*;/)[1];
obj.glyphWidths[name] = +line.match(/\bWX\s+(\d+)\s*;/)[1];
break;
case 'KernPairs':
match = line.match(/^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/);
if (match) {
obj.kernPairs[match[1] + match[2]] = parseInt(match[3]);
}
break;
}
}
return obj;
}
class AFMFont {
static open(filename) {
if (BROWSER) {
throw new Error('AFMFont.open not available on browser build');
}
return new AFMFont(fs.readFileSync(filename, 'utf8'));
}
static fromJson(json) {
return new AFMFont(json);
}
constructor(contents) {
if (typeof contents === 'string') {
this.contents = contents;
this.parse();
} else {
this.attributes = contents.attributes;
this.glyphWidths = contents.glyphWidths;
this.kernPairs = contents.kernPairs;
}
this.charWidths = range(0, 255, true).map(
(i) => this.glyphWidths[characters[i]]
);
this.bbox = Array.from(this.attributes.FontBBox.split(/\s+/)).map(
(e) => +e
);
this.ascender = +(this.attributes.Ascender || 0);
this.descender = +(this.attributes.Descender || 0);
this.xHeight = +(this.attributes.XHeight || 0);
this.capHeight = +(this.attributes.CapHeight || 0);
this.lineGap =
this.bbox[3] - this.bbox[1] - (this.ascender - this.descender);
}
parse() {
const parsed = parse(this.contents);
this.attributes = parsed.attributes;
this.glyphWidths = parsed.glyphWidths;
this.kernPairs = parsed.kernPairs;
}
encodeText(text) {
const res = [];
for (
let i = 0, end = text.length, asc = 0 <= end;
asc ? i < end : i > end;
asc ? i++ : i--
) {
let char = text.charCodeAt(i);
char = WIN_ANSI_MAP[char] || char;
res.push(char.toString(16));
}
return res;
}
glyphsForString(string) {
const glyphs = [];
for (
let i = 0, end = string.length, asc = 0 <= end;
asc ? i < end : i > end;
asc ? i++ : i--
) {
const charCode = string.charCodeAt(i);
glyphs.push(this.characterToGlyph(charCode));
}
return glyphs;
}
characterToGlyph(character) {
return characters[WIN_ANSI_MAP[character] || character] || '.notdef';
}
widthOfGlyph(glyph) {
return this.glyphWidths[glyph] || 0;
}
getKernPair(left, right) {
return this.kernPairs[left + right] || 0;
}
advancesForGlyphs(glyphs) {
const advances = [];
for (let index = 0; index < glyphs.length; index++) {
const left = glyphs[index];
const right = glyphs[index + 1];
advances.push(this.widthOfGlyph(left) + this.getKernPair(left, right));
}
return advances;
}
}
export { parse };
export default AFMFont;
================================================
FILE: packages/pdfkit/src/font/data/Courier-Bold.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Mon Jun 23 16:28:00 1997
Comment UniqueID 43048
Comment VMusage 41139 52164
FontName Courier-Bold
FullName Courier Bold
FamilyName Courier
Weight Bold
ItalicAngle 0
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -113 -250 749 801
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme AdobeStandardEncoding
CapHeight 562
XHeight 439
Ascender 629
Descender -157
StdHW 84
StdVW 106
StartCharMetrics 315
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 202 -15 398 572 ;
C 34 ; WX 600 ; N quotedbl ; B 135 277 465 562 ;
C 35 ; WX 600 ; N numbersign ; B 56 -45 544 651 ;
C 36 ; WX 600 ; N dollar ; B 82 -126 519 666 ;
C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ;
C 38 ; WX 600 ; N ampersand ; B 36 -15 546 543 ;
C 39 ; WX 600 ; N quoteright ; B 171 277 423 562 ;
C 40 ; WX 600 ; N parenleft ; B 219 -102 461 616 ;
C 41 ; WX 600 ; N parenright ; B 139 -102 381 616 ;
C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ;
C 43 ; WX 600 ; N plus ; B 71 39 529 478 ;
C 44 ; WX 600 ; N comma ; B 123 -111 393 174 ;
C 45 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
C 46 ; WX 600 ; N period ; B 192 -15 408 171 ;
C 47 ; WX 600 ; N slash ; B 98 -77 502 626 ;
C 48 ; WX 600 ; N zero ; B 87 -15 513 616 ;
C 49 ; WX 600 ; N one ; B 81 0 539 616 ;
C 50 ; WX 600 ; N two ; B 61 0 499 616 ;
C 51 ; WX 600 ; N three ; B 63 -15 501 616 ;
C 52 ; WX 600 ; N four ; B 53 0 507 616 ;
C 53 ; WX 600 ; N five ; B 70 -15 521 601 ;
C 54 ; WX 600 ; N six ; B 90 -15 521 616 ;
C 55 ; WX 600 ; N seven ; B 55 0 494 601 ;
C 56 ; WX 600 ; N eight ; B 83 -15 517 616 ;
C 57 ; WX 600 ; N nine ; B 79 -15 510 616 ;
C 58 ; WX 600 ; N colon ; B 191 -15 407 425 ;
C 59 ; WX 600 ; N semicolon ; B 123 -111 408 425 ;
C 60 ; WX 600 ; N less ; B 66 15 523 501 ;
C 61 ; WX 600 ; N equal ; B 71 118 529 398 ;
C 62 ; WX 600 ; N greater ; B 77 15 534 501 ;
C 63 ; WX 600 ; N question ; B 98 -14 501 580 ;
C 64 ; WX 600 ; N at ; B 16 -15 584 616 ;
C 65 ; WX 600 ; N A ; B -9 0 609 562 ;
C 66 ; WX 600 ; N B ; B 30 0 573 562 ;
C 67 ; WX 600 ; N C ; B 22 -18 560 580 ;
C 68 ; WX 600 ; N D ; B 30 0 594 562 ;
C 69 ; WX 600 ; N E ; B 25 0 560 562 ;
C 70 ; WX 600 ; N F ; B 39 0 570 562 ;
C 71 ; WX 600 ; N G ; B 22 -18 594 580 ;
C 72 ; WX 600 ; N H ; B 20 0 580 562 ;
C 73 ; WX 600 ; N I ; B 77 0 523 562 ;
C 74 ; WX 600 ; N J ; B 37 -18 601 562 ;
C 75 ; WX 600 ; N K ; B 21 0 599 562 ;
C 76 ; WX 600 ; N L ; B 39 0 578 562 ;
C 77 ; WX 600 ; N M ; B -2 0 602 562 ;
C 78 ; WX 600 ; N N ; B 8 -12 610 562 ;
C 79 ; WX 600 ; N O ; B 22 -18 578 580 ;
C 80 ; WX 600 ; N P ; B 48 0 559 562 ;
C 81 ; WX 600 ; N Q ; B 32 -138 578 580 ;
C 82 ; WX 600 ; N R ; B 24 0 599 562 ;
C 83 ; WX 600 ; N S ; B 47 -22 553 582 ;
C 84 ; WX 600 ; N T ; B 21 0 579 562 ;
C 85 ; WX 600 ; N U ; B 4 -18 596 562 ;
C 86 ; WX 600 ; N V ; B -13 0 613 562 ;
C 87 ; WX 600 ; N W ; B -18 0 618 562 ;
C 88 ; WX 600 ; N X ; B 12 0 588 562 ;
C 89 ; WX 600 ; N Y ; B 12 0 589 562 ;
C 90 ; WX 600 ; N Z ; B 62 0 539 562 ;
C 91 ; WX 600 ; N bracketleft ; B 245 -102 475 616 ;
C 92 ; WX 600 ; N backslash ; B 99 -77 503 626 ;
C 93 ; WX 600 ; N bracketright ; B 125 -102 355 616 ;
C 94 ; WX 600 ; N asciicircum ; B 108 250 492 616 ;
C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
C 96 ; WX 600 ; N quoteleft ; B 178 277 428 562 ;
C 97 ; WX 600 ; N a ; B 35 -15 570 454 ;
C 98 ; WX 600 ; N b ; B 0 -15 584 626 ;
C 99 ; WX 600 ; N c ; B 40 -15 545 459 ;
C 100 ; WX 600 ; N d ; B 20 -15 591 626 ;
C 101 ; WX 600 ; N e ; B 40 -15 563 454 ;
C 102 ; WX 600 ; N f ; B 83 0 547 626 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 30 -146 580 454 ;
C 104 ; WX 600 ; N h ; B 5 0 592 626 ;
C 105 ; WX 600 ; N i ; B 77 0 523 658 ;
C 106 ; WX 600 ; N j ; B 63 -146 440 658 ;
C 107 ; WX 600 ; N k ; B 20 0 585 626 ;
C 108 ; WX 600 ; N l ; B 77 0 523 626 ;
C 109 ; WX 600 ; N m ; B -22 0 626 454 ;
C 110 ; WX 600 ; N n ; B 18 0 592 454 ;
C 111 ; WX 600 ; N o ; B 30 -15 570 454 ;
C 112 ; WX 600 ; N p ; B -1 -142 570 454 ;
C 113 ; WX 600 ; N q ; B 20 -142 591 454 ;
C 114 ; WX 600 ; N r ; B 47 0 580 454 ;
C 115 ; WX 600 ; N s ; B 68 -17 535 459 ;
C 116 ; WX 600 ; N t ; B 47 -15 532 562 ;
C 117 ; WX 600 ; N u ; B -1 -15 569 439 ;
C 118 ; WX 600 ; N v ; B -1 0 601 439 ;
C 119 ; WX 600 ; N w ; B -18 0 618 439 ;
C 120 ; WX 600 ; N x ; B 6 0 594 439 ;
C 121 ; WX 600 ; N y ; B -4 -142 601 439 ;
C 122 ; WX 600 ; N z ; B 81 0 520 439 ;
C 123 ; WX 600 ; N braceleft ; B 160 -102 464 616 ;
C 124 ; WX 600 ; N bar ; B 255 -250 345 750 ;
C 125 ; WX 600 ; N braceright ; B 136 -102 440 616 ;
C 126 ; WX 600 ; N asciitilde ; B 71 153 530 356 ;
C 161 ; WX 600 ; N exclamdown ; B 202 -146 398 449 ;
C 162 ; WX 600 ; N cent ; B 66 -49 518 614 ;
C 163 ; WX 600 ; N sterling ; B 72 -28 558 611 ;
C 164 ; WX 600 ; N fraction ; B 25 -60 576 661 ;
C 165 ; WX 600 ; N yen ; B 10 0 590 562 ;
C 166 ; WX 600 ; N florin ; B -30 -131 572 616 ;
C 167 ; WX 600 ; N section ; B 83 -70 517 580 ;
C 168 ; WX 600 ; N currency ; B 54 49 546 517 ;
C 169 ; WX 600 ; N quotesingle ; B 227 277 373 562 ;
C 170 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
C 172 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
C 173 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
C 174 ; WX 600 ; N fi ; B 12 0 593 626 ;
C 175 ; WX 600 ; N fl ; B 12 0 593 626 ;
C 177 ; WX 600 ; N endash ; B 65 203 535 313 ;
C 178 ; WX 600 ; N dagger ; B 106 -70 494 580 ;
C 179 ; WX 600 ; N daggerdbl ; B 106 -70 494 580 ;
C 180 ; WX 600 ; N periodcentered ; B 196 165 404 351 ;
C 182 ; WX 600 ; N paragraph ; B 6 -70 576 580 ;
C 183 ; WX 600 ; N bullet ; B 140 132 460 430 ;
C 184 ; WX 600 ; N quotesinglbase ; B 175 -142 427 143 ;
C 185 ; WX 600 ; N quotedblbase ; B 65 -142 529 143 ;
C 186 ; WX 600 ; N quotedblright ; B 61 277 525 562 ;
C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ;
C 188 ; WX 600 ; N ellipsis ; B 26 -15 574 116 ;
C 189 ; WX 600 ; N perthousand ; B -113 -15 713 616 ;
C 191 ; WX 600 ; N questiondown ; B 99 -146 502 449 ;
C 193 ; WX 600 ; N grave ; B 132 508 395 661 ;
C 194 ; WX 600 ; N acute ; B 205 508 468 661 ;
C 195 ; WX 600 ; N circumflex ; B 103 483 497 657 ;
C 196 ; WX 600 ; N tilde ; B 89 493 512 636 ;
C 197 ; WX 600 ; N macron ; B 88 505 512 585 ;
C 198 ; WX 600 ; N breve ; B 83 468 517 631 ;
C 199 ; WX 600 ; N dotaccent ; B 230 498 370 638 ;
C 200 ; WX 600 ; N dieresis ; B 128 498 472 638 ;
C 202 ; WX 600 ; N ring ; B 198 481 402 678 ;
C 203 ; WX 600 ; N cedilla ; B 205 -206 387 0 ;
C 205 ; WX 600 ; N hungarumlaut ; B 68 488 588 661 ;
C 206 ; WX 600 ; N ogonek ; B 169 -199 400 0 ;
C 207 ; WX 600 ; N caron ; B 103 493 497 667 ;
C 208 ; WX 600 ; N emdash ; B -10 203 610 313 ;
C 225 ; WX 600 ; N AE ; B -29 0 602 562 ;
C 227 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ;
C 232 ; WX 600 ; N Lslash ; B 39 0 578 562 ;
C 233 ; WX 600 ; N Oslash ; B 22 -22 578 584 ;
C 234 ; WX 600 ; N OE ; B -25 0 595 562 ;
C 235 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ;
C 241 ; WX 600 ; N ae ; B -4 -15 601 454 ;
C 245 ; WX 600 ; N dotlessi ; B 77 0 523 439 ;
C 248 ; WX 600 ; N lslash ; B 77 0 523 626 ;
C 249 ; WX 600 ; N oslash ; B 30 -24 570 463 ;
C 250 ; WX 600 ; N oe ; B -18 -15 611 454 ;
C 251 ; WX 600 ; N germandbls ; B 22 -15 596 626 ;
C -1 ; WX 600 ; N Idieresis ; B 77 0 523 761 ;
C -1 ; WX 600 ; N eacute ; B 40 -15 563 661 ;
C -1 ; WX 600 ; N abreve ; B 35 -15 570 661 ;
C -1 ; WX 600 ; N uhungarumlaut ; B -1 -15 628 661 ;
C -1 ; WX 600 ; N ecaron ; B 40 -15 563 667 ;
C -1 ; WX 600 ; N Ydieresis ; B 12 0 589 761 ;
C -1 ; WX 600 ; N divide ; B 71 16 529 500 ;
C -1 ; WX 600 ; N Yacute ; B 12 0 589 784 ;
C -1 ; WX 600 ; N Acircumflex ; B -9 0 609 780 ;
C -1 ; WX 600 ; N aacute ; B 35 -15 570 661 ;
C -1 ; WX 600 ; N Ucircumflex ; B 4 -18 596 780 ;
C -1 ; WX 600 ; N yacute ; B -4 -142 601 661 ;
C -1 ; WX 600 ; N scommaaccent ; B 68 -250 535 459 ;
C -1 ; WX 600 ; N ecircumflex ; B 40 -15 563 657 ;
C -1 ; WX 600 ; N Uring ; B 4 -18 596 801 ;
C -1 ; WX 600 ; N Udieresis ; B 4 -18 596 761 ;
C -1 ; WX 600 ; N aogonek ; B 35 -199 586 454 ;
C -1 ; WX 600 ; N Uacute ; B 4 -18 596 784 ;
C -1 ; WX 600 ; N uogonek ; B -1 -199 585 439 ;
C -1 ; WX 600 ; N Edieresis ; B 25 0 560 761 ;
C -1 ; WX 600 ; N Dcroat ; B 30 0 594 562 ;
C -1 ; WX 600 ; N commaaccent ; B 205 -250 397 -57 ;
C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Emacron ; B 25 0 560 708 ;
C -1 ; WX 600 ; N ccaron ; B 40 -15 545 667 ;
C -1 ; WX 600 ; N aring ; B 35 -15 570 678 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 610 562 ;
C -1 ; WX 600 ; N lacute ; B 77 0 523 801 ;
C -1 ; WX 600 ; N agrave ; B 35 -15 570 661 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 21 -250 579 562 ;
C -1 ; WX 600 ; N Cacute ; B 22 -18 560 784 ;
C -1 ; WX 600 ; N atilde ; B 35 -15 570 636 ;
C -1 ; WX 600 ; N Edotaccent ; B 25 0 560 761 ;
C -1 ; WX 600 ; N scaron ; B 68 -17 535 667 ;
C -1 ; WX 600 ; N scedilla ; B 68 -206 535 459 ;
C -1 ; WX 600 ; N iacute ; B 77 0 523 661 ;
C -1 ; WX 600 ; N lozenge ; B 66 0 534 740 ;
C -1 ; WX 600 ; N Rcaron ; B 24 0 599 790 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 22 -250 594 580 ;
C -1 ; WX 600 ; N ucircumflex ; B -1 -15 569 657 ;
C -1 ; WX 600 ; N acircumflex ; B 35 -15 570 657 ;
C -1 ; WX 600 ; N Amacron ; B -9 0 609 708 ;
C -1 ; WX 600 ; N rcaron ; B 47 0 580 667 ;
C -1 ; WX 600 ; N ccedilla ; B 40 -206 545 459 ;
C -1 ; WX 600 ; N Zdotaccent ; B 62 0 539 761 ;
C -1 ; WX 600 ; N Thorn ; B 48 0 557 562 ;
C -1 ; WX 600 ; N Omacron ; B 22 -18 578 708 ;
C -1 ; WX 600 ; N Racute ; B 24 0 599 784 ;
C -1 ; WX 600 ; N Sacute ; B 47 -22 553 784 ;
C -1 ; WX 600 ; N dcaron ; B 20 -15 727 626 ;
C -1 ; WX 600 ; N Umacron ; B 4 -18 596 708 ;
C -1 ; WX 600 ; N uring ; B -1 -15 569 678 ;
C -1 ; WX 600 ; N threesuperior ; B 138 222 433 616 ;
C -1 ; WX 600 ; N Ograve ; B 22 -18 578 784 ;
C -1 ; WX 600 ; N Agrave ; B -9 0 609 784 ;
C -1 ; WX 600 ; N Abreve ; B -9 0 609 784 ;
C -1 ; WX 600 ; N multiply ; B 81 39 520 478 ;
C -1 ; WX 600 ; N uacute ; B -1 -15 569 661 ;
C -1 ; WX 600 ; N Tcaron ; B 21 0 579 790 ;
C -1 ; WX 600 ; N partialdiff ; B 63 -38 537 728 ;
C -1 ; WX 600 ; N ydieresis ; B -4 -142 601 638 ;
C -1 ; WX 600 ; N Nacute ; B 8 -12 610 784 ;
C -1 ; WX 600 ; N icircumflex ; B 73 0 523 657 ;
C -1 ; WX 600 ; N Ecircumflex ; B 25 0 560 780 ;
C -1 ; WX 600 ; N adieresis ; B 35 -15 570 638 ;
C -1 ; WX 600 ; N edieresis ; B 40 -15 563 638 ;
C -1 ; WX 600 ; N cacute ; B 40 -15 545 661 ;
C -1 ; WX 600 ; N nacute ; B 18 0 592 661 ;
C -1 ; WX 600 ; N umacron ; B -1 -15 569 585 ;
C -1 ; WX 600 ; N Ncaron ; B 8 -12 610 790 ;
C -1 ; WX 600 ; N Iacute ; B 77 0 523 784 ;
C -1 ; WX 600 ; N plusminus ; B 71 24 529 515 ;
C -1 ; WX 600 ; N brokenbar ; B 255 -175 345 675 ;
C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Gbreve ; B 22 -18 594 784 ;
C -1 ; WX 600 ; N Idotaccent ; B 77 0 523 761 ;
C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ;
C -1 ; WX 600 ; N Egrave ; B 25 0 560 784 ;
C -1 ; WX 600 ; N racute ; B 47 0 580 661 ;
C -1 ; WX 600 ; N omacron ; B 30 -15 570 585 ;
C -1 ; WX 600 ; N Zacute ; B 62 0 539 784 ;
C -1 ; WX 600 ; N Zcaron ; B 62 0 539 790 ;
C -1 ; WX 600 ; N greaterequal ; B 26 0 523 696 ;
C -1 ; WX 600 ; N Eth ; B 30 0 594 562 ;
C -1 ; WX 600 ; N Ccedilla ; B 22 -206 560 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 523 626 ;
C -1 ; WX 600 ; N tcaron ; B 47 -15 532 703 ;
C -1 ; WX 600 ; N eogonek ; B 40 -199 563 454 ;
C -1 ; WX 600 ; N Uogonek ; B 4 -199 596 562 ;
C -1 ; WX 600 ; N Aacute ; B -9 0 609 784 ;
C -1 ; WX 600 ; N Adieresis ; B -9 0 609 761 ;
C -1 ; WX 600 ; N egrave ; B 40 -15 563 661 ;
C -1 ; WX 600 ; N zacute ; B 81 0 520 661 ;
C -1 ; WX 600 ; N iogonek ; B 77 -199 523 658 ;
C -1 ; WX 600 ; N Oacute ; B 22 -18 578 784 ;
C -1 ; WX 600 ; N oacute ; B 30 -15 570 661 ;
C -1 ; WX 600 ; N amacron ; B 35 -15 570 585 ;
C -1 ; WX 600 ; N sacute ; B 68 -17 535 661 ;
C -1 ; WX 600 ; N idieresis ; B 77 0 523 618 ;
C -1 ; WX 600 ; N Ocircumflex ; B 22 -18 578 780 ;
C -1 ; WX 600 ; N Ugrave ; B 4 -18 596 784 ;
C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
C -1 ; WX 600 ; N thorn ; B -14 -142 570 626 ;
C -1 ; WX 600 ; N twosuperior ; B 143 230 436 616 ;
C -1 ; WX 600 ; N Odieresis ; B 22 -18 578 761 ;
C -1 ; WX 600 ; N mu ; B -1 -142 569 439 ;
C -1 ; WX 600 ; N igrave ; B 77 0 523 661 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 30 -15 668 661 ;
C -1 ; WX 600 ; N Eogonek ; B 25 -199 576 562 ;
C -1 ; WX 600 ; N dcroat ; B 20 -15 591 626 ;
C -1 ; WX 600 ; N threequarters ; B -47 -60 648 661 ;
C -1 ; WX 600 ; N Scedilla ; B 47 -206 553 582 ;
C -1 ; WX 600 ; N lcaron ; B 77 0 597 626 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 599 562 ;
C -1 ; WX 600 ; N Lacute ; B 39 0 578 784 ;
C -1 ; WX 600 ; N trademark ; B -9 230 749 562 ;
C -1 ; WX 600 ; N edotaccent ; B 40 -15 563 638 ;
C -1 ; WX 600 ; N Igrave ; B 77 0 523 784 ;
C -1 ; WX 600 ; N Imacron ; B 77 0 523 708 ;
C -1 ; WX 600 ; N Lcaron ; B 39 0 637 562 ;
C -1 ; WX 600 ; N onehalf ; B -47 -60 648 661 ;
C -1 ; WX 600 ; N lessequal ; B 26 0 523 696 ;
C -1 ; WX 600 ; N ocircumflex ; B 30 -15 570 657 ;
C -1 ; WX 600 ; N ntilde ; B 18 0 592 636 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 4 -18 638 784 ;
C -1 ; WX 600 ; N Eacute ; B 25 0 560 784 ;
C -1 ; WX 600 ; N emacron ; B 40 -15 563 585 ;
C -1 ; WX 600 ; N gbreve ; B 30 -146 580 661 ;
C -1 ; WX 600 ; N onequarter ; B -56 -60 656 661 ;
C -1 ; WX 600 ; N Scaron ; B 47 -22 553 790 ;
C -1 ; WX 600 ; N Scommaaccent ; B 47 -250 553 582 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 22 -18 628 784 ;
C -1 ; WX 600 ; N degree ; B 86 243 474 616 ;
C -1 ; WX 600 ; N ograve ; B 30 -15 570 661 ;
C -1 ; WX 600 ; N Ccaron ; B 22 -18 560 790 ;
C -1 ; WX 600 ; N ugrave ; B -1 -15 569 661 ;
C -1 ; WX 600 ; N radical ; B -19 -104 473 778 ;
C -1 ; WX 600 ; N Dcaron ; B 30 0 594 790 ;
C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 580 454 ;
C -1 ; WX 600 ; N Ntilde ; B 8 -12 610 759 ;
C -1 ; WX 600 ; N otilde ; B 30 -15 570 636 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 599 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 578 562 ;
C -1 ; WX 600 ; N Atilde ; B -9 0 609 759 ;
C -1 ; WX 600 ; N Aogonek ; B -9 -199 625 562 ;
C -1 ; WX 600 ; N Aring ; B -9 0 609 801 ;
C -1 ; WX 600 ; N Otilde ; B 22 -18 578 759 ;
C -1 ; WX 600 ; N zdotaccent ; B 81 0 520 638 ;
C -1 ; WX 600 ; N Ecaron ; B 25 0 560 790 ;
C -1 ; WX 600 ; N Iogonek ; B 77 -199 523 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 20 -250 585 626 ;
C -1 ; WX 600 ; N minus ; B 71 203 529 313 ;
C -1 ; WX 600 ; N Icircumflex ; B 77 0 523 780 ;
C -1 ; WX 600 ; N ncaron ; B 18 0 592 667 ;
C -1 ; WX 600 ; N tcommaaccent ; B 47 -250 532 562 ;
C -1 ; WX 600 ; N logicalnot ; B 71 103 529 413 ;
C -1 ; WX 600 ; N odieresis ; B 30 -15 570 638 ;
C -1 ; WX 600 ; N udieresis ; B -1 -15 569 638 ;
C -1 ; WX 600 ; N notequal ; B 12 -47 537 563 ;
C -1 ; WX 600 ; N gcommaaccent ; B 30 -146 580 714 ;
C -1 ; WX 600 ; N eth ; B 58 -27 543 626 ;
C -1 ; WX 600 ; N zcaron ; B 81 0 520 667 ;
C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 592 454 ;
C -1 ; WX 600 ; N onesuperior ; B 153 230 447 616 ;
C -1 ; WX 600 ; N imacron ; B 77 0 523 585 ;
C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Courier-BoldOblique.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Mon Jun 23 16:28:46 1997
Comment UniqueID 43049
Comment VMusage 17529 79244
FontName Courier-BoldOblique
FullName Courier Bold Oblique
FamilyName Courier
Weight Bold
ItalicAngle -12
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -57 -250 869 801
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme AdobeStandardEncoding
CapHeight 562
XHeight 439
Ascender 629
Descender -157
StdHW 84
StdVW 106
StartCharMetrics 315
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 215 -15 495 572 ;
C 34 ; WX 600 ; N quotedbl ; B 211 277 585 562 ;
C 35 ; WX 600 ; N numbersign ; B 88 -45 641 651 ;
C 36 ; WX 600 ; N dollar ; B 87 -126 630 666 ;
C 37 ; WX 600 ; N percent ; B 101 -15 625 616 ;
C 38 ; WX 600 ; N ampersand ; B 61 -15 595 543 ;
C 39 ; WX 600 ; N quoteright ; B 229 277 543 562 ;
C 40 ; WX 600 ; N parenleft ; B 265 -102 592 616 ;
C 41 ; WX 600 ; N parenright ; B 117 -102 444 616 ;
C 42 ; WX 600 ; N asterisk ; B 179 219 598 601 ;
C 43 ; WX 600 ; N plus ; B 114 39 596 478 ;
C 44 ; WX 600 ; N comma ; B 99 -111 430 174 ;
C 45 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
C 46 ; WX 600 ; N period ; B 206 -15 427 171 ;
C 47 ; WX 600 ; N slash ; B 90 -77 626 626 ;
C 48 ; WX 600 ; N zero ; B 135 -15 593 616 ;
C 49 ; WX 600 ; N one ; B 93 0 562 616 ;
C 50 ; WX 600 ; N two ; B 61 0 594 616 ;
C 51 ; WX 600 ; N three ; B 71 -15 571 616 ;
C 52 ; WX 600 ; N four ; B 81 0 559 616 ;
C 53 ; WX 600 ; N five ; B 77 -15 621 601 ;
C 54 ; WX 600 ; N six ; B 135 -15 652 616 ;
C 55 ; WX 600 ; N seven ; B 147 0 622 601 ;
C 56 ; WX 600 ; N eight ; B 115 -15 604 616 ;
C 57 ; WX 600 ; N nine ; B 75 -15 592 616 ;
C 58 ; WX 600 ; N colon ; B 205 -15 480 425 ;
C 59 ; WX 600 ; N semicolon ; B 99 -111 481 425 ;
C 60 ; WX 600 ; N less ; B 120 15 613 501 ;
C 61 ; WX 600 ; N equal ; B 96 118 614 398 ;
C 62 ; WX 600 ; N greater ; B 97 15 589 501 ;
C 63 ; WX 600 ; N question ; B 183 -14 592 580 ;
C 64 ; WX 600 ; N at ; B 65 -15 642 616 ;
C 65 ; WX 600 ; N A ; B -9 0 632 562 ;
C 66 ; WX 600 ; N B ; B 30 0 630 562 ;
C 67 ; WX 600 ; N C ; B 74 -18 675 580 ;
C 68 ; WX 600 ; N D ; B 30 0 664 562 ;
C 69 ; WX 600 ; N E ; B 25 0 670 562 ;
C 70 ; WX 600 ; N F ; B 39 0 684 562 ;
C 71 ; WX 600 ; N G ; B 74 -18 675 580 ;
C 72 ; WX 600 ; N H ; B 20 0 700 562 ;
C 73 ; WX 600 ; N I ; B 77 0 643 562 ;
C 74 ; WX 600 ; N J ; B 58 -18 721 562 ;
C 75 ; WX 600 ; N K ; B 21 0 692 562 ;
C 76 ; WX 600 ; N L ; B 39 0 636 562 ;
C 77 ; WX 600 ; N M ; B -2 0 722 562 ;
C 78 ; WX 600 ; N N ; B 8 -12 730 562 ;
C 79 ; WX 600 ; N O ; B 74 -18 645 580 ;
C 80 ; WX 600 ; N P ; B 48 0 643 562 ;
C 81 ; WX 600 ; N Q ; B 83 -138 636 580 ;
C 82 ; WX 600 ; N R ; B 24 0 617 562 ;
C 83 ; WX 600 ; N S ; B 54 -22 673 582 ;
C 84 ; WX 600 ; N T ; B 86 0 679 562 ;
C 85 ; WX 600 ; N U ; B 101 -18 716 562 ;
C 86 ; WX 600 ; N V ; B 84 0 733 562 ;
C 87 ; WX 600 ; N W ; B 79 0 738 562 ;
C 88 ; WX 600 ; N X ; B 12 0 690 562 ;
C 89 ; WX 600 ; N Y ; B 109 0 709 562 ;
C 90 ; WX 600 ; N Z ; B 62 0 637 562 ;
C 91 ; WX 600 ; N bracketleft ; B 223 -102 606 616 ;
C 92 ; WX 600 ; N backslash ; B 222 -77 496 626 ;
C 93 ; WX 600 ; N bracketright ; B 103 -102 486 616 ;
C 94 ; WX 600 ; N asciicircum ; B 171 250 556 616 ;
C 95 ; WX 600 ; N underscore ; B -27 -125 585 -75 ;
C 96 ; WX 600 ; N quoteleft ; B 297 277 487 562 ;
C 97 ; WX 600 ; N a ; B 61 -15 593 454 ;
C 98 ; WX 600 ; N b ; B 13 -15 636 626 ;
C 99 ; WX 600 ; N c ; B 81 -15 631 459 ;
C 100 ; WX 600 ; N d ; B 60 -15 645 626 ;
C 101 ; WX 600 ; N e ; B 81 -15 605 454 ;
C 102 ; WX 600 ; N f ; B 83 0 677 626 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 40 -146 674 454 ;
C 104 ; WX 600 ; N h ; B 18 0 615 626 ;
C 105 ; WX 600 ; N i ; B 77 0 546 658 ;
C 106 ; WX 600 ; N j ; B 36 -146 580 658 ;
C 107 ; WX 600 ; N k ; B 33 0 643 626 ;
C 108 ; WX 600 ; N l ; B 77 0 546 626 ;
C 109 ; WX 600 ; N m ; B -22 0 649 454 ;
C 110 ; WX 600 ; N n ; B 18 0 615 454 ;
C 111 ; WX 600 ; N o ; B 71 -15 622 454 ;
C 112 ; WX 600 ; N p ; B -32 -142 622 454 ;
C 113 ; WX 600 ; N q ; B 60 -142 685 454 ;
C 114 ; WX 600 ; N r ; B 47 0 655 454 ;
C 115 ; WX 600 ; N s ; B 66 -17 608 459 ;
C 116 ; WX 600 ; N t ; B 118 -15 567 562 ;
C 117 ; WX 600 ; N u ; B 70 -15 592 439 ;
C 118 ; WX 600 ; N v ; B 70 0 695 439 ;
C 119 ; WX 600 ; N w ; B 53 0 712 439 ;
C 120 ; WX 600 ; N x ; B 6 0 671 439 ;
C 121 ; WX 600 ; N y ; B -21 -142 695 439 ;
C 122 ; WX 600 ; N z ; B 81 0 614 439 ;
C 123 ; WX 600 ; N braceleft ; B 203 -102 595 616 ;
C 124 ; WX 600 ; N bar ; B 201 -250 505 750 ;
C 125 ; WX 600 ; N braceright ; B 114 -102 506 616 ;
C 126 ; WX 600 ; N asciitilde ; B 120 153 590 356 ;
C 161 ; WX 600 ; N exclamdown ; B 196 -146 477 449 ;
C 162 ; WX 600 ; N cent ; B 121 -49 605 614 ;
C 163 ; WX 600 ; N sterling ; B 106 -28 650 611 ;
C 164 ; WX 600 ; N fraction ; B 22 -60 708 661 ;
C 165 ; WX 600 ; N yen ; B 98 0 710 562 ;
C 166 ; WX 600 ; N florin ; B -57 -131 702 616 ;
C 167 ; WX 600 ; N section ; B 74 -70 620 580 ;
C 168 ; WX 600 ; N currency ; B 77 49 644 517 ;
C 169 ; WX 600 ; N quotesingle ; B 303 277 493 562 ;
C 170 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ;
C 172 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ;
C 173 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ;
C 174 ; WX 600 ; N fi ; B 12 0 644 626 ;
C 175 ; WX 600 ; N fl ; B 12 0 644 626 ;
C 177 ; WX 600 ; N endash ; B 108 203 602 313 ;
C 178 ; WX 600 ; N dagger ; B 175 -70 586 580 ;
C 179 ; WX 600 ; N daggerdbl ; B 121 -70 587 580 ;
C 180 ; WX 600 ; N periodcentered ; B 248 165 461 351 ;
C 182 ; WX 600 ; N paragraph ; B 61 -70 700 580 ;
C 183 ; WX 600 ; N bullet ; B 196 132 523 430 ;
C 184 ; WX 600 ; N quotesinglbase ; B 144 -142 458 143 ;
C 185 ; WX 600 ; N quotedblbase ; B 34 -142 560 143 ;
C 186 ; WX 600 ; N quotedblright ; B 119 277 645 562 ;
C 187 ; WX 600 ; N guillemotright ; B 71 70 647 446 ;
C 188 ; WX 600 ; N ellipsis ; B 35 -15 587 116 ;
C 189 ; WX 600 ; N perthousand ; B -45 -15 743 616 ;
C 191 ; WX 600 ; N questiondown ; B 100 -146 509 449 ;
C 193 ; WX 600 ; N grave ; B 272 508 503 661 ;
C 194 ; WX 600 ; N acute ; B 312 508 609 661 ;
C 195 ; WX 600 ; N circumflex ; B 212 483 607 657 ;
C 196 ; WX 600 ; N tilde ; B 199 493 643 636 ;
C 197 ; WX 600 ; N macron ; B 195 505 637 585 ;
C 198 ; WX 600 ; N breve ; B 217 468 652 631 ;
C 199 ; WX 600 ; N dotaccent ; B 348 498 493 638 ;
C 200 ; WX 600 ; N dieresis ; B 246 498 595 638 ;
C 202 ; WX 600 ; N ring ; B 319 481 528 678 ;
C 203 ; WX 600 ; N cedilla ; B 168 -206 368 0 ;
C 205 ; WX 600 ; N hungarumlaut ; B 171 488 729 661 ;
C 206 ; WX 600 ; N ogonek ; B 143 -199 367 0 ;
C 207 ; WX 600 ; N caron ; B 238 493 633 667 ;
C 208 ; WX 600 ; N emdash ; B 33 203 677 313 ;
C 225 ; WX 600 ; N AE ; B -29 0 708 562 ;
C 227 ; WX 600 ; N ordfeminine ; B 188 196 526 580 ;
C 232 ; WX 600 ; N Lslash ; B 39 0 636 562 ;
C 233 ; WX 600 ; N Oslash ; B 48 -22 673 584 ;
C 234 ; WX 600 ; N OE ; B 26 0 701 562 ;
C 235 ; WX 600 ; N ordmasculine ; B 188 196 543 580 ;
C 241 ; WX 600 ; N ae ; B 21 -15 652 454 ;
C 245 ; WX 600 ; N dotlessi ; B 77 0 546 439 ;
C 248 ; WX 600 ; N lslash ; B 77 0 587 626 ;
C 249 ; WX 600 ; N oslash ; B 54 -24 638 463 ;
C 250 ; WX 600 ; N oe ; B 18 -15 662 454 ;
C 251 ; WX 600 ; N germandbls ; B 22 -15 629 626 ;
C -1 ; WX 600 ; N Idieresis ; B 77 0 643 761 ;
C -1 ; WX 600 ; N eacute ; B 81 -15 609 661 ;
C -1 ; WX 600 ; N abreve ; B 61 -15 658 661 ;
C -1 ; WX 600 ; N uhungarumlaut ; B 70 -15 769 661 ;
C -1 ; WX 600 ; N ecaron ; B 81 -15 633 667 ;
C -1 ; WX 600 ; N Ydieresis ; B 109 0 709 761 ;
C -1 ; WX 600 ; N divide ; B 114 16 596 500 ;
C -1 ; WX 600 ; N Yacute ; B 109 0 709 784 ;
C -1 ; WX 600 ; N Acircumflex ; B -9 0 632 780 ;
C -1 ; WX 600 ; N aacute ; B 61 -15 609 661 ;
C -1 ; WX 600 ; N Ucircumflex ; B 101 -18 716 780 ;
C -1 ; WX 600 ; N yacute ; B -21 -142 695 661 ;
C -1 ; WX 600 ; N scommaaccent ; B 66 -250 608 459 ;
C -1 ; WX 600 ; N ecircumflex ; B 81 -15 607 657 ;
C -1 ; WX 600 ; N Uring ; B 101 -18 716 801 ;
C -1 ; WX 600 ; N Udieresis ; B 101 -18 716 761 ;
C -1 ; WX 600 ; N aogonek ; B 61 -199 593 454 ;
C -1 ; WX 600 ; N Uacute ; B 101 -18 716 784 ;
C -1 ; WX 600 ; N uogonek ; B 70 -199 592 439 ;
C -1 ; WX 600 ; N Edieresis ; B 25 0 670 761 ;
C -1 ; WX 600 ; N Dcroat ; B 30 0 664 562 ;
C -1 ; WX 600 ; N commaaccent ; B 151 -250 385 -57 ;
C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Emacron ; B 25 0 670 708 ;
C -1 ; WX 600 ; N ccaron ; B 81 -15 633 667 ;
C -1 ; WX 600 ; N aring ; B 61 -15 593 678 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 730 562 ;
C -1 ; WX 600 ; N lacute ; B 77 0 639 801 ;
C -1 ; WX 600 ; N agrave ; B 61 -15 593 661 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 86 -250 679 562 ;
C -1 ; WX 600 ; N Cacute ; B 74 -18 675 784 ;
C -1 ; WX 600 ; N atilde ; B 61 -15 643 636 ;
C -1 ; WX 600 ; N Edotaccent ; B 25 0 670 761 ;
C -1 ; WX 600 ; N scaron ; B 66 -17 633 667 ;
C -1 ; WX 600 ; N scedilla ; B 66 -206 608 459 ;
C -1 ; WX 600 ; N iacute ; B 77 0 609 661 ;
C -1 ; WX 600 ; N lozenge ; B 145 0 614 740 ;
C -1 ; WX 600 ; N Rcaron ; B 24 0 659 790 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 74 -250 675 580 ;
C -1 ; WX 600 ; N ucircumflex ; B 70 -15 597 657 ;
C -1 ; WX 600 ; N acircumflex ; B 61 -15 607 657 ;
C -1 ; WX 600 ; N Amacron ; B -9 0 633 708 ;
C -1 ; WX 600 ; N rcaron ; B 47 0 655 667 ;
C -1 ; WX 600 ; N ccedilla ; B 81 -206 631 459 ;
C -1 ; WX 600 ; N Zdotaccent ; B 62 0 637 761 ;
C -1 ; WX 600 ; N Thorn ; B 48 0 620 562 ;
C -1 ; WX 600 ; N Omacron ; B 74 -18 663 708 ;
C -1 ; WX 600 ; N Racute ; B 24 0 665 784 ;
C -1 ; WX 600 ; N Sacute ; B 54 -22 673 784 ;
C -1 ; WX 600 ; N dcaron ; B 60 -15 861 626 ;
C -1 ; WX 600 ; N Umacron ; B 101 -18 716 708 ;
C -1 ; WX 600 ; N uring ; B 70 -15 592 678 ;
C -1 ; WX 600 ; N threesuperior ; B 193 222 526 616 ;
C -1 ; WX 600 ; N Ograve ; B 74 -18 645 784 ;
C -1 ; WX 600 ; N Agrave ; B -9 0 632 784 ;
C -1 ; WX 600 ; N Abreve ; B -9 0 684 784 ;
C -1 ; WX 600 ; N multiply ; B 104 39 606 478 ;
C -1 ; WX 600 ; N uacute ; B 70 -15 599 661 ;
C -1 ; WX 600 ; N Tcaron ; B 86 0 679 790 ;
C -1 ; WX 600 ; N partialdiff ; B 91 -38 627 728 ;
C -1 ; WX 600 ; N ydieresis ; B -21 -142 695 638 ;
C -1 ; WX 600 ; N Nacute ; B 8 -12 730 784 ;
C -1 ; WX 600 ; N icircumflex ; B 77 0 577 657 ;
C -1 ; WX 600 ; N Ecircumflex ; B 25 0 670 780 ;
C -1 ; WX 600 ; N adieresis ; B 61 -15 595 638 ;
C -1 ; WX 600 ; N edieresis ; B 81 -15 605 638 ;
C -1 ; WX 600 ; N cacute ; B 81 -15 649 661 ;
C -1 ; WX 600 ; N nacute ; B 18 0 639 661 ;
C -1 ; WX 600 ; N umacron ; B 70 -15 637 585 ;
C -1 ; WX 600 ; N Ncaron ; B 8 -12 730 790 ;
C -1 ; WX 600 ; N Iacute ; B 77 0 643 784 ;
C -1 ; WX 600 ; N plusminus ; B 76 24 614 515 ;
C -1 ; WX 600 ; N brokenbar ; B 217 -175 489 675 ;
C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Gbreve ; B 74 -18 684 784 ;
C -1 ; WX 600 ; N Idotaccent ; B 77 0 643 761 ;
C -1 ; WX 600 ; N summation ; B 15 -10 672 706 ;
C -1 ; WX 600 ; N Egrave ; B 25 0 670 784 ;
C -1 ; WX 600 ; N racute ; B 47 0 655 661 ;
C -1 ; WX 600 ; N omacron ; B 71 -15 637 585 ;
C -1 ; WX 600 ; N Zacute ; B 62 0 665 784 ;
C -1 ; WX 600 ; N Zcaron ; B 62 0 659 790 ;
C -1 ; WX 600 ; N greaterequal ; B 26 0 627 696 ;
C -1 ; WX 600 ; N Eth ; B 30 0 664 562 ;
C -1 ; WX 600 ; N Ccedilla ; B 74 -206 675 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 546 626 ;
C -1 ; WX 600 ; N tcaron ; B 118 -15 627 703 ;
C -1 ; WX 600 ; N eogonek ; B 81 -199 605 454 ;
C -1 ; WX 600 ; N Uogonek ; B 101 -199 716 562 ;
C -1 ; WX 600 ; N Aacute ; B -9 0 655 784 ;
C -1 ; WX 600 ; N Adieresis ; B -9 0 632 761 ;
C -1 ; WX 600 ; N egrave ; B 81 -15 605 661 ;
C -1 ; WX 600 ; N zacute ; B 81 0 614 661 ;
C -1 ; WX 600 ; N iogonek ; B 77 -199 546 658 ;
C -1 ; WX 600 ; N Oacute ; B 74 -18 645 784 ;
C -1 ; WX 600 ; N oacute ; B 71 -15 649 661 ;
C -1 ; WX 600 ; N amacron ; B 61 -15 637 585 ;
C -1 ; WX 600 ; N sacute ; B 66 -17 609 661 ;
C -1 ; WX 600 ; N idieresis ; B 77 0 561 618 ;
C -1 ; WX 600 ; N Ocircumflex ; B 74 -18 645 780 ;
C -1 ; WX 600 ; N Ugrave ; B 101 -18 716 784 ;
C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
C -1 ; WX 600 ; N thorn ; B -32 -142 622 626 ;
C -1 ; WX 600 ; N twosuperior ; B 191 230 542 616 ;
C -1 ; WX 600 ; N Odieresis ; B 74 -18 645 761 ;
C -1 ; WX 600 ; N mu ; B 49 -142 592 439 ;
C -1 ; WX 600 ; N igrave ; B 77 0 546 661 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 71 -15 809 661 ;
C -1 ; WX 600 ; N Eogonek ; B 25 -199 670 562 ;
C -1 ; WX 600 ; N dcroat ; B 60 -15 712 626 ;
C -1 ; WX 600 ; N threequarters ; B 8 -60 699 661 ;
C -1 ; WX 600 ; N Scedilla ; B 54 -206 673 582 ;
C -1 ; WX 600 ; N lcaron ; B 77 0 731 626 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 692 562 ;
C -1 ; WX 600 ; N Lacute ; B 39 0 636 784 ;
C -1 ; WX 600 ; N trademark ; B 86 230 869 562 ;
C -1 ; WX 600 ; N edotaccent ; B 81 -15 605 638 ;
C -1 ; WX 600 ; N Igrave ; B 77 0 643 784 ;
C -1 ; WX 600 ; N Imacron ; B 77 0 663 708 ;
C -1 ; WX 600 ; N Lcaron ; B 39 0 757 562 ;
C -1 ; WX 600 ; N onehalf ; B 22 -60 716 661 ;
C -1 ; WX 600 ; N lessequal ; B 26 0 671 696 ;
C -1 ; WX 600 ; N ocircumflex ; B 71 -15 622 657 ;
C -1 ; WX 600 ; N ntilde ; B 18 0 643 636 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 101 -18 805 784 ;
C -1 ; WX 600 ; N Eacute ; B 25 0 670 784 ;
C -1 ; WX 600 ; N emacron ; B 81 -15 637 585 ;
C -1 ; WX 600 ; N gbreve ; B 40 -146 674 661 ;
C -1 ; WX 600 ; N onequarter ; B 13 -60 707 661 ;
C -1 ; WX 600 ; N Scaron ; B 54 -22 689 790 ;
C -1 ; WX 600 ; N Scommaaccent ; B 54 -250 673 582 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 74 -18 795 784 ;
C -1 ; WX 600 ; N degree ; B 173 243 570 616 ;
C -1 ; WX 600 ; N ograve ; B 71 -15 622 661 ;
C -1 ; WX 600 ; N Ccaron ; B 74 -18 689 790 ;
C -1 ; WX 600 ; N ugrave ; B 70 -15 592 661 ;
C -1 ; WX 600 ; N radical ; B 67 -104 635 778 ;
C -1 ; WX 600 ; N Dcaron ; B 30 0 664 790 ;
C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 655 454 ;
C -1 ; WX 600 ; N Ntilde ; B 8 -12 730 759 ;
C -1 ; WX 600 ; N otilde ; B 71 -15 643 636 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 617 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 636 562 ;
C -1 ; WX 600 ; N Atilde ; B -9 0 669 759 ;
C -1 ; WX 600 ; N Aogonek ; B -9 -199 632 562 ;
C -1 ; WX 600 ; N Aring ; B -9 0 632 801 ;
C -1 ; WX 600 ; N Otilde ; B 74 -18 669 759 ;
C -1 ; WX 600 ; N zdotaccent ; B 81 0 614 638 ;
C -1 ; WX 600 ; N Ecaron ; B 25 0 670 790 ;
C -1 ; WX 600 ; N Iogonek ; B 77 -199 643 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 33 -250 643 626 ;
C -1 ; WX 600 ; N minus ; B 114 203 596 313 ;
C -1 ; WX 600 ; N Icircumflex ; B 77 0 643 780 ;
C -1 ; WX 600 ; N ncaron ; B 18 0 633 667 ;
C -1 ; WX 600 ; N tcommaaccent ; B 118 -250 567 562 ;
C -1 ; WX 600 ; N logicalnot ; B 135 103 617 413 ;
C -1 ; WX 600 ; N odieresis ; B 71 -15 622 638 ;
C -1 ; WX 600 ; N udieresis ; B 70 -15 595 638 ;
C -1 ; WX 600 ; N notequal ; B 30 -47 626 563 ;
C -1 ; WX 600 ; N gcommaaccent ; B 40 -146 674 714 ;
C -1 ; WX 600 ; N eth ; B 93 -27 661 626 ;
C -1 ; WX 600 ; N zcaron ; B 81 0 643 667 ;
C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 615 454 ;
C -1 ; WX 600 ; N onesuperior ; B 212 230 514 616 ;
C -1 ; WX 600 ; N imacron ; B 77 0 575 585 ;
C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Courier-Oblique.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 17:37:52 1997
Comment UniqueID 43051
Comment VMusage 16248 75829
FontName Courier-Oblique
FullName Courier Oblique
FamilyName Courier
Weight Medium
ItalicAngle -12
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -27 -250 849 805
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme AdobeStandardEncoding
CapHeight 562
XHeight 426
Ascender 629
Descender -157
StdHW 51
StdVW 51
StartCharMetrics 315
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 243 -15 464 572 ;
C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ;
C 35 ; WX 600 ; N numbersign ; B 133 -32 596 639 ;
C 36 ; WX 600 ; N dollar ; B 108 -126 596 662 ;
C 37 ; WX 600 ; N percent ; B 134 -15 599 622 ;
C 38 ; WX 600 ; N ampersand ; B 87 -15 580 543 ;
C 39 ; WX 600 ; N quoteright ; B 283 328 495 562 ;
C 40 ; WX 600 ; N parenleft ; B 313 -108 572 622 ;
C 41 ; WX 600 ; N parenright ; B 137 -108 396 622 ;
C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ;
C 43 ; WX 600 ; N plus ; B 129 44 580 470 ;
C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ;
C 45 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
C 46 ; WX 600 ; N period ; B 238 -15 382 109 ;
C 47 ; WX 600 ; N slash ; B 112 -80 604 629 ;
C 48 ; WX 600 ; N zero ; B 154 -15 575 622 ;
C 49 ; WX 600 ; N one ; B 98 0 515 622 ;
C 50 ; WX 600 ; N two ; B 70 0 568 622 ;
C 51 ; WX 600 ; N three ; B 82 -15 538 622 ;
C 52 ; WX 600 ; N four ; B 108 0 541 622 ;
C 53 ; WX 600 ; N five ; B 99 -15 589 607 ;
C 54 ; WX 600 ; N six ; B 155 -15 629 622 ;
C 55 ; WX 600 ; N seven ; B 182 0 612 607 ;
C 56 ; WX 600 ; N eight ; B 132 -15 588 622 ;
C 57 ; WX 600 ; N nine ; B 93 -15 574 622 ;
C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ;
C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ;
C 60 ; WX 600 ; N less ; B 96 42 610 472 ;
C 61 ; WX 600 ; N equal ; B 109 138 600 376 ;
C 62 ; WX 600 ; N greater ; B 85 42 599 472 ;
C 63 ; WX 600 ; N question ; B 222 -15 583 572 ;
C 64 ; WX 600 ; N at ; B 127 -15 582 622 ;
C 65 ; WX 600 ; N A ; B 3 0 607 562 ;
C 66 ; WX 600 ; N B ; B 43 0 616 562 ;
C 67 ; WX 600 ; N C ; B 93 -18 655 580 ;
C 68 ; WX 600 ; N D ; B 43 0 645 562 ;
C 69 ; WX 600 ; N E ; B 53 0 660 562 ;
C 70 ; WX 600 ; N F ; B 53 0 660 562 ;
C 71 ; WX 600 ; N G ; B 83 -18 645 580 ;
C 72 ; WX 600 ; N H ; B 32 0 687 562 ;
C 73 ; WX 600 ; N I ; B 96 0 623 562 ;
C 74 ; WX 600 ; N J ; B 52 -18 685 562 ;
C 75 ; WX 600 ; N K ; B 38 0 671 562 ;
C 76 ; WX 600 ; N L ; B 47 0 607 562 ;
C 77 ; WX 600 ; N M ; B 4 0 715 562 ;
C 78 ; WX 600 ; N N ; B 7 -13 712 562 ;
C 79 ; WX 600 ; N O ; B 94 -18 625 580 ;
C 80 ; WX 600 ; N P ; B 79 0 644 562 ;
C 81 ; WX 600 ; N Q ; B 95 -138 625 580 ;
C 82 ; WX 600 ; N R ; B 38 0 598 562 ;
C 83 ; WX 600 ; N S ; B 76 -20 650 580 ;
C 84 ; WX 600 ; N T ; B 108 0 665 562 ;
C 85 ; WX 600 ; N U ; B 125 -18 702 562 ;
C 86 ; WX 600 ; N V ; B 105 -13 723 562 ;
C 87 ; WX 600 ; N W ; B 106 -13 722 562 ;
C 88 ; WX 600 ; N X ; B 23 0 675 562 ;
C 89 ; WX 600 ; N Y ; B 133 0 695 562 ;
C 90 ; WX 600 ; N Z ; B 86 0 610 562 ;
C 91 ; WX 600 ; N bracketleft ; B 246 -108 574 622 ;
C 92 ; WX 600 ; N backslash ; B 249 -80 468 629 ;
C 93 ; WX 600 ; N bracketright ; B 135 -108 463 622 ;
C 94 ; WX 600 ; N asciicircum ; B 175 354 587 622 ;
C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
C 96 ; WX 600 ; N quoteleft ; B 343 328 457 562 ;
C 97 ; WX 600 ; N a ; B 76 -15 569 441 ;
C 98 ; WX 600 ; N b ; B 29 -15 625 629 ;
C 99 ; WX 600 ; N c ; B 106 -15 608 441 ;
C 100 ; WX 600 ; N d ; B 85 -15 640 629 ;
C 101 ; WX 600 ; N e ; B 106 -15 598 441 ;
C 102 ; WX 600 ; N f ; B 114 0 662 629 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 61 -157 657 441 ;
C 104 ; WX 600 ; N h ; B 33 0 592 629 ;
C 105 ; WX 600 ; N i ; B 95 0 515 657 ;
C 106 ; WX 600 ; N j ; B 52 -157 550 657 ;
C 107 ; WX 600 ; N k ; B 58 0 633 629 ;
C 108 ; WX 600 ; N l ; B 95 0 515 629 ;
C 109 ; WX 600 ; N m ; B -5 0 615 441 ;
C 110 ; WX 600 ; N n ; B 26 0 585 441 ;
C 111 ; WX 600 ; N o ; B 102 -15 588 441 ;
C 112 ; WX 600 ; N p ; B -24 -157 605 441 ;
C 113 ; WX 600 ; N q ; B 85 -157 682 441 ;
C 114 ; WX 600 ; N r ; B 60 0 636 441 ;
C 115 ; WX 600 ; N s ; B 78 -15 584 441 ;
C 116 ; WX 600 ; N t ; B 167 -15 561 561 ;
C 117 ; WX 600 ; N u ; B 101 -15 572 426 ;
C 118 ; WX 600 ; N v ; B 90 -10 681 426 ;
C 119 ; WX 600 ; N w ; B 76 -10 695 426 ;
C 120 ; WX 600 ; N x ; B 20 0 655 426 ;
C 121 ; WX 600 ; N y ; B -4 -157 683 426 ;
C 122 ; WX 600 ; N z ; B 99 0 593 426 ;
C 123 ; WX 600 ; N braceleft ; B 233 -108 569 622 ;
C 124 ; WX 600 ; N bar ; B 222 -250 485 750 ;
C 125 ; WX 600 ; N braceright ; B 140 -108 477 622 ;
C 126 ; WX 600 ; N asciitilde ; B 116 197 600 320 ;
C 161 ; WX 600 ; N exclamdown ; B 225 -157 445 430 ;
C 162 ; WX 600 ; N cent ; B 151 -49 588 614 ;
C 163 ; WX 600 ; N sterling ; B 124 -21 621 611 ;
C 164 ; WX 600 ; N fraction ; B 84 -57 646 665 ;
C 165 ; WX 600 ; N yen ; B 120 0 693 562 ;
C 166 ; WX 600 ; N florin ; B -26 -143 671 622 ;
C 167 ; WX 600 ; N section ; B 104 -78 590 580 ;
C 168 ; WX 600 ; N currency ; B 94 58 628 506 ;
C 169 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
C 170 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
C 172 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
C 173 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
C 174 ; WX 600 ; N fi ; B 3 0 619 629 ;
C 175 ; WX 600 ; N fl ; B 3 0 619 629 ;
C 177 ; WX 600 ; N endash ; B 124 231 586 285 ;
C 178 ; WX 600 ; N dagger ; B 217 -78 546 580 ;
C 179 ; WX 600 ; N daggerdbl ; B 163 -78 546 580 ;
C 180 ; WX 600 ; N periodcentered ; B 275 189 434 327 ;
C 182 ; WX 600 ; N paragraph ; B 100 -78 630 562 ;
C 183 ; WX 600 ; N bullet ; B 224 130 485 383 ;
C 184 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ;
C 185 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ;
C 186 ; WX 600 ; N quotedblright ; B 213 328 576 562 ;
C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ;
C 188 ; WX 600 ; N ellipsis ; B 46 -15 575 111 ;
C 189 ; WX 600 ; N perthousand ; B 59 -15 627 622 ;
C 191 ; WX 600 ; N questiondown ; B 105 -157 466 430 ;
C 193 ; WX 600 ; N grave ; B 294 497 484 672 ;
C 194 ; WX 600 ; N acute ; B 348 497 612 672 ;
C 195 ; WX 600 ; N circumflex ; B 229 477 581 654 ;
C 196 ; WX 600 ; N tilde ; B 212 489 629 606 ;
C 197 ; WX 600 ; N macron ; B 232 525 600 565 ;
C 198 ; WX 600 ; N breve ; B 279 501 576 609 ;
C 199 ; WX 600 ; N dotaccent ; B 373 537 478 640 ;
C 200 ; WX 600 ; N dieresis ; B 272 537 579 640 ;
C 202 ; WX 600 ; N ring ; B 332 463 500 627 ;
C 203 ; WX 600 ; N cedilla ; B 197 -151 344 10 ;
C 205 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ;
C 206 ; WX 600 ; N ogonek ; B 189 -172 377 4 ;
C 207 ; WX 600 ; N caron ; B 262 492 614 669 ;
C 208 ; WX 600 ; N emdash ; B 49 231 661 285 ;
C 225 ; WX 600 ; N AE ; B 3 0 655 562 ;
C 227 ; WX 600 ; N ordfeminine ; B 209 249 512 580 ;
C 232 ; WX 600 ; N Lslash ; B 47 0 607 562 ;
C 233 ; WX 600 ; N Oslash ; B 94 -80 625 629 ;
C 234 ; WX 600 ; N OE ; B 59 0 672 562 ;
C 235 ; WX 600 ; N ordmasculine ; B 210 249 535 580 ;
C 241 ; WX 600 ; N ae ; B 41 -15 626 441 ;
C 245 ; WX 600 ; N dotlessi ; B 95 0 515 426 ;
C 248 ; WX 600 ; N lslash ; B 95 0 587 629 ;
C 249 ; WX 600 ; N oslash ; B 102 -80 588 506 ;
C 250 ; WX 600 ; N oe ; B 54 -15 615 441 ;
C 251 ; WX 600 ; N germandbls ; B 48 -15 617 629 ;
C -1 ; WX 600 ; N Idieresis ; B 96 0 623 753 ;
C -1 ; WX 600 ; N eacute ; B 106 -15 612 672 ;
C -1 ; WX 600 ; N abreve ; B 76 -15 576 609 ;
C -1 ; WX 600 ; N uhungarumlaut ; B 101 -15 723 672 ;
C -1 ; WX 600 ; N ecaron ; B 106 -15 614 669 ;
C -1 ; WX 600 ; N Ydieresis ; B 133 0 695 753 ;
C -1 ; WX 600 ; N divide ; B 136 48 573 467 ;
C -1 ; WX 600 ; N Yacute ; B 133 0 695 805 ;
C -1 ; WX 600 ; N Acircumflex ; B 3 0 607 787 ;
C -1 ; WX 600 ; N aacute ; B 76 -15 612 672 ;
C -1 ; WX 600 ; N Ucircumflex ; B 125 -18 702 787 ;
C -1 ; WX 600 ; N yacute ; B -4 -157 683 672 ;
C -1 ; WX 600 ; N scommaaccent ; B 78 -250 584 441 ;
C -1 ; WX 600 ; N ecircumflex ; B 106 -15 598 654 ;
C -1 ; WX 600 ; N Uring ; B 125 -18 702 760 ;
C -1 ; WX 600 ; N Udieresis ; B 125 -18 702 753 ;
C -1 ; WX 600 ; N aogonek ; B 76 -172 569 441 ;
C -1 ; WX 600 ; N Uacute ; B 125 -18 702 805 ;
C -1 ; WX 600 ; N uogonek ; B 101 -172 572 426 ;
C -1 ; WX 600 ; N Edieresis ; B 53 0 660 753 ;
C -1 ; WX 600 ; N Dcroat ; B 43 0 645 562 ;
C -1 ; WX 600 ; N commaaccent ; B 145 -250 323 -58 ;
C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Emacron ; B 53 0 660 698 ;
C -1 ; WX 600 ; N ccaron ; B 106 -15 614 669 ;
C -1 ; WX 600 ; N aring ; B 76 -15 569 627 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 712 562 ;
C -1 ; WX 600 ; N lacute ; B 95 0 640 805 ;
C -1 ; WX 600 ; N agrave ; B 76 -15 569 672 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 108 -250 665 562 ;
C -1 ; WX 600 ; N Cacute ; B 93 -18 655 805 ;
C -1 ; WX 600 ; N atilde ; B 76 -15 629 606 ;
C -1 ; WX 600 ; N Edotaccent ; B 53 0 660 753 ;
C -1 ; WX 600 ; N scaron ; B 78 -15 614 669 ;
C -1 ; WX 600 ; N scedilla ; B 78 -151 584 441 ;
C -1 ; WX 600 ; N iacute ; B 95 0 612 672 ;
C -1 ; WX 600 ; N lozenge ; B 94 0 519 706 ;
C -1 ; WX 600 ; N Rcaron ; B 38 0 642 802 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 83 -250 645 580 ;
C -1 ; WX 600 ; N ucircumflex ; B 101 -15 572 654 ;
C -1 ; WX 600 ; N acircumflex ; B 76 -15 581 654 ;
C -1 ; WX 600 ; N Amacron ; B 3 0 607 698 ;
C -1 ; WX 600 ; N rcaron ; B 60 0 636 669 ;
C -1 ; WX 600 ; N ccedilla ; B 106 -151 614 441 ;
C -1 ; WX 600 ; N Zdotaccent ; B 86 0 610 753 ;
C -1 ; WX 600 ; N Thorn ; B 79 0 606 562 ;
C -1 ; WX 600 ; N Omacron ; B 94 -18 628 698 ;
C -1 ; WX 600 ; N Racute ; B 38 0 670 805 ;
C -1 ; WX 600 ; N Sacute ; B 76 -20 650 805 ;
C -1 ; WX 600 ; N dcaron ; B 85 -15 849 629 ;
C -1 ; WX 600 ; N Umacron ; B 125 -18 702 698 ;
C -1 ; WX 600 ; N uring ; B 101 -15 572 627 ;
C -1 ; WX 600 ; N threesuperior ; B 213 240 501 622 ;
C -1 ; WX 600 ; N Ograve ; B 94 -18 625 805 ;
C -1 ; WX 600 ; N Agrave ; B 3 0 607 805 ;
C -1 ; WX 600 ; N Abreve ; B 3 0 607 732 ;
C -1 ; WX 600 ; N multiply ; B 103 43 607 470 ;
C -1 ; WX 600 ; N uacute ; B 101 -15 602 672 ;
C -1 ; WX 600 ; N Tcaron ; B 108 0 665 802 ;
C -1 ; WX 600 ; N partialdiff ; B 45 -38 546 710 ;
C -1 ; WX 600 ; N ydieresis ; B -4 -157 683 620 ;
C -1 ; WX 600 ; N Nacute ; B 7 -13 712 805 ;
C -1 ; WX 600 ; N icircumflex ; B 95 0 551 654 ;
C -1 ; WX 600 ; N Ecircumflex ; B 53 0 660 787 ;
C -1 ; WX 600 ; N adieresis ; B 76 -15 575 620 ;
C -1 ; WX 600 ; N edieresis ; B 106 -15 598 620 ;
C -1 ; WX 600 ; N cacute ; B 106 -15 612 672 ;
C -1 ; WX 600 ; N nacute ; B 26 0 602 672 ;
C -1 ; WX 600 ; N umacron ; B 101 -15 600 565 ;
C -1 ; WX 600 ; N Ncaron ; B 7 -13 712 802 ;
C -1 ; WX 600 ; N Iacute ; B 96 0 640 805 ;
C -1 ; WX 600 ; N plusminus ; B 96 44 594 558 ;
C -1 ; WX 600 ; N brokenbar ; B 238 -175 469 675 ;
C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ;
C -1 ; WX 600 ; N Gbreve ; B 83 -18 645 732 ;
C -1 ; WX 600 ; N Idotaccent ; B 96 0 623 753 ;
C -1 ; WX 600 ; N summation ; B 15 -10 670 706 ;
C -1 ; WX 600 ; N Egrave ; B 53 0 660 805 ;
C -1 ; WX 600 ; N racute ; B 60 0 636 672 ;
C -1 ; WX 600 ; N omacron ; B 102 -15 600 565 ;
C -1 ; WX 600 ; N Zacute ; B 86 0 670 805 ;
C -1 ; WX 600 ; N Zcaron ; B 86 0 642 802 ;
C -1 ; WX 600 ; N greaterequal ; B 98 0 594 710 ;
C -1 ; WX 600 ; N Eth ; B 43 0 645 562 ;
C -1 ; WX 600 ; N Ccedilla ; B 93 -151 658 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 515 629 ;
C -1 ; WX 600 ; N tcaron ; B 167 -15 587 717 ;
C -1 ; WX 600 ; N eogonek ; B 106 -172 598 441 ;
C -1 ; WX 600 ; N Uogonek ; B 124 -172 702 562 ;
C -1 ; WX 600 ; N Aacute ; B 3 0 660 805 ;
C -1 ; WX 600 ; N Adieresis ; B 3 0 607 753 ;
C -1 ; WX 600 ; N egrave ; B 106 -15 598 672 ;
C -1 ; WX 600 ; N zacute ; B 99 0 612 672 ;
C -1 ; WX 600 ; N iogonek ; B 95 -172 515 657 ;
C -1 ; WX 600 ; N Oacute ; B 94 -18 640 805 ;
C -1 ; WX 600 ; N oacute ; B 102 -15 612 672 ;
C -1 ; WX 600 ; N amacron ; B 76 -15 600 565 ;
C -1 ; WX 600 ; N sacute ; B 78 -15 612 672 ;
C -1 ; WX 600 ; N idieresis ; B 95 0 545 620 ;
C -1 ; WX 600 ; N Ocircumflex ; B 94 -18 625 787 ;
C -1 ; WX 600 ; N Ugrave ; B 125 -18 702 805 ;
C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
C -1 ; WX 600 ; N thorn ; B -24 -157 605 629 ;
C -1 ; WX 600 ; N twosuperior ; B 230 249 535 622 ;
C -1 ; WX 600 ; N Odieresis ; B 94 -18 625 753 ;
C -1 ; WX 600 ; N mu ; B 72 -157 572 426 ;
C -1 ; WX 600 ; N igrave ; B 95 0 515 672 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 102 -15 723 672 ;
C -1 ; WX 600 ; N Eogonek ; B 53 -172 660 562 ;
C -1 ; WX 600 ; N dcroat ; B 85 -15 704 629 ;
C -1 ; WX 600 ; N threequarters ; B 73 -56 659 666 ;
C -1 ; WX 600 ; N Scedilla ; B 76 -151 650 580 ;
C -1 ; WX 600 ; N lcaron ; B 95 0 667 629 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 671 562 ;
C -1 ; WX 600 ; N Lacute ; B 47 0 607 805 ;
C -1 ; WX 600 ; N trademark ; B 75 263 742 562 ;
C -1 ; WX 600 ; N edotaccent ; B 106 -15 598 620 ;
C -1 ; WX 600 ; N Igrave ; B 96 0 623 805 ;
C -1 ; WX 600 ; N Imacron ; B 96 0 628 698 ;
C -1 ; WX 600 ; N Lcaron ; B 47 0 632 562 ;
C -1 ; WX 600 ; N onehalf ; B 65 -57 669 665 ;
C -1 ; WX 600 ; N lessequal ; B 98 0 645 710 ;
C -1 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ;
C -1 ; WX 600 ; N ntilde ; B 26 0 629 606 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 125 -18 761 805 ;
C -1 ; WX 600 ; N Eacute ; B 53 0 670 805 ;
C -1 ; WX 600 ; N emacron ; B 106 -15 600 565 ;
C -1 ; WX 600 ; N gbreve ; B 61 -157 657 609 ;
C -1 ; WX 600 ; N onequarter ; B 65 -57 674 665 ;
C -1 ; WX 600 ; N Scaron ; B 76 -20 672 802 ;
C -1 ; WX 600 ; N Scommaaccent ; B 76 -250 650 580 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 94 -18 751 805 ;
C -1 ; WX 600 ; N degree ; B 214 269 576 622 ;
C -1 ; WX 600 ; N ograve ; B 102 -15 588 672 ;
C -1 ; WX 600 ; N Ccaron ; B 93 -18 672 802 ;
C -1 ; WX 600 ; N ugrave ; B 101 -15 572 672 ;
C -1 ; WX 600 ; N radical ; B 85 -15 765 792 ;
C -1 ; WX 600 ; N Dcaron ; B 43 0 645 802 ;
C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 636 441 ;
C -1 ; WX 600 ; N Ntilde ; B 7 -13 712 729 ;
C -1 ; WX 600 ; N otilde ; B 102 -15 629 606 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 598 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 607 562 ;
C -1 ; WX 600 ; N Atilde ; B 3 0 655 729 ;
C -1 ; WX 600 ; N Aogonek ; B 3 -172 607 562 ;
C -1 ; WX 600 ; N Aring ; B 3 0 607 750 ;
C -1 ; WX 600 ; N Otilde ; B 94 -18 655 729 ;
C -1 ; WX 600 ; N zdotaccent ; B 99 0 593 620 ;
C -1 ; WX 600 ; N Ecaron ; B 53 0 660 802 ;
C -1 ; WX 600 ; N Iogonek ; B 96 -172 623 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 58 -250 633 629 ;
C -1 ; WX 600 ; N minus ; B 129 232 580 283 ;
C -1 ; WX 600 ; N Icircumflex ; B 96 0 623 787 ;
C -1 ; WX 600 ; N ncaron ; B 26 0 614 669 ;
C -1 ; WX 600 ; N tcommaaccent ; B 165 -250 561 561 ;
C -1 ; WX 600 ; N logicalnot ; B 155 108 591 369 ;
C -1 ; WX 600 ; N odieresis ; B 102 -15 588 620 ;
C -1 ; WX 600 ; N udieresis ; B 101 -15 575 620 ;
C -1 ; WX 600 ; N notequal ; B 43 -16 621 529 ;
C -1 ; WX 600 ; N gcommaaccent ; B 61 -157 657 708 ;
C -1 ; WX 600 ; N eth ; B 102 -15 639 629 ;
C -1 ; WX 600 ; N zcaron ; B 99 0 624 669 ;
C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 585 441 ;
C -1 ; WX 600 ; N onesuperior ; B 231 249 491 622 ;
C -1 ; WX 600 ; N imacron ; B 95 0 543 565 ;
C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Courier.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 17:27:09 1997
Comment UniqueID 43050
Comment VMusage 39754 50779
FontName Courier
FullName Courier
FamilyName Courier
Weight Medium
ItalicAngle 0
IsFixedPitch true
CharacterSet ExtendedRoman
FontBBox -23 -250 715 805
UnderlinePosition -100
UnderlineThickness 50
Version 003.000
Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
EncodingScheme AdobeStandardEncoding
CapHeight 562
XHeight 426
Ascender 629
Descender -157
StdHW 51
StdVW 51
StartCharMetrics 315
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ;
C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ;
C 35 ; WX 600 ; N numbersign ; B 93 -32 507 639 ;
C 36 ; WX 600 ; N dollar ; B 105 -126 496 662 ;
C 37 ; WX 600 ; N percent ; B 81 -15 518 622 ;
C 38 ; WX 600 ; N ampersand ; B 63 -15 538 543 ;
C 39 ; WX 600 ; N quoteright ; B 213 328 376 562 ;
C 40 ; WX 600 ; N parenleft ; B 269 -108 440 622 ;
C 41 ; WX 600 ; N parenright ; B 160 -108 331 622 ;
C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ;
C 43 ; WX 600 ; N plus ; B 80 44 520 470 ;
C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ;
C 45 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
C 46 ; WX 600 ; N period ; B 229 -15 371 109 ;
C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ;
C 48 ; WX 600 ; N zero ; B 106 -15 494 622 ;
C 49 ; WX 600 ; N one ; B 96 0 505 622 ;
C 50 ; WX 600 ; N two ; B 70 0 471 622 ;
C 51 ; WX 600 ; N three ; B 75 -15 466 622 ;
C 52 ; WX 600 ; N four ; B 78 0 500 622 ;
C 53 ; WX 600 ; N five ; B 92 -15 497 607 ;
C 54 ; WX 600 ; N six ; B 111 -15 497 622 ;
C 55 ; WX 600 ; N seven ; B 82 0 483 607 ;
C 56 ; WX 600 ; N eight ; B 102 -15 498 622 ;
C 57 ; WX 600 ; N nine ; B 96 -15 489 622 ;
C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ;
C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ;
C 60 ; WX 600 ; N less ; B 41 42 519 472 ;
C 61 ; WX 600 ; N equal ; B 80 138 520 376 ;
C 62 ; WX 600 ; N greater ; B 66 42 544 472 ;
C 63 ; WX 600 ; N question ; B 129 -15 492 572 ;
C 64 ; WX 600 ; N at ; B 77 -15 533 622 ;
C 65 ; WX 600 ; N A ; B 3 0 597 562 ;
C 66 ; WX 600 ; N B ; B 43 0 559 562 ;
C 67 ; WX 600 ; N C ; B 41 -18 540 580 ;
C 68 ; WX 600 ; N D ; B 43 0 574 562 ;
C 69 ; WX 600 ; N E ; B 53 0 550 562 ;
C 70 ; WX 600 ; N F ; B 53 0 545 562 ;
C 71 ; WX 600 ; N G ; B 31 -18 575 580 ;
C 72 ; WX 600 ; N H ; B 32 0 568 562 ;
C 73 ; WX 600 ; N I ; B 96 0 504 562 ;
C 74 ; WX 600 ; N J ; B 34 -18 566 562 ;
C 75 ; WX 600 ; N K ; B 38 0 582 562 ;
C 76 ; WX 600 ; N L ; B 47 0 554 562 ;
C 77 ; WX 600 ; N M ; B 4 0 596 562 ;
C 78 ; WX 600 ; N N ; B 7 -13 593 562 ;
C 79 ; WX 600 ; N O ; B 43 -18 557 580 ;
C 80 ; WX 600 ; N P ; B 79 0 558 562 ;
C 81 ; WX 600 ; N Q ; B 43 -138 557 580 ;
C 82 ; WX 600 ; N R ; B 38 0 588 562 ;
C 83 ; WX 600 ; N S ; B 72 -20 529 580 ;
C 84 ; WX 600 ; N T ; B 38 0 563 562 ;
C 85 ; WX 600 ; N U ; B 17 -18 583 562 ;
C 86 ; WX 600 ; N V ; B -4 -13 604 562 ;
C 87 ; WX 600 ; N W ; B -3 -13 603 562 ;
C 88 ; WX 600 ; N X ; B 23 0 577 562 ;
C 89 ; WX 600 ; N Y ; B 24 0 576 562 ;
C 90 ; WX 600 ; N Z ; B 86 0 514 562 ;
C 91 ; WX 600 ; N bracketleft ; B 269 -108 442 622 ;
C 92 ; WX 600 ; N backslash ; B 118 -80 482 629 ;
C 93 ; WX 600 ; N bracketright ; B 158 -108 331 622 ;
C 94 ; WX 600 ; N asciicircum ; B 94 354 506 622 ;
C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
C 96 ; WX 600 ; N quoteleft ; B 224 328 387 562 ;
C 97 ; WX 600 ; N a ; B 53 -15 559 441 ;
C 98 ; WX 600 ; N b ; B 14 -15 575 629 ;
C 99 ; WX 600 ; N c ; B 66 -15 529 441 ;
C 100 ; WX 600 ; N d ; B 45 -15 591 629 ;
C 101 ; WX 600 ; N e ; B 66 -15 548 441 ;
C 102 ; WX 600 ; N f ; B 114 0 531 629 ; L i fi ; L l fl ;
C 103 ; WX 600 ; N g ; B 45 -157 566 441 ;
C 104 ; WX 600 ; N h ; B 18 0 582 629 ;
C 105 ; WX 600 ; N i ; B 95 0 505 657 ;
C 106 ; WX 600 ; N j ; B 82 -157 410 657 ;
C 107 ; WX 600 ; N k ; B 43 0 580 629 ;
C 108 ; WX 600 ; N l ; B 95 0 505 629 ;
C 109 ; WX 600 ; N m ; B -5 0 605 441 ;
C 110 ; WX 600 ; N n ; B 26 0 575 441 ;
C 111 ; WX 600 ; N o ; B 62 -15 538 441 ;
C 112 ; WX 600 ; N p ; B 9 -157 555 441 ;
C 113 ; WX 600 ; N q ; B 45 -157 591 441 ;
C 114 ; WX 600 ; N r ; B 60 0 559 441 ;
C 115 ; WX 600 ; N s ; B 80 -15 513 441 ;
C 116 ; WX 600 ; N t ; B 87 -15 530 561 ;
C 117 ; WX 600 ; N u ; B 21 -15 562 426 ;
C 118 ; WX 600 ; N v ; B 10 -10 590 426 ;
C 119 ; WX 600 ; N w ; B -4 -10 604 426 ;
C 120 ; WX 600 ; N x ; B 20 0 580 426 ;
C 121 ; WX 600 ; N y ; B 7 -157 592 426 ;
C 122 ; WX 600 ; N z ; B 99 0 502 426 ;
C 123 ; WX 600 ; N braceleft ; B 182 -108 437 622 ;
C 124 ; WX 600 ; N bar ; B 275 -250 326 750 ;
C 125 ; WX 600 ; N braceright ; B 163 -108 418 622 ;
C 126 ; WX 600 ; N asciitilde ; B 63 197 540 320 ;
C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ;
C 162 ; WX 600 ; N cent ; B 96 -49 500 614 ;
C 163 ; WX 600 ; N sterling ; B 84 -21 521 611 ;
C 164 ; WX 600 ; N fraction ; B 92 -57 509 665 ;
C 165 ; WX 600 ; N yen ; B 26 0 574 562 ;
C 166 ; WX 600 ; N florin ; B 4 -143 539 622 ;
C 167 ; WX 600 ; N section ; B 113 -78 488 580 ;
C 168 ; WX 600 ; N currency ; B 73 58 527 506 ;
C 169 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
C 170 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ;
C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
C 172 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
C 173 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
C 174 ; WX 600 ; N fi ; B 3 0 597 629 ;
C 175 ; WX 600 ; N fl ; B 3 0 597 629 ;
C 177 ; WX 600 ; N endash ; B 75 231 525 285 ;
C 178 ; WX 600 ; N dagger ; B 141 -78 459 580 ;
C 179 ; WX 600 ; N daggerdbl ; B 141 -78 459 580 ;
C 180 ; WX 600 ; N periodcentered ; B 222 189 378 327 ;
C 182 ; WX 600 ; N paragraph ; B 50 -78 511 562 ;
C 183 ; WX 600 ; N bullet ; B 172 130 428 383 ;
C 184 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ;
C 185 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ;
C 186 ; WX 600 ; N quotedblright ; B 143 328 457 562 ;
C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ;
C 188 ; WX 600 ; N ellipsis ; B 37 -15 563 111 ;
C 189 ; WX 600 ; N perthousand ; B 3 -15 600 622 ;
C 191 ; WX 600 ; N questiondown ; B 108 -157 471 430 ;
C 193 ; WX 600 ; N grave ; B 151 497 378 672 ;
C 194 ; WX 600 ; N acute ; B 242 497 469 672 ;
C 195 ; WX 600 ; N circumflex ; B 124 477 476 654 ;
C 196 ; WX 600 ; N tilde ; B 105 489 503 606 ;
C 197 ; WX 600 ; N macron ; B 120 525 480 565 ;
C 198 ; WX 600 ; N breve ; B 153 501 447 609 ;
C 199 ; WX 600 ; N dotaccent ; B 249 537 352 640 ;
C 200 ; WX 600 ; N dieresis ; B 148 537 453 640 ;
C 202 ; WX 600 ; N ring ; B 218 463 382 627 ;
C 203 ; WX 600 ; N cedilla ; B 224 -151 362 10 ;
C 205 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ;
C 206 ; WX 600 ; N ogonek ; B 211 -172 407 4 ;
C 207 ; WX 600 ; N caron ; B 124 492 476 669 ;
C 208 ; WX 600 ; N emdash ; B 0 231 600 285 ;
C 225 ; WX 600 ; N AE ; B 3 0 550 562 ;
C 227 ; WX 600 ; N ordfeminine ; B 156 249 442 580 ;
C 232 ; WX 600 ; N Lslash ; B 47 0 554 562 ;
C 233 ; WX 600 ; N Oslash ; B 43 -80 557 629 ;
C 234 ; WX 600 ; N OE ; B 7 0 567 562 ;
C 235 ; WX 600 ; N ordmasculine ; B 157 249 443 580 ;
C 241 ; WX 600 ; N ae ; B 19 -15 570 441 ;
C 245 ; WX 600 ; N dotlessi ; B 95 0 505 426 ;
C 248 ; WX 600 ; N lslash ; B 95 0 505 629 ;
C 249 ; WX 600 ; N oslash ; B 62 -80 538 506 ;
C 250 ; WX 600 ; N oe ; B 19 -15 559 441 ;
C 251 ; WX 600 ; N germandbls ; B 48 -15 588 629 ;
C -1 ; WX 600 ; N Idieresis ; B 96 0 504 753 ;
C -1 ; WX 600 ; N eacute ; B 66 -15 548 672 ;
C -1 ; WX 600 ; N abreve ; B 53 -15 559 609 ;
C -1 ; WX 600 ; N uhungarumlaut ; B 21 -15 580 672 ;
C -1 ; WX 600 ; N ecaron ; B 66 -15 548 669 ;
C -1 ; WX 600 ; N Ydieresis ; B 24 0 576 753 ;
C -1 ; WX 600 ; N divide ; B 87 48 513 467 ;
C -1 ; WX 600 ; N Yacute ; B 24 0 576 805 ;
C -1 ; WX 600 ; N Acircumflex ; B 3 0 597 787 ;
C -1 ; WX 600 ; N aacute ; B 53 -15 559 672 ;
C -1 ; WX 600 ; N Ucircumflex ; B 17 -18 583 787 ;
C -1 ; WX 600 ; N yacute ; B 7 -157 592 672 ;
C -1 ; WX 600 ; N scommaaccent ; B 80 -250 513 441 ;
C -1 ; WX 600 ; N ecircumflex ; B 66 -15 548 654 ;
C -1 ; WX 600 ; N Uring ; B 17 -18 583 760 ;
C -1 ; WX 600 ; N Udieresis ; B 17 -18 583 753 ;
C -1 ; WX 600 ; N aogonek ; B 53 -172 587 441 ;
C -1 ; WX 600 ; N Uacute ; B 17 -18 583 805 ;
C -1 ; WX 600 ; N uogonek ; B 21 -172 590 426 ;
C -1 ; WX 600 ; N Edieresis ; B 53 0 550 753 ;
C -1 ; WX 600 ; N Dcroat ; B 30 0 574 562 ;
C -1 ; WX 600 ; N commaaccent ; B 198 -250 335 -58 ;
C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Emacron ; B 53 0 550 698 ;
C -1 ; WX 600 ; N ccaron ; B 66 -15 529 669 ;
C -1 ; WX 600 ; N aring ; B 53 -15 559 627 ;
C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 593 562 ;
C -1 ; WX 600 ; N lacute ; B 95 0 505 805 ;
C -1 ; WX 600 ; N agrave ; B 53 -15 559 672 ;
C -1 ; WX 600 ; N Tcommaaccent ; B 38 -250 563 562 ;
C -1 ; WX 600 ; N Cacute ; B 41 -18 540 805 ;
C -1 ; WX 600 ; N atilde ; B 53 -15 559 606 ;
C -1 ; WX 600 ; N Edotaccent ; B 53 0 550 753 ;
C -1 ; WX 600 ; N scaron ; B 80 -15 513 669 ;
C -1 ; WX 600 ; N scedilla ; B 80 -151 513 441 ;
C -1 ; WX 600 ; N iacute ; B 95 0 505 672 ;
C -1 ; WX 600 ; N lozenge ; B 18 0 443 706 ;
C -1 ; WX 600 ; N Rcaron ; B 38 0 588 802 ;
C -1 ; WX 600 ; N Gcommaaccent ; B 31 -250 575 580 ;
C -1 ; WX 600 ; N ucircumflex ; B 21 -15 562 654 ;
C -1 ; WX 600 ; N acircumflex ; B 53 -15 559 654 ;
C -1 ; WX 600 ; N Amacron ; B 3 0 597 698 ;
C -1 ; WX 600 ; N rcaron ; B 60 0 559 669 ;
C -1 ; WX 600 ; N ccedilla ; B 66 -151 529 441 ;
C -1 ; WX 600 ; N Zdotaccent ; B 86 0 514 753 ;
C -1 ; WX 600 ; N Thorn ; B 79 0 538 562 ;
C -1 ; WX 600 ; N Omacron ; B 43 -18 557 698 ;
C -1 ; WX 600 ; N Racute ; B 38 0 588 805 ;
C -1 ; WX 600 ; N Sacute ; B 72 -20 529 805 ;
C -1 ; WX 600 ; N dcaron ; B 45 -15 715 629 ;
C -1 ; WX 600 ; N Umacron ; B 17 -18 583 698 ;
C -1 ; WX 600 ; N uring ; B 21 -15 562 627 ;
C -1 ; WX 600 ; N threesuperior ; B 155 240 406 622 ;
C -1 ; WX 600 ; N Ograve ; B 43 -18 557 805 ;
C -1 ; WX 600 ; N Agrave ; B 3 0 597 805 ;
C -1 ; WX 600 ; N Abreve ; B 3 0 597 732 ;
C -1 ; WX 600 ; N multiply ; B 87 43 515 470 ;
C -1 ; WX 600 ; N uacute ; B 21 -15 562 672 ;
C -1 ; WX 600 ; N Tcaron ; B 38 0 563 802 ;
C -1 ; WX 600 ; N partialdiff ; B 17 -38 459 710 ;
C -1 ; WX 600 ; N ydieresis ; B 7 -157 592 620 ;
C -1 ; WX 600 ; N Nacute ; B 7 -13 593 805 ;
C -1 ; WX 600 ; N icircumflex ; B 94 0 505 654 ;
C -1 ; WX 600 ; N Ecircumflex ; B 53 0 550 787 ;
C -1 ; WX 600 ; N adieresis ; B 53 -15 559 620 ;
C -1 ; WX 600 ; N edieresis ; B 66 -15 548 620 ;
C -1 ; WX 600 ; N cacute ; B 66 -15 529 672 ;
C -1 ; WX 600 ; N nacute ; B 26 0 575 672 ;
C -1 ; WX 600 ; N umacron ; B 21 -15 562 565 ;
C -1 ; WX 600 ; N Ncaron ; B 7 -13 593 802 ;
C -1 ; WX 600 ; N Iacute ; B 96 0 504 805 ;
C -1 ; WX 600 ; N plusminus ; B 87 44 513 558 ;
C -1 ; WX 600 ; N brokenbar ; B 275 -175 326 675 ;
C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ;
C -1 ; WX 600 ; N Gbreve ; B 31 -18 575 732 ;
C -1 ; WX 600 ; N Idotaccent ; B 96 0 504 753 ;
C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ;
C -1 ; WX 600 ; N Egrave ; B 53 0 550 805 ;
C -1 ; WX 600 ; N racute ; B 60 0 559 672 ;
C -1 ; WX 600 ; N omacron ; B 62 -15 538 565 ;
C -1 ; WX 600 ; N Zacute ; B 86 0 514 805 ;
C -1 ; WX 600 ; N Zcaron ; B 86 0 514 802 ;
C -1 ; WX 600 ; N greaterequal ; B 98 0 502 710 ;
C -1 ; WX 600 ; N Eth ; B 30 0 574 562 ;
C -1 ; WX 600 ; N Ccedilla ; B 41 -151 540 580 ;
C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 505 629 ;
C -1 ; WX 600 ; N tcaron ; B 87 -15 530 717 ;
C -1 ; WX 600 ; N eogonek ; B 66 -172 548 441 ;
C -1 ; WX 600 ; N Uogonek ; B 17 -172 583 562 ;
C -1 ; WX 600 ; N Aacute ; B 3 0 597 805 ;
C -1 ; WX 600 ; N Adieresis ; B 3 0 597 753 ;
C -1 ; WX 600 ; N egrave ; B 66 -15 548 672 ;
C -1 ; WX 600 ; N zacute ; B 99 0 502 672 ;
C -1 ; WX 600 ; N iogonek ; B 95 -172 505 657 ;
C -1 ; WX 600 ; N Oacute ; B 43 -18 557 805 ;
C -1 ; WX 600 ; N oacute ; B 62 -15 538 672 ;
C -1 ; WX 600 ; N amacron ; B 53 -15 559 565 ;
C -1 ; WX 600 ; N sacute ; B 80 -15 513 672 ;
C -1 ; WX 600 ; N idieresis ; B 95 0 505 620 ;
C -1 ; WX 600 ; N Ocircumflex ; B 43 -18 557 787 ;
C -1 ; WX 600 ; N Ugrave ; B 17 -18 583 805 ;
C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
C -1 ; WX 600 ; N thorn ; B -6 -157 555 629 ;
C -1 ; WX 600 ; N twosuperior ; B 177 249 424 622 ;
C -1 ; WX 600 ; N Odieresis ; B 43 -18 557 753 ;
C -1 ; WX 600 ; N mu ; B 21 -157 562 426 ;
C -1 ; WX 600 ; N igrave ; B 95 0 505 672 ;
C -1 ; WX 600 ; N ohungarumlaut ; B 62 -15 580 672 ;
C -1 ; WX 600 ; N Eogonek ; B 53 -172 561 562 ;
C -1 ; WX 600 ; N dcroat ; B 45 -15 591 629 ;
C -1 ; WX 600 ; N threequarters ; B 8 -56 593 666 ;
C -1 ; WX 600 ; N Scedilla ; B 72 -151 529 580 ;
C -1 ; WX 600 ; N lcaron ; B 95 0 533 629 ;
C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 582 562 ;
C -1 ; WX 600 ; N Lacute ; B 47 0 554 805 ;
C -1 ; WX 600 ; N trademark ; B -23 263 623 562 ;
C -1 ; WX 600 ; N edotaccent ; B 66 -15 548 620 ;
C -1 ; WX 600 ; N Igrave ; B 96 0 504 805 ;
C -1 ; WX 600 ; N Imacron ; B 96 0 504 698 ;
C -1 ; WX 600 ; N Lcaron ; B 47 0 554 562 ;
C -1 ; WX 600 ; N onehalf ; B 0 -57 611 665 ;
C -1 ; WX 600 ; N lessequal ; B 98 0 502 710 ;
C -1 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ;
C -1 ; WX 600 ; N ntilde ; B 26 0 575 606 ;
C -1 ; WX 600 ; N Uhungarumlaut ; B 17 -18 590 805 ;
C -1 ; WX 600 ; N Eacute ; B 53 0 550 805 ;
C -1 ; WX 600 ; N emacron ; B 66 -15 548 565 ;
C -1 ; WX 600 ; N gbreve ; B 45 -157 566 609 ;
C -1 ; WX 600 ; N onequarter ; B 0 -57 600 665 ;
C -1 ; WX 600 ; N Scaron ; B 72 -20 529 802 ;
C -1 ; WX 600 ; N Scommaaccent ; B 72 -250 529 580 ;
C -1 ; WX 600 ; N Ohungarumlaut ; B 43 -18 580 805 ;
C -1 ; WX 600 ; N degree ; B 123 269 477 622 ;
C -1 ; WX 600 ; N ograve ; B 62 -15 538 672 ;
C -1 ; WX 600 ; N Ccaron ; B 41 -18 540 802 ;
C -1 ; WX 600 ; N ugrave ; B 21 -15 562 672 ;
C -1 ; WX 600 ; N radical ; B 3 -15 597 792 ;
C -1 ; WX 600 ; N Dcaron ; B 43 0 574 802 ;
C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 559 441 ;
C -1 ; WX 600 ; N Ntilde ; B 7 -13 593 729 ;
C -1 ; WX 600 ; N otilde ; B 62 -15 538 606 ;
C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 588 562 ;
C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 554 562 ;
C -1 ; WX 600 ; N Atilde ; B 3 0 597 729 ;
C -1 ; WX 600 ; N Aogonek ; B 3 -172 608 562 ;
C -1 ; WX 600 ; N Aring ; B 3 0 597 750 ;
C -1 ; WX 600 ; N Otilde ; B 43 -18 557 729 ;
C -1 ; WX 600 ; N zdotaccent ; B 99 0 502 620 ;
C -1 ; WX 600 ; N Ecaron ; B 53 0 550 802 ;
C -1 ; WX 600 ; N Iogonek ; B 96 -172 504 562 ;
C -1 ; WX 600 ; N kcommaaccent ; B 43 -250 580 629 ;
C -1 ; WX 600 ; N minus ; B 80 232 520 283 ;
C -1 ; WX 600 ; N Icircumflex ; B 96 0 504 787 ;
C -1 ; WX 600 ; N ncaron ; B 26 0 575 669 ;
C -1 ; WX 600 ; N tcommaaccent ; B 87 -250 530 561 ;
C -1 ; WX 600 ; N logicalnot ; B 87 108 513 369 ;
C -1 ; WX 600 ; N odieresis ; B 62 -15 538 620 ;
C -1 ; WX 600 ; N udieresis ; B 21 -15 562 620 ;
C -1 ; WX 600 ; N notequal ; B 15 -16 540 529 ;
C -1 ; WX 600 ; N gcommaaccent ; B 45 -157 566 708 ;
C -1 ; WX 600 ; N eth ; B 62 -15 538 629 ;
C -1 ; WX 600 ; N zcaron ; B 99 0 502 669 ;
C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 575 441 ;
C -1 ; WX 600 ; N onesuperior ; B 172 249 428 622 ;
C -1 ; WX 600 ; N imacron ; B 95 0 505 565 ;
C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Helvetica-Bold.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:43:52 1997
Comment UniqueID 43052
Comment VMusage 37169 48194
FontName Helvetica-Bold
FullName Helvetica Bold
FamilyName Helvetica
Weight Bold
ItalicAngle 0
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -170 -228 1003 962
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 718
XHeight 532
Ascender 718
Descender -207
StdHW 118
StdVW 140
StartCharMetrics 315
C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
C 33 ; WX 333 ; N exclam ; B 90 0 244 718 ;
C 34 ; WX 474 ; N quotedbl ; B 98 447 376 718 ;
C 35 ; WX 556 ; N numbersign ; B 18 0 538 698 ;
C 36 ; WX 556 ; N dollar ; B 30 -115 523 775 ;
C 37 ; WX 889 ; N percent ; B 28 -19 861 710 ;
C 38 ; WX 722 ; N ampersand ; B 54 -19 701 718 ;
C 39 ; WX 278 ; N quoteright ; B 69 445 209 718 ;
C 40 ; WX 333 ; N parenleft ; B 35 -208 314 734 ;
C 41 ; WX 333 ; N parenright ; B 19 -208 298 734 ;
C 42 ; WX 389 ; N asterisk ; B 27 387 362 718 ;
C 43 ; WX 584 ; N plus ; B 40 0 544 506 ;
C 44 ; WX 278 ; N comma ; B 64 -168 214 146 ;
C 45 ; WX 333 ; N hyphen ; B 27 215 306 345 ;
C 46 ; WX 278 ; N period ; B 64 0 214 146 ;
C 47 ; WX 278 ; N slash ; B -33 -19 311 737 ;
C 48 ; WX 556 ; N zero ; B 32 -19 524 710 ;
C 49 ; WX 556 ; N one ; B 69 0 378 710 ;
C 50 ; WX 556 ; N two ; B 26 0 511 710 ;
C 51 ; WX 556 ; N three ; B 27 -19 516 710 ;
C 52 ; WX 556 ; N four ; B 27 0 526 710 ;
C 53 ; WX 556 ; N five ; B 27 -19 516 698 ;
C 54 ; WX 556 ; N six ; B 31 -19 520 710 ;
C 55 ; WX 556 ; N seven ; B 25 0 528 698 ;
C 56 ; WX 556 ; N eight ; B 32 -19 524 710 ;
C 57 ; WX 556 ; N nine ; B 30 -19 522 710 ;
C 58 ; WX 333 ; N colon ; B 92 0 242 512 ;
C 59 ; WX 333 ; N semicolon ; B 92 -168 242 512 ;
C 60 ; WX 584 ; N less ; B 38 -8 546 514 ;
C 61 ; WX 584 ; N equal ; B 40 87 544 419 ;
C 62 ; WX 584 ; N greater ; B 38 -8 546 514 ;
C 63 ; WX 611 ; N question ; B 60 0 556 727 ;
C 64 ; WX 975 ; N at ; B 118 -19 856 737 ;
C 65 ; WX 722 ; N A ; B 20 0 702 718 ;
C 66 ; WX 722 ; N B ; B 76 0 669 718 ;
C 67 ; WX 722 ; N C ; B 44 -19 684 737 ;
C 68 ; WX 722 ; N D ; B 76 0 685 718 ;
C 69 ; WX 667 ; N E ; B 76 0 621 718 ;
C 70 ; WX 611 ; N F ; B 76 0 587 718 ;
C 71 ; WX 778 ; N G ; B 44 -19 713 737 ;
C 72 ; WX 722 ; N H ; B 71 0 651 718 ;
C 73 ; WX 278 ; N I ; B 64 0 214 718 ;
C 74 ; WX 556 ; N J ; B 22 -18 484 718 ;
C 75 ; WX 722 ; N K ; B 87 0 722 718 ;
C 76 ; WX 611 ; N L ; B 76 0 583 718 ;
C 77 ; WX 833 ; N M ; B 69 0 765 718 ;
C 78 ; WX 722 ; N N ; B 69 0 654 718 ;
C 79 ; WX 778 ; N O ; B 44 -19 734 737 ;
C 80 ; WX 667 ; N P ; B 76 0 627 718 ;
C 81 ; WX 778 ; N Q ; B 44 -52 737 737 ;
C 82 ; WX 722 ; N R ; B 76 0 677 718 ;
C 83 ; WX 667 ; N S ; B 39 -19 629 737 ;
C 84 ; WX 611 ; N T ; B 14 0 598 718 ;
C 85 ; WX 722 ; N U ; B 72 -19 651 718 ;
C 86 ; WX 667 ; N V ; B 19 0 648 718 ;
C 87 ; WX 944 ; N W ; B 16 0 929 718 ;
C 88 ; WX 667 ; N X ; B 14 0 653 718 ;
C 89 ; WX 667 ; N Y ; B 15 0 653 718 ;
C 90 ; WX 611 ; N Z ; B 25 0 586 718 ;
C 91 ; WX 333 ; N bracketleft ; B 63 -196 309 722 ;
C 92 ; WX 278 ; N backslash ; B -33 -19 311 737 ;
C 93 ; WX 333 ; N bracketright ; B 24 -196 270 722 ;
C 94 ; WX 584 ; N asciicircum ; B 62 323 522 698 ;
C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ;
C 96 ; WX 278 ; N quoteleft ; B 69 454 209 727 ;
C 97 ; WX 556 ; N a ; B 29 -14 527 546 ;
C 98 ; WX 611 ; N b ; B 61 -14 578 718 ;
C 99 ; WX 556 ; N c ; B 34 -14 524 546 ;
C 100 ; WX 611 ; N d ; B 34 -14 551 718 ;
C 101 ; WX 556 ; N e ; B 23 -14 528 546 ;
C 102 ; WX 333 ; N f ; B 10 0 318 727 ; L i fi ; L l fl ;
C 103 ; WX 611 ; N g ; B 40 -217 553 546 ;
C 104 ; WX 611 ; N h ; B 65 0 546 718 ;
C 105 ; WX 278 ; N i ; B 69 0 209 725 ;
C 106 ; WX 278 ; N j ; B 3 -214 209 725 ;
C 107 ; WX 556 ; N k ; B 69 0 562 718 ;
C 108 ; WX 278 ; N l ; B 69 0 209 718 ;
C 109 ; WX 889 ; N m ; B 64 0 826 546 ;
C 110 ; WX 611 ; N n ; B 65 0 546 546 ;
C 111 ; WX 611 ; N o ; B 34 -14 578 546 ;
C 112 ; WX 611 ; N p ; B 62 -207 578 546 ;
C 113 ; WX 611 ; N q ; B 34 -207 552 546 ;
C 114 ; WX 389 ; N r ; B 64 0 373 546 ;
C 115 ; WX 556 ; N s ; B 30 -14 519 546 ;
C 116 ; WX 333 ; N t ; B 10 -6 309 676 ;
C 117 ; WX 611 ; N u ; B 66 -14 545 532 ;
C 118 ; WX 556 ; N v ; B 13 0 543 532 ;
C 119 ; WX 778 ; N w ; B 10 0 769 532 ;
C 120 ; WX 556 ; N x ; B 15 0 541 532 ;
C 121 ; WX 556 ; N y ; B 10 -214 539 532 ;
C 122 ; WX 500 ; N z ; B 20 0 480 532 ;
C 123 ; WX 389 ; N braceleft ; B 48 -196 365 722 ;
C 124 ; WX 280 ; N bar ; B 84 -225 196 775 ;
C 125 ; WX 389 ; N braceright ; B 24 -196 341 722 ;
C 126 ; WX 584 ; N asciitilde ; B 61 163 523 343 ;
C 161 ; WX 333 ; N exclamdown ; B 90 -186 244 532 ;
C 162 ; WX 556 ; N cent ; B 34 -118 524 628 ;
C 163 ; WX 556 ; N sterling ; B 28 -16 541 718 ;
C 164 ; WX 167 ; N fraction ; B -170 -19 336 710 ;
C 165 ; WX 556 ; N yen ; B -9 0 565 698 ;
C 166 ; WX 556 ; N florin ; B -10 -210 516 737 ;
C 167 ; WX 556 ; N section ; B 34 -184 522 727 ;
C 168 ; WX 556 ; N currency ; B -3 76 559 636 ;
C 169 ; WX 238 ; N quotesingle ; B 70 447 168 718 ;
C 170 ; WX 500 ; N quotedblleft ; B 64 454 436 727 ;
C 171 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ;
C 172 ; WX 333 ; N guilsinglleft ; B 83 76 250 484 ;
C 173 ; WX 333 ; N guilsinglright ; B 83 76 250 484 ;
C 174 ; WX 611 ; N fi ; B 10 0 542 727 ;
C 175 ; WX 611 ; N fl ; B 10 0 542 727 ;
C 177 ; WX 556 ; N endash ; B 0 227 556 333 ;
C 178 ; WX 556 ; N dagger ; B 36 -171 520 718 ;
C 179 ; WX 556 ; N daggerdbl ; B 36 -171 520 718 ;
C 180 ; WX 278 ; N periodcentered ; B 58 172 220 334 ;
C 182 ; WX 556 ; N paragraph ; B -8 -191 539 700 ;
C 183 ; WX 350 ; N bullet ; B 10 194 340 524 ;
C 184 ; WX 278 ; N quotesinglbase ; B 69 -146 209 127 ;
C 185 ; WX 500 ; N quotedblbase ; B 64 -146 436 127 ;
C 186 ; WX 500 ; N quotedblright ; B 64 445 436 718 ;
C 187 ; WX 556 ; N guillemotright ; B 88 76 468 484 ;
C 188 ; WX 1000 ; N ellipsis ; B 92 0 908 146 ;
C 189 ; WX 1000 ; N perthousand ; B -3 -19 1003 710 ;
C 191 ; WX 611 ; N questiondown ; B 55 -195 551 532 ;
C 193 ; WX 333 ; N grave ; B -23 604 225 750 ;
C 194 ; WX 333 ; N acute ; B 108 604 356 750 ;
C 195 ; WX 333 ; N circumflex ; B -10 604 343 750 ;
C 196 ; WX 333 ; N tilde ; B -17 610 350 737 ;
C 197 ; WX 333 ; N macron ; B -6 604 339 678 ;
C 198 ; WX 333 ; N breve ; B -2 604 335 750 ;
C 199 ; WX 333 ; N dotaccent ; B 104 614 230 729 ;
C 200 ; WX 333 ; N dieresis ; B 6 614 327 729 ;
C 202 ; WX 333 ; N ring ; B 59 568 275 776 ;
C 203 ; WX 333 ; N cedilla ; B 6 -228 245 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B 9 604 486 750 ;
C 206 ; WX 333 ; N ogonek ; B 71 -228 304 0 ;
C 207 ; WX 333 ; N caron ; B -10 604 343 750 ;
C 208 ; WX 1000 ; N emdash ; B 0 227 1000 333 ;
C 225 ; WX 1000 ; N AE ; B 5 0 954 718 ;
C 227 ; WX 370 ; N ordfeminine ; B 22 401 347 737 ;
C 232 ; WX 611 ; N Lslash ; B -20 0 583 718 ;
C 233 ; WX 778 ; N Oslash ; B 33 -27 744 745 ;
C 234 ; WX 1000 ; N OE ; B 37 -19 961 737 ;
C 235 ; WX 365 ; N ordmasculine ; B 6 401 360 737 ;
C 241 ; WX 889 ; N ae ; B 29 -14 858 546 ;
C 245 ; WX 278 ; N dotlessi ; B 69 0 209 532 ;
C 248 ; WX 278 ; N lslash ; B -18 0 296 718 ;
C 249 ; WX 611 ; N oslash ; B 22 -29 589 560 ;
C 250 ; WX 944 ; N oe ; B 34 -14 912 546 ;
C 251 ; WX 611 ; N germandbls ; B 69 -14 579 731 ;
C -1 ; WX 278 ; N Idieresis ; B -21 0 300 915 ;
C -1 ; WX 556 ; N eacute ; B 23 -14 528 750 ;
C -1 ; WX 556 ; N abreve ; B 29 -14 527 750 ;
C -1 ; WX 611 ; N uhungarumlaut ; B 66 -14 625 750 ;
C -1 ; WX 556 ; N ecaron ; B 23 -14 528 750 ;
C -1 ; WX 667 ; N Ydieresis ; B 15 0 653 915 ;
C -1 ; WX 584 ; N divide ; B 40 -42 544 548 ;
C -1 ; WX 667 ; N Yacute ; B 15 0 653 936 ;
C -1 ; WX 722 ; N Acircumflex ; B 20 0 702 936 ;
C -1 ; WX 556 ; N aacute ; B 29 -14 527 750 ;
C -1 ; WX 722 ; N Ucircumflex ; B 72 -19 651 936 ;
C -1 ; WX 556 ; N yacute ; B 10 -214 539 750 ;
C -1 ; WX 556 ; N scommaaccent ; B 30 -228 519 546 ;
C -1 ; WX 556 ; N ecircumflex ; B 23 -14 528 750 ;
C -1 ; WX 722 ; N Uring ; B 72 -19 651 962 ;
C -1 ; WX 722 ; N Udieresis ; B 72 -19 651 915 ;
C -1 ; WX 556 ; N aogonek ; B 29 -224 545 546 ;
C -1 ; WX 722 ; N Uacute ; B 72 -19 651 936 ;
C -1 ; WX 611 ; N uogonek ; B 66 -228 545 532 ;
C -1 ; WX 667 ; N Edieresis ; B 76 0 621 915 ;
C -1 ; WX 722 ; N Dcroat ; B -5 0 685 718 ;
C -1 ; WX 250 ; N commaaccent ; B 64 -228 199 -50 ;
C -1 ; WX 737 ; N copyright ; B -11 -19 749 737 ;
C -1 ; WX 667 ; N Emacron ; B 76 0 621 864 ;
C -1 ; WX 556 ; N ccaron ; B 34 -14 524 750 ;
C -1 ; WX 556 ; N aring ; B 29 -14 527 776 ;
C -1 ; WX 722 ; N Ncommaaccent ; B 69 -228 654 718 ;
C -1 ; WX 278 ; N lacute ; B 69 0 329 936 ;
C -1 ; WX 556 ; N agrave ; B 29 -14 527 750 ;
C -1 ; WX 611 ; N Tcommaaccent ; B 14 -228 598 718 ;
C -1 ; WX 722 ; N Cacute ; B 44 -19 684 936 ;
C -1 ; WX 556 ; N atilde ; B 29 -14 527 737 ;
C -1 ; WX 667 ; N Edotaccent ; B 76 0 621 915 ;
C -1 ; WX 556 ; N scaron ; B 30 -14 519 750 ;
C -1 ; WX 556 ; N scedilla ; B 30 -228 519 546 ;
C -1 ; WX 278 ; N iacute ; B 69 0 329 750 ;
C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ;
C -1 ; WX 722 ; N Rcaron ; B 76 0 677 936 ;
C -1 ; WX 778 ; N Gcommaaccent ; B 44 -228 713 737 ;
C -1 ; WX 611 ; N ucircumflex ; B 66 -14 545 750 ;
C -1 ; WX 556 ; N acircumflex ; B 29 -14 527 750 ;
C -1 ; WX 722 ; N Amacron ; B 20 0 702 864 ;
C -1 ; WX 389 ; N rcaron ; B 18 0 373 750 ;
C -1 ; WX 556 ; N ccedilla ; B 34 -228 524 546 ;
C -1 ; WX 611 ; N Zdotaccent ; B 25 0 586 915 ;
C -1 ; WX 667 ; N Thorn ; B 76 0 627 718 ;
C -1 ; WX 778 ; N Omacron ; B 44 -19 734 864 ;
C -1 ; WX 722 ; N Racute ; B 76 0 677 936 ;
C -1 ; WX 667 ; N Sacute ; B 39 -19 629 936 ;
C -1 ; WX 743 ; N dcaron ; B 34 -14 750 718 ;
C -1 ; WX 722 ; N Umacron ; B 72 -19 651 864 ;
C -1 ; WX 611 ; N uring ; B 66 -14 545 776 ;
C -1 ; WX 333 ; N threesuperior ; B 8 271 326 710 ;
C -1 ; WX 778 ; N Ograve ; B 44 -19 734 936 ;
C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ;
C -1 ; WX 722 ; N Abreve ; B 20 0 702 936 ;
C -1 ; WX 584 ; N multiply ; B 40 1 545 505 ;
C -1 ; WX 611 ; N uacute ; B 66 -14 545 750 ;
C -1 ; WX 611 ; N Tcaron ; B 14 0 598 936 ;
C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ;
C -1 ; WX 556 ; N ydieresis ; B 10 -214 539 729 ;
C -1 ; WX 722 ; N Nacute ; B 69 0 654 936 ;
C -1 ; WX 278 ; N icircumflex ; B -37 0 316 750 ;
C -1 ; WX 667 ; N Ecircumflex ; B 76 0 621 936 ;
C -1 ; WX 556 ; N adieresis ; B 29 -14 527 729 ;
C -1 ; WX 556 ; N edieresis ; B 23 -14 528 729 ;
C -1 ; WX 556 ; N cacute ; B 34 -14 524 750 ;
C -1 ; WX 611 ; N nacute ; B 65 0 546 750 ;
C -1 ; WX 611 ; N umacron ; B 66 -14 545 678 ;
C -1 ; WX 722 ; N Ncaron ; B 69 0 654 936 ;
C -1 ; WX 278 ; N Iacute ; B 64 0 329 936 ;
C -1 ; WX 584 ; N plusminus ; B 40 0 544 506 ;
C -1 ; WX 280 ; N brokenbar ; B 84 -150 196 700 ;
C -1 ; WX 737 ; N registered ; B -11 -19 748 737 ;
C -1 ; WX 778 ; N Gbreve ; B 44 -19 713 936 ;
C -1 ; WX 278 ; N Idotaccent ; B 64 0 214 915 ;
C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ;
C -1 ; WX 667 ; N Egrave ; B 76 0 621 936 ;
C -1 ; WX 389 ; N racute ; B 64 0 384 750 ;
C -1 ; WX 611 ; N omacron ; B 34 -14 578 678 ;
C -1 ; WX 611 ; N Zacute ; B 25 0 586 936 ;
C -1 ; WX 611 ; N Zcaron ; B 25 0 586 936 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ;
C -1 ; WX 722 ; N Eth ; B -5 0 685 718 ;
C -1 ; WX 722 ; N Ccedilla ; B 44 -228 684 737 ;
C -1 ; WX 278 ; N lcommaaccent ; B 69 -228 213 718 ;
C -1 ; WX 389 ; N tcaron ; B 10 -6 421 878 ;
C -1 ; WX 556 ; N eogonek ; B 23 -228 528 546 ;
C -1 ; WX 722 ; N Uogonek ; B 72 -228 651 718 ;
C -1 ; WX 722 ; N Aacute ; B 20 0 702 936 ;
C -1 ; WX 722 ; N Adieresis ; B 20 0 702 915 ;
C -1 ; WX 556 ; N egrave ; B 23 -14 528 750 ;
C -1 ; WX 500 ; N zacute ; B 20 0 480 750 ;
C -1 ; WX 278 ; N iogonek ; B 16 -224 249 725 ;
C -1 ; WX 778 ; N Oacute ; B 44 -19 734 936 ;
C -1 ; WX 611 ; N oacute ; B 34 -14 578 750 ;
C -1 ; WX 556 ; N amacron ; B 29 -14 527 678 ;
C -1 ; WX 556 ; N sacute ; B 30 -14 519 750 ;
C -1 ; WX 278 ; N idieresis ; B -21 0 300 729 ;
C -1 ; WX 778 ; N Ocircumflex ; B 44 -19 734 936 ;
C -1 ; WX 722 ; N Ugrave ; B 72 -19 651 936 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 611 ; N thorn ; B 62 -208 578 718 ;
C -1 ; WX 333 ; N twosuperior ; B 9 283 324 710 ;
C -1 ; WX 778 ; N Odieresis ; B 44 -19 734 915 ;
C -1 ; WX 611 ; N mu ; B 66 -207 545 532 ;
C -1 ; WX 278 ; N igrave ; B -50 0 209 750 ;
C -1 ; WX 611 ; N ohungarumlaut ; B 34 -14 625 750 ;
C -1 ; WX 667 ; N Eogonek ; B 76 -224 639 718 ;
C -1 ; WX 611 ; N dcroat ; B 34 -14 650 718 ;
C -1 ; WX 834 ; N threequarters ; B 16 -19 799 710 ;
C -1 ; WX 667 ; N Scedilla ; B 39 -228 629 737 ;
C -1 ; WX 400 ; N lcaron ; B 69 0 408 718 ;
C -1 ; WX 722 ; N Kcommaaccent ; B 87 -228 722 718 ;
C -1 ; WX 611 ; N Lacute ; B 76 0 583 936 ;
C -1 ; WX 1000 ; N trademark ; B 44 306 956 718 ;
C -1 ; WX 556 ; N edotaccent ; B 23 -14 528 729 ;
C -1 ; WX 278 ; N Igrave ; B -50 0 214 936 ;
C -1 ; WX 278 ; N Imacron ; B -33 0 312 864 ;
C -1 ; WX 611 ; N Lcaron ; B 76 0 583 718 ;
C -1 ; WX 834 ; N onehalf ; B 26 -19 794 710 ;
C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ;
C -1 ; WX 611 ; N ocircumflex ; B 34 -14 578 750 ;
C -1 ; WX 611 ; N ntilde ; B 65 0 546 737 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 72 -19 681 936 ;
C -1 ; WX 667 ; N Eacute ; B 76 0 621 936 ;
C -1 ; WX 556 ; N emacron ; B 23 -14 528 678 ;
C -1 ; WX 611 ; N gbreve ; B 40 -217 553 750 ;
C -1 ; WX 834 ; N onequarter ; B 26 -19 766 710 ;
C -1 ; WX 667 ; N Scaron ; B 39 -19 629 936 ;
C -1 ; WX 667 ; N Scommaaccent ; B 39 -228 629 737 ;
C -1 ; WX 778 ; N Ohungarumlaut ; B 44 -19 734 936 ;
C -1 ; WX 400 ; N degree ; B 57 426 343 712 ;
C -1 ; WX 611 ; N ograve ; B 34 -14 578 750 ;
C -1 ; WX 722 ; N Ccaron ; B 44 -19 684 936 ;
C -1 ; WX 611 ; N ugrave ; B 66 -14 545 750 ;
C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ;
C -1 ; WX 722 ; N Dcaron ; B 76 0 685 936 ;
C -1 ; WX 389 ; N rcommaaccent ; B 64 -228 373 546 ;
C -1 ; WX 722 ; N Ntilde ; B 69 0 654 923 ;
C -1 ; WX 611 ; N otilde ; B 34 -14 578 737 ;
C -1 ; WX 722 ; N Rcommaaccent ; B 76 -228 677 718 ;
C -1 ; WX 611 ; N Lcommaaccent ; B 76 -228 583 718 ;
C -1 ; WX 722 ; N Atilde ; B 20 0 702 923 ;
C -1 ; WX 722 ; N Aogonek ; B 20 -224 742 718 ;
C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ;
C -1 ; WX 778 ; N Otilde ; B 44 -19 734 923 ;
C -1 ; WX 500 ; N zdotaccent ; B 20 0 480 729 ;
C -1 ; WX 667 ; N Ecaron ; B 76 0 621 936 ;
C -1 ; WX 278 ; N Iogonek ; B -11 -228 222 718 ;
C -1 ; WX 556 ; N kcommaaccent ; B 69 -228 562 718 ;
C -1 ; WX 584 ; N minus ; B 40 197 544 309 ;
C -1 ; WX 278 ; N Icircumflex ; B -37 0 316 936 ;
C -1 ; WX 611 ; N ncaron ; B 65 0 546 750 ;
C -1 ; WX 333 ; N tcommaaccent ; B 10 -228 309 676 ;
C -1 ; WX 584 ; N logicalnot ; B 40 108 544 419 ;
C -1 ; WX 611 ; N odieresis ; B 34 -14 578 729 ;
C -1 ; WX 611 ; N udieresis ; B 66 -14 545 729 ;
C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ;
C -1 ; WX 611 ; N gcommaaccent ; B 40 -217 553 850 ;
C -1 ; WX 611 ; N eth ; B 34 -14 578 737 ;
C -1 ; WX 500 ; N zcaron ; B 20 0 480 750 ;
C -1 ; WX 611 ; N ncommaaccent ; B 65 -228 546 546 ;
C -1 ; WX 333 ; N onesuperior ; B 26 283 237 710 ;
C -1 ; WX 278 ; N imacron ; B -8 0 285 678 ;
C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2481
KPX A C -40
KPX A Cacute -40
KPX A Ccaron -40
KPX A Ccedilla -40
KPX A G -50
KPX A Gbreve -50
KPX A Gcommaaccent -50
KPX A O -40
KPX A Oacute -40
KPX A Ocircumflex -40
KPX A Odieresis -40
KPX A Ograve -40
KPX A Ohungarumlaut -40
KPX A Omacron -40
KPX A Oslash -40
KPX A Otilde -40
KPX A Q -40
KPX A T -90
KPX A Tcaron -90
KPX A Tcommaaccent -90
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -80
KPX A W -60
KPX A Y -110
KPX A Yacute -110
KPX A Ydieresis -110
KPX A u -30
KPX A uacute -30
KPX A ucircumflex -30
KPX A udieresis -30
KPX A ugrave -30
KPX A uhungarumlaut -30
KPX A umacron -30
KPX A uogonek -30
KPX A uring -30
KPX A v -40
KPX A w -30
KPX A y -30
KPX A yacute -30
KPX A ydieresis -30
KPX Aacute C -40
KPX Aacute Cacute -40
KPX Aacute Ccaron -40
KPX Aacute Ccedilla -40
KPX Aacute G -50
KPX Aacute Gbreve -50
KPX Aacute Gcommaaccent -50
KPX Aacute O -40
KPX Aacute Oacute -40
KPX Aacute Ocircumflex -40
KPX Aacute Odieresis -40
KPX Aacute Ograve -40
KPX Aacute Ohungarumlaut -40
KPX Aacute Omacron -40
KPX Aacute Oslash -40
KPX Aacute Otilde -40
KPX Aacute Q -40
KPX Aacute T -90
KPX Aacute Tcaron -90
KPX Aacute Tcommaaccent -90
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -80
KPX Aacute W -60
KPX Aacute Y -110
KPX Aacute Yacute -110
KPX Aacute Ydieresis -110
KPX Aacute u -30
KPX Aacute uacute -30
KPX Aacute ucircumflex -30
KPX Aacute udieresis -30
KPX Aacute ugrave -30
KPX Aacute uhungarumlaut -30
KPX Aacute umacron -30
KPX Aacute uogonek -30
KPX Aacute uring -30
KPX Aacute v -40
KPX Aacute w -30
KPX Aacute y -30
KPX Aacute yacute -30
KPX Aacute ydieresis -30
KPX Abreve C -40
KPX Abreve Cacute -40
KPX Abreve Ccaron -40
KPX Abreve Ccedilla -40
KPX Abreve G -50
KPX Abreve Gbreve -50
KPX Abreve Gcommaaccent -50
KPX Abreve O -40
KPX Abreve Oacute -40
KPX Abreve Ocircumflex -40
KPX Abreve Odieresis -40
KPX Abreve Ograve -40
KPX Abreve Ohungarumlaut -40
KPX Abreve Omacron -40
KPX Abreve Oslash -40
KPX Abreve Otilde -40
KPX Abreve Q -40
KPX Abreve T -90
KPX Abreve Tcaron -90
KPX Abreve Tcommaaccent -90
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -80
KPX Abreve W -60
KPX Abreve Y -110
KPX Abreve Yacute -110
KPX Abreve Ydieresis -110
KPX Abreve u -30
KPX Abreve uacute -30
KPX Abreve ucircumflex -30
KPX Abreve udieresis -30
KPX Abreve ugrave -30
KPX Abreve uhungarumlaut -30
KPX Abreve umacron -30
KPX Abreve uogonek -30
KPX Abreve uring -30
KPX Abreve v -40
KPX Abreve w -30
KPX Abreve y -30
KPX Abreve yacute -30
KPX Abreve ydieresis -30
KPX Acircumflex C -40
KPX Acircumflex Cacute -40
KPX Acircumflex Ccaron -40
KPX Acircumflex Ccedilla -40
KPX Acircumflex G -50
KPX Acircumflex Gbreve -50
KPX Acircumflex Gcommaaccent -50
KPX Acircumflex O -40
KPX Acircumflex Oacute -40
KPX Acircumflex Ocircumflex -40
KPX Acircumflex Odieresis -40
KPX Acircumflex Ograve -40
KPX Acircumflex Ohungarumlaut -40
KPX Acircumflex Omacron -40
KPX Acircumflex Oslash -40
KPX Acircumflex Otilde -40
KPX Acircumflex Q -40
KPX Acircumflex T -90
KPX Acircumflex Tcaron -90
KPX Acircumflex Tcommaaccent -90
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -80
KPX Acircumflex W -60
KPX Acircumflex Y -110
KPX Acircumflex Yacute -110
KPX Acircumflex Ydieresis -110
KPX Acircumflex u -30
KPX Acircumflex uacute -30
KPX Acircumflex ucircumflex -30
KPX Acircumflex udieresis -30
KPX Acircumflex ugrave -30
KPX Acircumflex uhungarumlaut -30
KPX Acircumflex umacron -30
KPX Acircumflex uogonek -30
KPX Acircumflex uring -30
KPX Acircumflex v -40
KPX Acircumflex w -30
KPX Acircumflex y -30
KPX Acircumflex yacute -30
KPX Acircumflex ydieresis -30
KPX Adieresis C -40
KPX Adieresis Cacute -40
KPX Adieresis Ccaron -40
KPX Adieresis Ccedilla -40
KPX Adieresis G -50
KPX Adieresis Gbreve -50
KPX Adieresis Gcommaaccent -50
KPX Adieresis O -40
KPX Adieresis Oacute -40
KPX Adieresis Ocircumflex -40
KPX Adieresis Odieresis -40
KPX Adieresis Ograve -40
KPX Adieresis Ohungarumlaut -40
KPX Adieresis Omacron -40
KPX Adieresis Oslash -40
KPX Adieresis Otilde -40
KPX Adieresis Q -40
KPX Adieresis T -90
KPX Adieresis Tcaron -90
KPX Adieresis Tcommaaccent -90
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -80
KPX Adieresis W -60
KPX Adieresis Y -110
KPX Adieresis Yacute -110
KPX Adieresis Ydieresis -110
KPX Adieresis u -30
KPX Adieresis uacute -30
KPX Adieresis ucircumflex -30
KPX Adieresis udieresis -30
KPX Adieresis ugrave -30
KPX Adieresis uhungarumlaut -30
KPX Adieresis umacron -30
KPX Adieresis uogonek -30
KPX Adieresis uring -30
KPX Adieresis v -40
KPX Adieresis w -30
KPX Adieresis y -30
KPX Adieresis yacute -30
KPX Adieresis ydieresis -30
KPX Agrave C -40
KPX Agrave Cacute -40
KPX Agrave Ccaron -40
KPX Agrave Ccedilla -40
KPX Agrave G -50
KPX Agrave Gbreve -50
KPX Agrave Gcommaaccent -50
KPX Agrave O -40
KPX Agrave Oacute -40
KPX Agrave Ocircumflex -40
KPX Agrave Odieresis -40
KPX Agrave Ograve -40
KPX Agrave Ohungarumlaut -40
KPX Agrave Omacron -40
KPX Agrave Oslash -40
KPX Agrave Otilde -40
KPX Agrave Q -40
KPX Agrave T -90
KPX Agrave Tcaron -90
KPX Agrave Tcommaaccent -90
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -80
KPX Agrave W -60
KPX Agrave Y -110
KPX Agrave Yacute -110
KPX Agrave Ydieresis -110
KPX Agrave u -30
KPX Agrave uacute -30
KPX Agrave ucircumflex -30
KPX Agrave udieresis -30
KPX Agrave ugrave -30
KPX Agrave uhungarumlaut -30
KPX Agrave umacron -30
KPX Agrave uogonek -30
KPX Agrave uring -30
KPX Agrave v -40
KPX Agrave w -30
KPX Agrave y -30
KPX Agrave yacute -30
KPX Agrave ydieresis -30
KPX Amacron C -40
KPX Amacron Cacute -40
KPX Amacron Ccaron -40
KPX Amacron Ccedilla -40
KPX Amacron G -50
KPX Amacron Gbreve -50
KPX Amacron Gcommaaccent -50
KPX Amacron O -40
KPX Amacron Oacute -40
KPX Amacron Ocircumflex -40
KPX Amacron Odieresis -40
KPX Amacron Ograve -40
KPX Amacron Ohungarumlaut -40
KPX Amacron Omacron -40
KPX Amacron Oslash -40
KPX Amacron Otilde -40
KPX Amacron Q -40
KPX Amacron T -90
KPX Amacron Tcaron -90
KPX Amacron Tcommaaccent -90
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -80
KPX Amacron W -60
KPX Amacron Y -110
KPX Amacron Yacute -110
KPX Amacron Ydieresis -110
KPX Amacron u -30
KPX Amacron uacute -30
KPX Amacron ucircumflex -30
KPX Amacron udieresis -30
KPX Amacron ugrave -30
KPX Amacron uhungarumlaut -30
KPX Amacron umacron -30
KPX Amacron uogonek -30
KPX Amacron uring -30
KPX Amacron v -40
KPX Amacron w -30
KPX Amacron y -30
KPX Amacron yacute -30
KPX Amacron ydieresis -30
KPX Aogonek C -40
KPX Aogonek Cacute -40
KPX Aogonek Ccaron -40
KPX Aogonek Ccedilla -40
KPX Aogonek G -50
KPX Aogonek Gbreve -50
KPX Aogonek Gcommaaccent -50
KPX Aogonek O -40
KPX Aogonek Oacute -40
KPX Aogonek Ocircumflex -40
KPX Aogonek Odieresis -40
KPX Aogonek Ograve -40
KPX Aogonek Ohungarumlaut -40
KPX Aogonek Omacron -40
KPX Aogonek Oslash -40
KPX Aogonek Otilde -40
KPX Aogonek Q -40
KPX Aogonek T -90
KPX Aogonek Tcaron -90
KPX Aogonek Tcommaaccent -90
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -80
KPX Aogonek W -60
KPX Aogonek Y -110
KPX Aogonek Yacute -110
KPX Aogonek Ydieresis -110
KPX Aogonek u -30
KPX Aogonek uacute -30
KPX Aogonek ucircumflex -30
KPX Aogonek udieresis -30
KPX Aogonek ugrave -30
KPX Aogonek uhungarumlaut -30
KPX Aogonek umacron -30
KPX Aogonek uogonek -30
KPX Aogonek uring -30
KPX Aogonek v -40
KPX Aogonek w -30
KPX Aogonek y -30
KPX Aogonek yacute -30
KPX Aogonek ydieresis -30
KPX Aring C -40
KPX Aring Cacute -40
KPX Aring Ccaron -40
KPX Aring Ccedilla -40
KPX Aring G -50
KPX Aring Gbreve -50
KPX Aring Gcommaaccent -50
KPX Aring O -40
KPX Aring Oacute -40
KPX Aring Ocircumflex -40
KPX Aring Odieresis -40
KPX Aring Ograve -40
KPX Aring Ohungarumlaut -40
KPX Aring Omacron -40
KPX Aring Oslash -40
KPX Aring Otilde -40
KPX Aring Q -40
KPX Aring T -90
KPX Aring Tcaron -90
KPX Aring Tcommaaccent -90
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -80
KPX Aring W -60
KPX Aring Y -110
KPX Aring Yacute -110
KPX Aring Ydieresis -110
KPX Aring u -30
KPX Aring uacute -30
KPX Aring ucircumflex -30
KPX Aring udieresis -30
KPX Aring ugrave -30
KPX Aring uhungarumlaut -30
KPX Aring umacron -30
KPX Aring uogonek -30
KPX Aring uring -30
KPX Aring v -40
KPX Aring w -30
KPX Aring y -30
KPX Aring yacute -30
KPX Aring ydieresis -30
KPX Atilde C -40
KPX Atilde Cacute -40
KPX Atilde Ccaron -40
KPX Atilde Ccedilla -40
KPX Atilde G -50
KPX Atilde Gbreve -50
KPX Atilde Gcommaaccent -50
KPX Atilde O -40
KPX Atilde Oacute -40
KPX Atilde Ocircumflex -40
KPX Atilde Odieresis -40
KPX Atilde Ograve -40
KPX Atilde Ohungarumlaut -40
KPX Atilde Omacron -40
KPX Atilde Oslash -40
KPX Atilde Otilde -40
KPX Atilde Q -40
KPX Atilde T -90
KPX Atilde Tcaron -90
KPX Atilde Tcommaaccent -90
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -80
KPX Atilde W -60
KPX Atilde Y -110
KPX Atilde Yacute -110
KPX Atilde Ydieresis -110
KPX Atilde u -30
KPX Atilde uacute -30
KPX Atilde ucircumflex -30
KPX Atilde udieresis -30
KPX Atilde ugrave -30
KPX Atilde uhungarumlaut -30
KPX Atilde umacron -30
KPX Atilde uogonek -30
KPX Atilde uring -30
KPX Atilde v -40
KPX Atilde w -30
KPX Atilde y -30
KPX Atilde yacute -30
KPX Atilde ydieresis -30
KPX B A -30
KPX B Aacute -30
KPX B Abreve -30
KPX B Acircumflex -30
KPX B Adieresis -30
KPX B Agrave -30
KPX B Amacron -30
KPX B Aogonek -30
KPX B Aring -30
KPX B Atilde -30
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX D A -40
KPX D Aacute -40
KPX D Abreve -40
KPX D Acircumflex -40
KPX D Adieresis -40
KPX D Agrave -40
KPX D Amacron -40
KPX D Aogonek -40
KPX D Aring -40
KPX D Atilde -40
KPX D V -40
KPX D W -40
KPX D Y -70
KPX D Yacute -70
KPX D Ydieresis -70
KPX D comma -30
KPX D period -30
KPX Dcaron A -40
KPX Dcaron Aacute -40
KPX Dcaron Abreve -40
KPX Dcaron Acircumflex -40
KPX Dcaron Adieresis -40
KPX Dcaron Agrave -40
KPX Dcaron Amacron -40
KPX Dcaron Aogonek -40
KPX Dcaron Aring -40
KPX Dcaron Atilde -40
KPX Dcaron V -40
KPX Dcaron W -40
KPX Dcaron Y -70
KPX Dcaron Yacute -70
KPX Dcaron Ydieresis -70
KPX Dcaron comma -30
KPX Dcaron period -30
KPX Dcroat A -40
KPX Dcroat Aacute -40
KPX Dcroat Abreve -40
KPX Dcroat Acircumflex -40
KPX Dcroat Adieresis -40
KPX Dcroat Agrave -40
KPX Dcroat Amacron -40
KPX Dcroat Aogonek -40
KPX Dcroat Aring -40
KPX Dcroat Atilde -40
KPX Dcroat V -40
KPX Dcroat W -40
KPX Dcroat Y -70
KPX Dcroat Yacute -70
KPX Dcroat Ydieresis -70
KPX Dcroat comma -30
KPX Dcroat period -30
KPX F A -80
KPX F Aacute -80
KPX F Abreve -80
KPX F Acircumflex -80
KPX F Adieresis -80
KPX F Agrave -80
KPX F Amacron -80
KPX F Aogonek -80
KPX F Aring -80
KPX F Atilde -80
KPX F a -20
KPX F aacute -20
KPX F abreve -20
KPX F acircumflex -20
KPX F adieresis -20
KPX F agrave -20
KPX F amacron -20
KPX F aogonek -20
KPX F aring -20
KPX F atilde -20
KPX F comma -100
KPX F period -100
KPX J A -20
KPX J Aacute -20
KPX J Abreve -20
KPX J Acircumflex -20
KPX J Adieresis -20
KPX J Agrave -20
KPX J Amacron -20
KPX J Aogonek -20
KPX J Aring -20
KPX J Atilde -20
KPX J comma -20
KPX J period -20
KPX J u -20
KPX J uacute -20
KPX J ucircumflex -20
KPX J udieresis -20
KPX J ugrave -20
KPX J uhungarumlaut -20
KPX J umacron -20
KPX J uogonek -20
KPX J uring -20
KPX K O -30
KPX K Oacute -30
KPX K Ocircumflex -30
KPX K Odieresis -30
KPX K Ograve -30
KPX K Ohungarumlaut -30
KPX K Omacron -30
KPX K Oslash -30
KPX K Otilde -30
KPX K e -15
KPX K eacute -15
KPX K ecaron -15
KPX K ecircumflex -15
KPX K edieresis -15
KPX K edotaccent -15
KPX K egrave -15
KPX K emacron -15
KPX K eogonek -15
KPX K o -35
KPX K oacute -35
KPX K ocircumflex -35
KPX K odieresis -35
KPX K ograve -35
KPX K ohungarumlaut -35
KPX K omacron -35
KPX K oslash -35
KPX K otilde -35
KPX K u -30
KPX K uacute -30
KPX K ucircumflex -30
KPX K udieresis -30
KPX K ugrave -30
KPX K uhungarumlaut -30
KPX K umacron -30
KPX K uogonek -30
KPX K uring -30
KPX K y -40
KPX K yacute -40
KPX K ydieresis -40
KPX Kcommaaccent O -30
KPX Kcommaaccent Oacute -30
KPX Kcommaaccent Ocircumflex -30
KPX Kcommaaccent Odieresis -30
KPX Kcommaaccent Ograve -30
KPX Kcommaaccent Ohungarumlaut -30
KPX Kcommaaccent Omacron -30
KPX Kcommaaccent Oslash -30
KPX Kcommaaccent Otilde -30
KPX Kcommaaccent e -15
KPX Kcommaaccent eacute -15
KPX Kcommaaccent ecaron -15
KPX Kcommaaccent ecircumflex -15
KPX Kcommaaccent edieresis -15
KPX Kcommaaccent edotaccent -15
KPX Kcommaaccent egrave -15
KPX Kcommaaccent emacron -15
KPX Kcommaaccent eogonek -15
KPX Kcommaaccent o -35
KPX Kcommaaccent oacute -35
KPX Kcommaaccent ocircumflex -35
KPX Kcommaaccent odieresis -35
KPX Kcommaaccent ograve -35
KPX Kcommaaccent ohungarumlaut -35
KPX Kcommaaccent omacron -35
KPX Kcommaaccent oslash -35
KPX Kcommaaccent otilde -35
KPX Kcommaaccent u -30
KPX Kcommaaccent uacute -30
KPX Kcommaaccent ucircumflex -30
KPX Kcommaaccent udieresis -30
KPX Kcommaaccent ugrave -30
KPX Kcommaaccent uhungarumlaut -30
KPX Kcommaaccent umacron -30
KPX Kcommaaccent uogonek -30
KPX Kcommaaccent uring -30
KPX Kcommaaccent y -40
KPX Kcommaaccent yacute -40
KPX Kcommaaccent ydieresis -40
KPX L T -90
KPX L Tcaron -90
KPX L Tcommaaccent -90
KPX L V -110
KPX L W -80
KPX L Y -120
KPX L Yacute -120
KPX L Ydieresis -120
KPX L quotedblright -140
KPX L quoteright -140
KPX L y -30
KPX L yacute -30
KPX L ydieresis -30
KPX Lacute T -90
KPX Lacute Tcaron -90
KPX Lacute Tcommaaccent -90
KPX Lacute V -110
KPX Lacute W -80
KPX Lacute Y -120
KPX Lacute Yacute -120
KPX Lacute Ydieresis -120
KPX Lacute quotedblright -140
KPX Lacute quoteright -140
KPX Lacute y -30
KPX Lacute yacute -30
KPX Lacute ydieresis -30
KPX Lcommaaccent T -90
KPX Lcommaaccent Tcaron -90
KPX Lcommaaccent Tcommaaccent -90
KPX Lcommaaccent V -110
KPX Lcommaaccent W -80
KPX Lcommaaccent Y -120
KPX Lcommaaccent Yacute -120
KPX Lcommaaccent Ydieresis -120
KPX Lcommaaccent quotedblright -140
KPX Lcommaaccent quoteright -140
KPX Lcommaaccent y -30
KPX Lcommaaccent yacute -30
KPX Lcommaaccent ydieresis -30
KPX Lslash T -90
KPX Lslash Tcaron -90
KPX Lslash Tcommaaccent -90
KPX Lslash V -110
KPX Lslash W -80
KPX Lslash Y -120
KPX Lslash Yacute -120
KPX Lslash Ydieresis -120
KPX Lslash quotedblright -140
KPX Lslash quoteright -140
KPX Lslash y -30
KPX Lslash yacute -30
KPX Lslash ydieresis -30
KPX O A -50
KPX O Aacute -50
KPX O Abreve -50
KPX O Acircumflex -50
KPX O Adieresis -50
KPX O Agrave -50
KPX O Amacron -50
KPX O Aogonek -50
KPX O Aring -50
KPX O Atilde -50
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -50
KPX O X -50
KPX O Y -70
KPX O Yacute -70
KPX O Ydieresis -70
KPX O comma -40
KPX O period -40
KPX Oacute A -50
KPX Oacute Aacute -50
KPX Oacute Abreve -50
KPX Oacute Acircumflex -50
KPX Oacute Adieresis -50
KPX Oacute Agrave -50
KPX Oacute Amacron -50
KPX Oacute Aogonek -50
KPX Oacute Aring -50
KPX Oacute Atilde -50
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -50
KPX Oacute X -50
KPX Oacute Y -70
KPX Oacute Yacute -70
KPX Oacute Ydieresis -70
KPX Oacute comma -40
KPX Oacute period -40
KPX Ocircumflex A -50
KPX Ocircumflex Aacute -50
KPX Ocircumflex Abreve -50
KPX Ocircumflex Acircumflex -50
KPX Ocircumflex Adieresis -50
KPX Ocircumflex Agrave -50
KPX Ocircumflex Amacron -50
KPX Ocircumflex Aogonek -50
KPX Ocircumflex Aring -50
KPX Ocircumflex Atilde -50
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -50
KPX Ocircumflex X -50
KPX Ocircumflex Y -70
KPX Ocircumflex Yacute -70
KPX Ocircumflex Ydieresis -70
KPX Ocircumflex comma -40
KPX Ocircumflex period -40
KPX Odieresis A -50
KPX Odieresis Aacute -50
KPX Odieresis Abreve -50
KPX Odieresis Acircumflex -50
KPX Odieresis Adieresis -50
KPX Odieresis Agrave -50
KPX Odieresis Amacron -50
KPX Odieresis Aogonek -50
KPX Odieresis Aring -50
KPX Odieresis Atilde -50
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -50
KPX Odieresis X -50
KPX Odieresis Y -70
KPX Odieresis Yacute -70
KPX Odieresis Ydieresis -70
KPX Odieresis comma -40
KPX Odieresis period -40
KPX Ograve A -50
KPX Ograve Aacute -50
KPX Ograve Abreve -50
KPX Ograve Acircumflex -50
KPX Ograve Adieresis -50
KPX Ograve Agrave -50
KPX Ograve Amacron -50
KPX Ograve Aogonek -50
KPX Ograve Aring -50
KPX Ograve Atilde -50
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -50
KPX Ograve X -50
KPX Ograve Y -70
KPX Ograve Yacute -70
KPX Ograve Ydieresis -70
KPX Ograve comma -40
KPX Ograve period -40
KPX Ohungarumlaut A -50
KPX Ohungarumlaut Aacute -50
KPX Ohungarumlaut Abreve -50
KPX Ohungarumlaut Acircumflex -50
KPX Ohungarumlaut Adieresis -50
KPX Ohungarumlaut Agrave -50
KPX Ohungarumlaut Amacron -50
KPX Ohungarumlaut Aogonek -50
KPX Ohungarumlaut Aring -50
KPX Ohungarumlaut Atilde -50
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -50
KPX Ohungarumlaut X -50
KPX Ohungarumlaut Y -70
KPX Ohungarumlaut Yacute -70
KPX Ohungarumlaut Ydieresis -70
KPX Ohungarumlaut comma -40
KPX Ohungarumlaut period -40
KPX Omacron A -50
KPX Omacron Aacute -50
KPX Omacron Abreve -50
KPX Omacron Acircumflex -50
KPX Omacron Adieresis -50
KPX Omacron Agrave -50
KPX Omacron Amacron -50
KPX Omacron Aogonek -50
KPX Omacron Aring -50
KPX Omacron Atilde -50
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -50
KPX Omacron X -50
KPX Omacron Y -70
KPX Omacron Yacute -70
KPX Omacron Ydieresis -70
KPX Omacron comma -40
KPX Omacron period -40
KPX Oslash A -50
KPX Oslash Aacute -50
KPX Oslash Abreve -50
KPX Oslash Acircumflex -50
KPX Oslash Adieresis -50
KPX Oslash Agrave -50
KPX Oslash Amacron -50
KPX Oslash Aogonek -50
KPX Oslash Aring -50
KPX Oslash Atilde -50
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -50
KPX Oslash X -50
KPX Oslash Y -70
KPX Oslash Yacute -70
KPX Oslash Ydieresis -70
KPX Oslash comma -40
KPX Oslash period -40
KPX Otilde A -50
KPX Otilde Aacute -50
KPX Otilde Abreve -50
KPX Otilde Acircumflex -50
KPX Otilde Adieresis -50
KPX Otilde Agrave -50
KPX Otilde Amacron -50
KPX Otilde Aogonek -50
KPX Otilde Aring -50
KPX Otilde Atilde -50
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -50
KPX Otilde X -50
KPX Otilde Y -70
KPX Otilde Yacute -70
KPX Otilde Ydieresis -70
KPX Otilde comma -40
KPX Otilde period -40
KPX P A -100
KPX P Aacute -100
KPX P Abreve -100
KPX P Acircumflex -100
KPX P Adieresis -100
KPX P Agrave -100
KPX P Amacron -100
KPX P Aogonek -100
KPX P Aring -100
KPX P Atilde -100
KPX P a -30
KPX P aacute -30
KPX P abreve -30
KPX P acircumflex -30
KPX P adieresis -30
KPX P agrave -30
KPX P amacron -30
KPX P aogonek -30
KPX P aring -30
KPX P atilde -30
KPX P comma -120
KPX P e -30
KPX P eacute -30
KPX P ecaron -30
KPX P ecircumflex -30
KPX P edieresis -30
KPX P edotaccent -30
KPX P egrave -30
KPX P emacron -30
KPX P eogonek -30
KPX P o -40
KPX P oacute -40
KPX P ocircumflex -40
KPX P odieresis -40
KPX P ograve -40
KPX P ohungarumlaut -40
KPX P omacron -40
KPX P oslash -40
KPX P otilde -40
KPX P period -120
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX Q comma 20
KPX Q period 20
KPX R O -20
KPX R Oacute -20
KPX R Ocircumflex -20
KPX R Odieresis -20
KPX R Ograve -20
KPX R Ohungarumlaut -20
KPX R Omacron -20
KPX R Oslash -20
KPX R Otilde -20
KPX R T -20
KPX R Tcaron -20
KPX R Tcommaaccent -20
KPX R U -20
KPX R Uacute -20
KPX R Ucircumflex -20
KPX R Udieresis -20
KPX R Ugrave -20
KPX R Uhungarumlaut -20
KPX R Umacron -20
KPX R Uogonek -20
KPX R Uring -20
KPX R V -50
KPX R W -40
KPX R Y -50
KPX R Yacute -50
KPX R Ydieresis -50
KPX Racute O -20
KPX Racute Oacute -20
KPX Racute Ocircumflex -20
KPX Racute Odieresis -20
KPX Racute Ograve -20
KPX Racute Ohungarumlaut -20
KPX Racute Omacron -20
KPX Racute Oslash -20
KPX Racute Otilde -20
KPX Racute T -20
KPX Racute Tcaron -20
KPX Racute Tcommaaccent -20
KPX Racute U -20
KPX Racute Uacute -20
KPX Racute Ucircumflex -20
KPX Racute Udieresis -20
KPX Racute Ugrave -20
KPX Racute Uhungarumlaut -20
KPX Racute Umacron -20
KPX Racute Uogonek -20
KPX Racute Uring -20
KPX Racute V -50
KPX Racute W -40
KPX Racute Y -50
KPX Racute Yacute -50
KPX Racute Ydieresis -50
KPX Rcaron O -20
KPX Rcaron Oacute -20
KPX Rcaron Ocircumflex -20
KPX Rcaron Odieresis -20
KPX Rcaron Ograve -20
KPX Rcaron Ohungarumlaut -20
KPX Rcaron Omacron -20
KPX Rcaron Oslash -20
KPX Rcaron Otilde -20
KPX Rcaron T -20
KPX Rcaron Tcaron -20
KPX Rcaron Tcommaaccent -20
KPX Rcaron U -20
KPX Rcaron Uacute -20
KPX Rcaron Ucircumflex -20
KPX Rcaron Udieresis -20
KPX Rcaron Ugrave -20
KPX Rcaron Uhungarumlaut -20
KPX Rcaron Umacron -20
KPX Rcaron Uogonek -20
KPX Rcaron Uring -20
KPX Rcaron V -50
KPX Rcaron W -40
KPX Rcaron Y -50
KPX Rcaron Yacute -50
KPX Rcaron Ydieresis -50
KPX Rcommaaccent O -20
KPX Rcommaaccent Oacute -20
KPX Rcommaaccent Ocircumflex -20
KPX Rcommaaccent Odieresis -20
KPX Rcommaaccent Ograve -20
KPX Rcommaaccent Ohungarumlaut -20
KPX Rcommaaccent Omacron -20
KPX Rcommaaccent Oslash -20
KPX Rcommaaccent Otilde -20
KPX Rcommaaccent T -20
KPX Rcommaaccent Tcaron -20
KPX Rcommaaccent Tcommaaccent -20
KPX Rcommaaccent U -20
KPX Rcommaaccent Uacute -20
KPX Rcommaaccent Ucircumflex -20
KPX Rcommaaccent Udieresis -20
KPX Rcommaaccent Ugrave -20
KPX Rcommaaccent Uhungarumlaut -20
KPX Rcommaaccent Umacron -20
KPX Rcommaaccent Uogonek -20
KPX Rcommaaccent Uring -20
KPX Rcommaaccent V -50
KPX Rcommaaccent W -40
KPX Rcommaaccent Y -50
KPX Rcommaaccent Yacute -50
KPX Rcommaaccent Ydieresis -50
KPX T A -90
KPX T Aacute -90
KPX T Abreve -90
KPX T Acircumflex -90
KPX T Adieresis -90
KPX T Agrave -90
KPX T Amacron -90
KPX T Aogonek -90
KPX T Aring -90
KPX T Atilde -90
KPX T O -40
KPX T Oacute -40
KPX T Ocircumflex -40
KPX T Odieresis -40
KPX T Ograve -40
KPX T Ohungarumlaut -40
KPX T Omacron -40
KPX T Oslash -40
KPX T Otilde -40
KPX T a -80
KPX T aacute -80
KPX T abreve -80
KPX T acircumflex -80
KPX T adieresis -80
KPX T agrave -80
KPX T amacron -80
KPX T aogonek -80
KPX T aring -80
KPX T atilde -80
KPX T colon -40
KPX T comma -80
KPX T e -60
KPX T eacute -60
KPX T ecaron -60
KPX T ecircumflex -60
KPX T edieresis -60
KPX T edotaccent -60
KPX T egrave -60
KPX T emacron -60
KPX T eogonek -60
KPX T hyphen -120
KPX T o -80
KPX T oacute -80
KPX T ocircumflex -80
KPX T odieresis -80
KPX T ograve -80
KPX T ohungarumlaut -80
KPX T omacron -80
KPX T oslash -80
KPX T otilde -80
KPX T period -80
KPX T r -80
KPX T racute -80
KPX T rcommaaccent -80
KPX T semicolon -40
KPX T u -90
KPX T uacute -90
KPX T ucircumflex -90
KPX T udieresis -90
KPX T ugrave -90
KPX T uhungarumlaut -90
KPX T umacron -90
KPX T uogonek -90
KPX T uring -90
KPX T w -60
KPX T y -60
KPX T yacute -60
KPX T ydieresis -60
KPX Tcaron A -90
KPX Tcaron Aacute -90
KPX Tcaron Abreve -90
KPX Tcaron Acircumflex -90
KPX Tcaron Adieresis -90
KPX Tcaron Agrave -90
KPX Tcaron Amacron -90
KPX Tcaron Aogonek -90
KPX Tcaron Aring -90
KPX Tcaron Atilde -90
KPX Tcaron O -40
KPX Tcaron Oacute -40
KPX Tcaron Ocircumflex -40
KPX Tcaron Odieresis -40
KPX Tcaron Ograve -40
KPX Tcaron Ohungarumlaut -40
KPX Tcaron Omacron -40
KPX Tcaron Oslash -40
KPX Tcaron Otilde -40
KPX Tcaron a -80
KPX Tcaron aacute -80
KPX Tcaron abreve -80
KPX Tcaron acircumflex -80
KPX Tcaron adieresis -80
KPX Tcaron agrave -80
KPX Tcaron amacron -80
KPX Tcaron aogonek -80
KPX Tcaron aring -80
KPX Tcaron atilde -80
KPX Tcaron colon -40
KPX Tcaron comma -80
KPX Tcaron e -60
KPX Tcaron eacute -60
KPX Tcaron ecaron -60
KPX Tcaron ecircumflex -60
KPX Tcaron edieresis -60
KPX Tcaron edotaccent -60
KPX Tcaron egrave -60
KPX Tcaron emacron -60
KPX Tcaron eogonek -60
KPX Tcaron hyphen -120
KPX Tcaron o -80
KPX Tcaron oacute -80
KPX Tcaron ocircumflex -80
KPX Tcaron odieresis -80
KPX Tcaron ograve -80
KPX Tcaron ohungarumlaut -80
KPX Tcaron omacron -80
KPX Tcaron oslash -80
KPX Tcaron otilde -80
KPX Tcaron period -80
KPX Tcaron r -80
KPX Tcaron racute -80
KPX Tcaron rcommaaccent -80
KPX Tcaron semicolon -40
KPX Tcaron u -90
KPX Tcaron uacute -90
KPX Tcaron ucircumflex -90
KPX Tcaron udieresis -90
KPX Tcaron ugrave -90
KPX Tcaron uhungarumlaut -90
KPX Tcaron umacron -90
KPX Tcaron uogonek -90
KPX Tcaron uring -90
KPX Tcaron w -60
KPX Tcaron y -60
KPX Tcaron yacute -60
KPX Tcaron ydieresis -60
KPX Tcommaaccent A -90
KPX Tcommaaccent Aacute -90
KPX Tcommaaccent Abreve -90
KPX Tcommaaccent Acircumflex -90
KPX Tcommaaccent Adieresis -90
KPX Tcommaaccent Agrave -90
KPX Tcommaaccent Amacron -90
KPX Tcommaaccent Aogonek -90
KPX Tcommaaccent Aring -90
KPX Tcommaaccent Atilde -90
KPX Tcommaaccent O -40
KPX Tcommaaccent Oacute -40
KPX Tcommaaccent Ocircumflex -40
KPX Tcommaaccent Odieresis -40
KPX Tcommaaccent Ograve -40
KPX Tcommaaccent Ohungarumlaut -40
KPX Tcommaaccent Omacron -40
KPX Tcommaaccent Oslash -40
KPX Tcommaaccent Otilde -40
KPX Tcommaaccent a -80
KPX Tcommaaccent aacute -80
KPX Tcommaaccent abreve -80
KPX Tcommaaccent acircumflex -80
KPX Tcommaaccent adieresis -80
KPX Tcommaaccent agrave -80
KPX Tcommaaccent amacron -80
KPX Tcommaaccent aogonek -80
KPX Tcommaaccent aring -80
KPX Tcommaaccent atilde -80
KPX Tcommaaccent colon -40
KPX Tcommaaccent comma -80
KPX Tcommaaccent e -60
KPX Tcommaaccent eacute -60
KPX Tcommaaccent ecaron -60
KPX Tcommaaccent ecircumflex -60
KPX Tcommaaccent edieresis -60
KPX Tcommaaccent edotaccent -60
KPX Tcommaaccent egrave -60
KPX Tcommaaccent emacron -60
KPX Tcommaaccent eogonek -60
KPX Tcommaaccent hyphen -120
KPX Tcommaaccent o -80
KPX Tcommaaccent oacute -80
KPX Tcommaaccent ocircumflex -80
KPX Tcommaaccent odieresis -80
KPX Tcommaaccent ograve -80
KPX Tcommaaccent ohungarumlaut -80
KPX Tcommaaccent omacron -80
KPX Tcommaaccent oslash -80
KPX Tcommaaccent otilde -80
KPX Tcommaaccent period -80
KPX Tcommaaccent r -80
KPX Tcommaaccent racute -80
KPX Tcommaaccent rcommaaccent -80
KPX Tcommaaccent semicolon -40
KPX Tcommaaccent u -90
KPX Tcommaaccent uacute -90
KPX Tcommaaccent ucircumflex -90
KPX Tcommaaccent udieresis -90
KPX Tcommaaccent ugrave -90
KPX Tcommaaccent uhungarumlaut -90
KPX Tcommaaccent umacron -90
KPX Tcommaaccent uogonek -90
KPX Tcommaaccent uring -90
KPX Tcommaaccent w -60
KPX Tcommaaccent y -60
KPX Tcommaaccent yacute -60
KPX Tcommaaccent ydieresis -60
KPX U A -50
KPX U Aacute -50
KPX U Abreve -50
KPX U Acircumflex -50
KPX U Adieresis -50
KPX U Agrave -50
KPX U Amacron -50
KPX U Aogonek -50
KPX U Aring -50
KPX U Atilde -50
KPX U comma -30
KPX U period -30
KPX Uacute A -50
KPX Uacute Aacute -50
KPX Uacute Abreve -50
KPX Uacute Acircumflex -50
KPX Uacute Adieresis -50
KPX Uacute Agrave -50
KPX Uacute Amacron -50
KPX Uacute Aogonek -50
KPX Uacute Aring -50
KPX Uacute Atilde -50
KPX Uacute comma -30
KPX Uacute period -30
KPX Ucircumflex A -50
KPX Ucircumflex Aacute -50
KPX Ucircumflex Abreve -50
KPX Ucircumflex Acircumflex -50
KPX Ucircumflex Adieresis -50
KPX Ucircumflex Agrave -50
KPX Ucircumflex Amacron -50
KPX Ucircumflex Aogonek -50
KPX Ucircumflex Aring -50
KPX Ucircumflex Atilde -50
KPX Ucircumflex comma -30
KPX Ucircumflex period -30
KPX Udieresis A -50
KPX Udieresis Aacute -50
KPX Udieresis Abreve -50
KPX Udieresis Acircumflex -50
KPX Udieresis Adieresis -50
KPX Udieresis Agrave -50
KPX Udieresis Amacron -50
KPX Udieresis Aogonek -50
KPX Udieresis Aring -50
KPX Udieresis Atilde -50
KPX Udieresis comma -30
KPX Udieresis period -30
KPX Ugrave A -50
KPX Ugrave Aacute -50
KPX Ugrave Abreve -50
KPX Ugrave Acircumflex -50
KPX Ugrave Adieresis -50
KPX Ugrave Agrave -50
KPX Ugrave Amacron -50
KPX Ugrave Aogonek -50
KPX Ugrave Aring -50
KPX Ugrave Atilde -50
KPX Ugrave comma -30
KPX Ugrave period -30
KPX Uhungarumlaut A -50
KPX Uhungarumlaut Aacute -50
KPX Uhungarumlaut Abreve -50
KPX Uhungarumlaut Acircumflex -50
KPX Uhungarumlaut Adieresis -50
KPX Uhungarumlaut Agrave -50
KPX Uhungarumlaut Amacron -50
KPX Uhungarumlaut Aogonek -50
KPX Uhungarumlaut Aring -50
KPX Uhungarumlaut Atilde -50
KPX Uhungarumlaut comma -30
KPX Uhungarumlaut period -30
KPX Umacron A -50
KPX Umacron Aacute -50
KPX Umacron Abreve -50
KPX Umacron Acircumflex -50
KPX Umacron Adieresis -50
KPX Umacron Agrave -50
KPX Umacron Amacron -50
KPX Umacron Aogonek -50
KPX Umacron Aring -50
KPX Umacron Atilde -50
KPX Umacron comma -30
KPX Umacron period -30
KPX Uogonek A -50
KPX Uogonek Aacute -50
KPX Uogonek Abreve -50
KPX Uogonek Acircumflex -50
KPX Uogonek Adieresis -50
KPX Uogonek Agrave -50
KPX Uogonek Amacron -50
KPX Uogonek Aogonek -50
KPX Uogonek Aring -50
KPX Uogonek Atilde -50
KPX Uogonek comma -30
KPX Uogonek period -30
KPX Uring A -50
KPX Uring Aacute -50
KPX Uring Abreve -50
KPX Uring Acircumflex -50
KPX Uring Adieresis -50
KPX Uring Agrave -50
KPX Uring Amacron -50
KPX Uring Aogonek -50
KPX Uring Aring -50
KPX Uring Atilde -50
KPX Uring comma -30
KPX Uring period -30
KPX V A -80
KPX V Aacute -80
KPX V Abreve -80
KPX V Acircumflex -80
KPX V Adieresis -80
KPX V Agrave -80
KPX V Amacron -80
KPX V Aogonek -80
KPX V Aring -80
KPX V Atilde -80
KPX V G -50
KPX V Gbreve -50
KPX V Gcommaaccent -50
KPX V O -50
KPX V Oacute -50
KPX V Ocircumflex -50
KPX V Odieresis -50
KPX V Ograve -50
KPX V Ohungarumlaut -50
KPX V Omacron -50
KPX V Oslash -50
KPX V Otilde -50
KPX V a -60
KPX V aacute -60
KPX V abreve -60
KPX V acircumflex -60
KPX V adieresis -60
KPX V agrave -60
KPX V amacron -60
KPX V aogonek -60
KPX V aring -60
KPX V atilde -60
KPX V colon -40
KPX V comma -120
KPX V e -50
KPX V eacute -50
KPX V ecaron -50
KPX V ecircumflex -50
KPX V edieresis -50
KPX V edotaccent -50
KPX V egrave -50
KPX V emacron -50
KPX V eogonek -50
KPX V hyphen -80
KPX V o -90
KPX V oacute -90
KPX V ocircumflex -90
KPX V odieresis -90
KPX V ograve -90
KPX V ohungarumlaut -90
KPX V omacron -90
KPX V oslash -90
KPX V otilde -90
KPX V period -120
KPX V semicolon -40
KPX V u -60
KPX V uacute -60
KPX V ucircumflex -60
KPX V udieresis -60
KPX V ugrave -60
KPX V uhungarumlaut -60
KPX V umacron -60
KPX V uogonek -60
KPX V uring -60
KPX W A -60
KPX W Aacute -60
KPX W Abreve -60
KPX W Acircumflex -60
KPX W Adieresis -60
KPX W Agrave -60
KPX W Amacron -60
KPX W Aogonek -60
KPX W Aring -60
KPX W Atilde -60
KPX W O -20
KPX W Oacute -20
KPX W Ocircumflex -20
KPX W Odieresis -20
KPX W Ograve -20
KPX W Ohungarumlaut -20
KPX W Omacron -20
KPX W Oslash -20
KPX W Otilde -20
KPX W a -40
KPX W aacute -40
KPX W abreve -40
KPX W acircumflex -40
KPX W adieresis -40
KPX W agrave -40
KPX W amacron -40
KPX W aogonek -40
KPX W aring -40
KPX W atilde -40
KPX W colon -10
KPX W comma -80
KPX W e -35
KPX W eacute -35
KPX W ecaron -35
KPX W ecircumflex -35
KPX W edieresis -35
KPX W edotaccent -35
KPX W egrave -35
KPX W emacron -35
KPX W eogonek -35
KPX W hyphen -40
KPX W o -60
KPX W oacute -60
KPX W ocircumflex -60
KPX W odieresis -60
KPX W ograve -60
KPX W ohungarumlaut -60
KPX W omacron -60
KPX W oslash -60
KPX W otilde -60
KPX W period -80
KPX W semicolon -10
KPX W u -45
KPX W uacute -45
KPX W ucircumflex -45
KPX W udieresis -45
KPX W ugrave -45
KPX W uhungarumlaut -45
KPX W umacron -45
KPX W uogonek -45
KPX W uring -45
KPX W y -20
KPX W yacute -20
KPX W ydieresis -20
KPX Y A -110
KPX Y Aacute -110
KPX Y Abreve -110
KPX Y Acircumflex -110
KPX Y Adieresis -110
KPX Y Agrave -110
KPX Y Amacron -110
KPX Y Aogonek -110
KPX Y Aring -110
KPX Y Atilde -110
KPX Y O -70
KPX Y Oacute -70
KPX Y Ocircumflex -70
KPX Y Odieresis -70
KPX Y Ograve -70
KPX Y Ohungarumlaut -70
KPX Y Omacron -70
KPX Y Oslash -70
KPX Y Otilde -70
KPX Y a -90
KPX Y aacute -90
KPX Y abreve -90
KPX Y acircumflex -90
KPX Y adieresis -90
KPX Y agrave -90
KPX Y amacron -90
KPX Y aogonek -90
KPX Y aring -90
KPX Y atilde -90
KPX Y colon -50
KPX Y comma -100
KPX Y e -80
KPX Y eacute -80
KPX Y ecaron -80
KPX Y ecircumflex -80
KPX Y edieresis -80
KPX Y edotaccent -80
KPX Y egrave -80
KPX Y emacron -80
KPX Y eogonek -80
KPX Y o -100
KPX Y oacute -100
KPX Y ocircumflex -100
KPX Y odieresis -100
KPX Y ograve -100
KPX Y ohungarumlaut -100
KPX Y omacron -100
KPX Y oslash -100
KPX Y otilde -100
KPX Y period -100
KPX Y semicolon -50
KPX Y u -100
KPX Y uacute -100
KPX Y ucircumflex -100
KPX Y udieresis -100
KPX Y ugrave -100
KPX Y uhungarumlaut -100
KPX Y umacron -100
KPX Y uogonek -100
KPX Y uring -100
KPX Yacute A -110
KPX Yacute Aacute -110
KPX Yacute Abreve -110
KPX Yacute Acircumflex -110
KPX Yacute Adieresis -110
KPX Yacute Agrave -110
KPX Yacute Amacron -110
KPX Yacute Aogonek -110
KPX Yacute Aring -110
KPX Yacute Atilde -110
KPX Yacute O -70
KPX Yacute Oacute -70
KPX Yacute Ocircumflex -70
KPX Yacute Odieresis -70
KPX Yacute Ograve -70
KPX Yacute Ohungarumlaut -70
KPX Yacute Omacron -70
KPX Yacute Oslash -70
KPX Yacute Otilde -70
KPX Yacute a -90
KPX Yacute aacute -90
KPX Yacute abreve -90
KPX Yacute acircumflex -90
KPX Yacute adieresis -90
KPX Yacute agrave -90
KPX Yacute amacron -90
KPX Yacute aogonek -90
KPX Yacute aring -90
KPX Yacute atilde -90
KPX Yacute colon -50
KPX Yacute comma -100
KPX Yacute e -80
KPX Yacute eacute -80
KPX Yacute ecaron -80
KPX Yacute ecircumflex -80
KPX Yacute edieresis -80
KPX Yacute edotaccent -80
KPX Yacute egrave -80
KPX Yacute emacron -80
KPX Yacute eogonek -80
KPX Yacute o -100
KPX Yacute oacute -100
KPX Yacute ocircumflex -100
KPX Yacute odieresis -100
KPX Yacute ograve -100
KPX Yacute ohungarumlaut -100
KPX Yacute omacron -100
KPX Yacute oslash -100
KPX Yacute otilde -100
KPX Yacute period -100
KPX Yacute semicolon -50
KPX Yacute u -100
KPX Yacute uacute -100
KPX Yacute ucircumflex -100
KPX Yacute udieresis -100
KPX Yacute ugrave -100
KPX Yacute uhungarumlaut -100
KPX Yacute umacron -100
KPX Yacute uogonek -100
KPX Yacute uring -100
KPX Ydieresis A -110
KPX Ydieresis Aacute -110
KPX Ydieresis Abreve -110
KPX Ydieresis Acircumflex -110
KPX Ydieresis Adieresis -110
KPX Ydieresis Agrave -110
KPX Ydieresis Amacron -110
KPX Ydieresis Aogonek -110
KPX Ydieresis Aring -110
KPX Ydieresis Atilde -110
KPX Ydieresis O -70
KPX Ydieresis Oacute -70
KPX Ydieresis Ocircumflex -70
KPX Ydieresis Odieresis -70
KPX Ydieresis Ograve -70
KPX Ydieresis Ohungarumlaut -70
KPX Ydieresis Omacron -70
KPX Ydieresis Oslash -70
KPX Ydieresis Otilde -70
KPX Ydieresis a -90
KPX Ydieresis aacute -90
KPX Ydieresis abreve -90
KPX Ydieresis acircumflex -90
KPX Ydieresis adieresis -90
KPX Ydieresis agrave -90
KPX Ydieresis amacron -90
KPX Ydieresis aogonek -90
KPX Ydieresis aring -90
KPX Ydieresis atilde -90
KPX Ydieresis colon -50
KPX Ydieresis comma -100
KPX Ydieresis e -80
KPX Ydieresis eacute -80
KPX Ydieresis ecaron -80
KPX Ydieresis ecircumflex -80
KPX Ydieresis edieresis -80
KPX Ydieresis edotaccent -80
KPX Ydieresis egrave -80
KPX Ydieresis emacron -80
KPX Ydieresis eogonek -80
KPX Ydieresis o -100
KPX Ydieresis oacute -100
KPX Ydieresis ocircumflex -100
KPX Ydieresis odieresis -100
KPX Ydieresis ograve -100
KPX Ydieresis ohungarumlaut -100
KPX Ydieresis omacron -100
KPX Ydieresis oslash -100
KPX Ydieresis otilde -100
KPX Ydieresis period -100
KPX Ydieresis semicolon -50
KPX Ydieresis u -100
KPX Ydieresis uacute -100
KPX Ydieresis ucircumflex -100
KPX Ydieresis udieresis -100
KPX Ydieresis ugrave -100
KPX Ydieresis uhungarumlaut -100
KPX Ydieresis umacron -100
KPX Ydieresis uogonek -100
KPX Ydieresis uring -100
KPX a g -10
KPX a gbreve -10
KPX a gcommaaccent -10
KPX a v -15
KPX a w -15
KPX a y -20
KPX a yacute -20
KPX a ydieresis -20
KPX aacute g -10
KPX aacute gbreve -10
KPX aacute gcommaaccent -10
KPX aacute v -15
KPX aacute w -15
KPX aacute y -20
KPX aacute yacute -20
KPX aacute ydieresis -20
KPX abreve g -10
KPX abreve gbreve -10
KPX abreve gcommaaccent -10
KPX abreve v -15
KPX abreve w -15
KPX abreve y -20
KPX abreve yacute -20
KPX abreve ydieresis -20
KPX acircumflex g -10
KPX acircumflex gbreve -10
KPX acircumflex gcommaaccent -10
KPX acircumflex v -15
KPX acircumflex w -15
KPX acircumflex y -20
KPX acircumflex yacute -20
KPX acircumflex ydieresis -20
KPX adieresis g -10
KPX adieresis gbreve -10
KPX adieresis gcommaaccent -10
KPX adieresis v -15
KPX adieresis w -15
KPX adieresis y -20
KPX adieresis yacute -20
KPX adieresis ydieresis -20
KPX agrave g -10
KPX agrave gbreve -10
KPX agrave gcommaaccent -10
KPX agrave v -15
KPX agrave w -15
KPX agrave y -20
KPX agrave yacute -20
KPX agrave ydieresis -20
KPX amacron g -10
KPX amacron gbreve -10
KPX amacron gcommaaccent -10
KPX amacron v -15
KPX amacron w -15
KPX amacron y -20
KPX amacron yacute -20
KPX amacron ydieresis -20
KPX aogonek g -10
KPX aogonek gbreve -10
KPX aogonek gcommaaccent -10
KPX aogonek v -15
KPX aogonek w -15
KPX aogonek y -20
KPX aogonek yacute -20
KPX aogonek ydieresis -20
KPX aring g -10
KPX aring gbreve -10
KPX aring gcommaaccent -10
KPX aring v -15
KPX aring w -15
KPX aring y -20
KPX aring yacute -20
KPX aring ydieresis -20
KPX atilde g -10
KPX atilde gbreve -10
KPX atilde gcommaaccent -10
KPX atilde v -15
KPX atilde w -15
KPX atilde y -20
KPX atilde yacute -20
KPX atilde ydieresis -20
KPX b l -10
KPX b lacute -10
KPX b lcommaaccent -10
KPX b lslash -10
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX b v -20
KPX b y -20
KPX b yacute -20
KPX b ydieresis -20
KPX c h -10
KPX c k -20
KPX c kcommaaccent -20
KPX c l -20
KPX c lacute -20
KPX c lcommaaccent -20
KPX c lslash -20
KPX c y -10
KPX c yacute -10
KPX c ydieresis -10
KPX cacute h -10
KPX cacute k -20
KPX cacute kcommaaccent -20
KPX cacute l -20
KPX cacute lacute -20
KPX cacute lcommaaccent -20
KPX cacute lslash -20
KPX cacute y -10
KPX cacute yacute -10
KPX cacute ydieresis -10
KPX ccaron h -10
KPX ccaron k -20
KPX ccaron kcommaaccent -20
KPX ccaron l -20
KPX ccaron lacute -20
KPX ccaron lcommaaccent -20
KPX ccaron lslash -20
KPX ccaron y -10
KPX ccaron yacute -10
KPX ccaron ydieresis -10
KPX ccedilla h -10
KPX ccedilla k -20
KPX ccedilla kcommaaccent -20
KPX ccedilla l -20
KPX ccedilla lacute -20
KPX ccedilla lcommaaccent -20
KPX ccedilla lslash -20
KPX ccedilla y -10
KPX ccedilla yacute -10
KPX ccedilla ydieresis -10
KPX colon space -40
KPX comma quotedblright -120
KPX comma quoteright -120
KPX comma space -40
KPX d d -10
KPX d dcroat -10
KPX d v -15
KPX d w -15
KPX d y -15
KPX d yacute -15
KPX d ydieresis -15
KPX dcroat d -10
KPX dcroat dcroat -10
KPX dcroat v -15
KPX dcroat w -15
KPX dcroat y -15
KPX dcroat yacute -15
KPX dcroat ydieresis -15
KPX e comma 10
KPX e period 20
KPX e v -15
KPX e w -15
KPX e x -15
KPX e y -15
KPX e yacute -15
KPX e ydieresis -15
KPX eacute comma 10
KPX eacute period 20
KPX eacute v -15
KPX eacute w -15
KPX eacute x -15
KPX eacute y -15
KPX eacute yacute -15
KPX eacute ydieresis -15
KPX ecaron comma 10
KPX ecaron period 20
KPX ecaron v -15
KPX ecaron w -15
KPX ecaron x -15
KPX ecaron y -15
KPX ecaron yacute -15
KPX ecaron ydieresis -15
KPX ecircumflex comma 10
KPX ecircumflex period 20
KPX ecircumflex v -15
KPX ecircumflex w -15
KPX ecircumflex x -15
KPX ecircumflex y -15
KPX ecircumflex yacute -15
KPX ecircumflex ydieresis -15
KPX edieresis comma 10
KPX edieresis period 20
KPX edieresis v -15
KPX edieresis w -15
KPX edieresis x -15
KPX edieresis y -15
KPX edieresis yacute -15
KPX edieresis ydieresis -15
KPX edotaccent comma 10
KPX edotaccent period 20
KPX edotaccent v -15
KPX edotaccent w -15
KPX edotaccent x -15
KPX edotaccent y -15
KPX edotaccent yacute -15
KPX edotaccent ydieresis -15
KPX egrave comma 10
KPX egrave period 20
KPX egrave v -15
KPX egrave w -15
KPX egrave x -15
KPX egrave y -15
KPX egrave yacute -15
KPX egrave ydieresis -15
KPX emacron comma 10
KPX emacron period 20
KPX emacron v -15
KPX emacron w -15
KPX emacron x -15
KPX emacron y -15
KPX emacron yacute -15
KPX emacron ydieresis -15
KPX eogonek comma 10
KPX eogonek period 20
KPX eogonek v -15
KPX eogonek w -15
KPX eogonek x -15
KPX eogonek y -15
KPX eogonek yacute -15
KPX eogonek ydieresis -15
KPX f comma -10
KPX f e -10
KPX f eacute -10
KPX f ecaron -10
KPX f ecircumflex -10
KPX f edieresis -10
KPX f edotaccent -10
KPX f egrave -10
KPX f emacron -10
KPX f eogonek -10
KPX f o -20
KPX f oacute -20
KPX f ocircumflex -20
KPX f odieresis -20
KPX f ograve -20
KPX f ohungarumlaut -20
KPX f omacron -20
KPX f oslash -20
KPX f otilde -20
KPX f period -10
KPX f quotedblright 30
KPX f quoteright 30
KPX g e 10
KPX g eacute 10
KPX g ecaron 10
KPX g ecircumflex 10
KPX g edieresis 10
KPX g edotaccent 10
KPX g egrave 10
KPX g emacron 10
KPX g eogonek 10
KPX g g -10
KPX g gbreve -10
KPX g gcommaaccent -10
KPX gbreve e 10
KPX gbreve eacute 10
KPX gbreve ecaron 10
KPX gbreve ecircumflex 10
KPX gbreve edieresis 10
KPX gbreve edotaccent 10
KPX gbreve egrave 10
KPX gbreve emacron 10
KPX gbreve eogonek 10
KPX gbreve g -10
KPX gbreve gbreve -10
KPX gbreve gcommaaccent -10
KPX gcommaaccent e 10
KPX gcommaaccent eacute 10
KPX gcommaaccent ecaron 10
KPX gcommaaccent ecircumflex 10
KPX gcommaaccent edieresis 10
KPX gcommaaccent edotaccent 10
KPX gcommaaccent egrave 10
KPX gcommaaccent emacron 10
KPX gcommaaccent eogonek 10
KPX gcommaaccent g -10
KPX gcommaaccent gbreve -10
KPX gcommaaccent gcommaaccent -10
KPX h y -20
KPX h yacute -20
KPX h ydieresis -20
KPX k o -15
KPX k oacute -15
KPX k ocircumflex -15
KPX k odieresis -15
KPX k ograve -15
KPX k ohungarumlaut -15
KPX k omacron -15
KPX k oslash -15
KPX k otilde -15
KPX kcommaaccent o -15
KPX kcommaaccent oacute -15
KPX kcommaaccent ocircumflex -15
KPX kcommaaccent odieresis -15
KPX kcommaaccent ograve -15
KPX kcommaaccent ohungarumlaut -15
KPX kcommaaccent omacron -15
KPX kcommaaccent oslash -15
KPX kcommaaccent otilde -15
KPX l w -15
KPX l y -15
KPX l yacute -15
KPX l ydieresis -15
KPX lacute w -15
KPX lacute y -15
KPX lacute yacute -15
KPX lacute ydieresis -15
KPX lcommaaccent w -15
KPX lcommaaccent y -15
KPX lcommaaccent yacute -15
KPX lcommaaccent ydieresis -15
KPX lslash w -15
KPX lslash y -15
KPX lslash yacute -15
KPX lslash ydieresis -15
KPX m u -20
KPX m uacute -20
KPX m ucircumflex -20
KPX m udieresis -20
KPX m ugrave -20
KPX m uhungarumlaut -20
KPX m umacron -20
KPX m uogonek -20
KPX m uring -20
KPX m y -30
KPX m yacute -30
KPX m ydieresis -30
KPX n u -10
KPX n uacute -10
KPX n ucircumflex -10
KPX n udieresis -10
KPX n ugrave -10
KPX n uhungarumlaut -10
KPX n umacron -10
KPX n uogonek -10
KPX n uring -10
KPX n v -40
KPX n y -20
KPX n yacute -20
KPX n ydieresis -20
KPX nacute u -10
KPX nacute uacute -10
KPX nacute ucircumflex -10
KPX nacute udieresis -10
KPX nacute ugrave -10
KPX nacute uhungarumlaut -10
KPX nacute umacron -10
KPX nacute uogonek -10
KPX nacute uring -10
KPX nacute v -40
KPX nacute y -20
KPX nacute yacute -20
KPX nacute ydieresis -20
KPX ncaron u -10
KPX ncaron uacute -10
KPX ncaron ucircumflex -10
KPX ncaron udieresis -10
KPX ncaron ugrave -10
KPX ncaron uhungarumlaut -10
KPX ncaron umacron -10
KPX ncaron uogonek -10
KPX ncaron uring -10
KPX ncaron v -40
KPX ncaron y -20
KPX ncaron yacute -20
KPX ncaron ydieresis -20
KPX ncommaaccent u -10
KPX ncommaaccent uacute -10
KPX ncommaaccent ucircumflex -10
KPX ncommaaccent udieresis -10
KPX ncommaaccent ugrave -10
KPX ncommaaccent uhungarumlaut -10
KPX ncommaaccent umacron -10
KPX ncommaaccent uogonek -10
KPX ncommaaccent uring -10
KPX ncommaaccent v -40
KPX ncommaaccent y -20
KPX ncommaaccent yacute -20
KPX ncommaaccent ydieresis -20
KPX ntilde u -10
KPX ntilde uacute -10
KPX ntilde ucircumflex -10
KPX ntilde udieresis -10
KPX ntilde ugrave -10
KPX ntilde uhungarumlaut -10
KPX ntilde umacron -10
KPX ntilde uogonek -10
KPX ntilde uring -10
KPX ntilde v -40
KPX ntilde y -20
KPX ntilde yacute -20
KPX ntilde ydieresis -20
KPX o v -20
KPX o w -15
KPX o x -30
KPX o y -20
KPX o yacute -20
KPX o ydieresis -20
KPX oacute v -20
KPX oacute w -15
KPX oacute x -30
KPX oacute y -20
KPX oacute yacute -20
KPX oacute ydieresis -20
KPX ocircumflex v -20
KPX ocircumflex w -15
KPX ocircumflex x -30
KPX ocircumflex y -20
KPX ocircumflex yacute -20
KPX ocircumflex ydieresis -20
KPX odieresis v -20
KPX odieresis w -15
KPX odieresis x -30
KPX odieresis y -20
KPX odieresis yacute -20
KPX odieresis ydieresis -20
KPX ograve v -20
KPX ograve w -15
KPX ograve x -30
KPX ograve y -20
KPX ograve yacute -20
KPX ograve ydieresis -20
KPX ohungarumlaut v -20
KPX ohungarumlaut w -15
KPX ohungarumlaut x -30
KPX ohungarumlaut y -20
KPX ohungarumlaut yacute -20
KPX ohungarumlaut ydieresis -20
KPX omacron v -20
KPX omacron w -15
KPX omacron x -30
KPX omacron y -20
KPX omacron yacute -20
KPX omacron ydieresis -20
KPX oslash v -20
KPX oslash w -15
KPX oslash x -30
KPX oslash y -20
KPX oslash yacute -20
KPX oslash ydieresis -20
KPX otilde v -20
KPX otilde w -15
KPX otilde x -30
KPX otilde y -20
KPX otilde yacute -20
KPX otilde ydieresis -20
KPX p y -15
KPX p yacute -15
KPX p ydieresis -15
KPX period quotedblright -120
KPX period quoteright -120
KPX period space -40
KPX quotedblright space -80
KPX quoteleft quoteleft -46
KPX quoteright d -80
KPX quoteright dcroat -80
KPX quoteright l -20
KPX quoteright lacute -20
KPX quoteright lcommaaccent -20
KPX quoteright lslash -20
KPX quoteright quoteright -46
KPX quoteright r -40
KPX quoteright racute -40
KPX quoteright rcaron -40
KPX quoteright rcommaaccent -40
KPX quoteright s -60
KPX quoteright sacute -60
KPX quoteright scaron -60
KPX quoteright scedilla -60
KPX quoteright scommaaccent -60
KPX quoteright space -80
KPX quoteright v -20
KPX r c -20
KPX r cacute -20
KPX r ccaron -20
KPX r ccedilla -20
KPX r comma -60
KPX r d -20
KPX r dcroat -20
KPX r g -15
KPX r gbreve -15
KPX r gcommaaccent -15
KPX r hyphen -20
KPX r o -20
KPX r oacute -20
KPX r ocircumflex -20
KPX r odieresis -20
KPX r ograve -20
KPX r ohungarumlaut -20
KPX r omacron -20
KPX r oslash -20
KPX r otilde -20
KPX r period -60
KPX r q -20
KPX r s -15
KPX r sacute -15
KPX r scaron -15
KPX r scedilla -15
KPX r scommaaccent -15
KPX r t 20
KPX r tcommaaccent 20
KPX r v 10
KPX r y 10
KPX r yacute 10
KPX r ydieresis 10
KPX racute c -20
KPX racute cacute -20
KPX racute ccaron -20
KPX racute ccedilla -20
KPX racute comma -60
KPX racute d -20
KPX racute dcroat -20
KPX racute g -15
KPX racute gbreve -15
KPX racute gcommaaccent -15
KPX racute hyphen -20
KPX racute o -20
KPX racute oacute -20
KPX racute ocircumflex -20
KPX racute odieresis -20
KPX racute ograve -20
KPX racute ohungarumlaut -20
KPX racute omacron -20
KPX racute oslash -20
KPX racute otilde -20
KPX racute period -60
KPX racute q -20
KPX racute s -15
KPX racute sacute -15
KPX racute scaron -15
KPX racute scedilla -15
KPX racute scommaaccent -15
KPX racute t 20
KPX racute tcommaaccent 20
KPX racute v 10
KPX racute y 10
KPX racute yacute 10
KPX racute ydieresis 10
KPX rcaron c -20
KPX rcaron cacute -20
KPX rcaron ccaron -20
KPX rcaron ccedilla -20
KPX rcaron comma -60
KPX rcaron d -20
KPX rcaron dcroat -20
KPX rcaron g -15
KPX rcaron gbreve -15
KPX rcaron gcommaaccent -15
KPX rcaron hyphen -20
KPX rcaron o -20
KPX rcaron oacute -20
KPX rcaron ocircumflex -20
KPX rcaron odieresis -20
KPX rcaron ograve -20
KPX rcaron ohungarumlaut -20
KPX rcaron omacron -20
KPX rcaron oslash -20
KPX rcaron otilde -20
KPX rcaron period -60
KPX rcaron q -20
KPX rcaron s -15
KPX rcaron sacute -15
KPX rcaron scaron -15
KPX rcaron scedilla -15
KPX rcaron scommaaccent -15
KPX rcaron t 20
KPX rcaron tcommaaccent 20
KPX rcaron v 10
KPX rcaron y 10
KPX rcaron yacute 10
KPX rcaron ydieresis 10
KPX rcommaaccent c -20
KPX rcommaaccent cacute -20
KPX rcommaaccent ccaron -20
KPX rcommaaccent ccedilla -20
KPX rcommaaccent comma -60
KPX rcommaaccent d -20
KPX rcommaaccent dcroat -20
KPX rcommaaccent g -15
KPX rcommaaccent gbreve -15
KPX rcommaaccent gcommaaccent -15
KPX rcommaaccent hyphen -20
KPX rcommaaccent o -20
KPX rcommaaccent oacute -20
KPX rcommaaccent ocircumflex -20
KPX rcommaaccent odieresis -20
KPX rcommaaccent ograve -20
KPX rcommaaccent ohungarumlaut -20
KPX rcommaaccent omacron -20
KPX rcommaaccent oslash -20
KPX rcommaaccent otilde -20
KPX rcommaaccent period -60
KPX rcommaaccent q -20
KPX rcommaaccent s -15
KPX rcommaaccent sacute -15
KPX rcommaaccent scaron -15
KPX rcommaaccent scedilla -15
KPX rcommaaccent scommaaccent -15
KPX rcommaaccent t 20
KPX rcommaaccent tcommaaccent 20
KPX rcommaaccent v 10
KPX rcommaaccent y 10
KPX rcommaaccent yacute 10
KPX rcommaaccent ydieresis 10
KPX s w -15
KPX sacute w -15
KPX scaron w -15
KPX scedilla w -15
KPX scommaaccent w -15
KPX semicolon space -40
KPX space T -100
KPX space Tcaron -100
KPX space Tcommaaccent -100
KPX space V -80
KPX space W -80
KPX space Y -120
KPX space Yacute -120
KPX space Ydieresis -120
KPX space quotedblleft -80
KPX space quoteleft -60
KPX v a -20
KPX v aacute -20
KPX v abreve -20
KPX v acircumflex -20
KPX v adieresis -20
KPX v agrave -20
KPX v amacron -20
KPX v aogonek -20
KPX v aring -20
KPX v atilde -20
KPX v comma -80
KPX v o -30
KPX v oacute -30
KPX v ocircumflex -30
KPX v odieresis -30
KPX v ograve -30
KPX v ohungarumlaut -30
KPX v omacron -30
KPX v oslash -30
KPX v otilde -30
KPX v period -80
KPX w comma -40
KPX w o -20
KPX w oacute -20
KPX w ocircumflex -20
KPX w odieresis -20
KPX w ograve -20
KPX w ohungarumlaut -20
KPX w omacron -20
KPX w oslash -20
KPX w otilde -20
KPX w period -40
KPX x e -10
KPX x eacute -10
KPX x ecaron -10
KPX x ecircumflex -10
KPX x edieresis -10
KPX x edotaccent -10
KPX x egrave -10
KPX x emacron -10
KPX x eogonek -10
KPX y a -30
KPX y aacute -30
KPX y abreve -30
KPX y acircumflex -30
KPX y adieresis -30
KPX y agrave -30
KPX y amacron -30
KPX y aogonek -30
KPX y aring -30
KPX y atilde -30
KPX y comma -80
KPX y e -10
KPX y eacute -10
KPX y ecaron -10
KPX y ecircumflex -10
KPX y edieresis -10
KPX y edotaccent -10
KPX y egrave -10
KPX y emacron -10
KPX y eogonek -10
KPX y o -25
KPX y oacute -25
KPX y ocircumflex -25
KPX y odieresis -25
KPX y ograve -25
KPX y ohungarumlaut -25
KPX y omacron -25
KPX y oslash -25
KPX y otilde -25
KPX y period -80
KPX yacute a -30
KPX yacute aacute -30
KPX yacute abreve -30
KPX yacute acircumflex -30
KPX yacute adieresis -30
KPX yacute agrave -30
KPX yacute amacron -30
KPX yacute aogonek -30
KPX yacute aring -30
KPX yacute atilde -30
KPX yacute comma -80
KPX yacute e -10
KPX yacute eacute -10
KPX yacute ecaron -10
KPX yacute ecircumflex -10
KPX yacute edieresis -10
KPX yacute edotaccent -10
KPX yacute egrave -10
KPX yacute emacron -10
KPX yacute eogonek -10
KPX yacute o -25
KPX yacute oacute -25
KPX yacute ocircumflex -25
KPX yacute odieresis -25
KPX yacute ograve -25
KPX yacute ohungarumlaut -25
KPX yacute omacron -25
KPX yacute oslash -25
KPX yacute otilde -25
KPX yacute period -80
KPX ydieresis a -30
KPX ydieresis aacute -30
KPX ydieresis abreve -30
KPX ydieresis acircumflex -30
KPX ydieresis adieresis -30
KPX ydieresis agrave -30
KPX ydieresis amacron -30
KPX ydieresis aogonek -30
KPX ydieresis aring -30
KPX ydieresis atilde -30
KPX ydieresis comma -80
KPX ydieresis e -10
KPX ydieresis eacute -10
KPX ydieresis ecaron -10
KPX ydieresis ecircumflex -10
KPX ydieresis edieresis -10
KPX ydieresis edotaccent -10
KPX ydieresis egrave -10
KPX ydieresis emacron -10
KPX ydieresis eogonek -10
KPX ydieresis o -25
KPX ydieresis oacute -25
KPX ydieresis ocircumflex -25
KPX ydieresis odieresis -25
KPX ydieresis ograve -25
KPX ydieresis ohungarumlaut -25
KPX ydieresis omacron -25
KPX ydieresis oslash -25
KPX ydieresis otilde -25
KPX ydieresis period -80
KPX z e 10
KPX z eacute 10
KPX z ecaron 10
KPX z ecircumflex 10
KPX z edieresis 10
KPX z edotaccent 10
KPX z egrave 10
KPX z emacron 10
KPX z eogonek 10
KPX zacute e 10
KPX zacute eacute 10
KPX zacute ecaron 10
KPX zacute ecircumflex 10
KPX zacute edieresis 10
KPX zacute edotaccent 10
KPX zacute egrave 10
KPX zacute emacron 10
KPX zacute eogonek 10
KPX zcaron e 10
KPX zcaron eacute 10
KPX zcaron ecaron 10
KPX zcaron ecircumflex 10
KPX zcaron edieresis 10
KPX zcaron edotaccent 10
KPX zcaron egrave 10
KPX zcaron emacron 10
KPX zcaron eogonek 10
KPX zdotaccent e 10
KPX zdotaccent eacute 10
KPX zdotaccent ecaron 10
KPX zdotaccent ecircumflex 10
KPX zdotaccent edieresis 10
KPX zdotaccent edotaccent 10
KPX zdotaccent egrave 10
KPX zdotaccent emacron 10
KPX zdotaccent eogonek 10
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Helvetica-BoldOblique.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:45:12 1997
Comment UniqueID 43053
Comment VMusage 14482 68586
FontName Helvetica-BoldOblique
FullName Helvetica Bold Oblique
FamilyName Helvetica
Weight Bold
ItalicAngle -12
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -174 -228 1114 962
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 718
XHeight 532
Ascender 718
Descender -207
StdHW 118
StdVW 140
StartCharMetrics 315
C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
C 33 ; WX 333 ; N exclam ; B 94 0 397 718 ;
C 34 ; WX 474 ; N quotedbl ; B 193 447 529 718 ;
C 35 ; WX 556 ; N numbersign ; B 60 0 644 698 ;
C 36 ; WX 556 ; N dollar ; B 67 -115 622 775 ;
C 37 ; WX 889 ; N percent ; B 136 -19 901 710 ;
C 38 ; WX 722 ; N ampersand ; B 89 -19 732 718 ;
C 39 ; WX 278 ; N quoteright ; B 167 445 362 718 ;
C 40 ; WX 333 ; N parenleft ; B 76 -208 470 734 ;
C 41 ; WX 333 ; N parenright ; B -25 -208 369 734 ;
C 42 ; WX 389 ; N asterisk ; B 146 387 481 718 ;
C 43 ; WX 584 ; N plus ; B 82 0 610 506 ;
C 44 ; WX 278 ; N comma ; B 28 -168 245 146 ;
C 45 ; WX 333 ; N hyphen ; B 73 215 379 345 ;
C 46 ; WX 278 ; N period ; B 64 0 245 146 ;
C 47 ; WX 278 ; N slash ; B -37 -19 468 737 ;
C 48 ; WX 556 ; N zero ; B 86 -19 617 710 ;
C 49 ; WX 556 ; N one ; B 173 0 529 710 ;
C 50 ; WX 556 ; N two ; B 26 0 619 710 ;
C 51 ; WX 556 ; N three ; B 65 -19 608 710 ;
C 52 ; WX 556 ; N four ; B 60 0 598 710 ;
C 53 ; WX 556 ; N five ; B 64 -19 636 698 ;
C 54 ; WX 556 ; N six ; B 85 -19 619 710 ;
C 55 ; WX 556 ; N seven ; B 125 0 676 698 ;
C 56 ; WX 556 ; N eight ; B 69 -19 616 710 ;
C 57 ; WX 556 ; N nine ; B 78 -19 615 710 ;
C 58 ; WX 333 ; N colon ; B 92 0 351 512 ;
C 59 ; WX 333 ; N semicolon ; B 56 -168 351 512 ;
C 60 ; WX 584 ; N less ; B 82 -8 655 514 ;
C 61 ; WX 584 ; N equal ; B 58 87 633 419 ;
C 62 ; WX 584 ; N greater ; B 36 -8 609 514 ;
C 63 ; WX 611 ; N question ; B 165 0 671 727 ;
C 64 ; WX 975 ; N at ; B 186 -19 954 737 ;
C 65 ; WX 722 ; N A ; B 20 0 702 718 ;
C 66 ; WX 722 ; N B ; B 76 0 764 718 ;
C 67 ; WX 722 ; N C ; B 107 -19 789 737 ;
C 68 ; WX 722 ; N D ; B 76 0 777 718 ;
C 69 ; WX 667 ; N E ; B 76 0 757 718 ;
C 70 ; WX 611 ; N F ; B 76 0 740 718 ;
C 71 ; WX 778 ; N G ; B 108 -19 817 737 ;
C 72 ; WX 722 ; N H ; B 71 0 804 718 ;
C 73 ; WX 278 ; N I ; B 64 0 367 718 ;
C 74 ; WX 556 ; N J ; B 60 -18 637 718 ;
C 75 ; WX 722 ; N K ; B 87 0 858 718 ;
C 76 ; WX 611 ; N L ; B 76 0 611 718 ;
C 77 ; WX 833 ; N M ; B 69 0 918 718 ;
C 78 ; WX 722 ; N N ; B 69 0 807 718 ;
C 79 ; WX 778 ; N O ; B 107 -19 823 737 ;
C 80 ; WX 667 ; N P ; B 76 0 738 718 ;
C 81 ; WX 778 ; N Q ; B 107 -52 823 737 ;
C 82 ; WX 722 ; N R ; B 76 0 778 718 ;
C 83 ; WX 667 ; N S ; B 81 -19 718 737 ;
C 84 ; WX 611 ; N T ; B 140 0 751 718 ;
C 85 ; WX 722 ; N U ; B 116 -19 804 718 ;
C 86 ; WX 667 ; N V ; B 172 0 801 718 ;
C 87 ; WX 944 ; N W ; B 169 0 1082 718 ;
C 88 ; WX 667 ; N X ; B 14 0 791 718 ;
C 89 ; WX 667 ; N Y ; B 168 0 806 718 ;
C 90 ; WX 611 ; N Z ; B 25 0 737 718 ;
C 91 ; WX 333 ; N bracketleft ; B 21 -196 462 722 ;
C 92 ; WX 278 ; N backslash ; B 124 -19 307 737 ;
C 93 ; WX 333 ; N bracketright ; B -18 -196 423 722 ;
C 94 ; WX 584 ; N asciicircum ; B 131 323 591 698 ;
C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ;
C 96 ; WX 278 ; N quoteleft ; B 165 454 361 727 ;
C 97 ; WX 556 ; N a ; B 55 -14 583 546 ;
C 98 ; WX 611 ; N b ; B 61 -14 645 718 ;
C 99 ; WX 556 ; N c ; B 79 -14 599 546 ;
C 100 ; WX 611 ; N d ; B 82 -14 704 718 ;
C 101 ; WX 556 ; N e ; B 70 -14 593 546 ;
C 102 ; WX 333 ; N f ; B 87 0 469 727 ; L i fi ; L l fl ;
C 103 ; WX 611 ; N g ; B 38 -217 666 546 ;
C 104 ; WX 611 ; N h ; B 65 0 629 718 ;
C 105 ; WX 278 ; N i ; B 69 0 363 725 ;
C 106 ; WX 278 ; N j ; B -42 -214 363 725 ;
C 107 ; WX 556 ; N k ; B 69 0 670 718 ;
C 108 ; WX 278 ; N l ; B 69 0 362 718 ;
C 109 ; WX 889 ; N m ; B 64 0 909 546 ;
C 110 ; WX 611 ; N n ; B 65 0 629 546 ;
C 111 ; WX 611 ; N o ; B 82 -14 643 546 ;
C 112 ; WX 611 ; N p ; B 18 -207 645 546 ;
C 113 ; WX 611 ; N q ; B 80 -207 665 546 ;
C 114 ; WX 389 ; N r ; B 64 0 489 546 ;
C 115 ; WX 556 ; N s ; B 63 -14 584 546 ;
C 116 ; WX 333 ; N t ; B 100 -6 422 676 ;
C 117 ; WX 611 ; N u ; B 98 -14 658 532 ;
C 118 ; WX 556 ; N v ; B 126 0 656 532 ;
C 119 ; WX 778 ; N w ; B 123 0 882 532 ;
C 120 ; WX 556 ; N x ; B 15 0 648 532 ;
C 121 ; WX 556 ; N y ; B 42 -214 652 532 ;
C 122 ; WX 500 ; N z ; B 20 0 583 532 ;
C 123 ; WX 389 ; N braceleft ; B 94 -196 518 722 ;
C 124 ; WX 280 ; N bar ; B 36 -225 361 775 ;
C 125 ; WX 389 ; N braceright ; B -18 -196 407 722 ;
C 126 ; WX 584 ; N asciitilde ; B 115 163 577 343 ;
C 161 ; WX 333 ; N exclamdown ; B 50 -186 353 532 ;
C 162 ; WX 556 ; N cent ; B 79 -118 599 628 ;
C 163 ; WX 556 ; N sterling ; B 50 -16 635 718 ;
C 164 ; WX 167 ; N fraction ; B -174 -19 487 710 ;
C 165 ; WX 556 ; N yen ; B 60 0 713 698 ;
C 166 ; WX 556 ; N florin ; B -50 -210 669 737 ;
C 167 ; WX 556 ; N section ; B 61 -184 598 727 ;
C 168 ; WX 556 ; N currency ; B 27 76 680 636 ;
C 169 ; WX 238 ; N quotesingle ; B 165 447 321 718 ;
C 170 ; WX 500 ; N quotedblleft ; B 160 454 588 727 ;
C 171 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ;
C 172 ; WX 333 ; N guilsinglleft ; B 130 76 353 484 ;
C 173 ; WX 333 ; N guilsinglright ; B 99 76 322 484 ;
C 174 ; WX 611 ; N fi ; B 87 0 696 727 ;
C 175 ; WX 611 ; N fl ; B 87 0 695 727 ;
C 177 ; WX 556 ; N endash ; B 48 227 627 333 ;
C 178 ; WX 556 ; N dagger ; B 118 -171 626 718 ;
C 179 ; WX 556 ; N daggerdbl ; B 46 -171 628 718 ;
C 180 ; WX 278 ; N periodcentered ; B 110 172 276 334 ;
C 182 ; WX 556 ; N paragraph ; B 98 -191 688 700 ;
C 183 ; WX 350 ; N bullet ; B 83 194 420 524 ;
C 184 ; WX 278 ; N quotesinglbase ; B 41 -146 236 127 ;
C 185 ; WX 500 ; N quotedblbase ; B 36 -146 463 127 ;
C 186 ; WX 500 ; N quotedblright ; B 162 445 589 718 ;
C 187 ; WX 556 ; N guillemotright ; B 104 76 540 484 ;
C 188 ; WX 1000 ; N ellipsis ; B 92 0 939 146 ;
C 189 ; WX 1000 ; N perthousand ; B 76 -19 1038 710 ;
C 191 ; WX 611 ; N questiondown ; B 53 -195 559 532 ;
C 193 ; WX 333 ; N grave ; B 136 604 353 750 ;
C 194 ; WX 333 ; N acute ; B 236 604 515 750 ;
C 195 ; WX 333 ; N circumflex ; B 118 604 471 750 ;
C 196 ; WX 333 ; N tilde ; B 113 610 507 737 ;
C 197 ; WX 333 ; N macron ; B 122 604 483 678 ;
C 198 ; WX 333 ; N breve ; B 156 604 494 750 ;
C 199 ; WX 333 ; N dotaccent ; B 235 614 385 729 ;
C 200 ; WX 333 ; N dieresis ; B 137 614 482 729 ;
C 202 ; WX 333 ; N ring ; B 200 568 420 776 ;
C 203 ; WX 333 ; N cedilla ; B -37 -228 220 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B 137 604 645 750 ;
C 206 ; WX 333 ; N ogonek ; B 41 -228 264 0 ;
C 207 ; WX 333 ; N caron ; B 149 604 502 750 ;
C 208 ; WX 1000 ; N emdash ; B 48 227 1071 333 ;
C 225 ; WX 1000 ; N AE ; B 5 0 1100 718 ;
C 227 ; WX 370 ; N ordfeminine ; B 125 401 465 737 ;
C 232 ; WX 611 ; N Lslash ; B 34 0 611 718 ;
C 233 ; WX 778 ; N Oslash ; B 35 -27 894 745 ;
C 234 ; WX 1000 ; N OE ; B 99 -19 1114 737 ;
C 235 ; WX 365 ; N ordmasculine ; B 123 401 485 737 ;
C 241 ; WX 889 ; N ae ; B 56 -14 923 546 ;
C 245 ; WX 278 ; N dotlessi ; B 69 0 322 532 ;
C 248 ; WX 278 ; N lslash ; B 40 0 407 718 ;
C 249 ; WX 611 ; N oslash ; B 22 -29 701 560 ;
C 250 ; WX 944 ; N oe ; B 82 -14 977 546 ;
C 251 ; WX 611 ; N germandbls ; B 69 -14 657 731 ;
C -1 ; WX 278 ; N Idieresis ; B 64 0 494 915 ;
C -1 ; WX 556 ; N eacute ; B 70 -14 627 750 ;
C -1 ; WX 556 ; N abreve ; B 55 -14 606 750 ;
C -1 ; WX 611 ; N uhungarumlaut ; B 98 -14 784 750 ;
C -1 ; WX 556 ; N ecaron ; B 70 -14 614 750 ;
C -1 ; WX 667 ; N Ydieresis ; B 168 0 806 915 ;
C -1 ; WX 584 ; N divide ; B 82 -42 610 548 ;
C -1 ; WX 667 ; N Yacute ; B 168 0 806 936 ;
C -1 ; WX 722 ; N Acircumflex ; B 20 0 706 936 ;
C -1 ; WX 556 ; N aacute ; B 55 -14 627 750 ;
C -1 ; WX 722 ; N Ucircumflex ; B 116 -19 804 936 ;
C -1 ; WX 556 ; N yacute ; B 42 -214 652 750 ;
C -1 ; WX 556 ; N scommaaccent ; B 63 -228 584 546 ;
C -1 ; WX 556 ; N ecircumflex ; B 70 -14 593 750 ;
C -1 ; WX 722 ; N Uring ; B 116 -19 804 962 ;
C -1 ; WX 722 ; N Udieresis ; B 116 -19 804 915 ;
C -1 ; WX 556 ; N aogonek ; B 55 -224 583 546 ;
C -1 ; WX 722 ; N Uacute ; B 116 -19 804 936 ;
C -1 ; WX 611 ; N uogonek ; B 98 -228 658 532 ;
C -1 ; WX 667 ; N Edieresis ; B 76 0 757 915 ;
C -1 ; WX 722 ; N Dcroat ; B 62 0 777 718 ;
C -1 ; WX 250 ; N commaaccent ; B 16 -228 188 -50 ;
C -1 ; WX 737 ; N copyright ; B 56 -19 835 737 ;
C -1 ; WX 667 ; N Emacron ; B 76 0 757 864 ;
C -1 ; WX 556 ; N ccaron ; B 79 -14 614 750 ;
C -1 ; WX 556 ; N aring ; B 55 -14 583 776 ;
C -1 ; WX 722 ; N Ncommaaccent ; B 69 -228 807 718 ;
C -1 ; WX 278 ; N lacute ; B 69 0 528 936 ;
C -1 ; WX 556 ; N agrave ; B 55 -14 583 750 ;
C -1 ; WX 611 ; N Tcommaaccent ; B 140 -228 751 718 ;
C -1 ; WX 722 ; N Cacute ; B 107 -19 789 936 ;
C -1 ; WX 556 ; N atilde ; B 55 -14 619 737 ;
C -1 ; WX 667 ; N Edotaccent ; B 76 0 757 915 ;
C -1 ; WX 556 ; N scaron ; B 63 -14 614 750 ;
C -1 ; WX 556 ; N scedilla ; B 63 -228 584 546 ;
C -1 ; WX 278 ; N iacute ; B 69 0 488 750 ;
C -1 ; WX 494 ; N lozenge ; B 90 0 564 745 ;
C -1 ; WX 722 ; N Rcaron ; B 76 0 778 936 ;
C -1 ; WX 778 ; N Gcommaaccent ; B 108 -228 817 737 ;
C -1 ; WX 611 ; N ucircumflex ; B 98 -14 658 750 ;
C -1 ; WX 556 ; N acircumflex ; B 55 -14 583 750 ;
C -1 ; WX 722 ; N Amacron ; B 20 0 718 864 ;
C -1 ; WX 389 ; N rcaron ; B 64 0 530 750 ;
C -1 ; WX 556 ; N ccedilla ; B 79 -228 599 546 ;
C -1 ; WX 611 ; N Zdotaccent ; B 25 0 737 915 ;
C -1 ; WX 667 ; N Thorn ; B 76 0 716 718 ;
C -1 ; WX 778 ; N Omacron ; B 107 -19 823 864 ;
C -1 ; WX 722 ; N Racute ; B 76 0 778 936 ;
C -1 ; WX 667 ; N Sacute ; B 81 -19 722 936 ;
C -1 ; WX 743 ; N dcaron ; B 82 -14 903 718 ;
C -1 ; WX 722 ; N Umacron ; B 116 -19 804 864 ;
C -1 ; WX 611 ; N uring ; B 98 -14 658 776 ;
C -1 ; WX 333 ; N threesuperior ; B 91 271 441 710 ;
C -1 ; WX 778 ; N Ograve ; B 107 -19 823 936 ;
C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ;
C -1 ; WX 722 ; N Abreve ; B 20 0 729 936 ;
C -1 ; WX 584 ; N multiply ; B 57 1 635 505 ;
C -1 ; WX 611 ; N uacute ; B 98 -14 658 750 ;
C -1 ; WX 611 ; N Tcaron ; B 140 0 751 936 ;
C -1 ; WX 494 ; N partialdiff ; B 43 -21 585 750 ;
C -1 ; WX 556 ; N ydieresis ; B 42 -214 652 729 ;
C -1 ; WX 722 ; N Nacute ; B 69 0 807 936 ;
C -1 ; WX 278 ; N icircumflex ; B 69 0 444 750 ;
C -1 ; WX 667 ; N Ecircumflex ; B 76 0 757 936 ;
C -1 ; WX 556 ; N adieresis ; B 55 -14 594 729 ;
C -1 ; WX 556 ; N edieresis ; B 70 -14 594 729 ;
C -1 ; WX 556 ; N cacute ; B 79 -14 627 750 ;
C -1 ; WX 611 ; N nacute ; B 65 0 654 750 ;
C -1 ; WX 611 ; N umacron ; B 98 -14 658 678 ;
C -1 ; WX 722 ; N Ncaron ; B 69 0 807 936 ;
C -1 ; WX 278 ; N Iacute ; B 64 0 528 936 ;
C -1 ; WX 584 ; N plusminus ; B 40 0 625 506 ;
C -1 ; WX 280 ; N brokenbar ; B 52 -150 345 700 ;
C -1 ; WX 737 ; N registered ; B 55 -19 834 737 ;
C -1 ; WX 778 ; N Gbreve ; B 108 -19 817 936 ;
C -1 ; WX 278 ; N Idotaccent ; B 64 0 397 915 ;
C -1 ; WX 600 ; N summation ; B 14 -10 670 706 ;
C -1 ; WX 667 ; N Egrave ; B 76 0 757 936 ;
C -1 ; WX 389 ; N racute ; B 64 0 543 750 ;
C -1 ; WX 611 ; N omacron ; B 82 -14 643 678 ;
C -1 ; WX 611 ; N Zacute ; B 25 0 737 936 ;
C -1 ; WX 611 ; N Zcaron ; B 25 0 737 936 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 629 704 ;
C -1 ; WX 722 ; N Eth ; B 62 0 777 718 ;
C -1 ; WX 722 ; N Ccedilla ; B 107 -228 789 737 ;
C -1 ; WX 278 ; N lcommaaccent ; B 30 -228 362 718 ;
C -1 ; WX 389 ; N tcaron ; B 100 -6 608 878 ;
C -1 ; WX 556 ; N eogonek ; B 70 -228 593 546 ;
C -1 ; WX 722 ; N Uogonek ; B 116 -228 804 718 ;
C -1 ; WX 722 ; N Aacute ; B 20 0 750 936 ;
C -1 ; WX 722 ; N Adieresis ; B 20 0 716 915 ;
C -1 ; WX 556 ; N egrave ; B 70 -14 593 750 ;
C -1 ; WX 500 ; N zacute ; B 20 0 599 750 ;
C -1 ; WX 278 ; N iogonek ; B -14 -224 363 725 ;
C -1 ; WX 778 ; N Oacute ; B 107 -19 823 936 ;
C -1 ; WX 611 ; N oacute ; B 82 -14 654 750 ;
C -1 ; WX 556 ; N amacron ; B 55 -14 595 678 ;
C -1 ; WX 556 ; N sacute ; B 63 -14 627 750 ;
C -1 ; WX 278 ; N idieresis ; B 69 0 455 729 ;
C -1 ; WX 778 ; N Ocircumflex ; B 107 -19 823 936 ;
C -1 ; WX 722 ; N Ugrave ; B 116 -19 804 936 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 611 ; N thorn ; B 18 -208 645 718 ;
C -1 ; WX 333 ; N twosuperior ; B 69 283 449 710 ;
C -1 ; WX 778 ; N Odieresis ; B 107 -19 823 915 ;
C -1 ; WX 611 ; N mu ; B 22 -207 658 532 ;
C -1 ; WX 278 ; N igrave ; B 69 0 326 750 ;
C -1 ; WX 611 ; N ohungarumlaut ; B 82 -14 784 750 ;
C -1 ; WX 667 ; N Eogonek ; B 76 -224 757 718 ;
C -1 ; WX 611 ; N dcroat ; B 82 -14 789 718 ;
C -1 ; WX 834 ; N threequarters ; B 99 -19 839 710 ;
C -1 ; WX 667 ; N Scedilla ; B 81 -228 718 737 ;
C -1 ; WX 400 ; N lcaron ; B 69 0 561 718 ;
C -1 ; WX 722 ; N Kcommaaccent ; B 87 -228 858 718 ;
C -1 ; WX 611 ; N Lacute ; B 76 0 611 936 ;
C -1 ; WX 1000 ; N trademark ; B 179 306 1109 718 ;
C -1 ; WX 556 ; N edotaccent ; B 70 -14 593 729 ;
C -1 ; WX 278 ; N Igrave ; B 64 0 367 936 ;
C -1 ; WX 278 ; N Imacron ; B 64 0 496 864 ;
C -1 ; WX 611 ; N Lcaron ; B 76 0 643 718 ;
C -1 ; WX 834 ; N onehalf ; B 132 -19 858 710 ;
C -1 ; WX 549 ; N lessequal ; B 29 0 676 704 ;
C -1 ; WX 611 ; N ocircumflex ; B 82 -14 643 750 ;
C -1 ; WX 611 ; N ntilde ; B 65 0 646 737 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 116 -19 880 936 ;
C -1 ; WX 667 ; N Eacute ; B 76 0 757 936 ;
C -1 ; WX 556 ; N emacron ; B 70 -14 595 678 ;
C -1 ; WX 611 ; N gbreve ; B 38 -217 666 750 ;
C -1 ; WX 834 ; N onequarter ; B 132 -19 806 710 ;
C -1 ; WX 667 ; N Scaron ; B 81 -19 718 936 ;
C -1 ; WX 667 ; N Scommaaccent ; B 81 -228 718 737 ;
C -1 ; WX 778 ; N Ohungarumlaut ; B 107 -19 908 936 ;
C -1 ; WX 400 ; N degree ; B 175 426 467 712 ;
C -1 ; WX 611 ; N ograve ; B 82 -14 643 750 ;
C -1 ; WX 722 ; N Ccaron ; B 107 -19 789 936 ;
C -1 ; WX 611 ; N ugrave ; B 98 -14 658 750 ;
C -1 ; WX 549 ; N radical ; B 112 -46 689 850 ;
C -1 ; WX 722 ; N Dcaron ; B 76 0 777 936 ;
C -1 ; WX 389 ; N rcommaaccent ; B 26 -228 489 546 ;
C -1 ; WX 722 ; N Ntilde ; B 69 0 807 923 ;
C -1 ; WX 611 ; N otilde ; B 82 -14 646 737 ;
C -1 ; WX 722 ; N Rcommaaccent ; B 76 -228 778 718 ;
C -1 ; WX 611 ; N Lcommaaccent ; B 76 -228 611 718 ;
C -1 ; WX 722 ; N Atilde ; B 20 0 741 923 ;
C -1 ; WX 722 ; N Aogonek ; B 20 -224 702 718 ;
C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ;
C -1 ; WX 778 ; N Otilde ; B 107 -19 823 923 ;
C -1 ; WX 500 ; N zdotaccent ; B 20 0 583 729 ;
C -1 ; WX 667 ; N Ecaron ; B 76 0 757 936 ;
C -1 ; WX 278 ; N Iogonek ; B -41 -228 367 718 ;
C -1 ; WX 556 ; N kcommaaccent ; B 69 -228 670 718 ;
C -1 ; WX 584 ; N minus ; B 82 197 610 309 ;
C -1 ; WX 278 ; N Icircumflex ; B 64 0 484 936 ;
C -1 ; WX 611 ; N ncaron ; B 65 0 641 750 ;
C -1 ; WX 333 ; N tcommaaccent ; B 58 -228 422 676 ;
C -1 ; WX 584 ; N logicalnot ; B 105 108 633 419 ;
C -1 ; WX 611 ; N odieresis ; B 82 -14 643 729 ;
C -1 ; WX 611 ; N udieresis ; B 98 -14 658 729 ;
C -1 ; WX 549 ; N notequal ; B 32 -49 630 570 ;
C -1 ; WX 611 ; N gcommaaccent ; B 38 -217 666 850 ;
C -1 ; WX 611 ; N eth ; B 82 -14 670 737 ;
C -1 ; WX 500 ; N zcaron ; B 20 0 586 750 ;
C -1 ; WX 611 ; N ncommaaccent ; B 65 -228 629 546 ;
C -1 ; WX 333 ; N onesuperior ; B 148 283 388 710 ;
C -1 ; WX 278 ; N imacron ; B 69 0 429 678 ;
C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2481
KPX A C -40
KPX A Cacute -40
KPX A Ccaron -40
KPX A Ccedilla -40
KPX A G -50
KPX A Gbreve -50
KPX A Gcommaaccent -50
KPX A O -40
KPX A Oacute -40
KPX A Ocircumflex -40
KPX A Odieresis -40
KPX A Ograve -40
KPX A Ohungarumlaut -40
KPX A Omacron -40
KPX A Oslash -40
KPX A Otilde -40
KPX A Q -40
KPX A T -90
KPX A Tcaron -90
KPX A Tcommaaccent -90
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -80
KPX A W -60
KPX A Y -110
KPX A Yacute -110
KPX A Ydieresis -110
KPX A u -30
KPX A uacute -30
KPX A ucircumflex -30
KPX A udieresis -30
KPX A ugrave -30
KPX A uhungarumlaut -30
KPX A umacron -30
KPX A uogonek -30
KPX A uring -30
KPX A v -40
KPX A w -30
KPX A y -30
KPX A yacute -30
KPX A ydieresis -30
KPX Aacute C -40
KPX Aacute Cacute -40
KPX Aacute Ccaron -40
KPX Aacute Ccedilla -40
KPX Aacute G -50
KPX Aacute Gbreve -50
KPX Aacute Gcommaaccent -50
KPX Aacute O -40
KPX Aacute Oacute -40
KPX Aacute Ocircumflex -40
KPX Aacute Odieresis -40
KPX Aacute Ograve -40
KPX Aacute Ohungarumlaut -40
KPX Aacute Omacron -40
KPX Aacute Oslash -40
KPX Aacute Otilde -40
KPX Aacute Q -40
KPX Aacute T -90
KPX Aacute Tcaron -90
KPX Aacute Tcommaaccent -90
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -80
KPX Aacute W -60
KPX Aacute Y -110
KPX Aacute Yacute -110
KPX Aacute Ydieresis -110
KPX Aacute u -30
KPX Aacute uacute -30
KPX Aacute ucircumflex -30
KPX Aacute udieresis -30
KPX Aacute ugrave -30
KPX Aacute uhungarumlaut -30
KPX Aacute umacron -30
KPX Aacute uogonek -30
KPX Aacute uring -30
KPX Aacute v -40
KPX Aacute w -30
KPX Aacute y -30
KPX Aacute yacute -30
KPX Aacute ydieresis -30
KPX Abreve C -40
KPX Abreve Cacute -40
KPX Abreve Ccaron -40
KPX Abreve Ccedilla -40
KPX Abreve G -50
KPX Abreve Gbreve -50
KPX Abreve Gcommaaccent -50
KPX Abreve O -40
KPX Abreve Oacute -40
KPX Abreve Ocircumflex -40
KPX Abreve Odieresis -40
KPX Abreve Ograve -40
KPX Abreve Ohungarumlaut -40
KPX Abreve Omacron -40
KPX Abreve Oslash -40
KPX Abreve Otilde -40
KPX Abreve Q -40
KPX Abreve T -90
KPX Abreve Tcaron -90
KPX Abreve Tcommaaccent -90
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -80
KPX Abreve W -60
KPX Abreve Y -110
KPX Abreve Yacute -110
KPX Abreve Ydieresis -110
KPX Abreve u -30
KPX Abreve uacute -30
KPX Abreve ucircumflex -30
KPX Abreve udieresis -30
KPX Abreve ugrave -30
KPX Abreve uhungarumlaut -30
KPX Abreve umacron -30
KPX Abreve uogonek -30
KPX Abreve uring -30
KPX Abreve v -40
KPX Abreve w -30
KPX Abreve y -30
KPX Abreve yacute -30
KPX Abreve ydieresis -30
KPX Acircumflex C -40
KPX Acircumflex Cacute -40
KPX Acircumflex Ccaron -40
KPX Acircumflex Ccedilla -40
KPX Acircumflex G -50
KPX Acircumflex Gbreve -50
KPX Acircumflex Gcommaaccent -50
KPX Acircumflex O -40
KPX Acircumflex Oacute -40
KPX Acircumflex Ocircumflex -40
KPX Acircumflex Odieresis -40
KPX Acircumflex Ograve -40
KPX Acircumflex Ohungarumlaut -40
KPX Acircumflex Omacron -40
KPX Acircumflex Oslash -40
KPX Acircumflex Otilde -40
KPX Acircumflex Q -40
KPX Acircumflex T -90
KPX Acircumflex Tcaron -90
KPX Acircumflex Tcommaaccent -90
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -80
KPX Acircumflex W -60
KPX Acircumflex Y -110
KPX Acircumflex Yacute -110
KPX Acircumflex Ydieresis -110
KPX Acircumflex u -30
KPX Acircumflex uacute -30
KPX Acircumflex ucircumflex -30
KPX Acircumflex udieresis -30
KPX Acircumflex ugrave -30
KPX Acircumflex uhungarumlaut -30
KPX Acircumflex umacron -30
KPX Acircumflex uogonek -30
KPX Acircumflex uring -30
KPX Acircumflex v -40
KPX Acircumflex w -30
KPX Acircumflex y -30
KPX Acircumflex yacute -30
KPX Acircumflex ydieresis -30
KPX Adieresis C -40
KPX Adieresis Cacute -40
KPX Adieresis Ccaron -40
KPX Adieresis Ccedilla -40
KPX Adieresis G -50
KPX Adieresis Gbreve -50
KPX Adieresis Gcommaaccent -50
KPX Adieresis O -40
KPX Adieresis Oacute -40
KPX Adieresis Ocircumflex -40
KPX Adieresis Odieresis -40
KPX Adieresis Ograve -40
KPX Adieresis Ohungarumlaut -40
KPX Adieresis Omacron -40
KPX Adieresis Oslash -40
KPX Adieresis Otilde -40
KPX Adieresis Q -40
KPX Adieresis T -90
KPX Adieresis Tcaron -90
KPX Adieresis Tcommaaccent -90
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -80
KPX Adieresis W -60
KPX Adieresis Y -110
KPX Adieresis Yacute -110
KPX Adieresis Ydieresis -110
KPX Adieresis u -30
KPX Adieresis uacute -30
KPX Adieresis ucircumflex -30
KPX Adieresis udieresis -30
KPX Adieresis ugrave -30
KPX Adieresis uhungarumlaut -30
KPX Adieresis umacron -30
KPX Adieresis uogonek -30
KPX Adieresis uring -30
KPX Adieresis v -40
KPX Adieresis w -30
KPX Adieresis y -30
KPX Adieresis yacute -30
KPX Adieresis ydieresis -30
KPX Agrave C -40
KPX Agrave Cacute -40
KPX Agrave Ccaron -40
KPX Agrave Ccedilla -40
KPX Agrave G -50
KPX Agrave Gbreve -50
KPX Agrave Gcommaaccent -50
KPX Agrave O -40
KPX Agrave Oacute -40
KPX Agrave Ocircumflex -40
KPX Agrave Odieresis -40
KPX Agrave Ograve -40
KPX Agrave Ohungarumlaut -40
KPX Agrave Omacron -40
KPX Agrave Oslash -40
KPX Agrave Otilde -40
KPX Agrave Q -40
KPX Agrave T -90
KPX Agrave Tcaron -90
KPX Agrave Tcommaaccent -90
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -80
KPX Agrave W -60
KPX Agrave Y -110
KPX Agrave Yacute -110
KPX Agrave Ydieresis -110
KPX Agrave u -30
KPX Agrave uacute -30
KPX Agrave ucircumflex -30
KPX Agrave udieresis -30
KPX Agrave ugrave -30
KPX Agrave uhungarumlaut -30
KPX Agrave umacron -30
KPX Agrave uogonek -30
KPX Agrave uring -30
KPX Agrave v -40
KPX Agrave w -30
KPX Agrave y -30
KPX Agrave yacute -30
KPX Agrave ydieresis -30
KPX Amacron C -40
KPX Amacron Cacute -40
KPX Amacron Ccaron -40
KPX Amacron Ccedilla -40
KPX Amacron G -50
KPX Amacron Gbreve -50
KPX Amacron Gcommaaccent -50
KPX Amacron O -40
KPX Amacron Oacute -40
KPX Amacron Ocircumflex -40
KPX Amacron Odieresis -40
KPX Amacron Ograve -40
KPX Amacron Ohungarumlaut -40
KPX Amacron Omacron -40
KPX Amacron Oslash -40
KPX Amacron Otilde -40
KPX Amacron Q -40
KPX Amacron T -90
KPX Amacron Tcaron -90
KPX Amacron Tcommaaccent -90
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -80
KPX Amacron W -60
KPX Amacron Y -110
KPX Amacron Yacute -110
KPX Amacron Ydieresis -110
KPX Amacron u -30
KPX Amacron uacute -30
KPX Amacron ucircumflex -30
KPX Amacron udieresis -30
KPX Amacron ugrave -30
KPX Amacron uhungarumlaut -30
KPX Amacron umacron -30
KPX Amacron uogonek -30
KPX Amacron uring -30
KPX Amacron v -40
KPX Amacron w -30
KPX Amacron y -30
KPX Amacron yacute -30
KPX Amacron ydieresis -30
KPX Aogonek C -40
KPX Aogonek Cacute -40
KPX Aogonek Ccaron -40
KPX Aogonek Ccedilla -40
KPX Aogonek G -50
KPX Aogonek Gbreve -50
KPX Aogonek Gcommaaccent -50
KPX Aogonek O -40
KPX Aogonek Oacute -40
KPX Aogonek Ocircumflex -40
KPX Aogonek Odieresis -40
KPX Aogonek Ograve -40
KPX Aogonek Ohungarumlaut -40
KPX Aogonek Omacron -40
KPX Aogonek Oslash -40
KPX Aogonek Otilde -40
KPX Aogonek Q -40
KPX Aogonek T -90
KPX Aogonek Tcaron -90
KPX Aogonek Tcommaaccent -90
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -80
KPX Aogonek W -60
KPX Aogonek Y -110
KPX Aogonek Yacute -110
KPX Aogonek Ydieresis -110
KPX Aogonek u -30
KPX Aogonek uacute -30
KPX Aogonek ucircumflex -30
KPX Aogonek udieresis -30
KPX Aogonek ugrave -30
KPX Aogonek uhungarumlaut -30
KPX Aogonek umacron -30
KPX Aogonek uogonek -30
KPX Aogonek uring -30
KPX Aogonek v -40
KPX Aogonek w -30
KPX Aogonek y -30
KPX Aogonek yacute -30
KPX Aogonek ydieresis -30
KPX Aring C -40
KPX Aring Cacute -40
KPX Aring Ccaron -40
KPX Aring Ccedilla -40
KPX Aring G -50
KPX Aring Gbreve -50
KPX Aring Gcommaaccent -50
KPX Aring O -40
KPX Aring Oacute -40
KPX Aring Ocircumflex -40
KPX Aring Odieresis -40
KPX Aring Ograve -40
KPX Aring Ohungarumlaut -40
KPX Aring Omacron -40
KPX Aring Oslash -40
KPX Aring Otilde -40
KPX Aring Q -40
KPX Aring T -90
KPX Aring Tcaron -90
KPX Aring Tcommaaccent -90
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -80
KPX Aring W -60
KPX Aring Y -110
KPX Aring Yacute -110
KPX Aring Ydieresis -110
KPX Aring u -30
KPX Aring uacute -30
KPX Aring ucircumflex -30
KPX Aring udieresis -30
KPX Aring ugrave -30
KPX Aring uhungarumlaut -30
KPX Aring umacron -30
KPX Aring uogonek -30
KPX Aring uring -30
KPX Aring v -40
KPX Aring w -30
KPX Aring y -30
KPX Aring yacute -30
KPX Aring ydieresis -30
KPX Atilde C -40
KPX Atilde Cacute -40
KPX Atilde Ccaron -40
KPX Atilde Ccedilla -40
KPX Atilde G -50
KPX Atilde Gbreve -50
KPX Atilde Gcommaaccent -50
KPX Atilde O -40
KPX Atilde Oacute -40
KPX Atilde Ocircumflex -40
KPX Atilde Odieresis -40
KPX Atilde Ograve -40
KPX Atilde Ohungarumlaut -40
KPX Atilde Omacron -40
KPX Atilde Oslash -40
KPX Atilde Otilde -40
KPX Atilde Q -40
KPX Atilde T -90
KPX Atilde Tcaron -90
KPX Atilde Tcommaaccent -90
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -80
KPX Atilde W -60
KPX Atilde Y -110
KPX Atilde Yacute -110
KPX Atilde Ydieresis -110
KPX Atilde u -30
KPX Atilde uacute -30
KPX Atilde ucircumflex -30
KPX Atilde udieresis -30
KPX Atilde ugrave -30
KPX Atilde uhungarumlaut -30
KPX Atilde umacron -30
KPX Atilde uogonek -30
KPX Atilde uring -30
KPX Atilde v -40
KPX Atilde w -30
KPX Atilde y -30
KPX Atilde yacute -30
KPX Atilde ydieresis -30
KPX B A -30
KPX B Aacute -30
KPX B Abreve -30
KPX B Acircumflex -30
KPX B Adieresis -30
KPX B Agrave -30
KPX B Amacron -30
KPX B Aogonek -30
KPX B Aring -30
KPX B Atilde -30
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX D A -40
KPX D Aacute -40
KPX D Abreve -40
KPX D Acircumflex -40
KPX D Adieresis -40
KPX D Agrave -40
KPX D Amacron -40
KPX D Aogonek -40
KPX D Aring -40
KPX D Atilde -40
KPX D V -40
KPX D W -40
KPX D Y -70
KPX D Yacute -70
KPX D Ydieresis -70
KPX D comma -30
KPX D period -30
KPX Dcaron A -40
KPX Dcaron Aacute -40
KPX Dcaron Abreve -40
KPX Dcaron Acircumflex -40
KPX Dcaron Adieresis -40
KPX Dcaron Agrave -40
KPX Dcaron Amacron -40
KPX Dcaron Aogonek -40
KPX Dcaron Aring -40
KPX Dcaron Atilde -40
KPX Dcaron V -40
KPX Dcaron W -40
KPX Dcaron Y -70
KPX Dcaron Yacute -70
KPX Dcaron Ydieresis -70
KPX Dcaron comma -30
KPX Dcaron period -30
KPX Dcroat A -40
KPX Dcroat Aacute -40
KPX Dcroat Abreve -40
KPX Dcroat Acircumflex -40
KPX Dcroat Adieresis -40
KPX Dcroat Agrave -40
KPX Dcroat Amacron -40
KPX Dcroat Aogonek -40
KPX Dcroat Aring -40
KPX Dcroat Atilde -40
KPX Dcroat V -40
KPX Dcroat W -40
KPX Dcroat Y -70
KPX Dcroat Yacute -70
KPX Dcroat Ydieresis -70
KPX Dcroat comma -30
KPX Dcroat period -30
KPX F A -80
KPX F Aacute -80
KPX F Abreve -80
KPX F Acircumflex -80
KPX F Adieresis -80
KPX F Agrave -80
KPX F Amacron -80
KPX F Aogonek -80
KPX F Aring -80
KPX F Atilde -80
KPX F a -20
KPX F aacute -20
KPX F abreve -20
KPX F acircumflex -20
KPX F adieresis -20
KPX F agrave -20
KPX F amacron -20
KPX F aogonek -20
KPX F aring -20
KPX F atilde -20
KPX F comma -100
KPX F period -100
KPX J A -20
KPX J Aacute -20
KPX J Abreve -20
KPX J Acircumflex -20
KPX J Adieresis -20
KPX J Agrave -20
KPX J Amacron -20
KPX J Aogonek -20
KPX J Aring -20
KPX J Atilde -20
KPX J comma -20
KPX J period -20
KPX J u -20
KPX J uacute -20
KPX J ucircumflex -20
KPX J udieresis -20
KPX J ugrave -20
KPX J uhungarumlaut -20
KPX J umacron -20
KPX J uogonek -20
KPX J uring -20
KPX K O -30
KPX K Oacute -30
KPX K Ocircumflex -30
KPX K Odieresis -30
KPX K Ograve -30
KPX K Ohungarumlaut -30
KPX K Omacron -30
KPX K Oslash -30
KPX K Otilde -30
KPX K e -15
KPX K eacute -15
KPX K ecaron -15
KPX K ecircumflex -15
KPX K edieresis -15
KPX K edotaccent -15
KPX K egrave -15
KPX K emacron -15
KPX K eogonek -15
KPX K o -35
KPX K oacute -35
KPX K ocircumflex -35
KPX K odieresis -35
KPX K ograve -35
KPX K ohungarumlaut -35
KPX K omacron -35
KPX K oslash -35
KPX K otilde -35
KPX K u -30
KPX K uacute -30
KPX K ucircumflex -30
KPX K udieresis -30
KPX K ugrave -30
KPX K uhungarumlaut -30
KPX K umacron -30
KPX K uogonek -30
KPX K uring -30
KPX K y -40
KPX K yacute -40
KPX K ydieresis -40
KPX Kcommaaccent O -30
KPX Kcommaaccent Oacute -30
KPX Kcommaaccent Ocircumflex -30
KPX Kcommaaccent Odieresis -30
KPX Kcommaaccent Ograve -30
KPX Kcommaaccent Ohungarumlaut -30
KPX Kcommaaccent Omacron -30
KPX Kcommaaccent Oslash -30
KPX Kcommaaccent Otilde -30
KPX Kcommaaccent e -15
KPX Kcommaaccent eacute -15
KPX Kcommaaccent ecaron -15
KPX Kcommaaccent ecircumflex -15
KPX Kcommaaccent edieresis -15
KPX Kcommaaccent edotaccent -15
KPX Kcommaaccent egrave -15
KPX Kcommaaccent emacron -15
KPX Kcommaaccent eogonek -15
KPX Kcommaaccent o -35
KPX Kcommaaccent oacute -35
KPX Kcommaaccent ocircumflex -35
KPX Kcommaaccent odieresis -35
KPX Kcommaaccent ograve -35
KPX Kcommaaccent ohungarumlaut -35
KPX Kcommaaccent omacron -35
KPX Kcommaaccent oslash -35
KPX Kcommaaccent otilde -35
KPX Kcommaaccent u -30
KPX Kcommaaccent uacute -30
KPX Kcommaaccent ucircumflex -30
KPX Kcommaaccent udieresis -30
KPX Kcommaaccent ugrave -30
KPX Kcommaaccent uhungarumlaut -30
KPX Kcommaaccent umacron -30
KPX Kcommaaccent uogonek -30
KPX Kcommaaccent uring -30
KPX Kcommaaccent y -40
KPX Kcommaaccent yacute -40
KPX Kcommaaccent ydieresis -40
KPX L T -90
KPX L Tcaron -90
KPX L Tcommaaccent -90
KPX L V -110
KPX L W -80
KPX L Y -120
KPX L Yacute -120
KPX L Ydieresis -120
KPX L quotedblright -140
KPX L quoteright -140
KPX L y -30
KPX L yacute -30
KPX L ydieresis -30
KPX Lacute T -90
KPX Lacute Tcaron -90
KPX Lacute Tcommaaccent -90
KPX Lacute V -110
KPX Lacute W -80
KPX Lacute Y -120
KPX Lacute Yacute -120
KPX Lacute Ydieresis -120
KPX Lacute quotedblright -140
KPX Lacute quoteright -140
KPX Lacute y -30
KPX Lacute yacute -30
KPX Lacute ydieresis -30
KPX Lcommaaccent T -90
KPX Lcommaaccent Tcaron -90
KPX Lcommaaccent Tcommaaccent -90
KPX Lcommaaccent V -110
KPX Lcommaaccent W -80
KPX Lcommaaccent Y -120
KPX Lcommaaccent Yacute -120
KPX Lcommaaccent Ydieresis -120
KPX Lcommaaccent quotedblright -140
KPX Lcommaaccent quoteright -140
KPX Lcommaaccent y -30
KPX Lcommaaccent yacute -30
KPX Lcommaaccent ydieresis -30
KPX Lslash T -90
KPX Lslash Tcaron -90
KPX Lslash Tcommaaccent -90
KPX Lslash V -110
KPX Lslash W -80
KPX Lslash Y -120
KPX Lslash Yacute -120
KPX Lslash Ydieresis -120
KPX Lslash quotedblright -140
KPX Lslash quoteright -140
KPX Lslash y -30
KPX Lslash yacute -30
KPX Lslash ydieresis -30
KPX O A -50
KPX O Aacute -50
KPX O Abreve -50
KPX O Acircumflex -50
KPX O Adieresis -50
KPX O Agrave -50
KPX O Amacron -50
KPX O Aogonek -50
KPX O Aring -50
KPX O Atilde -50
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -50
KPX O X -50
KPX O Y -70
KPX O Yacute -70
KPX O Ydieresis -70
KPX O comma -40
KPX O period -40
KPX Oacute A -50
KPX Oacute Aacute -50
KPX Oacute Abreve -50
KPX Oacute Acircumflex -50
KPX Oacute Adieresis -50
KPX Oacute Agrave -50
KPX Oacute Amacron -50
KPX Oacute Aogonek -50
KPX Oacute Aring -50
KPX Oacute Atilde -50
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -50
KPX Oacute X -50
KPX Oacute Y -70
KPX Oacute Yacute -70
KPX Oacute Ydieresis -70
KPX Oacute comma -40
KPX Oacute period -40
KPX Ocircumflex A -50
KPX Ocircumflex Aacute -50
KPX Ocircumflex Abreve -50
KPX Ocircumflex Acircumflex -50
KPX Ocircumflex Adieresis -50
KPX Ocircumflex Agrave -50
KPX Ocircumflex Amacron -50
KPX Ocircumflex Aogonek -50
KPX Ocircumflex Aring -50
KPX Ocircumflex Atilde -50
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -50
KPX Ocircumflex X -50
KPX Ocircumflex Y -70
KPX Ocircumflex Yacute -70
KPX Ocircumflex Ydieresis -70
KPX Ocircumflex comma -40
KPX Ocircumflex period -40
KPX Odieresis A -50
KPX Odieresis Aacute -50
KPX Odieresis Abreve -50
KPX Odieresis Acircumflex -50
KPX Odieresis Adieresis -50
KPX Odieresis Agrave -50
KPX Odieresis Amacron -50
KPX Odieresis Aogonek -50
KPX Odieresis Aring -50
KPX Odieresis Atilde -50
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -50
KPX Odieresis X -50
KPX Odieresis Y -70
KPX Odieresis Yacute -70
KPX Odieresis Ydieresis -70
KPX Odieresis comma -40
KPX Odieresis period -40
KPX Ograve A -50
KPX Ograve Aacute -50
KPX Ograve Abreve -50
KPX Ograve Acircumflex -50
KPX Ograve Adieresis -50
KPX Ograve Agrave -50
KPX Ograve Amacron -50
KPX Ograve Aogonek -50
KPX Ograve Aring -50
KPX Ograve Atilde -50
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -50
KPX Ograve X -50
KPX Ograve Y -70
KPX Ograve Yacute -70
KPX Ograve Ydieresis -70
KPX Ograve comma -40
KPX Ograve period -40
KPX Ohungarumlaut A -50
KPX Ohungarumlaut Aacute -50
KPX Ohungarumlaut Abreve -50
KPX Ohungarumlaut Acircumflex -50
KPX Ohungarumlaut Adieresis -50
KPX Ohungarumlaut Agrave -50
KPX Ohungarumlaut Amacron -50
KPX Ohungarumlaut Aogonek -50
KPX Ohungarumlaut Aring -50
KPX Ohungarumlaut Atilde -50
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -50
KPX Ohungarumlaut X -50
KPX Ohungarumlaut Y -70
KPX Ohungarumlaut Yacute -70
KPX Ohungarumlaut Ydieresis -70
KPX Ohungarumlaut comma -40
KPX Ohungarumlaut period -40
KPX Omacron A -50
KPX Omacron Aacute -50
KPX Omacron Abreve -50
KPX Omacron Acircumflex -50
KPX Omacron Adieresis -50
KPX Omacron Agrave -50
KPX Omacron Amacron -50
KPX Omacron Aogonek -50
KPX Omacron Aring -50
KPX Omacron Atilde -50
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -50
KPX Omacron X -50
KPX Omacron Y -70
KPX Omacron Yacute -70
KPX Omacron Ydieresis -70
KPX Omacron comma -40
KPX Omacron period -40
KPX Oslash A -50
KPX Oslash Aacute -50
KPX Oslash Abreve -50
KPX Oslash Acircumflex -50
KPX Oslash Adieresis -50
KPX Oslash Agrave -50
KPX Oslash Amacron -50
KPX Oslash Aogonek -50
KPX Oslash Aring -50
KPX Oslash Atilde -50
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -50
KPX Oslash X -50
KPX Oslash Y -70
KPX Oslash Yacute -70
KPX Oslash Ydieresis -70
KPX Oslash comma -40
KPX Oslash period -40
KPX Otilde A -50
KPX Otilde Aacute -50
KPX Otilde Abreve -50
KPX Otilde Acircumflex -50
KPX Otilde Adieresis -50
KPX Otilde Agrave -50
KPX Otilde Amacron -50
KPX Otilde Aogonek -50
KPX Otilde Aring -50
KPX Otilde Atilde -50
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -50
KPX Otilde X -50
KPX Otilde Y -70
KPX Otilde Yacute -70
KPX Otilde Ydieresis -70
KPX Otilde comma -40
KPX Otilde period -40
KPX P A -100
KPX P Aacute -100
KPX P Abreve -100
KPX P Acircumflex -100
KPX P Adieresis -100
KPX P Agrave -100
KPX P Amacron -100
KPX P Aogonek -100
KPX P Aring -100
KPX P Atilde -100
KPX P a -30
KPX P aacute -30
KPX P abreve -30
KPX P acircumflex -30
KPX P adieresis -30
KPX P agrave -30
KPX P amacron -30
KPX P aogonek -30
KPX P aring -30
KPX P atilde -30
KPX P comma -120
KPX P e -30
KPX P eacute -30
KPX P ecaron -30
KPX P ecircumflex -30
KPX P edieresis -30
KPX P edotaccent -30
KPX P egrave -30
KPX P emacron -30
KPX P eogonek -30
KPX P o -40
KPX P oacute -40
KPX P ocircumflex -40
KPX P odieresis -40
KPX P ograve -40
KPX P ohungarumlaut -40
KPX P omacron -40
KPX P oslash -40
KPX P otilde -40
KPX P period -120
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX Q comma 20
KPX Q period 20
KPX R O -20
KPX R Oacute -20
KPX R Ocircumflex -20
KPX R Odieresis -20
KPX R Ograve -20
KPX R Ohungarumlaut -20
KPX R Omacron -20
KPX R Oslash -20
KPX R Otilde -20
KPX R T -20
KPX R Tcaron -20
KPX R Tcommaaccent -20
KPX R U -20
KPX R Uacute -20
KPX R Ucircumflex -20
KPX R Udieresis -20
KPX R Ugrave -20
KPX R Uhungarumlaut -20
KPX R Umacron -20
KPX R Uogonek -20
KPX R Uring -20
KPX R V -50
KPX R W -40
KPX R Y -50
KPX R Yacute -50
KPX R Ydieresis -50
KPX Racute O -20
KPX Racute Oacute -20
KPX Racute Ocircumflex -20
KPX Racute Odieresis -20
KPX Racute Ograve -20
KPX Racute Ohungarumlaut -20
KPX Racute Omacron -20
KPX Racute Oslash -20
KPX Racute Otilde -20
KPX Racute T -20
KPX Racute Tcaron -20
KPX Racute Tcommaaccent -20
KPX Racute U -20
KPX Racute Uacute -20
KPX Racute Ucircumflex -20
KPX Racute Udieresis -20
KPX Racute Ugrave -20
KPX Racute Uhungarumlaut -20
KPX Racute Umacron -20
KPX Racute Uogonek -20
KPX Racute Uring -20
KPX Racute V -50
KPX Racute W -40
KPX Racute Y -50
KPX Racute Yacute -50
KPX Racute Ydieresis -50
KPX Rcaron O -20
KPX Rcaron Oacute -20
KPX Rcaron Ocircumflex -20
KPX Rcaron Odieresis -20
KPX Rcaron Ograve -20
KPX Rcaron Ohungarumlaut -20
KPX Rcaron Omacron -20
KPX Rcaron Oslash -20
KPX Rcaron Otilde -20
KPX Rcaron T -20
KPX Rcaron Tcaron -20
KPX Rcaron Tcommaaccent -20
KPX Rcaron U -20
KPX Rcaron Uacute -20
KPX Rcaron Ucircumflex -20
KPX Rcaron Udieresis -20
KPX Rcaron Ugrave -20
KPX Rcaron Uhungarumlaut -20
KPX Rcaron Umacron -20
KPX Rcaron Uogonek -20
KPX Rcaron Uring -20
KPX Rcaron V -50
KPX Rcaron W -40
KPX Rcaron Y -50
KPX Rcaron Yacute -50
KPX Rcaron Ydieresis -50
KPX Rcommaaccent O -20
KPX Rcommaaccent Oacute -20
KPX Rcommaaccent Ocircumflex -20
KPX Rcommaaccent Odieresis -20
KPX Rcommaaccent Ograve -20
KPX Rcommaaccent Ohungarumlaut -20
KPX Rcommaaccent Omacron -20
KPX Rcommaaccent Oslash -20
KPX Rcommaaccent Otilde -20
KPX Rcommaaccent T -20
KPX Rcommaaccent Tcaron -20
KPX Rcommaaccent Tcommaaccent -20
KPX Rcommaaccent U -20
KPX Rcommaaccent Uacute -20
KPX Rcommaaccent Ucircumflex -20
KPX Rcommaaccent Udieresis -20
KPX Rcommaaccent Ugrave -20
KPX Rcommaaccent Uhungarumlaut -20
KPX Rcommaaccent Umacron -20
KPX Rcommaaccent Uogonek -20
KPX Rcommaaccent Uring -20
KPX Rcommaaccent V -50
KPX Rcommaaccent W -40
KPX Rcommaaccent Y -50
KPX Rcommaaccent Yacute -50
KPX Rcommaaccent Ydieresis -50
KPX T A -90
KPX T Aacute -90
KPX T Abreve -90
KPX T Acircumflex -90
KPX T Adieresis -90
KPX T Agrave -90
KPX T Amacron -90
KPX T Aogonek -90
KPX T Aring -90
KPX T Atilde -90
KPX T O -40
KPX T Oacute -40
KPX T Ocircumflex -40
KPX T Odieresis -40
KPX T Ograve -40
KPX T Ohungarumlaut -40
KPX T Omacron -40
KPX T Oslash -40
KPX T Otilde -40
KPX T a -80
KPX T aacute -80
KPX T abreve -80
KPX T acircumflex -80
KPX T adieresis -80
KPX T agrave -80
KPX T amacron -80
KPX T aogonek -80
KPX T aring -80
KPX T atilde -80
KPX T colon -40
KPX T comma -80
KPX T e -60
KPX T eacute -60
KPX T ecaron -60
KPX T ecircumflex -60
KPX T edieresis -60
KPX T edotaccent -60
KPX T egrave -60
KPX T emacron -60
KPX T eogonek -60
KPX T hyphen -120
KPX T o -80
KPX T oacute -80
KPX T ocircumflex -80
KPX T odieresis -80
KPX T ograve -80
KPX T ohungarumlaut -80
KPX T omacron -80
KPX T oslash -80
KPX T otilde -80
KPX T period -80
KPX T r -80
KPX T racute -80
KPX T rcommaaccent -80
KPX T semicolon -40
KPX T u -90
KPX T uacute -90
KPX T ucircumflex -90
KPX T udieresis -90
KPX T ugrave -90
KPX T uhungarumlaut -90
KPX T umacron -90
KPX T uogonek -90
KPX T uring -90
KPX T w -60
KPX T y -60
KPX T yacute -60
KPX T ydieresis -60
KPX Tcaron A -90
KPX Tcaron Aacute -90
KPX Tcaron Abreve -90
KPX Tcaron Acircumflex -90
KPX Tcaron Adieresis -90
KPX Tcaron Agrave -90
KPX Tcaron Amacron -90
KPX Tcaron Aogonek -90
KPX Tcaron Aring -90
KPX Tcaron Atilde -90
KPX Tcaron O -40
KPX Tcaron Oacute -40
KPX Tcaron Ocircumflex -40
KPX Tcaron Odieresis -40
KPX Tcaron Ograve -40
KPX Tcaron Ohungarumlaut -40
KPX Tcaron Omacron -40
KPX Tcaron Oslash -40
KPX Tcaron Otilde -40
KPX Tcaron a -80
KPX Tcaron aacute -80
KPX Tcaron abreve -80
KPX Tcaron acircumflex -80
KPX Tcaron adieresis -80
KPX Tcaron agrave -80
KPX Tcaron amacron -80
KPX Tcaron aogonek -80
KPX Tcaron aring -80
KPX Tcaron atilde -80
KPX Tcaron colon -40
KPX Tcaron comma -80
KPX Tcaron e -60
KPX Tcaron eacute -60
KPX Tcaron ecaron -60
KPX Tcaron ecircumflex -60
KPX Tcaron edieresis -60
KPX Tcaron edotaccent -60
KPX Tcaron egrave -60
KPX Tcaron emacron -60
KPX Tcaron eogonek -60
KPX Tcaron hyphen -120
KPX Tcaron o -80
KPX Tcaron oacute -80
KPX Tcaron ocircumflex -80
KPX Tcaron odieresis -80
KPX Tcaron ograve -80
KPX Tcaron ohungarumlaut -80
KPX Tcaron omacron -80
KPX Tcaron oslash -80
KPX Tcaron otilde -80
KPX Tcaron period -80
KPX Tcaron r -80
KPX Tcaron racute -80
KPX Tcaron rcommaaccent -80
KPX Tcaron semicolon -40
KPX Tcaron u -90
KPX Tcaron uacute -90
KPX Tcaron ucircumflex -90
KPX Tcaron udieresis -90
KPX Tcaron ugrave -90
KPX Tcaron uhungarumlaut -90
KPX Tcaron umacron -90
KPX Tcaron uogonek -90
KPX Tcaron uring -90
KPX Tcaron w -60
KPX Tcaron y -60
KPX Tcaron yacute -60
KPX Tcaron ydieresis -60
KPX Tcommaaccent A -90
KPX Tcommaaccent Aacute -90
KPX Tcommaaccent Abreve -90
KPX Tcommaaccent Acircumflex -90
KPX Tcommaaccent Adieresis -90
KPX Tcommaaccent Agrave -90
KPX Tcommaaccent Amacron -90
KPX Tcommaaccent Aogonek -90
KPX Tcommaaccent Aring -90
KPX Tcommaaccent Atilde -90
KPX Tcommaaccent O -40
KPX Tcommaaccent Oacute -40
KPX Tcommaaccent Ocircumflex -40
KPX Tcommaaccent Odieresis -40
KPX Tcommaaccent Ograve -40
KPX Tcommaaccent Ohungarumlaut -40
KPX Tcommaaccent Omacron -40
KPX Tcommaaccent Oslash -40
KPX Tcommaaccent Otilde -40
KPX Tcommaaccent a -80
KPX Tcommaaccent aacute -80
KPX Tcommaaccent abreve -80
KPX Tcommaaccent acircumflex -80
KPX Tcommaaccent adieresis -80
KPX Tcommaaccent agrave -80
KPX Tcommaaccent amacron -80
KPX Tcommaaccent aogonek -80
KPX Tcommaaccent aring -80
KPX Tcommaaccent atilde -80
KPX Tcommaaccent colon -40
KPX Tcommaaccent comma -80
KPX Tcommaaccent e -60
KPX Tcommaaccent eacute -60
KPX Tcommaaccent ecaron -60
KPX Tcommaaccent ecircumflex -60
KPX Tcommaaccent edieresis -60
KPX Tcommaaccent edotaccent -60
KPX Tcommaaccent egrave -60
KPX Tcommaaccent emacron -60
KPX Tcommaaccent eogonek -60
KPX Tcommaaccent hyphen -120
KPX Tcommaaccent o -80
KPX Tcommaaccent oacute -80
KPX Tcommaaccent ocircumflex -80
KPX Tcommaaccent odieresis -80
KPX Tcommaaccent ograve -80
KPX Tcommaaccent ohungarumlaut -80
KPX Tcommaaccent omacron -80
KPX Tcommaaccent oslash -80
KPX Tcommaaccent otilde -80
KPX Tcommaaccent period -80
KPX Tcommaaccent r -80
KPX Tcommaaccent racute -80
KPX Tcommaaccent rcommaaccent -80
KPX Tcommaaccent semicolon -40
KPX Tcommaaccent u -90
KPX Tcommaaccent uacute -90
KPX Tcommaaccent ucircumflex -90
KPX Tcommaaccent udieresis -90
KPX Tcommaaccent ugrave -90
KPX Tcommaaccent uhungarumlaut -90
KPX Tcommaaccent umacron -90
KPX Tcommaaccent uogonek -90
KPX Tcommaaccent uring -90
KPX Tcommaaccent w -60
KPX Tcommaaccent y -60
KPX Tcommaaccent yacute -60
KPX Tcommaaccent ydieresis -60
KPX U A -50
KPX U Aacute -50
KPX U Abreve -50
KPX U Acircumflex -50
KPX U Adieresis -50
KPX U Agrave -50
KPX U Amacron -50
KPX U Aogonek -50
KPX U Aring -50
KPX U Atilde -50
KPX U comma -30
KPX U period -30
KPX Uacute A -50
KPX Uacute Aacute -50
KPX Uacute Abreve -50
KPX Uacute Acircumflex -50
KPX Uacute Adieresis -50
KPX Uacute Agrave -50
KPX Uacute Amacron -50
KPX Uacute Aogonek -50
KPX Uacute Aring -50
KPX Uacute Atilde -50
KPX Uacute comma -30
KPX Uacute period -30
KPX Ucircumflex A -50
KPX Ucircumflex Aacute -50
KPX Ucircumflex Abreve -50
KPX Ucircumflex Acircumflex -50
KPX Ucircumflex Adieresis -50
KPX Ucircumflex Agrave -50
KPX Ucircumflex Amacron -50
KPX Ucircumflex Aogonek -50
KPX Ucircumflex Aring -50
KPX Ucircumflex Atilde -50
KPX Ucircumflex comma -30
KPX Ucircumflex period -30
KPX Udieresis A -50
KPX Udieresis Aacute -50
KPX Udieresis Abreve -50
KPX Udieresis Acircumflex -50
KPX Udieresis Adieresis -50
KPX Udieresis Agrave -50
KPX Udieresis Amacron -50
KPX Udieresis Aogonek -50
KPX Udieresis Aring -50
KPX Udieresis Atilde -50
KPX Udieresis comma -30
KPX Udieresis period -30
KPX Ugrave A -50
KPX Ugrave Aacute -50
KPX Ugrave Abreve -50
KPX Ugrave Acircumflex -50
KPX Ugrave Adieresis -50
KPX Ugrave Agrave -50
KPX Ugrave Amacron -50
KPX Ugrave Aogonek -50
KPX Ugrave Aring -50
KPX Ugrave Atilde -50
KPX Ugrave comma -30
KPX Ugrave period -30
KPX Uhungarumlaut A -50
KPX Uhungarumlaut Aacute -50
KPX Uhungarumlaut Abreve -50
KPX Uhungarumlaut Acircumflex -50
KPX Uhungarumlaut Adieresis -50
KPX Uhungarumlaut Agrave -50
KPX Uhungarumlaut Amacron -50
KPX Uhungarumlaut Aogonek -50
KPX Uhungarumlaut Aring -50
KPX Uhungarumlaut Atilde -50
KPX Uhungarumlaut comma -30
KPX Uhungarumlaut period -30
KPX Umacron A -50
KPX Umacron Aacute -50
KPX Umacron Abreve -50
KPX Umacron Acircumflex -50
KPX Umacron Adieresis -50
KPX Umacron Agrave -50
KPX Umacron Amacron -50
KPX Umacron Aogonek -50
KPX Umacron Aring -50
KPX Umacron Atilde -50
KPX Umacron comma -30
KPX Umacron period -30
KPX Uogonek A -50
KPX Uogonek Aacute -50
KPX Uogonek Abreve -50
KPX Uogonek Acircumflex -50
KPX Uogonek Adieresis -50
KPX Uogonek Agrave -50
KPX Uogonek Amacron -50
KPX Uogonek Aogonek -50
KPX Uogonek Aring -50
KPX Uogonek Atilde -50
KPX Uogonek comma -30
KPX Uogonek period -30
KPX Uring A -50
KPX Uring Aacute -50
KPX Uring Abreve -50
KPX Uring Acircumflex -50
KPX Uring Adieresis -50
KPX Uring Agrave -50
KPX Uring Amacron -50
KPX Uring Aogonek -50
KPX Uring Aring -50
KPX Uring Atilde -50
KPX Uring comma -30
KPX Uring period -30
KPX V A -80
KPX V Aacute -80
KPX V Abreve -80
KPX V Acircumflex -80
KPX V Adieresis -80
KPX V Agrave -80
KPX V Amacron -80
KPX V Aogonek -80
KPX V Aring -80
KPX V Atilde -80
KPX V G -50
KPX V Gbreve -50
KPX V Gcommaaccent -50
KPX V O -50
KPX V Oacute -50
KPX V Ocircumflex -50
KPX V Odieresis -50
KPX V Ograve -50
KPX V Ohungarumlaut -50
KPX V Omacron -50
KPX V Oslash -50
KPX V Otilde -50
KPX V a -60
KPX V aacute -60
KPX V abreve -60
KPX V acircumflex -60
KPX V adieresis -60
KPX V agrave -60
KPX V amacron -60
KPX V aogonek -60
KPX V aring -60
KPX V atilde -60
KPX V colon -40
KPX V comma -120
KPX V e -50
KPX V eacute -50
KPX V ecaron -50
KPX V ecircumflex -50
KPX V edieresis -50
KPX V edotaccent -50
KPX V egrave -50
KPX V emacron -50
KPX V eogonek -50
KPX V hyphen -80
KPX V o -90
KPX V oacute -90
KPX V ocircumflex -90
KPX V odieresis -90
KPX V ograve -90
KPX V ohungarumlaut -90
KPX V omacron -90
KPX V oslash -90
KPX V otilde -90
KPX V period -120
KPX V semicolon -40
KPX V u -60
KPX V uacute -60
KPX V ucircumflex -60
KPX V udieresis -60
KPX V ugrave -60
KPX V uhungarumlaut -60
KPX V umacron -60
KPX V uogonek -60
KPX V uring -60
KPX W A -60
KPX W Aacute -60
KPX W Abreve -60
KPX W Acircumflex -60
KPX W Adieresis -60
KPX W Agrave -60
KPX W Amacron -60
KPX W Aogonek -60
KPX W Aring -60
KPX W Atilde -60
KPX W O -20
KPX W Oacute -20
KPX W Ocircumflex -20
KPX W Odieresis -20
KPX W Ograve -20
KPX W Ohungarumlaut -20
KPX W Omacron -20
KPX W Oslash -20
KPX W Otilde -20
KPX W a -40
KPX W aacute -40
KPX W abreve -40
KPX W acircumflex -40
KPX W adieresis -40
KPX W agrave -40
KPX W amacron -40
KPX W aogonek -40
KPX W aring -40
KPX W atilde -40
KPX W colon -10
KPX W comma -80
KPX W e -35
KPX W eacute -35
KPX W ecaron -35
KPX W ecircumflex -35
KPX W edieresis -35
KPX W edotaccent -35
KPX W egrave -35
KPX W emacron -35
KPX W eogonek -35
KPX W hyphen -40
KPX W o -60
KPX W oacute -60
KPX W ocircumflex -60
KPX W odieresis -60
KPX W ograve -60
KPX W ohungarumlaut -60
KPX W omacron -60
KPX W oslash -60
KPX W otilde -60
KPX W period -80
KPX W semicolon -10
KPX W u -45
KPX W uacute -45
KPX W ucircumflex -45
KPX W udieresis -45
KPX W ugrave -45
KPX W uhungarumlaut -45
KPX W umacron -45
KPX W uogonek -45
KPX W uring -45
KPX W y -20
KPX W yacute -20
KPX W ydieresis -20
KPX Y A -110
KPX Y Aacute -110
KPX Y Abreve -110
KPX Y Acircumflex -110
KPX Y Adieresis -110
KPX Y Agrave -110
KPX Y Amacron -110
KPX Y Aogonek -110
KPX Y Aring -110
KPX Y Atilde -110
KPX Y O -70
KPX Y Oacute -70
KPX Y Ocircumflex -70
KPX Y Odieresis -70
KPX Y Ograve -70
KPX Y Ohungarumlaut -70
KPX Y Omacron -70
KPX Y Oslash -70
KPX Y Otilde -70
KPX Y a -90
KPX Y aacute -90
KPX Y abreve -90
KPX Y acircumflex -90
KPX Y adieresis -90
KPX Y agrave -90
KPX Y amacron -90
KPX Y aogonek -90
KPX Y aring -90
KPX Y atilde -90
KPX Y colon -50
KPX Y comma -100
KPX Y e -80
KPX Y eacute -80
KPX Y ecaron -80
KPX Y ecircumflex -80
KPX Y edieresis -80
KPX Y edotaccent -80
KPX Y egrave -80
KPX Y emacron -80
KPX Y eogonek -80
KPX Y o -100
KPX Y oacute -100
KPX Y ocircumflex -100
KPX Y odieresis -100
KPX Y ograve -100
KPX Y ohungarumlaut -100
KPX Y omacron -100
KPX Y oslash -100
KPX Y otilde -100
KPX Y period -100
KPX Y semicolon -50
KPX Y u -100
KPX Y uacute -100
KPX Y ucircumflex -100
KPX Y udieresis -100
KPX Y ugrave -100
KPX Y uhungarumlaut -100
KPX Y umacron -100
KPX Y uogonek -100
KPX Y uring -100
KPX Yacute A -110
KPX Yacute Aacute -110
KPX Yacute Abreve -110
KPX Yacute Acircumflex -110
KPX Yacute Adieresis -110
KPX Yacute Agrave -110
KPX Yacute Amacron -110
KPX Yacute Aogonek -110
KPX Yacute Aring -110
KPX Yacute Atilde -110
KPX Yacute O -70
KPX Yacute Oacute -70
KPX Yacute Ocircumflex -70
KPX Yacute Odieresis -70
KPX Yacute Ograve -70
KPX Yacute Ohungarumlaut -70
KPX Yacute Omacron -70
KPX Yacute Oslash -70
KPX Yacute Otilde -70
KPX Yacute a -90
KPX Yacute aacute -90
KPX Yacute abreve -90
KPX Yacute acircumflex -90
KPX Yacute adieresis -90
KPX Yacute agrave -90
KPX Yacute amacron -90
KPX Yacute aogonek -90
KPX Yacute aring -90
KPX Yacute atilde -90
KPX Yacute colon -50
KPX Yacute comma -100
KPX Yacute e -80
KPX Yacute eacute -80
KPX Yacute ecaron -80
KPX Yacute ecircumflex -80
KPX Yacute edieresis -80
KPX Yacute edotaccent -80
KPX Yacute egrave -80
KPX Yacute emacron -80
KPX Yacute eogonek -80
KPX Yacute o -100
KPX Yacute oacute -100
KPX Yacute ocircumflex -100
KPX Yacute odieresis -100
KPX Yacute ograve -100
KPX Yacute ohungarumlaut -100
KPX Yacute omacron -100
KPX Yacute oslash -100
KPX Yacute otilde -100
KPX Yacute period -100
KPX Yacute semicolon -50
KPX Yacute u -100
KPX Yacute uacute -100
KPX Yacute ucircumflex -100
KPX Yacute udieresis -100
KPX Yacute ugrave -100
KPX Yacute uhungarumlaut -100
KPX Yacute umacron -100
KPX Yacute uogonek -100
KPX Yacute uring -100
KPX Ydieresis A -110
KPX Ydieresis Aacute -110
KPX Ydieresis Abreve -110
KPX Ydieresis Acircumflex -110
KPX Ydieresis Adieresis -110
KPX Ydieresis Agrave -110
KPX Ydieresis Amacron -110
KPX Ydieresis Aogonek -110
KPX Ydieresis Aring -110
KPX Ydieresis Atilde -110
KPX Ydieresis O -70
KPX Ydieresis Oacute -70
KPX Ydieresis Ocircumflex -70
KPX Ydieresis Odieresis -70
KPX Ydieresis Ograve -70
KPX Ydieresis Ohungarumlaut -70
KPX Ydieresis Omacron -70
KPX Ydieresis Oslash -70
KPX Ydieresis Otilde -70
KPX Ydieresis a -90
KPX Ydieresis aacute -90
KPX Ydieresis abreve -90
KPX Ydieresis acircumflex -90
KPX Ydieresis adieresis -90
KPX Ydieresis agrave -90
KPX Ydieresis amacron -90
KPX Ydieresis aogonek -90
KPX Ydieresis aring -90
KPX Ydieresis atilde -90
KPX Ydieresis colon -50
KPX Ydieresis comma -100
KPX Ydieresis e -80
KPX Ydieresis eacute -80
KPX Ydieresis ecaron -80
KPX Ydieresis ecircumflex -80
KPX Ydieresis edieresis -80
KPX Ydieresis edotaccent -80
KPX Ydieresis egrave -80
KPX Ydieresis emacron -80
KPX Ydieresis eogonek -80
KPX Ydieresis o -100
KPX Ydieresis oacute -100
KPX Ydieresis ocircumflex -100
KPX Ydieresis odieresis -100
KPX Ydieresis ograve -100
KPX Ydieresis ohungarumlaut -100
KPX Ydieresis omacron -100
KPX Ydieresis oslash -100
KPX Ydieresis otilde -100
KPX Ydieresis period -100
KPX Ydieresis semicolon -50
KPX Ydieresis u -100
KPX Ydieresis uacute -100
KPX Ydieresis ucircumflex -100
KPX Ydieresis udieresis -100
KPX Ydieresis ugrave -100
KPX Ydieresis uhungarumlaut -100
KPX Ydieresis umacron -100
KPX Ydieresis uogonek -100
KPX Ydieresis uring -100
KPX a g -10
KPX a gbreve -10
KPX a gcommaaccent -10
KPX a v -15
KPX a w -15
KPX a y -20
KPX a yacute -20
KPX a ydieresis -20
KPX aacute g -10
KPX aacute gbreve -10
KPX aacute gcommaaccent -10
KPX aacute v -15
KPX aacute w -15
KPX aacute y -20
KPX aacute yacute -20
KPX aacute ydieresis -20
KPX abreve g -10
KPX abreve gbreve -10
KPX abreve gcommaaccent -10
KPX abreve v -15
KPX abreve w -15
KPX abreve y -20
KPX abreve yacute -20
KPX abreve ydieresis -20
KPX acircumflex g -10
KPX acircumflex gbreve -10
KPX acircumflex gcommaaccent -10
KPX acircumflex v -15
KPX acircumflex w -15
KPX acircumflex y -20
KPX acircumflex yacute -20
KPX acircumflex ydieresis -20
KPX adieresis g -10
KPX adieresis gbreve -10
KPX adieresis gcommaaccent -10
KPX adieresis v -15
KPX adieresis w -15
KPX adieresis y -20
KPX adieresis yacute -20
KPX adieresis ydieresis -20
KPX agrave g -10
KPX agrave gbreve -10
KPX agrave gcommaaccent -10
KPX agrave v -15
KPX agrave w -15
KPX agrave y -20
KPX agrave yacute -20
KPX agrave ydieresis -20
KPX amacron g -10
KPX amacron gbreve -10
KPX amacron gcommaaccent -10
KPX amacron v -15
KPX amacron w -15
KPX amacron y -20
KPX amacron yacute -20
KPX amacron ydieresis -20
KPX aogonek g -10
KPX aogonek gbreve -10
KPX aogonek gcommaaccent -10
KPX aogonek v -15
KPX aogonek w -15
KPX aogonek y -20
KPX aogonek yacute -20
KPX aogonek ydieresis -20
KPX aring g -10
KPX aring gbreve -10
KPX aring gcommaaccent -10
KPX aring v -15
KPX aring w -15
KPX aring y -20
KPX aring yacute -20
KPX aring ydieresis -20
KPX atilde g -10
KPX atilde gbreve -10
KPX atilde gcommaaccent -10
KPX atilde v -15
KPX atilde w -15
KPX atilde y -20
KPX atilde yacute -20
KPX atilde ydieresis -20
KPX b l -10
KPX b lacute -10
KPX b lcommaaccent -10
KPX b lslash -10
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX b v -20
KPX b y -20
KPX b yacute -20
KPX b ydieresis -20
KPX c h -10
KPX c k -20
KPX c kcommaaccent -20
KPX c l -20
KPX c lacute -20
KPX c lcommaaccent -20
KPX c lslash -20
KPX c y -10
KPX c yacute -10
KPX c ydieresis -10
KPX cacute h -10
KPX cacute k -20
KPX cacute kcommaaccent -20
KPX cacute l -20
KPX cacute lacute -20
KPX cacute lcommaaccent -20
KPX cacute lslash -20
KPX cacute y -10
KPX cacute yacute -10
KPX cacute ydieresis -10
KPX ccaron h -10
KPX ccaron k -20
KPX ccaron kcommaaccent -20
KPX ccaron l -20
KPX ccaron lacute -20
KPX ccaron lcommaaccent -20
KPX ccaron lslash -20
KPX ccaron y -10
KPX ccaron yacute -10
KPX ccaron ydieresis -10
KPX ccedilla h -10
KPX ccedilla k -20
KPX ccedilla kcommaaccent -20
KPX ccedilla l -20
KPX ccedilla lacute -20
KPX ccedilla lcommaaccent -20
KPX ccedilla lslash -20
KPX ccedilla y -10
KPX ccedilla yacute -10
KPX ccedilla ydieresis -10
KPX colon space -40
KPX comma quotedblright -120
KPX comma quoteright -120
KPX comma space -40
KPX d d -10
KPX d dcroat -10
KPX d v -15
KPX d w -15
KPX d y -15
KPX d yacute -15
KPX d ydieresis -15
KPX dcroat d -10
KPX dcroat dcroat -10
KPX dcroat v -15
KPX dcroat w -15
KPX dcroat y -15
KPX dcroat yacute -15
KPX dcroat ydieresis -15
KPX e comma 10
KPX e period 20
KPX e v -15
KPX e w -15
KPX e x -15
KPX e y -15
KPX e yacute -15
KPX e ydieresis -15
KPX eacute comma 10
KPX eacute period 20
KPX eacute v -15
KPX eacute w -15
KPX eacute x -15
KPX eacute y -15
KPX eacute yacute -15
KPX eacute ydieresis -15
KPX ecaron comma 10
KPX ecaron period 20
KPX ecaron v -15
KPX ecaron w -15
KPX ecaron x -15
KPX ecaron y -15
KPX ecaron yacute -15
KPX ecaron ydieresis -15
KPX ecircumflex comma 10
KPX ecircumflex period 20
KPX ecircumflex v -15
KPX ecircumflex w -15
KPX ecircumflex x -15
KPX ecircumflex y -15
KPX ecircumflex yacute -15
KPX ecircumflex ydieresis -15
KPX edieresis comma 10
KPX edieresis period 20
KPX edieresis v -15
KPX edieresis w -15
KPX edieresis x -15
KPX edieresis y -15
KPX edieresis yacute -15
KPX edieresis ydieresis -15
KPX edotaccent comma 10
KPX edotaccent period 20
KPX edotaccent v -15
KPX edotaccent w -15
KPX edotaccent x -15
KPX edotaccent y -15
KPX edotaccent yacute -15
KPX edotaccent ydieresis -15
KPX egrave comma 10
KPX egrave period 20
KPX egrave v -15
KPX egrave w -15
KPX egrave x -15
KPX egrave y -15
KPX egrave yacute -15
KPX egrave ydieresis -15
KPX emacron comma 10
KPX emacron period 20
KPX emacron v -15
KPX emacron w -15
KPX emacron x -15
KPX emacron y -15
KPX emacron yacute -15
KPX emacron ydieresis -15
KPX eogonek comma 10
KPX eogonek period 20
KPX eogonek v -15
KPX eogonek w -15
KPX eogonek x -15
KPX eogonek y -15
KPX eogonek yacute -15
KPX eogonek ydieresis -15
KPX f comma -10
KPX f e -10
KPX f eacute -10
KPX f ecaron -10
KPX f ecircumflex -10
KPX f edieresis -10
KPX f edotaccent -10
KPX f egrave -10
KPX f emacron -10
KPX f eogonek -10
KPX f o -20
KPX f oacute -20
KPX f ocircumflex -20
KPX f odieresis -20
KPX f ograve -20
KPX f ohungarumlaut -20
KPX f omacron -20
KPX f oslash -20
KPX f otilde -20
KPX f period -10
KPX f quotedblright 30
KPX f quoteright 30
KPX g e 10
KPX g eacute 10
KPX g ecaron 10
KPX g ecircumflex 10
KPX g edieresis 10
KPX g edotaccent 10
KPX g egrave 10
KPX g emacron 10
KPX g eogonek 10
KPX g g -10
KPX g gbreve -10
KPX g gcommaaccent -10
KPX gbreve e 10
KPX gbreve eacute 10
KPX gbreve ecaron 10
KPX gbreve ecircumflex 10
KPX gbreve edieresis 10
KPX gbreve edotaccent 10
KPX gbreve egrave 10
KPX gbreve emacron 10
KPX gbreve eogonek 10
KPX gbreve g -10
KPX gbreve gbreve -10
KPX gbreve gcommaaccent -10
KPX gcommaaccent e 10
KPX gcommaaccent eacute 10
KPX gcommaaccent ecaron 10
KPX gcommaaccent ecircumflex 10
KPX gcommaaccent edieresis 10
KPX gcommaaccent edotaccent 10
KPX gcommaaccent egrave 10
KPX gcommaaccent emacron 10
KPX gcommaaccent eogonek 10
KPX gcommaaccent g -10
KPX gcommaaccent gbreve -10
KPX gcommaaccent gcommaaccent -10
KPX h y -20
KPX h yacute -20
KPX h ydieresis -20
KPX k o -15
KPX k oacute -15
KPX k ocircumflex -15
KPX k odieresis -15
KPX k ograve -15
KPX k ohungarumlaut -15
KPX k omacron -15
KPX k oslash -15
KPX k otilde -15
KPX kcommaaccent o -15
KPX kcommaaccent oacute -15
KPX kcommaaccent ocircumflex -15
KPX kcommaaccent odieresis -15
KPX kcommaaccent ograve -15
KPX kcommaaccent ohungarumlaut -15
KPX kcommaaccent omacron -15
KPX kcommaaccent oslash -15
KPX kcommaaccent otilde -15
KPX l w -15
KPX l y -15
KPX l yacute -15
KPX l ydieresis -15
KPX lacute w -15
KPX lacute y -15
KPX lacute yacute -15
KPX lacute ydieresis -15
KPX lcommaaccent w -15
KPX lcommaaccent y -15
KPX lcommaaccent yacute -15
KPX lcommaaccent ydieresis -15
KPX lslash w -15
KPX lslash y -15
KPX lslash yacute -15
KPX lslash ydieresis -15
KPX m u -20
KPX m uacute -20
KPX m ucircumflex -20
KPX m udieresis -20
KPX m ugrave -20
KPX m uhungarumlaut -20
KPX m umacron -20
KPX m uogonek -20
KPX m uring -20
KPX m y -30
KPX m yacute -30
KPX m ydieresis -30
KPX n u -10
KPX n uacute -10
KPX n ucircumflex -10
KPX n udieresis -10
KPX n ugrave -10
KPX n uhungarumlaut -10
KPX n umacron -10
KPX n uogonek -10
KPX n uring -10
KPX n v -40
KPX n y -20
KPX n yacute -20
KPX n ydieresis -20
KPX nacute u -10
KPX nacute uacute -10
KPX nacute ucircumflex -10
KPX nacute udieresis -10
KPX nacute ugrave -10
KPX nacute uhungarumlaut -10
KPX nacute umacron -10
KPX nacute uogonek -10
KPX nacute uring -10
KPX nacute v -40
KPX nacute y -20
KPX nacute yacute -20
KPX nacute ydieresis -20
KPX ncaron u -10
KPX ncaron uacute -10
KPX ncaron ucircumflex -10
KPX ncaron udieresis -10
KPX ncaron ugrave -10
KPX ncaron uhungarumlaut -10
KPX ncaron umacron -10
KPX ncaron uogonek -10
KPX ncaron uring -10
KPX ncaron v -40
KPX ncaron y -20
KPX ncaron yacute -20
KPX ncaron ydieresis -20
KPX ncommaaccent u -10
KPX ncommaaccent uacute -10
KPX ncommaaccent ucircumflex -10
KPX ncommaaccent udieresis -10
KPX ncommaaccent ugrave -10
KPX ncommaaccent uhungarumlaut -10
KPX ncommaaccent umacron -10
KPX ncommaaccent uogonek -10
KPX ncommaaccent uring -10
KPX ncommaaccent v -40
KPX ncommaaccent y -20
KPX ncommaaccent yacute -20
KPX ncommaaccent ydieresis -20
KPX ntilde u -10
KPX ntilde uacute -10
KPX ntilde ucircumflex -10
KPX ntilde udieresis -10
KPX ntilde ugrave -10
KPX ntilde uhungarumlaut -10
KPX ntilde umacron -10
KPX ntilde uogonek -10
KPX ntilde uring -10
KPX ntilde v -40
KPX ntilde y -20
KPX ntilde yacute -20
KPX ntilde ydieresis -20
KPX o v -20
KPX o w -15
KPX o x -30
KPX o y -20
KPX o yacute -20
KPX o ydieresis -20
KPX oacute v -20
KPX oacute w -15
KPX oacute x -30
KPX oacute y -20
KPX oacute yacute -20
KPX oacute ydieresis -20
KPX ocircumflex v -20
KPX ocircumflex w -15
KPX ocircumflex x -30
KPX ocircumflex y -20
KPX ocircumflex yacute -20
KPX ocircumflex ydieresis -20
KPX odieresis v -20
KPX odieresis w -15
KPX odieresis x -30
KPX odieresis y -20
KPX odieresis yacute -20
KPX odieresis ydieresis -20
KPX ograve v -20
KPX ograve w -15
KPX ograve x -30
KPX ograve y -20
KPX ograve yacute -20
KPX ograve ydieresis -20
KPX ohungarumlaut v -20
KPX ohungarumlaut w -15
KPX ohungarumlaut x -30
KPX ohungarumlaut y -20
KPX ohungarumlaut yacute -20
KPX ohungarumlaut ydieresis -20
KPX omacron v -20
KPX omacron w -15
KPX omacron x -30
KPX omacron y -20
KPX omacron yacute -20
KPX omacron ydieresis -20
KPX oslash v -20
KPX oslash w -15
KPX oslash x -30
KPX oslash y -20
KPX oslash yacute -20
KPX oslash ydieresis -20
KPX otilde v -20
KPX otilde w -15
KPX otilde x -30
KPX otilde y -20
KPX otilde yacute -20
KPX otilde ydieresis -20
KPX p y -15
KPX p yacute -15
KPX p ydieresis -15
KPX period quotedblright -120
KPX period quoteright -120
KPX period space -40
KPX quotedblright space -80
KPX quoteleft quoteleft -46
KPX quoteright d -80
KPX quoteright dcroat -80
KPX quoteright l -20
KPX quoteright lacute -20
KPX quoteright lcommaaccent -20
KPX quoteright lslash -20
KPX quoteright quoteright -46
KPX quoteright r -40
KPX quoteright racute -40
KPX quoteright rcaron -40
KPX quoteright rcommaaccent -40
KPX quoteright s -60
KPX quoteright sacute -60
KPX quoteright scaron -60
KPX quoteright scedilla -60
KPX quoteright scommaaccent -60
KPX quoteright space -80
KPX quoteright v -20
KPX r c -20
KPX r cacute -20
KPX r ccaron -20
KPX r ccedilla -20
KPX r comma -60
KPX r d -20
KPX r dcroat -20
KPX r g -15
KPX r gbreve -15
KPX r gcommaaccent -15
KPX r hyphen -20
KPX r o -20
KPX r oacute -20
KPX r ocircumflex -20
KPX r odieresis -20
KPX r ograve -20
KPX r ohungarumlaut -20
KPX r omacron -20
KPX r oslash -20
KPX r otilde -20
KPX r period -60
KPX r q -20
KPX r s -15
KPX r sacute -15
KPX r scaron -15
KPX r scedilla -15
KPX r scommaaccent -15
KPX r t 20
KPX r tcommaaccent 20
KPX r v 10
KPX r y 10
KPX r yacute 10
KPX r ydieresis 10
KPX racute c -20
KPX racute cacute -20
KPX racute ccaron -20
KPX racute ccedilla -20
KPX racute comma -60
KPX racute d -20
KPX racute dcroat -20
KPX racute g -15
KPX racute gbreve -15
KPX racute gcommaaccent -15
KPX racute hyphen -20
KPX racute o -20
KPX racute oacute -20
KPX racute ocircumflex -20
KPX racute odieresis -20
KPX racute ograve -20
KPX racute ohungarumlaut -20
KPX racute omacron -20
KPX racute oslash -20
KPX racute otilde -20
KPX racute period -60
KPX racute q -20
KPX racute s -15
KPX racute sacute -15
KPX racute scaron -15
KPX racute scedilla -15
KPX racute scommaaccent -15
KPX racute t 20
KPX racute tcommaaccent 20
KPX racute v 10
KPX racute y 10
KPX racute yacute 10
KPX racute ydieresis 10
KPX rcaron c -20
KPX rcaron cacute -20
KPX rcaron ccaron -20
KPX rcaron ccedilla -20
KPX rcaron comma -60
KPX rcaron d -20
KPX rcaron dcroat -20
KPX rcaron g -15
KPX rcaron gbreve -15
KPX rcaron gcommaaccent -15
KPX rcaron hyphen -20
KPX rcaron o -20
KPX rcaron oacute -20
KPX rcaron ocircumflex -20
KPX rcaron odieresis -20
KPX rcaron ograve -20
KPX rcaron ohungarumlaut -20
KPX rcaron omacron -20
KPX rcaron oslash -20
KPX rcaron otilde -20
KPX rcaron period -60
KPX rcaron q -20
KPX rcaron s -15
KPX rcaron sacute -15
KPX rcaron scaron -15
KPX rcaron scedilla -15
KPX rcaron scommaaccent -15
KPX rcaron t 20
KPX rcaron tcommaaccent 20
KPX rcaron v 10
KPX rcaron y 10
KPX rcaron yacute 10
KPX rcaron ydieresis 10
KPX rcommaaccent c -20
KPX rcommaaccent cacute -20
KPX rcommaaccent ccaron -20
KPX rcommaaccent ccedilla -20
KPX rcommaaccent comma -60
KPX rcommaaccent d -20
KPX rcommaaccent dcroat -20
KPX rcommaaccent g -15
KPX rcommaaccent gbreve -15
KPX rcommaaccent gcommaaccent -15
KPX rcommaaccent hyphen -20
KPX rcommaaccent o -20
KPX rcommaaccent oacute -20
KPX rcommaaccent ocircumflex -20
KPX rcommaaccent odieresis -20
KPX rcommaaccent ograve -20
KPX rcommaaccent ohungarumlaut -20
KPX rcommaaccent omacron -20
KPX rcommaaccent oslash -20
KPX rcommaaccent otilde -20
KPX rcommaaccent period -60
KPX rcommaaccent q -20
KPX rcommaaccent s -15
KPX rcommaaccent sacute -15
KPX rcommaaccent scaron -15
KPX rcommaaccent scedilla -15
KPX rcommaaccent scommaaccent -15
KPX rcommaaccent t 20
KPX rcommaaccent tcommaaccent 20
KPX rcommaaccent v 10
KPX rcommaaccent y 10
KPX rcommaaccent yacute 10
KPX rcommaaccent ydieresis 10
KPX s w -15
KPX sacute w -15
KPX scaron w -15
KPX scedilla w -15
KPX scommaaccent w -15
KPX semicolon space -40
KPX space T -100
KPX space Tcaron -100
KPX space Tcommaaccent -100
KPX space V -80
KPX space W -80
KPX space Y -120
KPX space Yacute -120
KPX space Ydieresis -120
KPX space quotedblleft -80
KPX space quoteleft -60
KPX v a -20
KPX v aacute -20
KPX v abreve -20
KPX v acircumflex -20
KPX v adieresis -20
KPX v agrave -20
KPX v amacron -20
KPX v aogonek -20
KPX v aring -20
KPX v atilde -20
KPX v comma -80
KPX v o -30
KPX v oacute -30
KPX v ocircumflex -30
KPX v odieresis -30
KPX v ograve -30
KPX v ohungarumlaut -30
KPX v omacron -30
KPX v oslash -30
KPX v otilde -30
KPX v period -80
KPX w comma -40
KPX w o -20
KPX w oacute -20
KPX w ocircumflex -20
KPX w odieresis -20
KPX w ograve -20
KPX w ohungarumlaut -20
KPX w omacron -20
KPX w oslash -20
KPX w otilde -20
KPX w period -40
KPX x e -10
KPX x eacute -10
KPX x ecaron -10
KPX x ecircumflex -10
KPX x edieresis -10
KPX x edotaccent -10
KPX x egrave -10
KPX x emacron -10
KPX x eogonek -10
KPX y a -30
KPX y aacute -30
KPX y abreve -30
KPX y acircumflex -30
KPX y adieresis -30
KPX y agrave -30
KPX y amacron -30
KPX y aogonek -30
KPX y aring -30
KPX y atilde -30
KPX y comma -80
KPX y e -10
KPX y eacute -10
KPX y ecaron -10
KPX y ecircumflex -10
KPX y edieresis -10
KPX y edotaccent -10
KPX y egrave -10
KPX y emacron -10
KPX y eogonek -10
KPX y o -25
KPX y oacute -25
KPX y ocircumflex -25
KPX y odieresis -25
KPX y ograve -25
KPX y ohungarumlaut -25
KPX y omacron -25
KPX y oslash -25
KPX y otilde -25
KPX y period -80
KPX yacute a -30
KPX yacute aacute -30
KPX yacute abreve -30
KPX yacute acircumflex -30
KPX yacute adieresis -30
KPX yacute agrave -30
KPX yacute amacron -30
KPX yacute aogonek -30
KPX yacute aring -30
KPX yacute atilde -30
KPX yacute comma -80
KPX yacute e -10
KPX yacute eacute -10
KPX yacute ecaron -10
KPX yacute ecircumflex -10
KPX yacute edieresis -10
KPX yacute edotaccent -10
KPX yacute egrave -10
KPX yacute emacron -10
KPX yacute eogonek -10
KPX yacute o -25
KPX yacute oacute -25
KPX yacute ocircumflex -25
KPX yacute odieresis -25
KPX yacute ograve -25
KPX yacute ohungarumlaut -25
KPX yacute omacron -25
KPX yacute oslash -25
KPX yacute otilde -25
KPX yacute period -80
KPX ydieresis a -30
KPX ydieresis aacute -30
KPX ydieresis abreve -30
KPX ydieresis acircumflex -30
KPX ydieresis adieresis -30
KPX ydieresis agrave -30
KPX ydieresis amacron -30
KPX ydieresis aogonek -30
KPX ydieresis aring -30
KPX ydieresis atilde -30
KPX ydieresis comma -80
KPX ydieresis e -10
KPX ydieresis eacute -10
KPX ydieresis ecaron -10
KPX ydieresis ecircumflex -10
KPX ydieresis edieresis -10
KPX ydieresis edotaccent -10
KPX ydieresis egrave -10
KPX ydieresis emacron -10
KPX ydieresis eogonek -10
KPX ydieresis o -25
KPX ydieresis oacute -25
KPX ydieresis ocircumflex -25
KPX ydieresis odieresis -25
KPX ydieresis ograve -25
KPX ydieresis ohungarumlaut -25
KPX ydieresis omacron -25
KPX ydieresis oslash -25
KPX ydieresis otilde -25
KPX ydieresis period -80
KPX z e 10
KPX z eacute 10
KPX z ecaron 10
KPX z ecircumflex 10
KPX z edieresis 10
KPX z edotaccent 10
KPX z egrave 10
KPX z emacron 10
KPX z eogonek 10
KPX zacute e 10
KPX zacute eacute 10
KPX zacute ecaron 10
KPX zacute ecircumflex 10
KPX zacute edieresis 10
KPX zacute edotaccent 10
KPX zacute egrave 10
KPX zacute emacron 10
KPX zacute eogonek 10
KPX zcaron e 10
KPX zcaron eacute 10
KPX zcaron ecaron 10
KPX zcaron ecircumflex 10
KPX zcaron edieresis 10
KPX zcaron edotaccent 10
KPX zcaron egrave 10
KPX zcaron emacron 10
KPX zcaron eogonek 10
KPX zdotaccent e 10
KPX zdotaccent eacute 10
KPX zdotaccent ecaron 10
KPX zdotaccent ecircumflex 10
KPX zdotaccent edieresis 10
KPX zdotaccent edotaccent 10
KPX zdotaccent egrave 10
KPX zdotaccent emacron 10
KPX zdotaccent eogonek 10
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Helvetica-Oblique.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:44:31 1997
Comment UniqueID 43055
Comment VMusage 14960 69346
FontName Helvetica-Oblique
FullName Helvetica Oblique
FamilyName Helvetica
Weight Medium
ItalicAngle -12
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -170 -225 1116 931
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 718
XHeight 523
Ascender 718
Descender -207
StdHW 76
StdVW 88
StartCharMetrics 315
C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
C 33 ; WX 278 ; N exclam ; B 90 0 340 718 ;
C 34 ; WX 355 ; N quotedbl ; B 168 463 438 718 ;
C 35 ; WX 556 ; N numbersign ; B 73 0 631 688 ;
C 36 ; WX 556 ; N dollar ; B 69 -115 617 775 ;
C 37 ; WX 889 ; N percent ; B 147 -19 889 703 ;
C 38 ; WX 667 ; N ampersand ; B 77 -15 647 718 ;
C 39 ; WX 222 ; N quoteright ; B 151 463 310 718 ;
C 40 ; WX 333 ; N parenleft ; B 108 -207 454 733 ;
C 41 ; WX 333 ; N parenright ; B -9 -207 337 733 ;
C 42 ; WX 389 ; N asterisk ; B 165 431 475 718 ;
C 43 ; WX 584 ; N plus ; B 85 0 606 505 ;
C 44 ; WX 278 ; N comma ; B 56 -147 214 106 ;
C 45 ; WX 333 ; N hyphen ; B 93 232 357 322 ;
C 46 ; WX 278 ; N period ; B 87 0 214 106 ;
C 47 ; WX 278 ; N slash ; B -21 -19 452 737 ;
C 48 ; WX 556 ; N zero ; B 93 -19 608 703 ;
C 49 ; WX 556 ; N one ; B 207 0 508 703 ;
C 50 ; WX 556 ; N two ; B 26 0 617 703 ;
C 51 ; WX 556 ; N three ; B 75 -19 610 703 ;
C 52 ; WX 556 ; N four ; B 61 0 576 703 ;
C 53 ; WX 556 ; N five ; B 68 -19 621 688 ;
C 54 ; WX 556 ; N six ; B 91 -19 615 703 ;
C 55 ; WX 556 ; N seven ; B 137 0 669 688 ;
C 56 ; WX 556 ; N eight ; B 74 -19 607 703 ;
C 57 ; WX 556 ; N nine ; B 82 -19 609 703 ;
C 58 ; WX 278 ; N colon ; B 87 0 301 516 ;
C 59 ; WX 278 ; N semicolon ; B 56 -147 301 516 ;
C 60 ; WX 584 ; N less ; B 94 11 641 495 ;
C 61 ; WX 584 ; N equal ; B 63 115 628 390 ;
C 62 ; WX 584 ; N greater ; B 50 11 597 495 ;
C 63 ; WX 556 ; N question ; B 161 0 610 727 ;
C 64 ; WX 1015 ; N at ; B 215 -19 965 737 ;
C 65 ; WX 667 ; N A ; B 14 0 654 718 ;
C 66 ; WX 667 ; N B ; B 74 0 712 718 ;
C 67 ; WX 722 ; N C ; B 108 -19 782 737 ;
C 68 ; WX 722 ; N D ; B 81 0 764 718 ;
C 69 ; WX 667 ; N E ; B 86 0 762 718 ;
C 70 ; WX 611 ; N F ; B 86 0 736 718 ;
C 71 ; WX 778 ; N G ; B 111 -19 799 737 ;
C 72 ; WX 722 ; N H ; B 77 0 799 718 ;
C 73 ; WX 278 ; N I ; B 91 0 341 718 ;
C 74 ; WX 500 ; N J ; B 47 -19 581 718 ;
C 75 ; WX 667 ; N K ; B 76 0 808 718 ;
C 76 ; WX 556 ; N L ; B 76 0 555 718 ;
C 77 ; WX 833 ; N M ; B 73 0 914 718 ;
C 78 ; WX 722 ; N N ; B 76 0 799 718 ;
C 79 ; WX 778 ; N O ; B 105 -19 826 737 ;
C 80 ; WX 667 ; N P ; B 86 0 737 718 ;
C 81 ; WX 778 ; N Q ; B 105 -56 826 737 ;
C 82 ; WX 722 ; N R ; B 88 0 773 718 ;
C 83 ; WX 667 ; N S ; B 90 -19 713 737 ;
C 84 ; WX 611 ; N T ; B 148 0 750 718 ;
C 85 ; WX 722 ; N U ; B 123 -19 797 718 ;
C 86 ; WX 667 ; N V ; B 173 0 800 718 ;
C 87 ; WX 944 ; N W ; B 169 0 1081 718 ;
C 88 ; WX 667 ; N X ; B 19 0 790 718 ;
C 89 ; WX 667 ; N Y ; B 167 0 806 718 ;
C 90 ; WX 611 ; N Z ; B 23 0 741 718 ;
C 91 ; WX 278 ; N bracketleft ; B 21 -196 403 722 ;
C 92 ; WX 278 ; N backslash ; B 140 -19 291 737 ;
C 93 ; WX 278 ; N bracketright ; B -14 -196 368 722 ;
C 94 ; WX 469 ; N asciicircum ; B 42 264 539 688 ;
C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ;
C 96 ; WX 222 ; N quoteleft ; B 165 470 323 725 ;
C 97 ; WX 556 ; N a ; B 61 -15 559 538 ;
C 98 ; WX 556 ; N b ; B 58 -15 584 718 ;
C 99 ; WX 500 ; N c ; B 74 -15 553 538 ;
C 100 ; WX 556 ; N d ; B 84 -15 652 718 ;
C 101 ; WX 556 ; N e ; B 84 -15 578 538 ;
C 102 ; WX 278 ; N f ; B 86 0 416 728 ; L i fi ; L l fl ;
C 103 ; WX 556 ; N g ; B 42 -220 610 538 ;
C 104 ; WX 556 ; N h ; B 65 0 573 718 ;
C 105 ; WX 222 ; N i ; B 67 0 308 718 ;
C 106 ; WX 222 ; N j ; B -60 -210 308 718 ;
C 107 ; WX 500 ; N k ; B 67 0 600 718 ;
C 108 ; WX 222 ; N l ; B 67 0 308 718 ;
C 109 ; WX 833 ; N m ; B 65 0 852 538 ;
C 110 ; WX 556 ; N n ; B 65 0 573 538 ;
C 111 ; WX 556 ; N o ; B 83 -14 585 538 ;
C 112 ; WX 556 ; N p ; B 14 -207 584 538 ;
C 113 ; WX 556 ; N q ; B 84 -207 605 538 ;
C 114 ; WX 333 ; N r ; B 77 0 446 538 ;
C 115 ; WX 500 ; N s ; B 63 -15 529 538 ;
C 116 ; WX 278 ; N t ; B 102 -7 368 669 ;
C 117 ; WX 556 ; N u ; B 94 -15 600 523 ;
C 118 ; WX 500 ; N v ; B 119 0 603 523 ;
C 119 ; WX 722 ; N w ; B 125 0 820 523 ;
C 120 ; WX 500 ; N x ; B 11 0 594 523 ;
C 121 ; WX 500 ; N y ; B 15 -214 600 523 ;
C 122 ; WX 500 ; N z ; B 31 0 571 523 ;
C 123 ; WX 334 ; N braceleft ; B 92 -196 445 722 ;
C 124 ; WX 260 ; N bar ; B 46 -225 332 775 ;
C 125 ; WX 334 ; N braceright ; B 0 -196 354 722 ;
C 126 ; WX 584 ; N asciitilde ; B 111 180 580 326 ;
C 161 ; WX 333 ; N exclamdown ; B 77 -195 326 523 ;
C 162 ; WX 556 ; N cent ; B 95 -115 584 623 ;
C 163 ; WX 556 ; N sterling ; B 49 -16 634 718 ;
C 164 ; WX 167 ; N fraction ; B -170 -19 482 703 ;
C 165 ; WX 556 ; N yen ; B 81 0 699 688 ;
C 166 ; WX 556 ; N florin ; B -52 -207 654 737 ;
C 167 ; WX 556 ; N section ; B 76 -191 584 737 ;
C 168 ; WX 556 ; N currency ; B 60 99 646 603 ;
C 169 ; WX 191 ; N quotesingle ; B 157 463 285 718 ;
C 170 ; WX 333 ; N quotedblleft ; B 138 470 461 725 ;
C 171 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ;
C 172 ; WX 333 ; N guilsinglleft ; B 137 108 340 446 ;
C 173 ; WX 333 ; N guilsinglright ; B 111 108 314 446 ;
C 174 ; WX 500 ; N fi ; B 86 0 587 728 ;
C 175 ; WX 500 ; N fl ; B 86 0 585 728 ;
C 177 ; WX 556 ; N endash ; B 51 240 623 313 ;
C 178 ; WX 556 ; N dagger ; B 135 -159 622 718 ;
C 179 ; WX 556 ; N daggerdbl ; B 52 -159 623 718 ;
C 180 ; WX 278 ; N periodcentered ; B 129 190 257 315 ;
C 182 ; WX 537 ; N paragraph ; B 126 -173 650 718 ;
C 183 ; WX 350 ; N bullet ; B 91 202 413 517 ;
C 184 ; WX 222 ; N quotesinglbase ; B 21 -149 180 106 ;
C 185 ; WX 333 ; N quotedblbase ; B -6 -149 318 106 ;
C 186 ; WX 333 ; N quotedblright ; B 124 463 448 718 ;
C 187 ; WX 556 ; N guillemotright ; B 120 108 528 446 ;
C 188 ; WX 1000 ; N ellipsis ; B 115 0 908 106 ;
C 189 ; WX 1000 ; N perthousand ; B 88 -19 1029 703 ;
C 191 ; WX 611 ; N questiondown ; B 85 -201 534 525 ;
C 193 ; WX 333 ; N grave ; B 170 593 337 734 ;
C 194 ; WX 333 ; N acute ; B 248 593 475 734 ;
C 195 ; WX 333 ; N circumflex ; B 147 593 438 734 ;
C 196 ; WX 333 ; N tilde ; B 125 606 490 722 ;
C 197 ; WX 333 ; N macron ; B 143 627 468 684 ;
C 198 ; WX 333 ; N breve ; B 167 595 476 731 ;
C 199 ; WX 333 ; N dotaccent ; B 249 604 362 706 ;
C 200 ; WX 333 ; N dieresis ; B 168 604 443 706 ;
C 202 ; WX 333 ; N ring ; B 214 572 402 756 ;
C 203 ; WX 333 ; N cedilla ; B 2 -225 232 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B 157 593 565 734 ;
C 206 ; WX 333 ; N ogonek ; B 43 -225 249 0 ;
C 207 ; WX 333 ; N caron ; B 177 593 468 734 ;
C 208 ; WX 1000 ; N emdash ; B 51 240 1067 313 ;
C 225 ; WX 1000 ; N AE ; B 8 0 1097 718 ;
C 227 ; WX 370 ; N ordfeminine ; B 127 405 449 737 ;
C 232 ; WX 556 ; N Lslash ; B 41 0 555 718 ;
C 233 ; WX 778 ; N Oslash ; B 43 -19 890 737 ;
C 234 ; WX 1000 ; N OE ; B 98 -19 1116 737 ;
C 235 ; WX 365 ; N ordmasculine ; B 141 405 468 737 ;
C 241 ; WX 889 ; N ae ; B 61 -15 909 538 ;
C 245 ; WX 278 ; N dotlessi ; B 95 0 294 523 ;
C 248 ; WX 222 ; N lslash ; B 41 0 347 718 ;
C 249 ; WX 611 ; N oslash ; B 29 -22 647 545 ;
C 250 ; WX 944 ; N oe ; B 83 -15 964 538 ;
C 251 ; WX 611 ; N germandbls ; B 67 -15 658 728 ;
C -1 ; WX 278 ; N Idieresis ; B 91 0 458 901 ;
C -1 ; WX 556 ; N eacute ; B 84 -15 587 734 ;
C -1 ; WX 556 ; N abreve ; B 61 -15 578 731 ;
C -1 ; WX 556 ; N uhungarumlaut ; B 94 -15 677 734 ;
C -1 ; WX 556 ; N ecaron ; B 84 -15 580 734 ;
C -1 ; WX 667 ; N Ydieresis ; B 167 0 806 901 ;
C -1 ; WX 584 ; N divide ; B 85 -19 606 524 ;
C -1 ; WX 667 ; N Yacute ; B 167 0 806 929 ;
C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ;
C -1 ; WX 556 ; N aacute ; B 61 -15 587 734 ;
C -1 ; WX 722 ; N Ucircumflex ; B 123 -19 797 929 ;
C -1 ; WX 500 ; N yacute ; B 15 -214 600 734 ;
C -1 ; WX 500 ; N scommaaccent ; B 63 -225 529 538 ;
C -1 ; WX 556 ; N ecircumflex ; B 84 -15 578 734 ;
C -1 ; WX 722 ; N Uring ; B 123 -19 797 931 ;
C -1 ; WX 722 ; N Udieresis ; B 123 -19 797 901 ;
C -1 ; WX 556 ; N aogonek ; B 61 -220 559 538 ;
C -1 ; WX 722 ; N Uacute ; B 123 -19 797 929 ;
C -1 ; WX 556 ; N uogonek ; B 94 -225 600 523 ;
C -1 ; WX 667 ; N Edieresis ; B 86 0 762 901 ;
C -1 ; WX 722 ; N Dcroat ; B 69 0 764 718 ;
C -1 ; WX 250 ; N commaaccent ; B 39 -225 172 -40 ;
C -1 ; WX 737 ; N copyright ; B 54 -19 837 737 ;
C -1 ; WX 667 ; N Emacron ; B 86 0 762 879 ;
C -1 ; WX 500 ; N ccaron ; B 74 -15 553 734 ;
C -1 ; WX 556 ; N aring ; B 61 -15 559 756 ;
C -1 ; WX 722 ; N Ncommaaccent ; B 76 -225 799 718 ;
C -1 ; WX 222 ; N lacute ; B 67 0 461 929 ;
C -1 ; WX 556 ; N agrave ; B 61 -15 559 734 ;
C -1 ; WX 611 ; N Tcommaaccent ; B 148 -225 750 718 ;
C -1 ; WX 722 ; N Cacute ; B 108 -19 782 929 ;
C -1 ; WX 556 ; N atilde ; B 61 -15 592 722 ;
C -1 ; WX 667 ; N Edotaccent ; B 86 0 762 901 ;
C -1 ; WX 500 ; N scaron ; B 63 -15 552 734 ;
C -1 ; WX 500 ; N scedilla ; B 63 -225 529 538 ;
C -1 ; WX 278 ; N iacute ; B 95 0 448 734 ;
C -1 ; WX 471 ; N lozenge ; B 88 0 540 728 ;
C -1 ; WX 722 ; N Rcaron ; B 88 0 773 929 ;
C -1 ; WX 778 ; N Gcommaaccent ; B 111 -225 799 737 ;
C -1 ; WX 556 ; N ucircumflex ; B 94 -15 600 734 ;
C -1 ; WX 556 ; N acircumflex ; B 61 -15 559 734 ;
C -1 ; WX 667 ; N Amacron ; B 14 0 677 879 ;
C -1 ; WX 333 ; N rcaron ; B 77 0 508 734 ;
C -1 ; WX 500 ; N ccedilla ; B 74 -225 553 538 ;
C -1 ; WX 611 ; N Zdotaccent ; B 23 0 741 901 ;
C -1 ; WX 667 ; N Thorn ; B 86 0 712 718 ;
C -1 ; WX 778 ; N Omacron ; B 105 -19 826 879 ;
C -1 ; WX 722 ; N Racute ; B 88 0 773 929 ;
C -1 ; WX 667 ; N Sacute ; B 90 -19 713 929 ;
C -1 ; WX 643 ; N dcaron ; B 84 -15 808 718 ;
C -1 ; WX 722 ; N Umacron ; B 123 -19 797 879 ;
C -1 ; WX 556 ; N uring ; B 94 -15 600 756 ;
C -1 ; WX 333 ; N threesuperior ; B 90 270 436 703 ;
C -1 ; WX 778 ; N Ograve ; B 105 -19 826 929 ;
C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ;
C -1 ; WX 667 ; N Abreve ; B 14 0 685 926 ;
C -1 ; WX 584 ; N multiply ; B 50 0 642 506 ;
C -1 ; WX 556 ; N uacute ; B 94 -15 600 734 ;
C -1 ; WX 611 ; N Tcaron ; B 148 0 750 929 ;
C -1 ; WX 476 ; N partialdiff ; B 41 -38 550 714 ;
C -1 ; WX 500 ; N ydieresis ; B 15 -214 600 706 ;
C -1 ; WX 722 ; N Nacute ; B 76 0 799 929 ;
C -1 ; WX 278 ; N icircumflex ; B 95 0 411 734 ;
C -1 ; WX 667 ; N Ecircumflex ; B 86 0 762 929 ;
C -1 ; WX 556 ; N adieresis ; B 61 -15 559 706 ;
C -1 ; WX 556 ; N edieresis ; B 84 -15 578 706 ;
C -1 ; WX 500 ; N cacute ; B 74 -15 559 734 ;
C -1 ; WX 556 ; N nacute ; B 65 0 587 734 ;
C -1 ; WX 556 ; N umacron ; B 94 -15 600 684 ;
C -1 ; WX 722 ; N Ncaron ; B 76 0 799 929 ;
C -1 ; WX 278 ; N Iacute ; B 91 0 489 929 ;
C -1 ; WX 584 ; N plusminus ; B 39 0 618 506 ;
C -1 ; WX 260 ; N brokenbar ; B 62 -150 316 700 ;
C -1 ; WX 737 ; N registered ; B 54 -19 837 737 ;
C -1 ; WX 778 ; N Gbreve ; B 111 -19 799 926 ;
C -1 ; WX 278 ; N Idotaccent ; B 91 0 377 901 ;
C -1 ; WX 600 ; N summation ; B 15 -10 671 706 ;
C -1 ; WX 667 ; N Egrave ; B 86 0 762 929 ;
C -1 ; WX 333 ; N racute ; B 77 0 475 734 ;
C -1 ; WX 556 ; N omacron ; B 83 -14 585 684 ;
C -1 ; WX 611 ; N Zacute ; B 23 0 741 929 ;
C -1 ; WX 611 ; N Zcaron ; B 23 0 741 929 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 620 674 ;
C -1 ; WX 722 ; N Eth ; B 69 0 764 718 ;
C -1 ; WX 722 ; N Ccedilla ; B 108 -225 782 737 ;
C -1 ; WX 222 ; N lcommaaccent ; B 25 -225 308 718 ;
C -1 ; WX 317 ; N tcaron ; B 102 -7 501 808 ;
C -1 ; WX 556 ; N eogonek ; B 84 -225 578 538 ;
C -1 ; WX 722 ; N Uogonek ; B 123 -225 797 718 ;
C -1 ; WX 667 ; N Aacute ; B 14 0 683 929 ;
C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ;
C -1 ; WX 556 ; N egrave ; B 84 -15 578 734 ;
C -1 ; WX 500 ; N zacute ; B 31 0 571 734 ;
C -1 ; WX 222 ; N iogonek ; B -61 -225 308 718 ;
C -1 ; WX 778 ; N Oacute ; B 105 -19 826 929 ;
C -1 ; WX 556 ; N oacute ; B 83 -14 587 734 ;
C -1 ; WX 556 ; N amacron ; B 61 -15 580 684 ;
C -1 ; WX 500 ; N sacute ; B 63 -15 559 734 ;
C -1 ; WX 278 ; N idieresis ; B 95 0 416 706 ;
C -1 ; WX 778 ; N Ocircumflex ; B 105 -19 826 929 ;
C -1 ; WX 722 ; N Ugrave ; B 123 -19 797 929 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 556 ; N thorn ; B 14 -207 584 718 ;
C -1 ; WX 333 ; N twosuperior ; B 64 281 449 703 ;
C -1 ; WX 778 ; N Odieresis ; B 105 -19 826 901 ;
C -1 ; WX 556 ; N mu ; B 24 -207 600 523 ;
C -1 ; WX 278 ; N igrave ; B 95 0 310 734 ;
C -1 ; WX 556 ; N ohungarumlaut ; B 83 -14 677 734 ;
C -1 ; WX 667 ; N Eogonek ; B 86 -220 762 718 ;
C -1 ; WX 556 ; N dcroat ; B 84 -15 689 718 ;
C -1 ; WX 834 ; N threequarters ; B 130 -19 861 703 ;
C -1 ; WX 667 ; N Scedilla ; B 90 -225 713 737 ;
C -1 ; WX 299 ; N lcaron ; B 67 0 464 718 ;
C -1 ; WX 667 ; N Kcommaaccent ; B 76 -225 808 718 ;
C -1 ; WX 556 ; N Lacute ; B 76 0 555 929 ;
C -1 ; WX 1000 ; N trademark ; B 186 306 1056 718 ;
C -1 ; WX 556 ; N edotaccent ; B 84 -15 578 706 ;
C -1 ; WX 278 ; N Igrave ; B 91 0 351 929 ;
C -1 ; WX 278 ; N Imacron ; B 91 0 483 879 ;
C -1 ; WX 556 ; N Lcaron ; B 76 0 570 718 ;
C -1 ; WX 834 ; N onehalf ; B 114 -19 839 703 ;
C -1 ; WX 549 ; N lessequal ; B 26 0 666 674 ;
C -1 ; WX 556 ; N ocircumflex ; B 83 -14 585 734 ;
C -1 ; WX 556 ; N ntilde ; B 65 0 592 722 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 123 -19 801 929 ;
C -1 ; WX 667 ; N Eacute ; B 86 0 762 929 ;
C -1 ; WX 556 ; N emacron ; B 84 -15 580 684 ;
C -1 ; WX 556 ; N gbreve ; B 42 -220 610 731 ;
C -1 ; WX 834 ; N onequarter ; B 150 -19 802 703 ;
C -1 ; WX 667 ; N Scaron ; B 90 -19 713 929 ;
C -1 ; WX 667 ; N Scommaaccent ; B 90 -225 713 737 ;
C -1 ; WX 778 ; N Ohungarumlaut ; B 105 -19 829 929 ;
C -1 ; WX 400 ; N degree ; B 169 411 468 703 ;
C -1 ; WX 556 ; N ograve ; B 83 -14 585 734 ;
C -1 ; WX 722 ; N Ccaron ; B 108 -19 782 929 ;
C -1 ; WX 556 ; N ugrave ; B 94 -15 600 734 ;
C -1 ; WX 453 ; N radical ; B 79 -80 617 762 ;
C -1 ; WX 722 ; N Dcaron ; B 81 0 764 929 ;
C -1 ; WX 333 ; N rcommaaccent ; B 30 -225 446 538 ;
C -1 ; WX 722 ; N Ntilde ; B 76 0 799 917 ;
C -1 ; WX 556 ; N otilde ; B 83 -14 602 722 ;
C -1 ; WX 722 ; N Rcommaaccent ; B 88 -225 773 718 ;
C -1 ; WX 556 ; N Lcommaaccent ; B 76 -225 555 718 ;
C -1 ; WX 667 ; N Atilde ; B 14 0 699 917 ;
C -1 ; WX 667 ; N Aogonek ; B 14 -225 654 718 ;
C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ;
C -1 ; WX 778 ; N Otilde ; B 105 -19 826 917 ;
C -1 ; WX 500 ; N zdotaccent ; B 31 0 571 706 ;
C -1 ; WX 667 ; N Ecaron ; B 86 0 762 929 ;
C -1 ; WX 278 ; N Iogonek ; B -33 -225 341 718 ;
C -1 ; WX 500 ; N kcommaaccent ; B 67 -225 600 718 ;
C -1 ; WX 584 ; N minus ; B 85 216 606 289 ;
C -1 ; WX 278 ; N Icircumflex ; B 91 0 452 929 ;
C -1 ; WX 556 ; N ncaron ; B 65 0 580 734 ;
C -1 ; WX 278 ; N tcommaaccent ; B 63 -225 368 669 ;
C -1 ; WX 584 ; N logicalnot ; B 106 108 628 390 ;
C -1 ; WX 556 ; N odieresis ; B 83 -14 585 706 ;
C -1 ; WX 556 ; N udieresis ; B 94 -15 600 706 ;
C -1 ; WX 549 ; N notequal ; B 34 -35 623 551 ;
C -1 ; WX 556 ; N gcommaaccent ; B 42 -220 610 822 ;
C -1 ; WX 556 ; N eth ; B 81 -15 617 737 ;
C -1 ; WX 500 ; N zcaron ; B 31 0 571 734 ;
C -1 ; WX 556 ; N ncommaaccent ; B 65 -225 573 538 ;
C -1 ; WX 333 ; N onesuperior ; B 166 281 371 703 ;
C -1 ; WX 278 ; N imacron ; B 95 0 417 684 ;
C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2705
KPX A C -30
KPX A Cacute -30
KPX A Ccaron -30
KPX A Ccedilla -30
KPX A G -30
KPX A Gbreve -30
KPX A Gcommaaccent -30
KPX A O -30
KPX A Oacute -30
KPX A Ocircumflex -30
KPX A Odieresis -30
KPX A Ograve -30
KPX A Ohungarumlaut -30
KPX A Omacron -30
KPX A Oslash -30
KPX A Otilde -30
KPX A Q -30
KPX A T -120
KPX A Tcaron -120
KPX A Tcommaaccent -120
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -70
KPX A W -50
KPX A Y -100
KPX A Yacute -100
KPX A Ydieresis -100
KPX A u -30
KPX A uacute -30
KPX A ucircumflex -30
KPX A udieresis -30
KPX A ugrave -30
KPX A uhungarumlaut -30
KPX A umacron -30
KPX A uogonek -30
KPX A uring -30
KPX A v -40
KPX A w -40
KPX A y -40
KPX A yacute -40
KPX A ydieresis -40
KPX Aacute C -30
KPX Aacute Cacute -30
KPX Aacute Ccaron -30
KPX Aacute Ccedilla -30
KPX Aacute G -30
KPX Aacute Gbreve -30
KPX Aacute Gcommaaccent -30
KPX Aacute O -30
KPX Aacute Oacute -30
KPX Aacute Ocircumflex -30
KPX Aacute Odieresis -30
KPX Aacute Ograve -30
KPX Aacute Ohungarumlaut -30
KPX Aacute Omacron -30
KPX Aacute Oslash -30
KPX Aacute Otilde -30
KPX Aacute Q -30
KPX Aacute T -120
KPX Aacute Tcaron -120
KPX Aacute Tcommaaccent -120
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -70
KPX Aacute W -50
KPX Aacute Y -100
KPX Aacute Yacute -100
KPX Aacute Ydieresis -100
KPX Aacute u -30
KPX Aacute uacute -30
KPX Aacute ucircumflex -30
KPX Aacute udieresis -30
KPX Aacute ugrave -30
KPX Aacute uhungarumlaut -30
KPX Aacute umacron -30
KPX Aacute uogonek -30
KPX Aacute uring -30
KPX Aacute v -40
KPX Aacute w -40
KPX Aacute y -40
KPX Aacute yacute -40
KPX Aacute ydieresis -40
KPX Abreve C -30
KPX Abreve Cacute -30
KPX Abreve Ccaron -30
KPX Abreve Ccedilla -30
KPX Abreve G -30
KPX Abreve Gbreve -30
KPX Abreve Gcommaaccent -30
KPX Abreve O -30
KPX Abreve Oacute -30
KPX Abreve Ocircumflex -30
KPX Abreve Odieresis -30
KPX Abreve Ograve -30
KPX Abreve Ohungarumlaut -30
KPX Abreve Omacron -30
KPX Abreve Oslash -30
KPX Abreve Otilde -30
KPX Abreve Q -30
KPX Abreve T -120
KPX Abreve Tcaron -120
KPX Abreve Tcommaaccent -120
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -70
KPX Abreve W -50
KPX Abreve Y -100
KPX Abreve Yacute -100
KPX Abreve Ydieresis -100
KPX Abreve u -30
KPX Abreve uacute -30
KPX Abreve ucircumflex -30
KPX Abreve udieresis -30
KPX Abreve ugrave -30
KPX Abreve uhungarumlaut -30
KPX Abreve umacron -30
KPX Abreve uogonek -30
KPX Abreve uring -30
KPX Abreve v -40
KPX Abreve w -40
KPX Abreve y -40
KPX Abreve yacute -40
KPX Abreve ydieresis -40
KPX Acircumflex C -30
KPX Acircumflex Cacute -30
KPX Acircumflex Ccaron -30
KPX Acircumflex Ccedilla -30
KPX Acircumflex G -30
KPX Acircumflex Gbreve -30
KPX Acircumflex Gcommaaccent -30
KPX Acircumflex O -30
KPX Acircumflex Oacute -30
KPX Acircumflex Ocircumflex -30
KPX Acircumflex Odieresis -30
KPX Acircumflex Ograve -30
KPX Acircumflex Ohungarumlaut -30
KPX Acircumflex Omacron -30
KPX Acircumflex Oslash -30
KPX Acircumflex Otilde -30
KPX Acircumflex Q -30
KPX Acircumflex T -120
KPX Acircumflex Tcaron -120
KPX Acircumflex Tcommaaccent -120
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -70
KPX Acircumflex W -50
KPX Acircumflex Y -100
KPX Acircumflex Yacute -100
KPX Acircumflex Ydieresis -100
KPX Acircumflex u -30
KPX Acircumflex uacute -30
KPX Acircumflex ucircumflex -30
KPX Acircumflex udieresis -30
KPX Acircumflex ugrave -30
KPX Acircumflex uhungarumlaut -30
KPX Acircumflex umacron -30
KPX Acircumflex uogonek -30
KPX Acircumflex uring -30
KPX Acircumflex v -40
KPX Acircumflex w -40
KPX Acircumflex y -40
KPX Acircumflex yacute -40
KPX Acircumflex ydieresis -40
KPX Adieresis C -30
KPX Adieresis Cacute -30
KPX Adieresis Ccaron -30
KPX Adieresis Ccedilla -30
KPX Adieresis G -30
KPX Adieresis Gbreve -30
KPX Adieresis Gcommaaccent -30
KPX Adieresis O -30
KPX Adieresis Oacute -30
KPX Adieresis Ocircumflex -30
KPX Adieresis Odieresis -30
KPX Adieresis Ograve -30
KPX Adieresis Ohungarumlaut -30
KPX Adieresis Omacron -30
KPX Adieresis Oslash -30
KPX Adieresis Otilde -30
KPX Adieresis Q -30
KPX Adieresis T -120
KPX Adieresis Tcaron -120
KPX Adieresis Tcommaaccent -120
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -70
KPX Adieresis W -50
KPX Adieresis Y -100
KPX Adieresis Yacute -100
KPX Adieresis Ydieresis -100
KPX Adieresis u -30
KPX Adieresis uacute -30
KPX Adieresis ucircumflex -30
KPX Adieresis udieresis -30
KPX Adieresis ugrave -30
KPX Adieresis uhungarumlaut -30
KPX Adieresis umacron -30
KPX Adieresis uogonek -30
KPX Adieresis uring -30
KPX Adieresis v -40
KPX Adieresis w -40
KPX Adieresis y -40
KPX Adieresis yacute -40
KPX Adieresis ydieresis -40
KPX Agrave C -30
KPX Agrave Cacute -30
KPX Agrave Ccaron -30
KPX Agrave Ccedilla -30
KPX Agrave G -30
KPX Agrave Gbreve -30
KPX Agrave Gcommaaccent -30
KPX Agrave O -30
KPX Agrave Oacute -30
KPX Agrave Ocircumflex -30
KPX Agrave Odieresis -30
KPX Agrave Ograve -30
KPX Agrave Ohungarumlaut -30
KPX Agrave Omacron -30
KPX Agrave Oslash -30
KPX Agrave Otilde -30
KPX Agrave Q -30
KPX Agrave T -120
KPX Agrave Tcaron -120
KPX Agrave Tcommaaccent -120
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -70
KPX Agrave W -50
KPX Agrave Y -100
KPX Agrave Yacute -100
KPX Agrave Ydieresis -100
KPX Agrave u -30
KPX Agrave uacute -30
KPX Agrave ucircumflex -30
KPX Agrave udieresis -30
KPX Agrave ugrave -30
KPX Agrave uhungarumlaut -30
KPX Agrave umacron -30
KPX Agrave uogonek -30
KPX Agrave uring -30
KPX Agrave v -40
KPX Agrave w -40
KPX Agrave y -40
KPX Agrave yacute -40
KPX Agrave ydieresis -40
KPX Amacron C -30
KPX Amacron Cacute -30
KPX Amacron Ccaron -30
KPX Amacron Ccedilla -30
KPX Amacron G -30
KPX Amacron Gbreve -30
KPX Amacron Gcommaaccent -30
KPX Amacron O -30
KPX Amacron Oacute -30
KPX Amacron Ocircumflex -30
KPX Amacron Odieresis -30
KPX Amacron Ograve -30
KPX Amacron Ohungarumlaut -30
KPX Amacron Omacron -30
KPX Amacron Oslash -30
KPX Amacron Otilde -30
KPX Amacron Q -30
KPX Amacron T -120
KPX Amacron Tcaron -120
KPX Amacron Tcommaaccent -120
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -70
KPX Amacron W -50
KPX Amacron Y -100
KPX Amacron Yacute -100
KPX Amacron Ydieresis -100
KPX Amacron u -30
KPX Amacron uacute -30
KPX Amacron ucircumflex -30
KPX Amacron udieresis -30
KPX Amacron ugrave -30
KPX Amacron uhungarumlaut -30
KPX Amacron umacron -30
KPX Amacron uogonek -30
KPX Amacron uring -30
KPX Amacron v -40
KPX Amacron w -40
KPX Amacron y -40
KPX Amacron yacute -40
KPX Amacron ydieresis -40
KPX Aogonek C -30
KPX Aogonek Cacute -30
KPX Aogonek Ccaron -30
KPX Aogonek Ccedilla -30
KPX Aogonek G -30
KPX Aogonek Gbreve -30
KPX Aogonek Gcommaaccent -30
KPX Aogonek O -30
KPX Aogonek Oacute -30
KPX Aogonek Ocircumflex -30
KPX Aogonek Odieresis -30
KPX Aogonek Ograve -30
KPX Aogonek Ohungarumlaut -30
KPX Aogonek Omacron -30
KPX Aogonek Oslash -30
KPX Aogonek Otilde -30
KPX Aogonek Q -30
KPX Aogonek T -120
KPX Aogonek Tcaron -120
KPX Aogonek Tcommaaccent -120
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -70
KPX Aogonek W -50
KPX Aogonek Y -100
KPX Aogonek Yacute -100
KPX Aogonek Ydieresis -100
KPX Aogonek u -30
KPX Aogonek uacute -30
KPX Aogonek ucircumflex -30
KPX Aogonek udieresis -30
KPX Aogonek ugrave -30
KPX Aogonek uhungarumlaut -30
KPX Aogonek umacron -30
KPX Aogonek uogonek -30
KPX Aogonek uring -30
KPX Aogonek v -40
KPX Aogonek w -40
KPX Aogonek y -40
KPX Aogonek yacute -40
KPX Aogonek ydieresis -40
KPX Aring C -30
KPX Aring Cacute -30
KPX Aring Ccaron -30
KPX Aring Ccedilla -30
KPX Aring G -30
KPX Aring Gbreve -30
KPX Aring Gcommaaccent -30
KPX Aring O -30
KPX Aring Oacute -30
KPX Aring Ocircumflex -30
KPX Aring Odieresis -30
KPX Aring Ograve -30
KPX Aring Ohungarumlaut -30
KPX Aring Omacron -30
KPX Aring Oslash -30
KPX Aring Otilde -30
KPX Aring Q -30
KPX Aring T -120
KPX Aring Tcaron -120
KPX Aring Tcommaaccent -120
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -70
KPX Aring W -50
KPX Aring Y -100
KPX Aring Yacute -100
KPX Aring Ydieresis -100
KPX Aring u -30
KPX Aring uacute -30
KPX Aring ucircumflex -30
KPX Aring udieresis -30
KPX Aring ugrave -30
KPX Aring uhungarumlaut -30
KPX Aring umacron -30
KPX Aring uogonek -30
KPX Aring uring -30
KPX Aring v -40
KPX Aring w -40
KPX Aring y -40
KPX Aring yacute -40
KPX Aring ydieresis -40
KPX Atilde C -30
KPX Atilde Cacute -30
KPX Atilde Ccaron -30
KPX Atilde Ccedilla -30
KPX Atilde G -30
KPX Atilde Gbreve -30
KPX Atilde Gcommaaccent -30
KPX Atilde O -30
KPX Atilde Oacute -30
KPX Atilde Ocircumflex -30
KPX Atilde Odieresis -30
KPX Atilde Ograve -30
KPX Atilde Ohungarumlaut -30
KPX Atilde Omacron -30
KPX Atilde Oslash -30
KPX Atilde Otilde -30
KPX Atilde Q -30
KPX Atilde T -120
KPX Atilde Tcaron -120
KPX Atilde Tcommaaccent -120
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -70
KPX Atilde W -50
KPX Atilde Y -100
KPX Atilde Yacute -100
KPX Atilde Ydieresis -100
KPX Atilde u -30
KPX Atilde uacute -30
KPX Atilde ucircumflex -30
KPX Atilde udieresis -30
KPX Atilde ugrave -30
KPX Atilde uhungarumlaut -30
KPX Atilde umacron -30
KPX Atilde uogonek -30
KPX Atilde uring -30
KPX Atilde v -40
KPX Atilde w -40
KPX Atilde y -40
KPX Atilde yacute -40
KPX Atilde ydieresis -40
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX B comma -20
KPX B period -20
KPX C comma -30
KPX C period -30
KPX Cacute comma -30
KPX Cacute period -30
KPX Ccaron comma -30
KPX Ccaron period -30
KPX Ccedilla comma -30
KPX Ccedilla period -30
KPX D A -40
KPX D Aacute -40
KPX D Abreve -40
KPX D Acircumflex -40
KPX D Adieresis -40
KPX D Agrave -40
KPX D Amacron -40
KPX D Aogonek -40
KPX D Aring -40
KPX D Atilde -40
KPX D V -70
KPX D W -40
KPX D Y -90
KPX D Yacute -90
KPX D Ydieresis -90
KPX D comma -70
KPX D period -70
KPX Dcaron A -40
KPX Dcaron Aacute -40
KPX Dcaron Abreve -40
KPX Dcaron Acircumflex -40
KPX Dcaron Adieresis -40
KPX Dcaron Agrave -40
KPX Dcaron Amacron -40
KPX Dcaron Aogonek -40
KPX Dcaron Aring -40
KPX Dcaron Atilde -40
KPX Dcaron V -70
KPX Dcaron W -40
KPX Dcaron Y -90
KPX Dcaron Yacute -90
KPX Dcaron Ydieresis -90
KPX Dcaron comma -70
KPX Dcaron period -70
KPX Dcroat A -40
KPX Dcroat Aacute -40
KPX Dcroat Abreve -40
KPX Dcroat Acircumflex -40
KPX Dcroat Adieresis -40
KPX Dcroat Agrave -40
KPX Dcroat Amacron -40
KPX Dcroat Aogonek -40
KPX Dcroat Aring -40
KPX Dcroat Atilde -40
KPX Dcroat V -70
KPX Dcroat W -40
KPX Dcroat Y -90
KPX Dcroat Yacute -90
KPX Dcroat Ydieresis -90
KPX Dcroat comma -70
KPX Dcroat period -70
KPX F A -80
KPX F Aacute -80
KPX F Abreve -80
KPX F Acircumflex -80
KPX F Adieresis -80
KPX F Agrave -80
KPX F Amacron -80
KPX F Aogonek -80
KPX F Aring -80
KPX F Atilde -80
KPX F a -50
KPX F aacute -50
KPX F abreve -50
KPX F acircumflex -50
KPX F adieresis -50
KPX F agrave -50
KPX F amacron -50
KPX F aogonek -50
KPX F aring -50
KPX F atilde -50
KPX F comma -150
KPX F e -30
KPX F eacute -30
KPX F ecaron -30
KPX F ecircumflex -30
KPX F edieresis -30
KPX F edotaccent -30
KPX F egrave -30
KPX F emacron -30
KPX F eogonek -30
KPX F o -30
KPX F oacute -30
KPX F ocircumflex -30
KPX F odieresis -30
KPX F ograve -30
KPX F ohungarumlaut -30
KPX F omacron -30
KPX F oslash -30
KPX F otilde -30
KPX F period -150
KPX F r -45
KPX F racute -45
KPX F rcaron -45
KPX F rcommaaccent -45
KPX J A -20
KPX J Aacute -20
KPX J Abreve -20
KPX J Acircumflex -20
KPX J Adieresis -20
KPX J Agrave -20
KPX J Amacron -20
KPX J Aogonek -20
KPX J Aring -20
KPX J Atilde -20
KPX J a -20
KPX J aacute -20
KPX J abreve -20
KPX J acircumflex -20
KPX J adieresis -20
KPX J agrave -20
KPX J amacron -20
KPX J aogonek -20
KPX J aring -20
KPX J atilde -20
KPX J comma -30
KPX J period -30
KPX J u -20
KPX J uacute -20
KPX J ucircumflex -20
KPX J udieresis -20
KPX J ugrave -20
KPX J uhungarumlaut -20
KPX J umacron -20
KPX J uogonek -20
KPX J uring -20
KPX K O -50
KPX K Oacute -50
KPX K Ocircumflex -50
KPX K Odieresis -50
KPX K Ograve -50
KPX K Ohungarumlaut -50
KPX K Omacron -50
KPX K Oslash -50
KPX K Otilde -50
KPX K e -40
KPX K eacute -40
KPX K ecaron -40
KPX K ecircumflex -40
KPX K edieresis -40
KPX K edotaccent -40
KPX K egrave -40
KPX K emacron -40
KPX K eogonek -40
KPX K o -40
KPX K oacute -40
KPX K ocircumflex -40
KPX K odieresis -40
KPX K ograve -40
KPX K ohungarumlaut -40
KPX K omacron -40
KPX K oslash -40
KPX K otilde -40
KPX K u -30
KPX K uacute -30
KPX K ucircumflex -30
KPX K udieresis -30
KPX K ugrave -30
KPX K uhungarumlaut -30
KPX K umacron -30
KPX K uogonek -30
KPX K uring -30
KPX K y -50
KPX K yacute -50
KPX K ydieresis -50
KPX Kcommaaccent O -50
KPX Kcommaaccent Oacute -50
KPX Kcommaaccent Ocircumflex -50
KPX Kcommaaccent Odieresis -50
KPX Kcommaaccent Ograve -50
KPX Kcommaaccent Ohungarumlaut -50
KPX Kcommaaccent Omacron -50
KPX Kcommaaccent Oslash -50
KPX Kcommaaccent Otilde -50
KPX Kcommaaccent e -40
KPX Kcommaaccent eacute -40
KPX Kcommaaccent ecaron -40
KPX Kcommaaccent ecircumflex -40
KPX Kcommaaccent edieresis -40
KPX Kcommaaccent edotaccent -40
KPX Kcommaaccent egrave -40
KPX Kcommaaccent emacron -40
KPX Kcommaaccent eogonek -40
KPX Kcommaaccent o -40
KPX Kcommaaccent oacute -40
KPX Kcommaaccent ocircumflex -40
KPX Kcommaaccent odieresis -40
KPX Kcommaaccent ograve -40
KPX Kcommaaccent ohungarumlaut -40
KPX Kcommaaccent omacron -40
KPX Kcommaaccent oslash -40
KPX Kcommaaccent otilde -40
KPX Kcommaaccent u -30
KPX Kcommaaccent uacute -30
KPX Kcommaaccent ucircumflex -30
KPX Kcommaaccent udieresis -30
KPX Kcommaaccent ugrave -30
KPX Kcommaaccent uhungarumlaut -30
KPX Kcommaaccent umacron -30
KPX Kcommaaccent uogonek -30
KPX Kcommaaccent uring -30
KPX Kcommaaccent y -50
KPX Kcommaaccent yacute -50
KPX Kcommaaccent ydieresis -50
KPX L T -110
KPX L Tcaron -110
KPX L Tcommaaccent -110
KPX L V -110
KPX L W -70
KPX L Y -140
KPX L Yacute -140
KPX L Ydieresis -140
KPX L quotedblright -140
KPX L quoteright -160
KPX L y -30
KPX L yacute -30
KPX L ydieresis -30
KPX Lacute T -110
KPX Lacute Tcaron -110
KPX Lacute Tcommaaccent -110
KPX Lacute V -110
KPX Lacute W -70
KPX Lacute Y -140
KPX Lacute Yacute -140
KPX Lacute Ydieresis -140
KPX Lacute quotedblright -140
KPX Lacute quoteright -160
KPX Lacute y -30
KPX Lacute yacute -30
KPX Lacute ydieresis -30
KPX Lcaron T -110
KPX Lcaron Tcaron -110
KPX Lcaron Tcommaaccent -110
KPX Lcaron V -110
KPX Lcaron W -70
KPX Lcaron Y -140
KPX Lcaron Yacute -140
KPX Lcaron Ydieresis -140
KPX Lcaron quotedblright -140
KPX Lcaron quoteright -160
KPX Lcaron y -30
KPX Lcaron yacute -30
KPX Lcaron ydieresis -30
KPX Lcommaaccent T -110
KPX Lcommaaccent Tcaron -110
KPX Lcommaaccent Tcommaaccent -110
KPX Lcommaaccent V -110
KPX Lcommaaccent W -70
KPX Lcommaaccent Y -140
KPX Lcommaaccent Yacute -140
KPX Lcommaaccent Ydieresis -140
KPX Lcommaaccent quotedblright -140
KPX Lcommaaccent quoteright -160
KPX Lcommaaccent y -30
KPX Lcommaaccent yacute -30
KPX Lcommaaccent ydieresis -30
KPX Lslash T -110
KPX Lslash Tcaron -110
KPX Lslash Tcommaaccent -110
KPX Lslash V -110
KPX Lslash W -70
KPX Lslash Y -140
KPX Lslash Yacute -140
KPX Lslash Ydieresis -140
KPX Lslash quotedblright -140
KPX Lslash quoteright -160
KPX Lslash y -30
KPX Lslash yacute -30
KPX Lslash ydieresis -30
KPX O A -20
KPX O Aacute -20
KPX O Abreve -20
KPX O Acircumflex -20
KPX O Adieresis -20
KPX O Agrave -20
KPX O Amacron -20
KPX O Aogonek -20
KPX O Aring -20
KPX O Atilde -20
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -30
KPX O X -60
KPX O Y -70
KPX O Yacute -70
KPX O Ydieresis -70
KPX O comma -40
KPX O period -40
KPX Oacute A -20
KPX Oacute Aacute -20
KPX Oacute Abreve -20
KPX Oacute Acircumflex -20
KPX Oacute Adieresis -20
KPX Oacute Agrave -20
KPX Oacute Amacron -20
KPX Oacute Aogonek -20
KPX Oacute Aring -20
KPX Oacute Atilde -20
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -30
KPX Oacute X -60
KPX Oacute Y -70
KPX Oacute Yacute -70
KPX Oacute Ydieresis -70
KPX Oacute comma -40
KPX Oacute period -40
KPX Ocircumflex A -20
KPX Ocircumflex Aacute -20
KPX Ocircumflex Abreve -20
KPX Ocircumflex Acircumflex -20
KPX Ocircumflex Adieresis -20
KPX Ocircumflex Agrave -20
KPX Ocircumflex Amacron -20
KPX Ocircumflex Aogonek -20
KPX Ocircumflex Aring -20
KPX Ocircumflex Atilde -20
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -30
KPX Ocircumflex X -60
KPX Ocircumflex Y -70
KPX Ocircumflex Yacute -70
KPX Ocircumflex Ydieresis -70
KPX Ocircumflex comma -40
KPX Ocircumflex period -40
KPX Odieresis A -20
KPX Odieresis Aacute -20
KPX Odieresis Abreve -20
KPX Odieresis Acircumflex -20
KPX Odieresis Adieresis -20
KPX Odieresis Agrave -20
KPX Odieresis Amacron -20
KPX Odieresis Aogonek -20
KPX Odieresis Aring -20
KPX Odieresis Atilde -20
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -30
KPX Odieresis X -60
KPX Odieresis Y -70
KPX Odieresis Yacute -70
KPX Odieresis Ydieresis -70
KPX Odieresis comma -40
KPX Odieresis period -40
KPX Ograve A -20
KPX Ograve Aacute -20
KPX Ograve Abreve -20
KPX Ograve Acircumflex -20
KPX Ograve Adieresis -20
KPX Ograve Agrave -20
KPX Ograve Amacron -20
KPX Ograve Aogonek -20
KPX Ograve Aring -20
KPX Ograve Atilde -20
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -30
KPX Ograve X -60
KPX Ograve Y -70
KPX Ograve Yacute -70
KPX Ograve Ydieresis -70
KPX Ograve comma -40
KPX Ograve period -40
KPX Ohungarumlaut A -20
KPX Ohungarumlaut Aacute -20
KPX Ohungarumlaut Abreve -20
KPX Ohungarumlaut Acircumflex -20
KPX Ohungarumlaut Adieresis -20
KPX Ohungarumlaut Agrave -20
KPX Ohungarumlaut Amacron -20
KPX Ohungarumlaut Aogonek -20
KPX Ohungarumlaut Aring -20
KPX Ohungarumlaut Atilde -20
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -30
KPX Ohungarumlaut X -60
KPX Ohungarumlaut Y -70
KPX Ohungarumlaut Yacute -70
KPX Ohungarumlaut Ydieresis -70
KPX Ohungarumlaut comma -40
KPX Ohungarumlaut period -40
KPX Omacron A -20
KPX Omacron Aacute -20
KPX Omacron Abreve -20
KPX Omacron Acircumflex -20
KPX Omacron Adieresis -20
KPX Omacron Agrave -20
KPX Omacron Amacron -20
KPX Omacron Aogonek -20
KPX Omacron Aring -20
KPX Omacron Atilde -20
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -30
KPX Omacron X -60
KPX Omacron Y -70
KPX Omacron Yacute -70
KPX Omacron Ydieresis -70
KPX Omacron comma -40
KPX Omacron period -40
KPX Oslash A -20
KPX Oslash Aacute -20
KPX Oslash Abreve -20
KPX Oslash Acircumflex -20
KPX Oslash Adieresis -20
KPX Oslash Agrave -20
KPX Oslash Amacron -20
KPX Oslash Aogonek -20
KPX Oslash Aring -20
KPX Oslash Atilde -20
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -30
KPX Oslash X -60
KPX Oslash Y -70
KPX Oslash Yacute -70
KPX Oslash Ydieresis -70
KPX Oslash comma -40
KPX Oslash period -40
KPX Otilde A -20
KPX Otilde Aacute -20
KPX Otilde Abreve -20
KPX Otilde Acircumflex -20
KPX Otilde Adieresis -20
KPX Otilde Agrave -20
KPX Otilde Amacron -20
KPX Otilde Aogonek -20
KPX Otilde Aring -20
KPX Otilde Atilde -20
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -30
KPX Otilde X -60
KPX Otilde Y -70
KPX Otilde Yacute -70
KPX Otilde Ydieresis -70
KPX Otilde comma -40
KPX Otilde period -40
KPX P A -120
KPX P Aacute -120
KPX P Abreve -120
KPX P Acircumflex -120
KPX P Adieresis -120
KPX P Agrave -120
KPX P Amacron -120
KPX P Aogonek -120
KPX P Aring -120
KPX P Atilde -120
KPX P a -40
KPX P aacute -40
KPX P abreve -40
KPX P acircumflex -40
KPX P adieresis -40
KPX P agrave -40
KPX P amacron -40
KPX P aogonek -40
KPX P aring -40
KPX P atilde -40
KPX P comma -180
KPX P e -50
KPX P eacute -50
KPX P ecaron -50
KPX P ecircumflex -50
KPX P edieresis -50
KPX P edotaccent -50
KPX P egrave -50
KPX P emacron -50
KPX P eogonek -50
KPX P o -50
KPX P oacute -50
KPX P ocircumflex -50
KPX P odieresis -50
KPX P ograve -50
KPX P ohungarumlaut -50
KPX P omacron -50
KPX P oslash -50
KPX P otilde -50
KPX P period -180
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX R O -20
KPX R Oacute -20
KPX R Ocircumflex -20
KPX R Odieresis -20
KPX R Ograve -20
KPX R Ohungarumlaut -20
KPX R Omacron -20
KPX R Oslash -20
KPX R Otilde -20
KPX R T -30
KPX R Tcaron -30
KPX R Tcommaaccent -30
KPX R U -40
KPX R Uacute -40
KPX R Ucircumflex -40
KPX R Udieresis -40
KPX R Ugrave -40
KPX R Uhungarumlaut -40
KPX R Umacron -40
KPX R Uogonek -40
KPX R Uring -40
KPX R V -50
KPX R W -30
KPX R Y -50
KPX R Yacute -50
KPX R Ydieresis -50
KPX Racute O -20
KPX Racute Oacute -20
KPX Racute Ocircumflex -20
KPX Racute Odieresis -20
KPX Racute Ograve -20
KPX Racute Ohungarumlaut -20
KPX Racute Omacron -20
KPX Racute Oslash -20
KPX Racute Otilde -20
KPX Racute T -30
KPX Racute Tcaron -30
KPX Racute Tcommaaccent -30
KPX Racute U -40
KPX Racute Uacute -40
KPX Racute Ucircumflex -40
KPX Racute Udieresis -40
KPX Racute Ugrave -40
KPX Racute Uhungarumlaut -40
KPX Racute Umacron -40
KPX Racute Uogonek -40
KPX Racute Uring -40
KPX Racute V -50
KPX Racute W -30
KPX Racute Y -50
KPX Racute Yacute -50
KPX Racute Ydieresis -50
KPX Rcaron O -20
KPX Rcaron Oacute -20
KPX Rcaron Ocircumflex -20
KPX Rcaron Odieresis -20
KPX Rcaron Ograve -20
KPX Rcaron Ohungarumlaut -20
KPX Rcaron Omacron -20
KPX Rcaron Oslash -20
KPX Rcaron Otilde -20
KPX Rcaron T -30
KPX Rcaron Tcaron -30
KPX Rcaron Tcommaaccent -30
KPX Rcaron U -40
KPX Rcaron Uacute -40
KPX Rcaron Ucircumflex -40
KPX Rcaron Udieresis -40
KPX Rcaron Ugrave -40
KPX Rcaron Uhungarumlaut -40
KPX Rcaron Umacron -40
KPX Rcaron Uogonek -40
KPX Rcaron Uring -40
KPX Rcaron V -50
KPX Rcaron W -30
KPX Rcaron Y -50
KPX Rcaron Yacute -50
KPX Rcaron Ydieresis -50
KPX Rcommaaccent O -20
KPX Rcommaaccent Oacute -20
KPX Rcommaaccent Ocircumflex -20
KPX Rcommaaccent Odieresis -20
KPX Rcommaaccent Ograve -20
KPX Rcommaaccent Ohungarumlaut -20
KPX Rcommaaccent Omacron -20
KPX Rcommaaccent Oslash -20
KPX Rcommaaccent Otilde -20
KPX Rcommaaccent T -30
KPX Rcommaaccent Tcaron -30
KPX Rcommaaccent Tcommaaccent -30
KPX Rcommaaccent U -40
KPX Rcommaaccent Uacute -40
KPX Rcommaaccent Ucircumflex -40
KPX Rcommaaccent Udieresis -40
KPX Rcommaaccent Ugrave -40
KPX Rcommaaccent Uhungarumlaut -40
KPX Rcommaaccent Umacron -40
KPX Rcommaaccent Uogonek -40
KPX Rcommaaccent Uring -40
KPX Rcommaaccent V -50
KPX Rcommaaccent W -30
KPX Rcommaaccent Y -50
KPX Rcommaaccent Yacute -50
KPX Rcommaaccent Ydieresis -50
KPX S comma -20
KPX S period -20
KPX Sacute comma -20
KPX Sacute period -20
KPX Scaron comma -20
KPX Scaron period -20
KPX Scedilla comma -20
KPX Scedilla period -20
KPX Scommaaccent comma -20
KPX Scommaaccent period -20
KPX T A -120
KPX T Aacute -120
KPX T Abreve -120
KPX T Acircumflex -120
KPX T Adieresis -120
KPX T Agrave -120
KPX T Amacron -120
KPX T Aogonek -120
KPX T Aring -120
KPX T Atilde -120
KPX T O -40
KPX T Oacute -40
KPX T Ocircumflex -40
KPX T Odieresis -40
KPX T Ograve -40
KPX T Ohungarumlaut -40
KPX T Omacron -40
KPX T Oslash -40
KPX T Otilde -40
KPX T a -120
KPX T aacute -120
KPX T abreve -60
KPX T acircumflex -120
KPX T adieresis -120
KPX T agrave -120
KPX T amacron -60
KPX T aogonek -120
KPX T aring -120
KPX T atilde -60
KPX T colon -20
KPX T comma -120
KPX T e -120
KPX T eacute -120
KPX T ecaron -120
KPX T ecircumflex -120
KPX T edieresis -120
KPX T edotaccent -120
KPX T egrave -60
KPX T emacron -60
KPX T eogonek -120
KPX T hyphen -140
KPX T o -120
KPX T oacute -120
KPX T ocircumflex -120
KPX T odieresis -120
KPX T ograve -120
KPX T ohungarumlaut -120
KPX T omacron -60
KPX T oslash -120
KPX T otilde -60
KPX T period -120
KPX T r -120
KPX T racute -120
KPX T rcaron -120
KPX T rcommaaccent -120
KPX T semicolon -20
KPX T u -120
KPX T uacute -120
KPX T ucircumflex -120
KPX T udieresis -120
KPX T ugrave -120
KPX T uhungarumlaut -120
KPX T umacron -60
KPX T uogonek -120
KPX T uring -120
KPX T w -120
KPX T y -120
KPX T yacute -120
KPX T ydieresis -60
KPX Tcaron A -120
KPX Tcaron Aacute -120
KPX Tcaron Abreve -120
KPX Tcaron Acircumflex -120
KPX Tcaron Adieresis -120
KPX Tcaron Agrave -120
KPX Tcaron Amacron -120
KPX Tcaron Aogonek -120
KPX Tcaron Aring -120
KPX Tcaron Atilde -120
KPX Tcaron O -40
KPX Tcaron Oacute -40
KPX Tcaron Ocircumflex -40
KPX Tcaron Odieresis -40
KPX Tcaron Ograve -40
KPX Tcaron Ohungarumlaut -40
KPX Tcaron Omacron -40
KPX Tcaron Oslash -40
KPX Tcaron Otilde -40
KPX Tcaron a -120
KPX Tcaron aacute -120
KPX Tcaron abreve -60
KPX Tcaron acircumflex -120
KPX Tcaron adieresis -120
KPX Tcaron agrave -120
KPX Tcaron amacron -60
KPX Tcaron aogonek -120
KPX Tcaron aring -120
KPX Tcaron atilde -60
KPX Tcaron colon -20
KPX Tcaron comma -120
KPX Tcaron e -120
KPX Tcaron eacute -120
KPX Tcaron ecaron -120
KPX Tcaron ecircumflex -120
KPX Tcaron edieresis -120
KPX Tcaron edotaccent -120
KPX Tcaron egrave -60
KPX Tcaron emacron -60
KPX Tcaron eogonek -120
KPX Tcaron hyphen -140
KPX Tcaron o -120
KPX Tcaron oacute -120
KPX Tcaron ocircumflex -120
KPX Tcaron odieresis -120
KPX Tcaron ograve -120
KPX Tcaron ohungarumlaut -120
KPX Tcaron omacron -60
KPX Tcaron oslash -120
KPX Tcaron otilde -60
KPX Tcaron period -120
KPX Tcaron r -120
KPX Tcaron racute -120
KPX Tcaron rcaron -120
KPX Tcaron rcommaaccent -120
KPX Tcaron semicolon -20
KPX Tcaron u -120
KPX Tcaron uacute -120
KPX Tcaron ucircumflex -120
KPX Tcaron udieresis -120
KPX Tcaron ugrave -120
KPX Tcaron uhungarumlaut -120
KPX Tcaron umacron -60
KPX Tcaron uogonek -120
KPX Tcaron uring -120
KPX Tcaron w -120
KPX Tcaron y -120
KPX Tcaron yacute -120
KPX Tcaron ydieresis -60
KPX Tcommaaccent A -120
KPX Tcommaaccent Aacute -120
KPX Tcommaaccent Abreve -120
KPX Tcommaaccent Acircumflex -120
KPX Tcommaaccent Adieresis -120
KPX Tcommaaccent Agrave -120
KPX Tcommaaccent Amacron -120
KPX Tcommaaccent Aogonek -120
KPX Tcommaaccent Aring -120
KPX Tcommaaccent Atilde -120
KPX Tcommaaccent O -40
KPX Tcommaaccent Oacute -40
KPX Tcommaaccent Ocircumflex -40
KPX Tcommaaccent Odieresis -40
KPX Tcommaaccent Ograve -40
KPX Tcommaaccent Ohungarumlaut -40
KPX Tcommaaccent Omacron -40
KPX Tcommaaccent Oslash -40
KPX Tcommaaccent Otilde -40
KPX Tcommaaccent a -120
KPX Tcommaaccent aacute -120
KPX Tcommaaccent abreve -60
KPX Tcommaaccent acircumflex -120
KPX Tcommaaccent adieresis -120
KPX Tcommaaccent agrave -120
KPX Tcommaaccent amacron -60
KPX Tcommaaccent aogonek -120
KPX Tcommaaccent aring -120
KPX Tcommaaccent atilde -60
KPX Tcommaaccent colon -20
KPX Tcommaaccent comma -120
KPX Tcommaaccent e -120
KPX Tcommaaccent eacute -120
KPX Tcommaaccent ecaron -120
KPX Tcommaaccent ecircumflex -120
KPX Tcommaaccent edieresis -120
KPX Tcommaaccent edotaccent -120
KPX Tcommaaccent egrave -60
KPX Tcommaaccent emacron -60
KPX Tcommaaccent eogonek -120
KPX Tcommaaccent hyphen -140
KPX Tcommaaccent o -120
KPX Tcommaaccent oacute -120
KPX Tcommaaccent ocircumflex -120
KPX Tcommaaccent odieresis -120
KPX Tcommaaccent ograve -120
KPX Tcommaaccent ohungarumlaut -120
KPX Tcommaaccent omacron -60
KPX Tcommaaccent oslash -120
KPX Tcommaaccent otilde -60
KPX Tcommaaccent period -120
KPX Tcommaaccent r -120
KPX Tcommaaccent racute -120
KPX Tcommaaccent rcaron -120
KPX Tcommaaccent rcommaaccent -120
KPX Tcommaaccent semicolon -20
KPX Tcommaaccent u -120
KPX Tcommaaccent uacute -120
KPX Tcommaaccent ucircumflex -120
KPX Tcommaaccent udieresis -120
KPX Tcommaaccent ugrave -120
KPX Tcommaaccent uhungarumlaut -120
KPX Tcommaaccent umacron -60
KPX Tcommaaccent uogonek -120
KPX Tcommaaccent uring -120
KPX Tcommaaccent w -120
KPX Tcommaaccent y -120
KPX Tcommaaccent yacute -120
KPX Tcommaaccent ydieresis -60
KPX U A -40
KPX U Aacute -40
KPX U Abreve -40
KPX U Acircumflex -40
KPX U Adieresis -40
KPX U Agrave -40
KPX U Amacron -40
KPX U Aogonek -40
KPX U Aring -40
KPX U Atilde -40
KPX U comma -40
KPX U period -40
KPX Uacute A -40
KPX Uacute Aacute -40
KPX Uacute Abreve -40
KPX Uacute Acircumflex -40
KPX Uacute Adieresis -40
KPX Uacute Agrave -40
KPX Uacute Amacron -40
KPX Uacute Aogonek -40
KPX Uacute Aring -40
KPX Uacute Atilde -40
KPX Uacute comma -40
KPX Uacute period -40
KPX Ucircumflex A -40
KPX Ucircumflex Aacute -40
KPX Ucircumflex Abreve -40
KPX Ucircumflex Acircumflex -40
KPX Ucircumflex Adieresis -40
KPX Ucircumflex Agrave -40
KPX Ucircumflex Amacron -40
KPX Ucircumflex Aogonek -40
KPX Ucircumflex Aring -40
KPX Ucircumflex Atilde -40
KPX Ucircumflex comma -40
KPX Ucircumflex period -40
KPX Udieresis A -40
KPX Udieresis Aacute -40
KPX Udieresis Abreve -40
KPX Udieresis Acircumflex -40
KPX Udieresis Adieresis -40
KPX Udieresis Agrave -40
KPX Udieresis Amacron -40
KPX Udieresis Aogonek -40
KPX Udieresis Aring -40
KPX Udieresis Atilde -40
KPX Udieresis comma -40
KPX Udieresis period -40
KPX Ugrave A -40
KPX Ugrave Aacute -40
KPX Ugrave Abreve -40
KPX Ugrave Acircumflex -40
KPX Ugrave Adieresis -40
KPX Ugrave Agrave -40
KPX Ugrave Amacron -40
KPX Ugrave Aogonek -40
KPX Ugrave Aring -40
KPX Ugrave Atilde -40
KPX Ugrave comma -40
KPX Ugrave period -40
KPX Uhungarumlaut A -40
KPX Uhungarumlaut Aacute -40
KPX Uhungarumlaut Abreve -40
KPX Uhungarumlaut Acircumflex -40
KPX Uhungarumlaut Adieresis -40
KPX Uhungarumlaut Agrave -40
KPX Uhungarumlaut Amacron -40
KPX Uhungarumlaut Aogonek -40
KPX Uhungarumlaut Aring -40
KPX Uhungarumlaut Atilde -40
KPX Uhungarumlaut comma -40
KPX Uhungarumlaut period -40
KPX Umacron A -40
KPX Umacron Aacute -40
KPX Umacron Abreve -40
KPX Umacron Acircumflex -40
KPX Umacron Adieresis -40
KPX Umacron Agrave -40
KPX Umacron Amacron -40
KPX Umacron Aogonek -40
KPX Umacron Aring -40
KPX Umacron Atilde -40
KPX Umacron comma -40
KPX Umacron period -40
KPX Uogonek A -40
KPX Uogonek Aacute -40
KPX Uogonek Abreve -40
KPX Uogonek Acircumflex -40
KPX Uogonek Adieresis -40
KPX Uogonek Agrave -40
KPX Uogonek Amacron -40
KPX Uogonek Aogonek -40
KPX Uogonek Aring -40
KPX Uogonek Atilde -40
KPX Uogonek comma -40
KPX Uogonek period -40
KPX Uring A -40
KPX Uring Aacute -40
KPX Uring Abreve -40
KPX Uring Acircumflex -40
KPX Uring Adieresis -40
KPX Uring Agrave -40
KPX Uring Amacron -40
KPX Uring Aogonek -40
KPX Uring Aring -40
KPX Uring Atilde -40
KPX Uring comma -40
KPX Uring period -40
KPX V A -80
KPX V Aacute -80
KPX V Abreve -80
KPX V Acircumflex -80
KPX V Adieresis -80
KPX V Agrave -80
KPX V Amacron -80
KPX V Aogonek -80
KPX V Aring -80
KPX V Atilde -80
KPX V G -40
KPX V Gbreve -40
KPX V Gcommaaccent -40
KPX V O -40
KPX V Oacute -40
KPX V Ocircumflex -40
KPX V Odieresis -40
KPX V Ograve -40
KPX V Ohungarumlaut -40
KPX V Omacron -40
KPX V Oslash -40
KPX V Otilde -40
KPX V a -70
KPX V aacute -70
KPX V abreve -70
KPX V acircumflex -70
KPX V adieresis -70
KPX V agrave -70
KPX V amacron -70
KPX V aogonek -70
KPX V aring -70
KPX V atilde -70
KPX V colon -40
KPX V comma -125
KPX V e -80
KPX V eacute -80
KPX V ecaron -80
KPX V ecircumflex -80
KPX V edieresis -80
KPX V edotaccent -80
KPX V egrave -80
KPX V emacron -80
KPX V eogonek -80
KPX V hyphen -80
KPX V o -80
KPX V oacute -80
KPX V ocircumflex -80
KPX V odieresis -80
KPX V ograve -80
KPX V ohungarumlaut -80
KPX V omacron -80
KPX V oslash -80
KPX V otilde -80
KPX V period -125
KPX V semicolon -40
KPX V u -70
KPX V uacute -70
KPX V ucircumflex -70
KPX V udieresis -70
KPX V ugrave -70
KPX V uhungarumlaut -70
KPX V umacron -70
KPX V uogonek -70
KPX V uring -70
KPX W A -50
KPX W Aacute -50
KPX W Abreve -50
KPX W Acircumflex -50
KPX W Adieresis -50
KPX W Agrave -50
KPX W Amacron -50
KPX W Aogonek -50
KPX W Aring -50
KPX W Atilde -50
KPX W O -20
KPX W Oacute -20
KPX W Ocircumflex -20
KPX W Odieresis -20
KPX W Ograve -20
KPX W Ohungarumlaut -20
KPX W Omacron -20
KPX W Oslash -20
KPX W Otilde -20
KPX W a -40
KPX W aacute -40
KPX W abreve -40
KPX W acircumflex -40
KPX W adieresis -40
KPX W agrave -40
KPX W amacron -40
KPX W aogonek -40
KPX W aring -40
KPX W atilde -40
KPX W comma -80
KPX W e -30
KPX W eacute -30
KPX W ecaron -30
KPX W ecircumflex -30
KPX W edieresis -30
KPX W edotaccent -30
KPX W egrave -30
KPX W emacron -30
KPX W eogonek -30
KPX W hyphen -40
KPX W o -30
KPX W oacute -30
KPX W ocircumflex -30
KPX W odieresis -30
KPX W ograve -30
KPX W ohungarumlaut -30
KPX W omacron -30
KPX W oslash -30
KPX W otilde -30
KPX W period -80
KPX W u -30
KPX W uacute -30
KPX W ucircumflex -30
KPX W udieresis -30
KPX W ugrave -30
KPX W uhungarumlaut -30
KPX W umacron -30
KPX W uogonek -30
KPX W uring -30
KPX W y -20
KPX W yacute -20
KPX W ydieresis -20
KPX Y A -110
KPX Y Aacute -110
KPX Y Abreve -110
KPX Y Acircumflex -110
KPX Y Adieresis -110
KPX Y Agrave -110
KPX Y Amacron -110
KPX Y Aogonek -110
KPX Y Aring -110
KPX Y Atilde -110
KPX Y O -85
KPX Y Oacute -85
KPX Y Ocircumflex -85
KPX Y Odieresis -85
KPX Y Ograve -85
KPX Y Ohungarumlaut -85
KPX Y Omacron -85
KPX Y Oslash -85
KPX Y Otilde -85
KPX Y a -140
KPX Y aacute -140
KPX Y abreve -70
KPX Y acircumflex -140
KPX Y adieresis -140
KPX Y agrave -140
KPX Y amacron -70
KPX Y aogonek -140
KPX Y aring -140
KPX Y atilde -140
KPX Y colon -60
KPX Y comma -140
KPX Y e -140
KPX Y eacute -140
KPX Y ecaron -140
KPX Y ecircumflex -140
KPX Y edieresis -140
KPX Y edotaccent -140
KPX Y egrave -140
KPX Y emacron -70
KPX Y eogonek -140
KPX Y hyphen -140
KPX Y i -20
KPX Y iacute -20
KPX Y iogonek -20
KPX Y o -140
KPX Y oacute -140
KPX Y ocircumflex -140
KPX Y odieresis -140
KPX Y ograve -140
KPX Y ohungarumlaut -140
KPX Y omacron -140
KPX Y oslash -140
KPX Y otilde -140
KPX Y period -140
KPX Y semicolon -60
KPX Y u -110
KPX Y uacute -110
KPX Y ucircumflex -110
KPX Y udieresis -110
KPX Y ugrave -110
KPX Y uhungarumlaut -110
KPX Y umacron -110
KPX Y uogonek -110
KPX Y uring -110
KPX Yacute A -110
KPX Yacute Aacute -110
KPX Yacute Abreve -110
KPX Yacute Acircumflex -110
KPX Yacute Adieresis -110
KPX Yacute Agrave -110
KPX Yacute Amacron -110
KPX Yacute Aogonek -110
KPX Yacute Aring -110
KPX Yacute Atilde -110
KPX Yacute O -85
KPX Yacute Oacute -85
KPX Yacute Ocircumflex -85
KPX Yacute Odieresis -85
KPX Yacute Ograve -85
KPX Yacute Ohungarumlaut -85
KPX Yacute Omacron -85
KPX Yacute Oslash -85
KPX Yacute Otilde -85
KPX Yacute a -140
KPX Yacute aacute -140
KPX Yacute abreve -70
KPX Yacute acircumflex -140
KPX Yacute adieresis -140
KPX Yacute agrave -140
KPX Yacute amacron -70
KPX Yacute aogonek -140
KPX Yacute aring -140
KPX Yacute atilde -70
KPX Yacute colon -60
KPX Yacute comma -140
KPX Yacute e -140
KPX Yacute eacute -140
KPX Yacute ecaron -140
KPX Yacute ecircumflex -140
KPX Yacute edieresis -140
KPX Yacute edotaccent -140
KPX Yacute egrave -140
KPX Yacute emacron -70
KPX Yacute eogonek -140
KPX Yacute hyphen -140
KPX Yacute i -20
KPX Yacute iacute -20
KPX Yacute iogonek -20
KPX Yacute o -140
KPX Yacute oacute -140
KPX Yacute ocircumflex -140
KPX Yacute odieresis -140
KPX Yacute ograve -140
KPX Yacute ohungarumlaut -140
KPX Yacute omacron -70
KPX Yacute oslash -140
KPX Yacute otilde -140
KPX Yacute period -140
KPX Yacute semicolon -60
KPX Yacute u -110
KPX Yacute uacute -110
KPX Yacute ucircumflex -110
KPX Yacute udieresis -110
KPX Yacute ugrave -110
KPX Yacute uhungarumlaut -110
KPX Yacute umacron -110
KPX Yacute uogonek -110
KPX Yacute uring -110
KPX Ydieresis A -110
KPX Ydieresis Aacute -110
KPX Ydieresis Abreve -110
KPX Ydieresis Acircumflex -110
KPX Ydieresis Adieresis -110
KPX Ydieresis Agrave -110
KPX Ydieresis Amacron -110
KPX Ydieresis Aogonek -110
KPX Ydieresis Aring -110
KPX Ydieresis Atilde -110
KPX Ydieresis O -85
KPX Ydieresis Oacute -85
KPX Ydieresis Ocircumflex -85
KPX Ydieresis Odieresis -85
KPX Ydieresis Ograve -85
KPX Ydieresis Ohungarumlaut -85
KPX Ydieresis Omacron -85
KPX Ydieresis Oslash -85
KPX Ydieresis Otilde -85
KPX Ydieresis a -140
KPX Ydieresis aacute -140
KPX Ydieresis abreve -70
KPX Ydieresis acircumflex -140
KPX Ydieresis adieresis -140
KPX Ydieresis agrave -140
KPX Ydieresis amacron -70
KPX Ydieresis aogonek -140
KPX Ydieresis aring -140
KPX Ydieresis atilde -70
KPX Ydieresis colon -60
KPX Ydieresis comma -140
KPX Ydieresis e -140
KPX Ydieresis eacute -140
KPX Ydieresis ecaron -140
KPX Ydieresis ecircumflex -140
KPX Ydieresis edieresis -140
KPX Ydieresis edotaccent -140
KPX Ydieresis egrave -140
KPX Ydieresis emacron -70
KPX Ydieresis eogonek -140
KPX Ydieresis hyphen -140
KPX Ydieresis i -20
KPX Ydieresis iacute -20
KPX Ydieresis iogonek -20
KPX Ydieresis o -140
KPX Ydieresis oacute -140
KPX Ydieresis ocircumflex -140
KPX Ydieresis odieresis -140
KPX Ydieresis ograve -140
KPX Ydieresis ohungarumlaut -140
KPX Ydieresis omacron -140
KPX Ydieresis oslash -140
KPX Ydieresis otilde -140
KPX Ydieresis period -140
KPX Ydieresis semicolon -60
KPX Ydieresis u -110
KPX Ydieresis uacute -110
KPX Ydieresis ucircumflex -110
KPX Ydieresis udieresis -110
KPX Ydieresis ugrave -110
KPX Ydieresis uhungarumlaut -110
KPX Ydieresis umacron -110
KPX Ydieresis uogonek -110
KPX Ydieresis uring -110
KPX a v -20
KPX a w -20
KPX a y -30
KPX a yacute -30
KPX a ydieresis -30
KPX aacute v -20
KPX aacute w -20
KPX aacute y -30
KPX aacute yacute -30
KPX aacute ydieresis -30
KPX abreve v -20
KPX abreve w -20
KPX abreve y -30
KPX abreve yacute -30
KPX abreve ydieresis -30
KPX acircumflex v -20
KPX acircumflex w -20
KPX acircumflex y -30
KPX acircumflex yacute -30
KPX acircumflex ydieresis -30
KPX adieresis v -20
KPX adieresis w -20
KPX adieresis y -30
KPX adieresis yacute -30
KPX adieresis ydieresis -30
KPX agrave v -20
KPX agrave w -20
KPX agrave y -30
KPX agrave yacute -30
KPX agrave ydieresis -30
KPX amacron v -20
KPX amacron w -20
KPX amacron y -30
KPX amacron yacute -30
KPX amacron ydieresis -30
KPX aogonek v -20
KPX aogonek w -20
KPX aogonek y -30
KPX aogonek yacute -30
KPX aogonek ydieresis -30
KPX aring v -20
KPX aring w -20
KPX aring y -30
KPX aring yacute -30
KPX aring ydieresis -30
KPX atilde v -20
KPX atilde w -20
KPX atilde y -30
KPX atilde yacute -30
KPX atilde ydieresis -30
KPX b b -10
KPX b comma -40
KPX b l -20
KPX b lacute -20
KPX b lcommaaccent -20
KPX b lslash -20
KPX b period -40
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX b v -20
KPX b y -20
KPX b yacute -20
KPX b ydieresis -20
KPX c comma -15
KPX c k -20
KPX c kcommaaccent -20
KPX cacute comma -15
KPX cacute k -20
KPX cacute kcommaaccent -20
KPX ccaron comma -15
KPX ccaron k -20
KPX ccaron kcommaaccent -20
KPX ccedilla comma -15
KPX ccedilla k -20
KPX ccedilla kcommaaccent -20
KPX colon space -50
KPX comma quotedblright -100
KPX comma quoteright -100
KPX e comma -15
KPX e period -15
KPX e v -30
KPX e w -20
KPX e x -30
KPX e y -20
KPX e yacute -20
KPX e ydieresis -20
KPX eacute comma -15
KPX eacute period -15
KPX eacute v -30
KPX eacute w -20
KPX eacute x -30
KPX eacute y -20
KPX eacute yacute -20
KPX eacute ydieresis -20
KPX ecaron comma -15
KPX ecaron period -15
KPX ecaron v -30
KPX ecaron w -20
KPX ecaron x -30
KPX ecaron y -20
KPX ecaron yacute -20
KPX ecaron ydieresis -20
KPX ecircumflex comma -15
KPX ecircumflex period -15
KPX ecircumflex v -30
KPX ecircumflex w -20
KPX ecircumflex x -30
KPX ecircumflex y -20
KPX ecircumflex yacute -20
KPX ecircumflex ydieresis -20
KPX edieresis comma -15
KPX edieresis period -15
KPX edieresis v -30
KPX edieresis w -20
KPX edieresis x -30
KPX edieresis y -20
KPX edieresis yacute -20
KPX edieresis ydieresis -20
KPX edotaccent comma -15
KPX edotaccent period -15
KPX edotaccent v -30
KPX edotaccent w -20
KPX edotaccent x -30
KPX edotaccent y -20
KPX edotaccent yacute -20
KPX edotaccent ydieresis -20
KPX egrave comma -15
KPX egrave period -15
KPX egrave v -30
KPX egrave w -20
KPX egrave x -30
KPX egrave y -20
KPX egrave yacute -20
KPX egrave ydieresis -20
KPX emacron comma -15
KPX emacron period -15
KPX emacron v -30
KPX emacron w -20
KPX emacron x -30
KPX emacron y -20
KPX emacron yacute -20
KPX emacron ydieresis -20
KPX eogonek comma -15
KPX eogonek period -15
KPX eogonek v -30
KPX eogonek w -20
KPX eogonek x -30
KPX eogonek y -20
KPX eogonek yacute -20
KPX eogonek ydieresis -20
KPX f a -30
KPX f aacute -30
KPX f abreve -30
KPX f acircumflex -30
KPX f adieresis -30
KPX f agrave -30
KPX f amacron -30
KPX f aogonek -30
KPX f aring -30
KPX f atilde -30
KPX f comma -30
KPX f dotlessi -28
KPX f e -30
KPX f eacute -30
KPX f ecaron -30
KPX f ecircumflex -30
KPX f edieresis -30
KPX f edotaccent -30
KPX f egrave -30
KPX f emacron -30
KPX f eogonek -30
KPX f o -30
KPX f oacute -30
KPX f ocircumflex -30
KPX f odieresis -30
KPX f ograve -30
KPX f ohungarumlaut -30
KPX f omacron -30
KPX f oslash -30
KPX f otilde -30
KPX f period -30
KPX f quotedblright 60
KPX f quoteright 50
KPX g r -10
KPX g racute -10
KPX g rcaron -10
KPX g rcommaaccent -10
KPX gbreve r -10
KPX gbreve racute -10
KPX gbreve rcaron -10
KPX gbreve rcommaaccent -10
KPX gcommaaccent r -10
KPX gcommaaccent racute -10
KPX gcommaaccent rcaron -10
KPX gcommaaccent rcommaaccent -10
KPX h y -30
KPX h yacute -30
KPX h ydieresis -30
KPX k e -20
KPX k eacute -20
KPX k ecaron -20
KPX k ecircumflex -20
KPX k edieresis -20
KPX k edotaccent -20
KPX k egrave -20
KPX k emacron -20
KPX k eogonek -20
KPX k o -20
KPX k oacute -20
KPX k ocircumflex -20
KPX k odieresis -20
KPX k ograve -20
KPX k ohungarumlaut -20
KPX k omacron -20
KPX k oslash -20
KPX k otilde -20
KPX kcommaaccent e -20
KPX kcommaaccent eacute -20
KPX kcommaaccent ecaron -20
KPX kcommaaccent ecircumflex -20
KPX kcommaaccent edieresis -20
KPX kcommaaccent edotaccent -20
KPX kcommaaccent egrave -20
KPX kcommaaccent emacron -20
KPX kcommaaccent eogonek -20
KPX kcommaaccent o -20
KPX kcommaaccent oacute -20
KPX kcommaaccent ocircumflex -20
KPX kcommaaccent odieresis -20
KPX kcommaaccent ograve -20
KPX kcommaaccent ohungarumlaut -20
KPX kcommaaccent omacron -20
KPX kcommaaccent oslash -20
KPX kcommaaccent otilde -20
KPX m u -10
KPX m uacute -10
KPX m ucircumflex -10
KPX m udieresis -10
KPX m ugrave -10
KPX m uhungarumlaut -10
KPX m umacron -10
KPX m uogonek -10
KPX m uring -10
KPX m y -15
KPX m yacute -15
KPX m ydieresis -15
KPX n u -10
KPX n uacute -10
KPX n ucircumflex -10
KPX n udieresis -10
KPX n ugrave -10
KPX n uhungarumlaut -10
KPX n umacron -10
KPX n uogonek -10
KPX n uring -10
KPX n v -20
KPX n y -15
KPX n yacute -15
KPX n ydieresis -15
KPX nacute u -10
KPX nacute uacute -10
KPX nacute ucircumflex -10
KPX nacute udieresis -10
KPX nacute ugrave -10
KPX nacute uhungarumlaut -10
KPX nacute umacron -10
KPX nacute uogonek -10
KPX nacute uring -10
KPX nacute v -20
KPX nacute y -15
KPX nacute yacute -15
KPX nacute ydieresis -15
KPX ncaron u -10
KPX ncaron uacute -10
KPX ncaron ucircumflex -10
KPX ncaron udieresis -10
KPX ncaron ugrave -10
KPX ncaron uhungarumlaut -10
KPX ncaron umacron -10
KPX ncaron uogonek -10
KPX ncaron uring -10
KPX ncaron v -20
KPX ncaron y -15
KPX ncaron yacute -15
KPX ncaron ydieresis -15
KPX ncommaaccent u -10
KPX ncommaaccent uacute -10
KPX ncommaaccent ucircumflex -10
KPX ncommaaccent udieresis -10
KPX ncommaaccent ugrave -10
KPX ncommaaccent uhungarumlaut -10
KPX ncommaaccent umacron -10
KPX ncommaaccent uogonek -10
KPX ncommaaccent uring -10
KPX ncommaaccent v -20
KPX ncommaaccent y -15
KPX ncommaaccent yacute -15
KPX ncommaaccent ydieresis -15
KPX ntilde u -10
KPX ntilde uacute -10
KPX ntilde ucircumflex -10
KPX ntilde udieresis -10
KPX ntilde ugrave -10
KPX ntilde uhungarumlaut -10
KPX ntilde umacron -10
KPX ntilde uogonek -10
KPX ntilde uring -10
KPX ntilde v -20
KPX ntilde y -15
KPX ntilde yacute -15
KPX ntilde ydieresis -15
KPX o comma -40
KPX o period -40
KPX o v -15
KPX o w -15
KPX o x -30
KPX o y -30
KPX o yacute -30
KPX o ydieresis -30
KPX oacute comma -40
KPX oacute period -40
KPX oacute v -15
KPX oacute w -15
KPX oacute x -30
KPX oacute y -30
KPX oacute yacute -30
KPX oacute ydieresis -30
KPX ocircumflex comma -40
KPX ocircumflex period -40
KPX ocircumflex v -15
KPX ocircumflex w -15
KPX ocircumflex x -30
KPX ocircumflex y -30
KPX ocircumflex yacute -30
KPX ocircumflex ydieresis -30
KPX odieresis comma -40
KPX odieresis period -40
KPX odieresis v -15
KPX odieresis w -15
KPX odieresis x -30
KPX odieresis y -30
KPX odieresis yacute -30
KPX odieresis ydieresis -30
KPX ograve comma -40
KPX ograve period -40
KPX ograve v -15
KPX ograve w -15
KPX ograve x -30
KPX ograve y -30
KPX ograve yacute -30
KPX ograve ydieresis -30
KPX ohungarumlaut comma -40
KPX ohungarumlaut period -40
KPX ohungarumlaut v -15
KPX ohungarumlaut w -15
KPX ohungarumlaut x -30
KPX ohungarumlaut y -30
KPX ohungarumlaut yacute -30
KPX ohungarumlaut ydieresis -30
KPX omacron comma -40
KPX omacron period -40
KPX omacron v -15
KPX omacron w -15
KPX omacron x -30
KPX omacron y -30
KPX omacron yacute -30
KPX omacron ydieresis -30
KPX oslash a -55
KPX oslash aacute -55
KPX oslash abreve -55
KPX oslash acircumflex -55
KPX oslash adieresis -55
KPX oslash agrave -55
KPX oslash amacron -55
KPX oslash aogonek -55
KPX oslash aring -55
KPX oslash atilde -55
KPX oslash b -55
KPX oslash c -55
KPX oslash cacute -55
KPX oslash ccaron -55
KPX oslash ccedilla -55
KPX oslash comma -95
KPX oslash d -55
KPX oslash dcroat -55
KPX oslash e -55
KPX oslash eacute -55
KPX oslash ecaron -55
KPX oslash ecircumflex -55
KPX oslash edieresis -55
KPX oslash edotaccent -55
KPX oslash egrave -55
KPX oslash emacron -55
KPX oslash eogonek -55
KPX oslash f -55
KPX oslash g -55
KPX oslash gbreve -55
KPX oslash gcommaaccent -55
KPX oslash h -55
KPX oslash i -55
KPX oslash iacute -55
KPX oslash icircumflex -55
KPX oslash idieresis -55
KPX oslash igrave -55
KPX oslash imacron -55
KPX oslash iogonek -55
KPX oslash j -55
KPX oslash k -55
KPX oslash kcommaaccent -55
KPX oslash l -55
KPX oslash lacute -55
KPX oslash lcommaaccent -55
KPX oslash lslash -55
KPX oslash m -55
KPX oslash n -55
KPX oslash nacute -55
KPX oslash ncaron -55
KPX oslash ncommaaccent -55
KPX oslash ntilde -55
KPX oslash o -55
KPX oslash oacute -55
KPX oslash ocircumflex -55
KPX oslash odieresis -55
KPX oslash ograve -55
KPX oslash ohungarumlaut -55
KPX oslash omacron -55
KPX oslash oslash -55
KPX oslash otilde -55
KPX oslash p -55
KPX oslash period -95
KPX oslash q -55
KPX oslash r -55
KPX oslash racute -55
KPX oslash rcaron -55
KPX oslash rcommaaccent -55
KPX oslash s -55
KPX oslash sacute -55
KPX oslash scaron -55
KPX oslash scedilla -55
KPX oslash scommaaccent -55
KPX oslash t -55
KPX oslash tcommaaccent -55
KPX oslash u -55
KPX oslash uacute -55
KPX oslash ucircumflex -55
KPX oslash udieresis -55
KPX oslash ugrave -55
KPX oslash uhungarumlaut -55
KPX oslash umacron -55
KPX oslash uogonek -55
KPX oslash uring -55
KPX oslash v -70
KPX oslash w -70
KPX oslash x -85
KPX oslash y -70
KPX oslash yacute -70
KPX oslash ydieresis -70
KPX oslash z -55
KPX oslash zacute -55
KPX oslash zcaron -55
KPX oslash zdotaccent -55
KPX otilde comma -40
KPX otilde period -40
KPX otilde v -15
KPX otilde w -15
KPX otilde x -30
KPX otilde y -30
KPX otilde yacute -30
KPX otilde ydieresis -30
KPX p comma -35
KPX p period -35
KPX p y -30
KPX p yacute -30
KPX p ydieresis -30
KPX period quotedblright -100
KPX period quoteright -100
KPX period space -60
KPX quotedblright space -40
KPX quoteleft quoteleft -57
KPX quoteright d -50
KPX quoteright dcroat -50
KPX quoteright quoteright -57
KPX quoteright r -50
KPX quoteright racute -50
KPX quoteright rcaron -50
KPX quoteright rcommaaccent -50
KPX quoteright s -50
KPX quoteright sacute -50
KPX quoteright scaron -50
KPX quoteright scedilla -50
KPX quoteright scommaaccent -50
KPX quoteright space -70
KPX r a -10
KPX r aacute -10
KPX r abreve -10
KPX r acircumflex -10
KPX r adieresis -10
KPX r agrave -10
KPX r amacron -10
KPX r aogonek -10
KPX r aring -10
KPX r atilde -10
KPX r colon 30
KPX r comma -50
KPX r i 15
KPX r iacute 15
KPX r icircumflex 15
KPX r idieresis 15
KPX r igrave 15
KPX r imacron 15
KPX r iogonek 15
KPX r k 15
KPX r kcommaaccent 15
KPX r l 15
KPX r lacute 15
KPX r lcommaaccent 15
KPX r lslash 15
KPX r m 25
KPX r n 25
KPX r nacute 25
KPX r ncaron 25
KPX r ncommaaccent 25
KPX r ntilde 25
KPX r p 30
KPX r period -50
KPX r semicolon 30
KPX r t 40
KPX r tcommaaccent 40
KPX r u 15
KPX r uacute 15
KPX r ucircumflex 15
KPX r udieresis 15
KPX r ugrave 15
KPX r uhungarumlaut 15
KPX r umacron 15
KPX r uogonek 15
KPX r uring 15
KPX r v 30
KPX r y 30
KPX r yacute 30
KPX r ydieresis 30
KPX racute a -10
KPX racute aacute -10
KPX racute abreve -10
KPX racute acircumflex -10
KPX racute adieresis -10
KPX racute agrave -10
KPX racute amacron -10
KPX racute aogonek -10
KPX racute aring -10
KPX racute atilde -10
KPX racute colon 30
KPX racute comma -50
KPX racute i 15
KPX racute iacute 15
KPX racute icircumflex 15
KPX racute idieresis 15
KPX racute igrave 15
KPX racute imacron 15
KPX racute iogonek 15
KPX racute k 15
KPX racute kcommaaccent 15
KPX racute l 15
KPX racute lacute 15
KPX racute lcommaaccent 15
KPX racute lslash 15
KPX racute m 25
KPX racute n 25
KPX racute nacute 25
KPX racute ncaron 25
KPX racute ncommaaccent 25
KPX racute ntilde 25
KPX racute p 30
KPX racute period -50
KPX racute semicolon 30
KPX racute t 40
KPX racute tcommaaccent 40
KPX racute u 15
KPX racute uacute 15
KPX racute ucircumflex 15
KPX racute udieresis 15
KPX racute ugrave 15
KPX racute uhungarumlaut 15
KPX racute umacron 15
KPX racute uogonek 15
KPX racute uring 15
KPX racute v 30
KPX racute y 30
KPX racute yacute 30
KPX racute ydieresis 30
KPX rcaron a -10
KPX rcaron aacute -10
KPX rcaron abreve -10
KPX rcaron acircumflex -10
KPX rcaron adieresis -10
KPX rcaron agrave -10
KPX rcaron amacron -10
KPX rcaron aogonek -10
KPX rcaron aring -10
KPX rcaron atilde -10
KPX rcaron colon 30
KPX rcaron comma -50
KPX rcaron i 15
KPX rcaron iacute 15
KPX rcaron icircumflex 15
KPX rcaron idieresis 15
KPX rcaron igrave 15
KPX rcaron imacron 15
KPX rcaron iogonek 15
KPX rcaron k 15
KPX rcaron kcommaaccent 15
KPX rcaron l 15
KPX rcaron lacute 15
KPX rcaron lcommaaccent 15
KPX rcaron lslash 15
KPX rcaron m 25
KPX rcaron n 25
KPX rcaron nacute 25
KPX rcaron ncaron 25
KPX rcaron ncommaaccent 25
KPX rcaron ntilde 25
KPX rcaron p 30
KPX rcaron period -50
KPX rcaron semicolon 30
KPX rcaron t 40
KPX rcaron tcommaaccent 40
KPX rcaron u 15
KPX rcaron uacute 15
KPX rcaron ucircumflex 15
KPX rcaron udieresis 15
KPX rcaron ugrave 15
KPX rcaron uhungarumlaut 15
KPX rcaron umacron 15
KPX rcaron uogonek 15
KPX rcaron uring 15
KPX rcaron v 30
KPX rcaron y 30
KPX rcaron yacute 30
KPX rcaron ydieresis 30
KPX rcommaaccent a -10
KPX rcommaaccent aacute -10
KPX rcommaaccent abreve -10
KPX rcommaaccent acircumflex -10
KPX rcommaaccent adieresis -10
KPX rcommaaccent agrave -10
KPX rcommaaccent amacron -10
KPX rcommaaccent aogonek -10
KPX rcommaaccent aring -10
KPX rcommaaccent atilde -10
KPX rcommaaccent colon 30
KPX rcommaaccent comma -50
KPX rcommaaccent i 15
KPX rcommaaccent iacute 15
KPX rcommaaccent icircumflex 15
KPX rcommaaccent idieresis 15
KPX rcommaaccent igrave 15
KPX rcommaaccent imacron 15
KPX rcommaaccent iogonek 15
KPX rcommaaccent k 15
KPX rcommaaccent kcommaaccent 15
KPX rcommaaccent l 15
KPX rcommaaccent lacute 15
KPX rcommaaccent lcommaaccent 15
KPX rcommaaccent lslash 15
KPX rcommaaccent m 25
KPX rcommaaccent n 25
KPX rcommaaccent nacute 25
KPX rcommaaccent ncaron 25
KPX rcommaaccent ncommaaccent 25
KPX rcommaaccent ntilde 25
KPX rcommaaccent p 30
KPX rcommaaccent period -50
KPX rcommaaccent semicolon 30
KPX rcommaaccent t 40
KPX rcommaaccent tcommaaccent 40
KPX rcommaaccent u 15
KPX rcommaaccent uacute 15
KPX rcommaaccent ucircumflex 15
KPX rcommaaccent udieresis 15
KPX rcommaaccent ugrave 15
KPX rcommaaccent uhungarumlaut 15
KPX rcommaaccent umacron 15
KPX rcommaaccent uogonek 15
KPX rcommaaccent uring 15
KPX rcommaaccent v 30
KPX rcommaaccent y 30
KPX rcommaaccent yacute 30
KPX rcommaaccent ydieresis 30
KPX s comma -15
KPX s period -15
KPX s w -30
KPX sacute comma -15
KPX sacute period -15
KPX sacute w -30
KPX scaron comma -15
KPX scaron period -15
KPX scaron w -30
KPX scedilla comma -15
KPX scedilla period -15
KPX scedilla w -30
KPX scommaaccent comma -15
KPX scommaaccent period -15
KPX scommaaccent w -30
KPX semicolon space -50
KPX space T -50
KPX space Tcaron -50
KPX space Tcommaaccent -50
KPX space V -50
KPX space W -40
KPX space Y -90
KPX space Yacute -90
KPX space Ydieresis -90
KPX space quotedblleft -30
KPX space quoteleft -60
KPX v a -25
KPX v aacute -25
KPX v abreve -25
KPX v acircumflex -25
KPX v adieresis -25
KPX v agrave -25
KPX v amacron -25
KPX v aogonek -25
KPX v aring -25
KPX v atilde -25
KPX v comma -80
KPX v e -25
KPX v eacute -25
KPX v ecaron -25
KPX v ecircumflex -25
KPX v edieresis -25
KPX v edotaccent -25
KPX v egrave -25
KPX v emacron -25
KPX v eogonek -25
KPX v o -25
KPX v oacute -25
KPX v ocircumflex -25
KPX v odieresis -25
KPX v ograve -25
KPX v ohungarumlaut -25
KPX v omacron -25
KPX v oslash -25
KPX v otilde -25
KPX v period -80
KPX w a -15
KPX w aacute -15
KPX w abreve -15
KPX w acircumflex -15
KPX w adieresis -15
KPX w agrave -15
KPX w amacron -15
KPX w aogonek -15
KPX w aring -15
KPX w atilde -15
KPX w comma -60
KPX w e -10
KPX w eacute -10
KPX w ecaron -10
KPX w ecircumflex -10
KPX w edieresis -10
KPX w edotaccent -10
KPX w egrave -10
KPX w emacron -10
KPX w eogonek -10
KPX w o -10
KPX w oacute -10
KPX w ocircumflex -10
KPX w odieresis -10
KPX w ograve -10
KPX w ohungarumlaut -10
KPX w omacron -10
KPX w oslash -10
KPX w otilde -10
KPX w period -60
KPX x e -30
KPX x eacute -30
KPX x ecaron -30
KPX x ecircumflex -30
KPX x edieresis -30
KPX x edotaccent -30
KPX x egrave -30
KPX x emacron -30
KPX x eogonek -30
KPX y a -20
KPX y aacute -20
KPX y abreve -20
KPX y acircumflex -20
KPX y adieresis -20
KPX y agrave -20
KPX y amacron -20
KPX y aogonek -20
KPX y aring -20
KPX y atilde -20
KPX y comma -100
KPX y e -20
KPX y eacute -20
KPX y ecaron -20
KPX y ecircumflex -20
KPX y edieresis -20
KPX y edotaccent -20
KPX y egrave -20
KPX y emacron -20
KPX y eogonek -20
KPX y o -20
KPX y oacute -20
KPX y ocircumflex -20
KPX y odieresis -20
KPX y ograve -20
KPX y ohungarumlaut -20
KPX y omacron -20
KPX y oslash -20
KPX y otilde -20
KPX y period -100
KPX yacute a -20
KPX yacute aacute -20
KPX yacute abreve -20
KPX yacute acircumflex -20
KPX yacute adieresis -20
KPX yacute agrave -20
KPX yacute amacron -20
KPX yacute aogonek -20
KPX yacute aring -20
KPX yacute atilde -20
KPX yacute comma -100
KPX yacute e -20
KPX yacute eacute -20
KPX yacute ecaron -20
KPX yacute ecircumflex -20
KPX yacute edieresis -20
KPX yacute edotaccent -20
KPX yacute egrave -20
KPX yacute emacron -20
KPX yacute eogonek -20
KPX yacute o -20
KPX yacute oacute -20
KPX yacute ocircumflex -20
KPX yacute odieresis -20
KPX yacute ograve -20
KPX yacute ohungarumlaut -20
KPX yacute omacron -20
KPX yacute oslash -20
KPX yacute otilde -20
KPX yacute period -100
KPX ydieresis a -20
KPX ydieresis aacute -20
KPX ydieresis abreve -20
KPX ydieresis acircumflex -20
KPX ydieresis adieresis -20
KPX ydieresis agrave -20
KPX ydieresis amacron -20
KPX ydieresis aogonek -20
KPX ydieresis aring -20
KPX ydieresis atilde -20
KPX ydieresis comma -100
KPX ydieresis e -20
KPX ydieresis eacute -20
KPX ydieresis ecaron -20
KPX ydieresis ecircumflex -20
KPX ydieresis edieresis -20
KPX ydieresis edotaccent -20
KPX ydieresis egrave -20
KPX ydieresis emacron -20
KPX ydieresis eogonek -20
KPX ydieresis o -20
KPX ydieresis oacute -20
KPX ydieresis ocircumflex -20
KPX ydieresis odieresis -20
KPX ydieresis ograve -20
KPX ydieresis ohungarumlaut -20
KPX ydieresis omacron -20
KPX ydieresis oslash -20
KPX ydieresis otilde -20
KPX ydieresis period -100
KPX z e -15
KPX z eacute -15
KPX z ecaron -15
KPX z ecircumflex -15
KPX z edieresis -15
KPX z edotaccent -15
KPX z egrave -15
KPX z emacron -15
KPX z eogonek -15
KPX z o -15
KPX z oacute -15
KPX z ocircumflex -15
KPX z odieresis -15
KPX z ograve -15
KPX z ohungarumlaut -15
KPX z omacron -15
KPX z oslash -15
KPX z otilde -15
KPX zacute e -15
KPX zacute eacute -15
KPX zacute ecaron -15
KPX zacute ecircumflex -15
KPX zacute edieresis -15
KPX zacute edotaccent -15
KPX zacute egrave -15
KPX zacute emacron -15
KPX zacute eogonek -15
KPX zacute o -15
KPX zacute oacute -15
KPX zacute ocircumflex -15
KPX zacute odieresis -15
KPX zacute ograve -15
KPX zacute ohungarumlaut -15
KPX zacute omacron -15
KPX zacute oslash -15
KPX zacute otilde -15
KPX zcaron e -15
KPX zcaron eacute -15
KPX zcaron ecaron -15
KPX zcaron ecircumflex -15
KPX zcaron edieresis -15
KPX zcaron edotaccent -15
KPX zcaron egrave -15
KPX zcaron emacron -15
KPX zcaron eogonek -15
KPX zcaron o -15
KPX zcaron oacute -15
KPX zcaron ocircumflex -15
KPX zcaron odieresis -15
KPX zcaron ograve -15
KPX zcaron ohungarumlaut -15
KPX zcaron omacron -15
KPX zcaron oslash -15
KPX zcaron otilde -15
KPX zdotaccent e -15
KPX zdotaccent eacute -15
KPX zdotaccent ecaron -15
KPX zdotaccent ecircumflex -15
KPX zdotaccent edieresis -15
KPX zdotaccent edotaccent -15
KPX zdotaccent egrave -15
KPX zdotaccent emacron -15
KPX zdotaccent eogonek -15
KPX zdotaccent o -15
KPX zdotaccent oacute -15
KPX zdotaccent ocircumflex -15
KPX zdotaccent odieresis -15
KPX zdotaccent ograve -15
KPX zdotaccent ohungarumlaut -15
KPX zdotaccent omacron -15
KPX zdotaccent oslash -15
KPX zdotaccent otilde -15
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Helvetica.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:38:23 1997
Comment UniqueID 43054
Comment VMusage 37069 48094
FontName Helvetica
FullName Helvetica
FamilyName Helvetica
Weight Medium
ItalicAngle 0
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -166 -225 1000 931
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 718
XHeight 523
Ascender 718
Descender -207
StdHW 76
StdVW 88
StartCharMetrics 315
C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ;
C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ;
C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ;
C 36 ; WX 556 ; N dollar ; B 32 -115 520 775 ;
C 37 ; WX 889 ; N percent ; B 39 -19 850 703 ;
C 38 ; WX 667 ; N ampersand ; B 44 -15 645 718 ;
C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
C 40 ; WX 333 ; N parenleft ; B 68 -207 299 733 ;
C 41 ; WX 333 ; N parenright ; B 34 -207 265 733 ;
C 42 ; WX 389 ; N asterisk ; B 39 431 349 718 ;
C 43 ; WX 584 ; N plus ; B 39 0 545 505 ;
C 44 ; WX 278 ; N comma ; B 87 -147 191 106 ;
C 45 ; WX 333 ; N hyphen ; B 44 232 289 322 ;
C 46 ; WX 278 ; N period ; B 87 0 191 106 ;
C 47 ; WX 278 ; N slash ; B -17 -19 295 737 ;
C 48 ; WX 556 ; N zero ; B 37 -19 519 703 ;
C 49 ; WX 556 ; N one ; B 101 0 359 703 ;
C 50 ; WX 556 ; N two ; B 26 0 507 703 ;
C 51 ; WX 556 ; N three ; B 34 -19 522 703 ;
C 52 ; WX 556 ; N four ; B 25 0 523 703 ;
C 53 ; WX 556 ; N five ; B 32 -19 514 688 ;
C 54 ; WX 556 ; N six ; B 38 -19 518 703 ;
C 55 ; WX 556 ; N seven ; B 37 0 523 688 ;
C 56 ; WX 556 ; N eight ; B 38 -19 517 703 ;
C 57 ; WX 556 ; N nine ; B 42 -19 514 703 ;
C 58 ; WX 278 ; N colon ; B 87 0 191 516 ;
C 59 ; WX 278 ; N semicolon ; B 87 -147 191 516 ;
C 60 ; WX 584 ; N less ; B 48 11 536 495 ;
C 61 ; WX 584 ; N equal ; B 39 115 545 390 ;
C 62 ; WX 584 ; N greater ; B 48 11 536 495 ;
C 63 ; WX 556 ; N question ; B 56 0 492 727 ;
C 64 ; WX 1015 ; N at ; B 147 -19 868 737 ;
C 65 ; WX 667 ; N A ; B 14 0 654 718 ;
C 66 ; WX 667 ; N B ; B 74 0 627 718 ;
C 67 ; WX 722 ; N C ; B 44 -19 681 737 ;
C 68 ; WX 722 ; N D ; B 81 0 674 718 ;
C 69 ; WX 667 ; N E ; B 86 0 616 718 ;
C 70 ; WX 611 ; N F ; B 86 0 583 718 ;
C 71 ; WX 778 ; N G ; B 48 -19 704 737 ;
C 72 ; WX 722 ; N H ; B 77 0 646 718 ;
C 73 ; WX 278 ; N I ; B 91 0 188 718 ;
C 74 ; WX 500 ; N J ; B 17 -19 428 718 ;
C 75 ; WX 667 ; N K ; B 76 0 663 718 ;
C 76 ; WX 556 ; N L ; B 76 0 537 718 ;
C 77 ; WX 833 ; N M ; B 73 0 761 718 ;
C 78 ; WX 722 ; N N ; B 76 0 646 718 ;
C 79 ; WX 778 ; N O ; B 39 -19 739 737 ;
C 80 ; WX 667 ; N P ; B 86 0 622 718 ;
C 81 ; WX 778 ; N Q ; B 39 -56 739 737 ;
C 82 ; WX 722 ; N R ; B 88 0 684 718 ;
C 83 ; WX 667 ; N S ; B 49 -19 620 737 ;
C 84 ; WX 611 ; N T ; B 14 0 597 718 ;
C 85 ; WX 722 ; N U ; B 79 -19 644 718 ;
C 86 ; WX 667 ; N V ; B 20 0 647 718 ;
C 87 ; WX 944 ; N W ; B 16 0 928 718 ;
C 88 ; WX 667 ; N X ; B 19 0 648 718 ;
C 89 ; WX 667 ; N Y ; B 14 0 653 718 ;
C 90 ; WX 611 ; N Z ; B 23 0 588 718 ;
C 91 ; WX 278 ; N bracketleft ; B 63 -196 250 722 ;
C 92 ; WX 278 ; N backslash ; B -17 -19 295 737 ;
C 93 ; WX 278 ; N bracketright ; B 28 -196 215 722 ;
C 94 ; WX 469 ; N asciicircum ; B -14 264 483 688 ;
C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ;
C 96 ; WX 222 ; N quoteleft ; B 65 470 169 725 ;
C 97 ; WX 556 ; N a ; B 36 -15 530 538 ;
C 98 ; WX 556 ; N b ; B 58 -15 517 718 ;
C 99 ; WX 500 ; N c ; B 30 -15 477 538 ;
C 100 ; WX 556 ; N d ; B 35 -15 499 718 ;
C 101 ; WX 556 ; N e ; B 40 -15 516 538 ;
C 102 ; WX 278 ; N f ; B 14 0 262 728 ; L i fi ; L l fl ;
C 103 ; WX 556 ; N g ; B 40 -220 499 538 ;
C 104 ; WX 556 ; N h ; B 65 0 491 718 ;
C 105 ; WX 222 ; N i ; B 67 0 155 718 ;
C 106 ; WX 222 ; N j ; B -16 -210 155 718 ;
C 107 ; WX 500 ; N k ; B 67 0 501 718 ;
C 108 ; WX 222 ; N l ; B 67 0 155 718 ;
C 109 ; WX 833 ; N m ; B 65 0 769 538 ;
C 110 ; WX 556 ; N n ; B 65 0 491 538 ;
C 111 ; WX 556 ; N o ; B 35 -14 521 538 ;
C 112 ; WX 556 ; N p ; B 58 -207 517 538 ;
C 113 ; WX 556 ; N q ; B 35 -207 494 538 ;
C 114 ; WX 333 ; N r ; B 77 0 332 538 ;
C 115 ; WX 500 ; N s ; B 32 -15 464 538 ;
C 116 ; WX 278 ; N t ; B 14 -7 257 669 ;
C 117 ; WX 556 ; N u ; B 68 -15 489 523 ;
C 118 ; WX 500 ; N v ; B 8 0 492 523 ;
C 119 ; WX 722 ; N w ; B 14 0 709 523 ;
C 120 ; WX 500 ; N x ; B 11 0 490 523 ;
C 121 ; WX 500 ; N y ; B 11 -214 489 523 ;
C 122 ; WX 500 ; N z ; B 31 0 469 523 ;
C 123 ; WX 334 ; N braceleft ; B 42 -196 292 722 ;
C 124 ; WX 260 ; N bar ; B 94 -225 167 775 ;
C 125 ; WX 334 ; N braceright ; B 42 -196 292 722 ;
C 126 ; WX 584 ; N asciitilde ; B 61 180 523 326 ;
C 161 ; WX 333 ; N exclamdown ; B 118 -195 215 523 ;
C 162 ; WX 556 ; N cent ; B 51 -115 513 623 ;
C 163 ; WX 556 ; N sterling ; B 33 -16 539 718 ;
C 164 ; WX 167 ; N fraction ; B -166 -19 333 703 ;
C 165 ; WX 556 ; N yen ; B 3 0 553 688 ;
C 166 ; WX 556 ; N florin ; B -11 -207 501 737 ;
C 167 ; WX 556 ; N section ; B 43 -191 512 737 ;
C 168 ; WX 556 ; N currency ; B 28 99 528 603 ;
C 169 ; WX 191 ; N quotesingle ; B 59 463 132 718 ;
C 170 ; WX 333 ; N quotedblleft ; B 38 470 307 725 ;
C 171 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ;
C 172 ; WX 333 ; N guilsinglleft ; B 88 108 245 446 ;
C 173 ; WX 333 ; N guilsinglright ; B 88 108 245 446 ;
C 174 ; WX 500 ; N fi ; B 14 0 434 728 ;
C 175 ; WX 500 ; N fl ; B 14 0 432 728 ;
C 177 ; WX 556 ; N endash ; B 0 240 556 313 ;
C 178 ; WX 556 ; N dagger ; B 43 -159 514 718 ;
C 179 ; WX 556 ; N daggerdbl ; B 43 -159 514 718 ;
C 180 ; WX 278 ; N periodcentered ; B 77 190 202 315 ;
C 182 ; WX 537 ; N paragraph ; B 18 -173 497 718 ;
C 183 ; WX 350 ; N bullet ; B 18 202 333 517 ;
C 184 ; WX 222 ; N quotesinglbase ; B 53 -149 157 106 ;
C 185 ; WX 333 ; N quotedblbase ; B 26 -149 295 106 ;
C 186 ; WX 333 ; N quotedblright ; B 26 463 295 718 ;
C 187 ; WX 556 ; N guillemotright ; B 97 108 459 446 ;
C 188 ; WX 1000 ; N ellipsis ; B 115 0 885 106 ;
C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 703 ;
C 191 ; WX 611 ; N questiondown ; B 91 -201 527 525 ;
C 193 ; WX 333 ; N grave ; B 14 593 211 734 ;
C 194 ; WX 333 ; N acute ; B 122 593 319 734 ;
C 195 ; WX 333 ; N circumflex ; B 21 593 312 734 ;
C 196 ; WX 333 ; N tilde ; B -4 606 337 722 ;
C 197 ; WX 333 ; N macron ; B 10 627 323 684 ;
C 198 ; WX 333 ; N breve ; B 13 595 321 731 ;
C 199 ; WX 333 ; N dotaccent ; B 121 604 212 706 ;
C 200 ; WX 333 ; N dieresis ; B 40 604 293 706 ;
C 202 ; WX 333 ; N ring ; B 75 572 259 756 ;
C 203 ; WX 333 ; N cedilla ; B 45 -225 259 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B 31 593 409 734 ;
C 206 ; WX 333 ; N ogonek ; B 73 -225 287 0 ;
C 207 ; WX 333 ; N caron ; B 21 593 312 734 ;
C 208 ; WX 1000 ; N emdash ; B 0 240 1000 313 ;
C 225 ; WX 1000 ; N AE ; B 8 0 951 718 ;
C 227 ; WX 370 ; N ordfeminine ; B 24 405 346 737 ;
C 232 ; WX 556 ; N Lslash ; B -20 0 537 718 ;
C 233 ; WX 778 ; N Oslash ; B 39 -19 740 737 ;
C 234 ; WX 1000 ; N OE ; B 36 -19 965 737 ;
C 235 ; WX 365 ; N ordmasculine ; B 25 405 341 737 ;
C 241 ; WX 889 ; N ae ; B 36 -15 847 538 ;
C 245 ; WX 278 ; N dotlessi ; B 95 0 183 523 ;
C 248 ; WX 222 ; N lslash ; B -20 0 242 718 ;
C 249 ; WX 611 ; N oslash ; B 28 -22 537 545 ;
C 250 ; WX 944 ; N oe ; B 35 -15 902 538 ;
C 251 ; WX 611 ; N germandbls ; B 67 -15 571 728 ;
C -1 ; WX 278 ; N Idieresis ; B 13 0 266 901 ;
C -1 ; WX 556 ; N eacute ; B 40 -15 516 734 ;
C -1 ; WX 556 ; N abreve ; B 36 -15 530 731 ;
C -1 ; WX 556 ; N uhungarumlaut ; B 68 -15 521 734 ;
C -1 ; WX 556 ; N ecaron ; B 40 -15 516 734 ;
C -1 ; WX 667 ; N Ydieresis ; B 14 0 653 901 ;
C -1 ; WX 584 ; N divide ; B 39 -19 545 524 ;
C -1 ; WX 667 ; N Yacute ; B 14 0 653 929 ;
C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ;
C -1 ; WX 556 ; N aacute ; B 36 -15 530 734 ;
C -1 ; WX 722 ; N Ucircumflex ; B 79 -19 644 929 ;
C -1 ; WX 500 ; N yacute ; B 11 -214 489 734 ;
C -1 ; WX 500 ; N scommaaccent ; B 32 -225 464 538 ;
C -1 ; WX 556 ; N ecircumflex ; B 40 -15 516 734 ;
C -1 ; WX 722 ; N Uring ; B 79 -19 644 931 ;
C -1 ; WX 722 ; N Udieresis ; B 79 -19 644 901 ;
C -1 ; WX 556 ; N aogonek ; B 36 -220 547 538 ;
C -1 ; WX 722 ; N Uacute ; B 79 -19 644 929 ;
C -1 ; WX 556 ; N uogonek ; B 68 -225 519 523 ;
C -1 ; WX 667 ; N Edieresis ; B 86 0 616 901 ;
C -1 ; WX 722 ; N Dcroat ; B 0 0 674 718 ;
C -1 ; WX 250 ; N commaaccent ; B 87 -225 181 -40 ;
C -1 ; WX 737 ; N copyright ; B -14 -19 752 737 ;
C -1 ; WX 667 ; N Emacron ; B 86 0 616 879 ;
C -1 ; WX 500 ; N ccaron ; B 30 -15 477 734 ;
C -1 ; WX 556 ; N aring ; B 36 -15 530 756 ;
C -1 ; WX 722 ; N Ncommaaccent ; B 76 -225 646 718 ;
C -1 ; WX 222 ; N lacute ; B 67 0 264 929 ;
C -1 ; WX 556 ; N agrave ; B 36 -15 530 734 ;
C -1 ; WX 611 ; N Tcommaaccent ; B 14 -225 597 718 ;
C -1 ; WX 722 ; N Cacute ; B 44 -19 681 929 ;
C -1 ; WX 556 ; N atilde ; B 36 -15 530 722 ;
C -1 ; WX 667 ; N Edotaccent ; B 86 0 616 901 ;
C -1 ; WX 500 ; N scaron ; B 32 -15 464 734 ;
C -1 ; WX 500 ; N scedilla ; B 32 -225 464 538 ;
C -1 ; WX 278 ; N iacute ; B 95 0 292 734 ;
C -1 ; WX 471 ; N lozenge ; B 10 0 462 728 ;
C -1 ; WX 722 ; N Rcaron ; B 88 0 684 929 ;
C -1 ; WX 778 ; N Gcommaaccent ; B 48 -225 704 737 ;
C -1 ; WX 556 ; N ucircumflex ; B 68 -15 489 734 ;
C -1 ; WX 556 ; N acircumflex ; B 36 -15 530 734 ;
C -1 ; WX 667 ; N Amacron ; B 14 0 654 879 ;
C -1 ; WX 333 ; N rcaron ; B 61 0 352 734 ;
C -1 ; WX 500 ; N ccedilla ; B 30 -225 477 538 ;
C -1 ; WX 611 ; N Zdotaccent ; B 23 0 588 901 ;
C -1 ; WX 667 ; N Thorn ; B 86 0 622 718 ;
C -1 ; WX 778 ; N Omacron ; B 39 -19 739 879 ;
C -1 ; WX 722 ; N Racute ; B 88 0 684 929 ;
C -1 ; WX 667 ; N Sacute ; B 49 -19 620 929 ;
C -1 ; WX 643 ; N dcaron ; B 35 -15 655 718 ;
C -1 ; WX 722 ; N Umacron ; B 79 -19 644 879 ;
C -1 ; WX 556 ; N uring ; B 68 -15 489 756 ;
C -1 ; WX 333 ; N threesuperior ; B 5 270 325 703 ;
C -1 ; WX 778 ; N Ograve ; B 39 -19 739 929 ;
C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ;
C -1 ; WX 667 ; N Abreve ; B 14 0 654 926 ;
C -1 ; WX 584 ; N multiply ; B 39 0 545 506 ;
C -1 ; WX 556 ; N uacute ; B 68 -15 489 734 ;
C -1 ; WX 611 ; N Tcaron ; B 14 0 597 929 ;
C -1 ; WX 476 ; N partialdiff ; B 13 -38 463 714 ;
C -1 ; WX 500 ; N ydieresis ; B 11 -214 489 706 ;
C -1 ; WX 722 ; N Nacute ; B 76 0 646 929 ;
C -1 ; WX 278 ; N icircumflex ; B -6 0 285 734 ;
C -1 ; WX 667 ; N Ecircumflex ; B 86 0 616 929 ;
C -1 ; WX 556 ; N adieresis ; B 36 -15 530 706 ;
C -1 ; WX 556 ; N edieresis ; B 40 -15 516 706 ;
C -1 ; WX 500 ; N cacute ; B 30 -15 477 734 ;
C -1 ; WX 556 ; N nacute ; B 65 0 491 734 ;
C -1 ; WX 556 ; N umacron ; B 68 -15 489 684 ;
C -1 ; WX 722 ; N Ncaron ; B 76 0 646 929 ;
C -1 ; WX 278 ; N Iacute ; B 91 0 292 929 ;
C -1 ; WX 584 ; N plusminus ; B 39 0 545 506 ;
C -1 ; WX 260 ; N brokenbar ; B 94 -150 167 700 ;
C -1 ; WX 737 ; N registered ; B -14 -19 752 737 ;
C -1 ; WX 778 ; N Gbreve ; B 48 -19 704 926 ;
C -1 ; WX 278 ; N Idotaccent ; B 91 0 188 901 ;
C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ;
C -1 ; WX 667 ; N Egrave ; B 86 0 616 929 ;
C -1 ; WX 333 ; N racute ; B 77 0 332 734 ;
C -1 ; WX 556 ; N omacron ; B 35 -14 521 684 ;
C -1 ; WX 611 ; N Zacute ; B 23 0 588 929 ;
C -1 ; WX 611 ; N Zcaron ; B 23 0 588 929 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 523 674 ;
C -1 ; WX 722 ; N Eth ; B 0 0 674 718 ;
C -1 ; WX 722 ; N Ccedilla ; B 44 -225 681 737 ;
C -1 ; WX 222 ; N lcommaaccent ; B 67 -225 167 718 ;
C -1 ; WX 317 ; N tcaron ; B 14 -7 329 808 ;
C -1 ; WX 556 ; N eogonek ; B 40 -225 516 538 ;
C -1 ; WX 722 ; N Uogonek ; B 79 -225 644 718 ;
C -1 ; WX 667 ; N Aacute ; B 14 0 654 929 ;
C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ;
C -1 ; WX 556 ; N egrave ; B 40 -15 516 734 ;
C -1 ; WX 500 ; N zacute ; B 31 0 469 734 ;
C -1 ; WX 222 ; N iogonek ; B -31 -225 183 718 ;
C -1 ; WX 778 ; N Oacute ; B 39 -19 739 929 ;
C -1 ; WX 556 ; N oacute ; B 35 -14 521 734 ;
C -1 ; WX 556 ; N amacron ; B 36 -15 530 684 ;
C -1 ; WX 500 ; N sacute ; B 32 -15 464 734 ;
C -1 ; WX 278 ; N idieresis ; B 13 0 266 706 ;
C -1 ; WX 778 ; N Ocircumflex ; B 39 -19 739 929 ;
C -1 ; WX 722 ; N Ugrave ; B 79 -19 644 929 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 556 ; N thorn ; B 58 -207 517 718 ;
C -1 ; WX 333 ; N twosuperior ; B 4 281 323 703 ;
C -1 ; WX 778 ; N Odieresis ; B 39 -19 739 901 ;
C -1 ; WX 556 ; N mu ; B 68 -207 489 523 ;
C -1 ; WX 278 ; N igrave ; B -13 0 184 734 ;
C -1 ; WX 556 ; N ohungarumlaut ; B 35 -14 521 734 ;
C -1 ; WX 667 ; N Eogonek ; B 86 -220 633 718 ;
C -1 ; WX 556 ; N dcroat ; B 35 -15 550 718 ;
C -1 ; WX 834 ; N threequarters ; B 45 -19 810 703 ;
C -1 ; WX 667 ; N Scedilla ; B 49 -225 620 737 ;
C -1 ; WX 299 ; N lcaron ; B 67 0 311 718 ;
C -1 ; WX 667 ; N Kcommaaccent ; B 76 -225 663 718 ;
C -1 ; WX 556 ; N Lacute ; B 76 0 537 929 ;
C -1 ; WX 1000 ; N trademark ; B 46 306 903 718 ;
C -1 ; WX 556 ; N edotaccent ; B 40 -15 516 706 ;
C -1 ; WX 278 ; N Igrave ; B -13 0 188 929 ;
C -1 ; WX 278 ; N Imacron ; B -17 0 296 879 ;
C -1 ; WX 556 ; N Lcaron ; B 76 0 537 718 ;
C -1 ; WX 834 ; N onehalf ; B 43 -19 773 703 ;
C -1 ; WX 549 ; N lessequal ; B 26 0 523 674 ;
C -1 ; WX 556 ; N ocircumflex ; B 35 -14 521 734 ;
C -1 ; WX 556 ; N ntilde ; B 65 0 491 722 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 79 -19 644 929 ;
C -1 ; WX 667 ; N Eacute ; B 86 0 616 929 ;
C -1 ; WX 556 ; N emacron ; B 40 -15 516 684 ;
C -1 ; WX 556 ; N gbreve ; B 40 -220 499 731 ;
C -1 ; WX 834 ; N onequarter ; B 73 -19 756 703 ;
C -1 ; WX 667 ; N Scaron ; B 49 -19 620 929 ;
C -1 ; WX 667 ; N Scommaaccent ; B 49 -225 620 737 ;
C -1 ; WX 778 ; N Ohungarumlaut ; B 39 -19 739 929 ;
C -1 ; WX 400 ; N degree ; B 54 411 346 703 ;
C -1 ; WX 556 ; N ograve ; B 35 -14 521 734 ;
C -1 ; WX 722 ; N Ccaron ; B 44 -19 681 929 ;
C -1 ; WX 556 ; N ugrave ; B 68 -15 489 734 ;
C -1 ; WX 453 ; N radical ; B -4 -80 458 762 ;
C -1 ; WX 722 ; N Dcaron ; B 81 0 674 929 ;
C -1 ; WX 333 ; N rcommaaccent ; B 77 -225 332 538 ;
C -1 ; WX 722 ; N Ntilde ; B 76 0 646 917 ;
C -1 ; WX 556 ; N otilde ; B 35 -14 521 722 ;
C -1 ; WX 722 ; N Rcommaaccent ; B 88 -225 684 718 ;
C -1 ; WX 556 ; N Lcommaaccent ; B 76 -225 537 718 ;
C -1 ; WX 667 ; N Atilde ; B 14 0 654 917 ;
C -1 ; WX 667 ; N Aogonek ; B 14 -225 654 718 ;
C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ;
C -1 ; WX 778 ; N Otilde ; B 39 -19 739 917 ;
C -1 ; WX 500 ; N zdotaccent ; B 31 0 469 706 ;
C -1 ; WX 667 ; N Ecaron ; B 86 0 616 929 ;
C -1 ; WX 278 ; N Iogonek ; B -3 -225 211 718 ;
C -1 ; WX 500 ; N kcommaaccent ; B 67 -225 501 718 ;
C -1 ; WX 584 ; N minus ; B 39 216 545 289 ;
C -1 ; WX 278 ; N Icircumflex ; B -6 0 285 929 ;
C -1 ; WX 556 ; N ncaron ; B 65 0 491 734 ;
C -1 ; WX 278 ; N tcommaaccent ; B 14 -225 257 669 ;
C -1 ; WX 584 ; N logicalnot ; B 39 108 545 390 ;
C -1 ; WX 556 ; N odieresis ; B 35 -14 521 706 ;
C -1 ; WX 556 ; N udieresis ; B 68 -15 489 706 ;
C -1 ; WX 549 ; N notequal ; B 12 -35 537 551 ;
C -1 ; WX 556 ; N gcommaaccent ; B 40 -220 499 822 ;
C -1 ; WX 556 ; N eth ; B 35 -15 522 737 ;
C -1 ; WX 500 ; N zcaron ; B 31 0 469 734 ;
C -1 ; WX 556 ; N ncommaaccent ; B 65 -225 491 538 ;
C -1 ; WX 333 ; N onesuperior ; B 43 281 222 703 ;
C -1 ; WX 278 ; N imacron ; B 5 0 272 684 ;
C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2705
KPX A C -30
KPX A Cacute -30
KPX A Ccaron -30
KPX A Ccedilla -30
KPX A G -30
KPX A Gbreve -30
KPX A Gcommaaccent -30
KPX A O -30
KPX A Oacute -30
KPX A Ocircumflex -30
KPX A Odieresis -30
KPX A Ograve -30
KPX A Ohungarumlaut -30
KPX A Omacron -30
KPX A Oslash -30
KPX A Otilde -30
KPX A Q -30
KPX A T -120
KPX A Tcaron -120
KPX A Tcommaaccent -120
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -70
KPX A W -50
KPX A Y -100
KPX A Yacute -100
KPX A Ydieresis -100
KPX A u -30
KPX A uacute -30
KPX A ucircumflex -30
KPX A udieresis -30
KPX A ugrave -30
KPX A uhungarumlaut -30
KPX A umacron -30
KPX A uogonek -30
KPX A uring -30
KPX A v -40
KPX A w -40
KPX A y -40
KPX A yacute -40
KPX A ydieresis -40
KPX Aacute C -30
KPX Aacute Cacute -30
KPX Aacute Ccaron -30
KPX Aacute Ccedilla -30
KPX Aacute G -30
KPX Aacute Gbreve -30
KPX Aacute Gcommaaccent -30
KPX Aacute O -30
KPX Aacute Oacute -30
KPX Aacute Ocircumflex -30
KPX Aacute Odieresis -30
KPX Aacute Ograve -30
KPX Aacute Ohungarumlaut -30
KPX Aacute Omacron -30
KPX Aacute Oslash -30
KPX Aacute Otilde -30
KPX Aacute Q -30
KPX Aacute T -120
KPX Aacute Tcaron -120
KPX Aacute Tcommaaccent -120
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -70
KPX Aacute W -50
KPX Aacute Y -100
KPX Aacute Yacute -100
KPX Aacute Ydieresis -100
KPX Aacute u -30
KPX Aacute uacute -30
KPX Aacute ucircumflex -30
KPX Aacute udieresis -30
KPX Aacute ugrave -30
KPX Aacute uhungarumlaut -30
KPX Aacute umacron -30
KPX Aacute uogonek -30
KPX Aacute uring -30
KPX Aacute v -40
KPX Aacute w -40
KPX Aacute y -40
KPX Aacute yacute -40
KPX Aacute ydieresis -40
KPX Abreve C -30
KPX Abreve Cacute -30
KPX Abreve Ccaron -30
KPX Abreve Ccedilla -30
KPX Abreve G -30
KPX Abreve Gbreve -30
KPX Abreve Gcommaaccent -30
KPX Abreve O -30
KPX Abreve Oacute -30
KPX Abreve Ocircumflex -30
KPX Abreve Odieresis -30
KPX Abreve Ograve -30
KPX Abreve Ohungarumlaut -30
KPX Abreve Omacron -30
KPX Abreve Oslash -30
KPX Abreve Otilde -30
KPX Abreve Q -30
KPX Abreve T -120
KPX Abreve Tcaron -120
KPX Abreve Tcommaaccent -120
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -70
KPX Abreve W -50
KPX Abreve Y -100
KPX Abreve Yacute -100
KPX Abreve Ydieresis -100
KPX Abreve u -30
KPX Abreve uacute -30
KPX Abreve ucircumflex -30
KPX Abreve udieresis -30
KPX Abreve ugrave -30
KPX Abreve uhungarumlaut -30
KPX Abreve umacron -30
KPX Abreve uogonek -30
KPX Abreve uring -30
KPX Abreve v -40
KPX Abreve w -40
KPX Abreve y -40
KPX Abreve yacute -40
KPX Abreve ydieresis -40
KPX Acircumflex C -30
KPX Acircumflex Cacute -30
KPX Acircumflex Ccaron -30
KPX Acircumflex Ccedilla -30
KPX Acircumflex G -30
KPX Acircumflex Gbreve -30
KPX Acircumflex Gcommaaccent -30
KPX Acircumflex O -30
KPX Acircumflex Oacute -30
KPX Acircumflex Ocircumflex -30
KPX Acircumflex Odieresis -30
KPX Acircumflex Ograve -30
KPX Acircumflex Ohungarumlaut -30
KPX Acircumflex Omacron -30
KPX Acircumflex Oslash -30
KPX Acircumflex Otilde -30
KPX Acircumflex Q -30
KPX Acircumflex T -120
KPX Acircumflex Tcaron -120
KPX Acircumflex Tcommaaccent -120
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -70
KPX Acircumflex W -50
KPX Acircumflex Y -100
KPX Acircumflex Yacute -100
KPX Acircumflex Ydieresis -100
KPX Acircumflex u -30
KPX Acircumflex uacute -30
KPX Acircumflex ucircumflex -30
KPX Acircumflex udieresis -30
KPX Acircumflex ugrave -30
KPX Acircumflex uhungarumlaut -30
KPX Acircumflex umacron -30
KPX Acircumflex uogonek -30
KPX Acircumflex uring -30
KPX Acircumflex v -40
KPX Acircumflex w -40
KPX Acircumflex y -40
KPX Acircumflex yacute -40
KPX Acircumflex ydieresis -40
KPX Adieresis C -30
KPX Adieresis Cacute -30
KPX Adieresis Ccaron -30
KPX Adieresis Ccedilla -30
KPX Adieresis G -30
KPX Adieresis Gbreve -30
KPX Adieresis Gcommaaccent -30
KPX Adieresis O -30
KPX Adieresis Oacute -30
KPX Adieresis Ocircumflex -30
KPX Adieresis Odieresis -30
KPX Adieresis Ograve -30
KPX Adieresis Ohungarumlaut -30
KPX Adieresis Omacron -30
KPX Adieresis Oslash -30
KPX Adieresis Otilde -30
KPX Adieresis Q -30
KPX Adieresis T -120
KPX Adieresis Tcaron -120
KPX Adieresis Tcommaaccent -120
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -70
KPX Adieresis W -50
KPX Adieresis Y -100
KPX Adieresis Yacute -100
KPX Adieresis Ydieresis -100
KPX Adieresis u -30
KPX Adieresis uacute -30
KPX Adieresis ucircumflex -30
KPX Adieresis udieresis -30
KPX Adieresis ugrave -30
KPX Adieresis uhungarumlaut -30
KPX Adieresis umacron -30
KPX Adieresis uogonek -30
KPX Adieresis uring -30
KPX Adieresis v -40
KPX Adieresis w -40
KPX Adieresis y -40
KPX Adieresis yacute -40
KPX Adieresis ydieresis -40
KPX Agrave C -30
KPX Agrave Cacute -30
KPX Agrave Ccaron -30
KPX Agrave Ccedilla -30
KPX Agrave G -30
KPX Agrave Gbreve -30
KPX Agrave Gcommaaccent -30
KPX Agrave O -30
KPX Agrave Oacute -30
KPX Agrave Ocircumflex -30
KPX Agrave Odieresis -30
KPX Agrave Ograve -30
KPX Agrave Ohungarumlaut -30
KPX Agrave Omacron -30
KPX Agrave Oslash -30
KPX Agrave Otilde -30
KPX Agrave Q -30
KPX Agrave T -120
KPX Agrave Tcaron -120
KPX Agrave Tcommaaccent -120
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -70
KPX Agrave W -50
KPX Agrave Y -100
KPX Agrave Yacute -100
KPX Agrave Ydieresis -100
KPX Agrave u -30
KPX Agrave uacute -30
KPX Agrave ucircumflex -30
KPX Agrave udieresis -30
KPX Agrave ugrave -30
KPX Agrave uhungarumlaut -30
KPX Agrave umacron -30
KPX Agrave uogonek -30
KPX Agrave uring -30
KPX Agrave v -40
KPX Agrave w -40
KPX Agrave y -40
KPX Agrave yacute -40
KPX Agrave ydieresis -40
KPX Amacron C -30
KPX Amacron Cacute -30
KPX Amacron Ccaron -30
KPX Amacron Ccedilla -30
KPX Amacron G -30
KPX Amacron Gbreve -30
KPX Amacron Gcommaaccent -30
KPX Amacron O -30
KPX Amacron Oacute -30
KPX Amacron Ocircumflex -30
KPX Amacron Odieresis -30
KPX Amacron Ograve -30
KPX Amacron Ohungarumlaut -30
KPX Amacron Omacron -30
KPX Amacron Oslash -30
KPX Amacron Otilde -30
KPX Amacron Q -30
KPX Amacron T -120
KPX Amacron Tcaron -120
KPX Amacron Tcommaaccent -120
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -70
KPX Amacron W -50
KPX Amacron Y -100
KPX Amacron Yacute -100
KPX Amacron Ydieresis -100
KPX Amacron u -30
KPX Amacron uacute -30
KPX Amacron ucircumflex -30
KPX Amacron udieresis -30
KPX Amacron ugrave -30
KPX Amacron uhungarumlaut -30
KPX Amacron umacron -30
KPX Amacron uogonek -30
KPX Amacron uring -30
KPX Amacron v -40
KPX Amacron w -40
KPX Amacron y -40
KPX Amacron yacute -40
KPX Amacron ydieresis -40
KPX Aogonek C -30
KPX Aogonek Cacute -30
KPX Aogonek Ccaron -30
KPX Aogonek Ccedilla -30
KPX Aogonek G -30
KPX Aogonek Gbreve -30
KPX Aogonek Gcommaaccent -30
KPX Aogonek O -30
KPX Aogonek Oacute -30
KPX Aogonek Ocircumflex -30
KPX Aogonek Odieresis -30
KPX Aogonek Ograve -30
KPX Aogonek Ohungarumlaut -30
KPX Aogonek Omacron -30
KPX Aogonek Oslash -30
KPX Aogonek Otilde -30
KPX Aogonek Q -30
KPX Aogonek T -120
KPX Aogonek Tcaron -120
KPX Aogonek Tcommaaccent -120
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -70
KPX Aogonek W -50
KPX Aogonek Y -100
KPX Aogonek Yacute -100
KPX Aogonek Ydieresis -100
KPX Aogonek u -30
KPX Aogonek uacute -30
KPX Aogonek ucircumflex -30
KPX Aogonek udieresis -30
KPX Aogonek ugrave -30
KPX Aogonek uhungarumlaut -30
KPX Aogonek umacron -30
KPX Aogonek uogonek -30
KPX Aogonek uring -30
KPX Aogonek v -40
KPX Aogonek w -40
KPX Aogonek y -40
KPX Aogonek yacute -40
KPX Aogonek ydieresis -40
KPX Aring C -30
KPX Aring Cacute -30
KPX Aring Ccaron -30
KPX Aring Ccedilla -30
KPX Aring G -30
KPX Aring Gbreve -30
KPX Aring Gcommaaccent -30
KPX Aring O -30
KPX Aring Oacute -30
KPX Aring Ocircumflex -30
KPX Aring Odieresis -30
KPX Aring Ograve -30
KPX Aring Ohungarumlaut -30
KPX Aring Omacron -30
KPX Aring Oslash -30
KPX Aring Otilde -30
KPX Aring Q -30
KPX Aring T -120
KPX Aring Tcaron -120
KPX Aring Tcommaaccent -120
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -70
KPX Aring W -50
KPX Aring Y -100
KPX Aring Yacute -100
KPX Aring Ydieresis -100
KPX Aring u -30
KPX Aring uacute -30
KPX Aring ucircumflex -30
KPX Aring udieresis -30
KPX Aring ugrave -30
KPX Aring uhungarumlaut -30
KPX Aring umacron -30
KPX Aring uogonek -30
KPX Aring uring -30
KPX Aring v -40
KPX Aring w -40
KPX Aring y -40
KPX Aring yacute -40
KPX Aring ydieresis -40
KPX Atilde C -30
KPX Atilde Cacute -30
KPX Atilde Ccaron -30
KPX Atilde Ccedilla -30
KPX Atilde G -30
KPX Atilde Gbreve -30
KPX Atilde Gcommaaccent -30
KPX Atilde O -30
KPX Atilde Oacute -30
KPX Atilde Ocircumflex -30
KPX Atilde Odieresis -30
KPX Atilde Ograve -30
KPX Atilde Ohungarumlaut -30
KPX Atilde Omacron -30
KPX Atilde Oslash -30
KPX Atilde Otilde -30
KPX Atilde Q -30
KPX Atilde T -120
KPX Atilde Tcaron -120
KPX Atilde Tcommaaccent -120
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -70
KPX Atilde W -50
KPX Atilde Y -100
KPX Atilde Yacute -100
KPX Atilde Ydieresis -100
KPX Atilde u -30
KPX Atilde uacute -30
KPX Atilde ucircumflex -30
KPX Atilde udieresis -30
KPX Atilde ugrave -30
KPX Atilde uhungarumlaut -30
KPX Atilde umacron -30
KPX Atilde uogonek -30
KPX Atilde uring -30
KPX Atilde v -40
KPX Atilde w -40
KPX Atilde y -40
KPX Atilde yacute -40
KPX Atilde ydieresis -40
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX B comma -20
KPX B period -20
KPX C comma -30
KPX C period -30
KPX Cacute comma -30
KPX Cacute period -30
KPX Ccaron comma -30
KPX Ccaron period -30
KPX Ccedilla comma -30
KPX Ccedilla period -30
KPX D A -40
KPX D Aacute -40
KPX D Abreve -40
KPX D Acircumflex -40
KPX D Adieresis -40
KPX D Agrave -40
KPX D Amacron -40
KPX D Aogonek -40
KPX D Aring -40
KPX D Atilde -40
KPX D V -70
KPX D W -40
KPX D Y -90
KPX D Yacute -90
KPX D Ydieresis -90
KPX D comma -70
KPX D period -70
KPX Dcaron A -40
KPX Dcaron Aacute -40
KPX Dcaron Abreve -40
KPX Dcaron Acircumflex -40
KPX Dcaron Adieresis -40
KPX Dcaron Agrave -40
KPX Dcaron Amacron -40
KPX Dcaron Aogonek -40
KPX Dcaron Aring -40
KPX Dcaron Atilde -40
KPX Dcaron V -70
KPX Dcaron W -40
KPX Dcaron Y -90
KPX Dcaron Yacute -90
KPX Dcaron Ydieresis -90
KPX Dcaron comma -70
KPX Dcaron period -70
KPX Dcroat A -40
KPX Dcroat Aacute -40
KPX Dcroat Abreve -40
KPX Dcroat Acircumflex -40
KPX Dcroat Adieresis -40
KPX Dcroat Agrave -40
KPX Dcroat Amacron -40
KPX Dcroat Aogonek -40
KPX Dcroat Aring -40
KPX Dcroat Atilde -40
KPX Dcroat V -70
KPX Dcroat W -40
KPX Dcroat Y -90
KPX Dcroat Yacute -90
KPX Dcroat Ydieresis -90
KPX Dcroat comma -70
KPX Dcroat period -70
KPX F A -80
KPX F Aacute -80
KPX F Abreve -80
KPX F Acircumflex -80
KPX F Adieresis -80
KPX F Agrave -80
KPX F Amacron -80
KPX F Aogonek -80
KPX F Aring -80
KPX F Atilde -80
KPX F a -50
KPX F aacute -50
KPX F abreve -50
KPX F acircumflex -50
KPX F adieresis -50
KPX F agrave -50
KPX F amacron -50
KPX F aogonek -50
KPX F aring -50
KPX F atilde -50
KPX F comma -150
KPX F e -30
KPX F eacute -30
KPX F ecaron -30
KPX F ecircumflex -30
KPX F edieresis -30
KPX F edotaccent -30
KPX F egrave -30
KPX F emacron -30
KPX F eogonek -30
KPX F o -30
KPX F oacute -30
KPX F ocircumflex -30
KPX F odieresis -30
KPX F ograve -30
KPX F ohungarumlaut -30
KPX F omacron -30
KPX F oslash -30
KPX F otilde -30
KPX F period -150
KPX F r -45
KPX F racute -45
KPX F rcaron -45
KPX F rcommaaccent -45
KPX J A -20
KPX J Aacute -20
KPX J Abreve -20
KPX J Acircumflex -20
KPX J Adieresis -20
KPX J Agrave -20
KPX J Amacron -20
KPX J Aogonek -20
KPX J Aring -20
KPX J Atilde -20
KPX J a -20
KPX J aacute -20
KPX J abreve -20
KPX J acircumflex -20
KPX J adieresis -20
KPX J agrave -20
KPX J amacron -20
KPX J aogonek -20
KPX J aring -20
KPX J atilde -20
KPX J comma -30
KPX J period -30
KPX J u -20
KPX J uacute -20
KPX J ucircumflex -20
KPX J udieresis -20
KPX J ugrave -20
KPX J uhungarumlaut -20
KPX J umacron -20
KPX J uogonek -20
KPX J uring -20
KPX K O -50
KPX K Oacute -50
KPX K Ocircumflex -50
KPX K Odieresis -50
KPX K Ograve -50
KPX K Ohungarumlaut -50
KPX K Omacron -50
KPX K Oslash -50
KPX K Otilde -50
KPX K e -40
KPX K eacute -40
KPX K ecaron -40
KPX K ecircumflex -40
KPX K edieresis -40
KPX K edotaccent -40
KPX K egrave -40
KPX K emacron -40
KPX K eogonek -40
KPX K o -40
KPX K oacute -40
KPX K ocircumflex -40
KPX K odieresis -40
KPX K ograve -40
KPX K ohungarumlaut -40
KPX K omacron -40
KPX K oslash -40
KPX K otilde -40
KPX K u -30
KPX K uacute -30
KPX K ucircumflex -30
KPX K udieresis -30
KPX K ugrave -30
KPX K uhungarumlaut -30
KPX K umacron -30
KPX K uogonek -30
KPX K uring -30
KPX K y -50
KPX K yacute -50
KPX K ydieresis -50
KPX Kcommaaccent O -50
KPX Kcommaaccent Oacute -50
KPX Kcommaaccent Ocircumflex -50
KPX Kcommaaccent Odieresis -50
KPX Kcommaaccent Ograve -50
KPX Kcommaaccent Ohungarumlaut -50
KPX Kcommaaccent Omacron -50
KPX Kcommaaccent Oslash -50
KPX Kcommaaccent Otilde -50
KPX Kcommaaccent e -40
KPX Kcommaaccent eacute -40
KPX Kcommaaccent ecaron -40
KPX Kcommaaccent ecircumflex -40
KPX Kcommaaccent edieresis -40
KPX Kcommaaccent edotaccent -40
KPX Kcommaaccent egrave -40
KPX Kcommaaccent emacron -40
KPX Kcommaaccent eogonek -40
KPX Kcommaaccent o -40
KPX Kcommaaccent oacute -40
KPX Kcommaaccent ocircumflex -40
KPX Kcommaaccent odieresis -40
KPX Kcommaaccent ograve -40
KPX Kcommaaccent ohungarumlaut -40
KPX Kcommaaccent omacron -40
KPX Kcommaaccent oslash -40
KPX Kcommaaccent otilde -40
KPX Kcommaaccent u -30
KPX Kcommaaccent uacute -30
KPX Kcommaaccent ucircumflex -30
KPX Kcommaaccent udieresis -30
KPX Kcommaaccent ugrave -30
KPX Kcommaaccent uhungarumlaut -30
KPX Kcommaaccent umacron -30
KPX Kcommaaccent uogonek -30
KPX Kcommaaccent uring -30
KPX Kcommaaccent y -50
KPX Kcommaaccent yacute -50
KPX Kcommaaccent ydieresis -50
KPX L T -110
KPX L Tcaron -110
KPX L Tcommaaccent -110
KPX L V -110
KPX L W -70
KPX L Y -140
KPX L Yacute -140
KPX L Ydieresis -140
KPX L quotedblright -140
KPX L quoteright -160
KPX L y -30
KPX L yacute -30
KPX L ydieresis -30
KPX Lacute T -110
KPX Lacute Tcaron -110
KPX Lacute Tcommaaccent -110
KPX Lacute V -110
KPX Lacute W -70
KPX Lacute Y -140
KPX Lacute Yacute -140
KPX Lacute Ydieresis -140
KPX Lacute quotedblright -140
KPX Lacute quoteright -160
KPX Lacute y -30
KPX Lacute yacute -30
KPX Lacute ydieresis -30
KPX Lcaron T -110
KPX Lcaron Tcaron -110
KPX Lcaron Tcommaaccent -110
KPX Lcaron V -110
KPX Lcaron W -70
KPX Lcaron Y -140
KPX Lcaron Yacute -140
KPX Lcaron Ydieresis -140
KPX Lcaron quotedblright -140
KPX Lcaron quoteright -160
KPX Lcaron y -30
KPX Lcaron yacute -30
KPX Lcaron ydieresis -30
KPX Lcommaaccent T -110
KPX Lcommaaccent Tcaron -110
KPX Lcommaaccent Tcommaaccent -110
KPX Lcommaaccent V -110
KPX Lcommaaccent W -70
KPX Lcommaaccent Y -140
KPX Lcommaaccent Yacute -140
KPX Lcommaaccent Ydieresis -140
KPX Lcommaaccent quotedblright -140
KPX Lcommaaccent quoteright -160
KPX Lcommaaccent y -30
KPX Lcommaaccent yacute -30
KPX Lcommaaccent ydieresis -30
KPX Lslash T -110
KPX Lslash Tcaron -110
KPX Lslash Tcommaaccent -110
KPX Lslash V -110
KPX Lslash W -70
KPX Lslash Y -140
KPX Lslash Yacute -140
KPX Lslash Ydieresis -140
KPX Lslash quotedblright -140
KPX Lslash quoteright -160
KPX Lslash y -30
KPX Lslash yacute -30
KPX Lslash ydieresis -30
KPX O A -20
KPX O Aacute -20
KPX O Abreve -20
KPX O Acircumflex -20
KPX O Adieresis -20
KPX O Agrave -20
KPX O Amacron -20
KPX O Aogonek -20
KPX O Aring -20
KPX O Atilde -20
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -30
KPX O X -60
KPX O Y -70
KPX O Yacute -70
KPX O Ydieresis -70
KPX O comma -40
KPX O period -40
KPX Oacute A -20
KPX Oacute Aacute -20
KPX Oacute Abreve -20
KPX Oacute Acircumflex -20
KPX Oacute Adieresis -20
KPX Oacute Agrave -20
KPX Oacute Amacron -20
KPX Oacute Aogonek -20
KPX Oacute Aring -20
KPX Oacute Atilde -20
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -30
KPX Oacute X -60
KPX Oacute Y -70
KPX Oacute Yacute -70
KPX Oacute Ydieresis -70
KPX Oacute comma -40
KPX Oacute period -40
KPX Ocircumflex A -20
KPX Ocircumflex Aacute -20
KPX Ocircumflex Abreve -20
KPX Ocircumflex Acircumflex -20
KPX Ocircumflex Adieresis -20
KPX Ocircumflex Agrave -20
KPX Ocircumflex Amacron -20
KPX Ocircumflex Aogonek -20
KPX Ocircumflex Aring -20
KPX Ocircumflex Atilde -20
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -30
KPX Ocircumflex X -60
KPX Ocircumflex Y -70
KPX Ocircumflex Yacute -70
KPX Ocircumflex Ydieresis -70
KPX Ocircumflex comma -40
KPX Ocircumflex period -40
KPX Odieresis A -20
KPX Odieresis Aacute -20
KPX Odieresis Abreve -20
KPX Odieresis Acircumflex -20
KPX Odieresis Adieresis -20
KPX Odieresis Agrave -20
KPX Odieresis Amacron -20
KPX Odieresis Aogonek -20
KPX Odieresis Aring -20
KPX Odieresis Atilde -20
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -30
KPX Odieresis X -60
KPX Odieresis Y -70
KPX Odieresis Yacute -70
KPX Odieresis Ydieresis -70
KPX Odieresis comma -40
KPX Odieresis period -40
KPX Ograve A -20
KPX Ograve Aacute -20
KPX Ograve Abreve -20
KPX Ograve Acircumflex -20
KPX Ograve Adieresis -20
KPX Ograve Agrave -20
KPX Ograve Amacron -20
KPX Ograve Aogonek -20
KPX Ograve Aring -20
KPX Ograve Atilde -20
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -30
KPX Ograve X -60
KPX Ograve Y -70
KPX Ograve Yacute -70
KPX Ograve Ydieresis -70
KPX Ograve comma -40
KPX Ograve period -40
KPX Ohungarumlaut A -20
KPX Ohungarumlaut Aacute -20
KPX Ohungarumlaut Abreve -20
KPX Ohungarumlaut Acircumflex -20
KPX Ohungarumlaut Adieresis -20
KPX Ohungarumlaut Agrave -20
KPX Ohungarumlaut Amacron -20
KPX Ohungarumlaut Aogonek -20
KPX Ohungarumlaut Aring -20
KPX Ohungarumlaut Atilde -20
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -30
KPX Ohungarumlaut X -60
KPX Ohungarumlaut Y -70
KPX Ohungarumlaut Yacute -70
KPX Ohungarumlaut Ydieresis -70
KPX Ohungarumlaut comma -40
KPX Ohungarumlaut period -40
KPX Omacron A -20
KPX Omacron Aacute -20
KPX Omacron Abreve -20
KPX Omacron Acircumflex -20
KPX Omacron Adieresis -20
KPX Omacron Agrave -20
KPX Omacron Amacron -20
KPX Omacron Aogonek -20
KPX Omacron Aring -20
KPX Omacron Atilde -20
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -30
KPX Omacron X -60
KPX Omacron Y -70
KPX Omacron Yacute -70
KPX Omacron Ydieresis -70
KPX Omacron comma -40
KPX Omacron period -40
KPX Oslash A -20
KPX Oslash Aacute -20
KPX Oslash Abreve -20
KPX Oslash Acircumflex -20
KPX Oslash Adieresis -20
KPX Oslash Agrave -20
KPX Oslash Amacron -20
KPX Oslash Aogonek -20
KPX Oslash Aring -20
KPX Oslash Atilde -20
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -30
KPX Oslash X -60
KPX Oslash Y -70
KPX Oslash Yacute -70
KPX Oslash Ydieresis -70
KPX Oslash comma -40
KPX Oslash period -40
KPX Otilde A -20
KPX Otilde Aacute -20
KPX Otilde Abreve -20
KPX Otilde Acircumflex -20
KPX Otilde Adieresis -20
KPX Otilde Agrave -20
KPX Otilde Amacron -20
KPX Otilde Aogonek -20
KPX Otilde Aring -20
KPX Otilde Atilde -20
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -30
KPX Otilde X -60
KPX Otilde Y -70
KPX Otilde Yacute -70
KPX Otilde Ydieresis -70
KPX Otilde comma -40
KPX Otilde period -40
KPX P A -120
KPX P Aacute -120
KPX P Abreve -120
KPX P Acircumflex -120
KPX P Adieresis -120
KPX P Agrave -120
KPX P Amacron -120
KPX P Aogonek -120
KPX P Aring -120
KPX P Atilde -120
KPX P a -40
KPX P aacute -40
KPX P abreve -40
KPX P acircumflex -40
KPX P adieresis -40
KPX P agrave -40
KPX P amacron -40
KPX P aogonek -40
KPX P aring -40
KPX P atilde -40
KPX P comma -180
KPX P e -50
KPX P eacute -50
KPX P ecaron -50
KPX P ecircumflex -50
KPX P edieresis -50
KPX P edotaccent -50
KPX P egrave -50
KPX P emacron -50
KPX P eogonek -50
KPX P o -50
KPX P oacute -50
KPX P ocircumflex -50
KPX P odieresis -50
KPX P ograve -50
KPX P ohungarumlaut -50
KPX P omacron -50
KPX P oslash -50
KPX P otilde -50
KPX P period -180
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX R O -20
KPX R Oacute -20
KPX R Ocircumflex -20
KPX R Odieresis -20
KPX R Ograve -20
KPX R Ohungarumlaut -20
KPX R Omacron -20
KPX R Oslash -20
KPX R Otilde -20
KPX R T -30
KPX R Tcaron -30
KPX R Tcommaaccent -30
KPX R U -40
KPX R Uacute -40
KPX R Ucircumflex -40
KPX R Udieresis -40
KPX R Ugrave -40
KPX R Uhungarumlaut -40
KPX R Umacron -40
KPX R Uogonek -40
KPX R Uring -40
KPX R V -50
KPX R W -30
KPX R Y -50
KPX R Yacute -50
KPX R Ydieresis -50
KPX Racute O -20
KPX Racute Oacute -20
KPX Racute Ocircumflex -20
KPX Racute Odieresis -20
KPX Racute Ograve -20
KPX Racute Ohungarumlaut -20
KPX Racute Omacron -20
KPX Racute Oslash -20
KPX Racute Otilde -20
KPX Racute T -30
KPX Racute Tcaron -30
KPX Racute Tcommaaccent -30
KPX Racute U -40
KPX Racute Uacute -40
KPX Racute Ucircumflex -40
KPX Racute Udieresis -40
KPX Racute Ugrave -40
KPX Racute Uhungarumlaut -40
KPX Racute Umacron -40
KPX Racute Uogonek -40
KPX Racute Uring -40
KPX Racute V -50
KPX Racute W -30
KPX Racute Y -50
KPX Racute Yacute -50
KPX Racute Ydieresis -50
KPX Rcaron O -20
KPX Rcaron Oacute -20
KPX Rcaron Ocircumflex -20
KPX Rcaron Odieresis -20
KPX Rcaron Ograve -20
KPX Rcaron Ohungarumlaut -20
KPX Rcaron Omacron -20
KPX Rcaron Oslash -20
KPX Rcaron Otilde -20
KPX Rcaron T -30
KPX Rcaron Tcaron -30
KPX Rcaron Tcommaaccent -30
KPX Rcaron U -40
KPX Rcaron Uacute -40
KPX Rcaron Ucircumflex -40
KPX Rcaron Udieresis -40
KPX Rcaron Ugrave -40
KPX Rcaron Uhungarumlaut -40
KPX Rcaron Umacron -40
KPX Rcaron Uogonek -40
KPX Rcaron Uring -40
KPX Rcaron V -50
KPX Rcaron W -30
KPX Rcaron Y -50
KPX Rcaron Yacute -50
KPX Rcaron Ydieresis -50
KPX Rcommaaccent O -20
KPX Rcommaaccent Oacute -20
KPX Rcommaaccent Ocircumflex -20
KPX Rcommaaccent Odieresis -20
KPX Rcommaaccent Ograve -20
KPX Rcommaaccent Ohungarumlaut -20
KPX Rcommaaccent Omacron -20
KPX Rcommaaccent Oslash -20
KPX Rcommaaccent Otilde -20
KPX Rcommaaccent T -30
KPX Rcommaaccent Tcaron -30
KPX Rcommaaccent Tcommaaccent -30
KPX Rcommaaccent U -40
KPX Rcommaaccent Uacute -40
KPX Rcommaaccent Ucircumflex -40
KPX Rcommaaccent Udieresis -40
KPX Rcommaaccent Ugrave -40
KPX Rcommaaccent Uhungarumlaut -40
KPX Rcommaaccent Umacron -40
KPX Rcommaaccent Uogonek -40
KPX Rcommaaccent Uring -40
KPX Rcommaaccent V -50
KPX Rcommaaccent W -30
KPX Rcommaaccent Y -50
KPX Rcommaaccent Yacute -50
KPX Rcommaaccent Ydieresis -50
KPX S comma -20
KPX S period -20
KPX Sacute comma -20
KPX Sacute period -20
KPX Scaron comma -20
KPX Scaron period -20
KPX Scedilla comma -20
KPX Scedilla period -20
KPX Scommaaccent comma -20
KPX Scommaaccent period -20
KPX T A -120
KPX T Aacute -120
KPX T Abreve -120
KPX T Acircumflex -120
KPX T Adieresis -120
KPX T Agrave -120
KPX T Amacron -120
KPX T Aogonek -120
KPX T Aring -120
KPX T Atilde -120
KPX T O -40
KPX T Oacute -40
KPX T Ocircumflex -40
KPX T Odieresis -40
KPX T Ograve -40
KPX T Ohungarumlaut -40
KPX T Omacron -40
KPX T Oslash -40
KPX T Otilde -40
KPX T a -120
KPX T aacute -120
KPX T abreve -60
KPX T acircumflex -120
KPX T adieresis -120
KPX T agrave -120
KPX T amacron -60
KPX T aogonek -120
KPX T aring -120
KPX T atilde -60
KPX T colon -20
KPX T comma -120
KPX T e -120
KPX T eacute -120
KPX T ecaron -120
KPX T ecircumflex -120
KPX T edieresis -120
KPX T edotaccent -120
KPX T egrave -60
KPX T emacron -60
KPX T eogonek -120
KPX T hyphen -140
KPX T o -120
KPX T oacute -120
KPX T ocircumflex -120
KPX T odieresis -120
KPX T ograve -120
KPX T ohungarumlaut -120
KPX T omacron -60
KPX T oslash -120
KPX T otilde -60
KPX T period -120
KPX T r -120
KPX T racute -120
KPX T rcaron -120
KPX T rcommaaccent -120
KPX T semicolon -20
KPX T u -120
KPX T uacute -120
KPX T ucircumflex -120
KPX T udieresis -120
KPX T ugrave -120
KPX T uhungarumlaut -120
KPX T umacron -60
KPX T uogonek -120
KPX T uring -120
KPX T w -120
KPX T y -120
KPX T yacute -120
KPX T ydieresis -60
KPX Tcaron A -120
KPX Tcaron Aacute -120
KPX Tcaron Abreve -120
KPX Tcaron Acircumflex -120
KPX Tcaron Adieresis -120
KPX Tcaron Agrave -120
KPX Tcaron Amacron -120
KPX Tcaron Aogonek -120
KPX Tcaron Aring -120
KPX Tcaron Atilde -120
KPX Tcaron O -40
KPX Tcaron Oacute -40
KPX Tcaron Ocircumflex -40
KPX Tcaron Odieresis -40
KPX Tcaron Ograve -40
KPX Tcaron Ohungarumlaut -40
KPX Tcaron Omacron -40
KPX Tcaron Oslash -40
KPX Tcaron Otilde -40
KPX Tcaron a -120
KPX Tcaron aacute -120
KPX Tcaron abreve -60
KPX Tcaron acircumflex -120
KPX Tcaron adieresis -120
KPX Tcaron agrave -120
KPX Tcaron amacron -60
KPX Tcaron aogonek -120
KPX Tcaron aring -120
KPX Tcaron atilde -60
KPX Tcaron colon -20
KPX Tcaron comma -120
KPX Tcaron e -120
KPX Tcaron eacute -120
KPX Tcaron ecaron -120
KPX Tcaron ecircumflex -120
KPX Tcaron edieresis -120
KPX Tcaron edotaccent -120
KPX Tcaron egrave -60
KPX Tcaron emacron -60
KPX Tcaron eogonek -120
KPX Tcaron hyphen -140
KPX Tcaron o -120
KPX Tcaron oacute -120
KPX Tcaron ocircumflex -120
KPX Tcaron odieresis -120
KPX Tcaron ograve -120
KPX Tcaron ohungarumlaut -120
KPX Tcaron omacron -60
KPX Tcaron oslash -120
KPX Tcaron otilde -60
KPX Tcaron period -120
KPX Tcaron r -120
KPX Tcaron racute -120
KPX Tcaron rcaron -120
KPX Tcaron rcommaaccent -120
KPX Tcaron semicolon -20
KPX Tcaron u -120
KPX Tcaron uacute -120
KPX Tcaron ucircumflex -120
KPX Tcaron udieresis -120
KPX Tcaron ugrave -120
KPX Tcaron uhungarumlaut -120
KPX Tcaron umacron -60
KPX Tcaron uogonek -120
KPX Tcaron uring -120
KPX Tcaron w -120
KPX Tcaron y -120
KPX Tcaron yacute -120
KPX Tcaron ydieresis -60
KPX Tcommaaccent A -120
KPX Tcommaaccent Aacute -120
KPX Tcommaaccent Abreve -120
KPX Tcommaaccent Acircumflex -120
KPX Tcommaaccent Adieresis -120
KPX Tcommaaccent Agrave -120
KPX Tcommaaccent Amacron -120
KPX Tcommaaccent Aogonek -120
KPX Tcommaaccent Aring -120
KPX Tcommaaccent Atilde -120
KPX Tcommaaccent O -40
KPX Tcommaaccent Oacute -40
KPX Tcommaaccent Ocircumflex -40
KPX Tcommaaccent Odieresis -40
KPX Tcommaaccent Ograve -40
KPX Tcommaaccent Ohungarumlaut -40
KPX Tcommaaccent Omacron -40
KPX Tcommaaccent Oslash -40
KPX Tcommaaccent Otilde -40
KPX Tcommaaccent a -120
KPX Tcommaaccent aacute -120
KPX Tcommaaccent abreve -60
KPX Tcommaaccent acircumflex -120
KPX Tcommaaccent adieresis -120
KPX Tcommaaccent agrave -120
KPX Tcommaaccent amacron -60
KPX Tcommaaccent aogonek -120
KPX Tcommaaccent aring -120
KPX Tcommaaccent atilde -60
KPX Tcommaaccent colon -20
KPX Tcommaaccent comma -120
KPX Tcommaaccent e -120
KPX Tcommaaccent eacute -120
KPX Tcommaaccent ecaron -120
KPX Tcommaaccent ecircumflex -120
KPX Tcommaaccent edieresis -120
KPX Tcommaaccent edotaccent -120
KPX Tcommaaccent egrave -60
KPX Tcommaaccent emacron -60
KPX Tcommaaccent eogonek -120
KPX Tcommaaccent hyphen -140
KPX Tcommaaccent o -120
KPX Tcommaaccent oacute -120
KPX Tcommaaccent ocircumflex -120
KPX Tcommaaccent odieresis -120
KPX Tcommaaccent ograve -120
KPX Tcommaaccent ohungarumlaut -120
KPX Tcommaaccent omacron -60
KPX Tcommaaccent oslash -120
KPX Tcommaaccent otilde -60
KPX Tcommaaccent period -120
KPX Tcommaaccent r -120
KPX Tcommaaccent racute -120
KPX Tcommaaccent rcaron -120
KPX Tcommaaccent rcommaaccent -120
KPX Tcommaaccent semicolon -20
KPX Tcommaaccent u -120
KPX Tcommaaccent uacute -120
KPX Tcommaaccent ucircumflex -120
KPX Tcommaaccent udieresis -120
KPX Tcommaaccent ugrave -120
KPX Tcommaaccent uhungarumlaut -120
KPX Tcommaaccent umacron -60
KPX Tcommaaccent uogonek -120
KPX Tcommaaccent uring -120
KPX Tcommaaccent w -120
KPX Tcommaaccent y -120
KPX Tcommaaccent yacute -120
KPX Tcommaaccent ydieresis -60
KPX U A -40
KPX U Aacute -40
KPX U Abreve -40
KPX U Acircumflex -40
KPX U Adieresis -40
KPX U Agrave -40
KPX U Amacron -40
KPX U Aogonek -40
KPX U Aring -40
KPX U Atilde -40
KPX U comma -40
KPX U period -40
KPX Uacute A -40
KPX Uacute Aacute -40
KPX Uacute Abreve -40
KPX Uacute Acircumflex -40
KPX Uacute Adieresis -40
KPX Uacute Agrave -40
KPX Uacute Amacron -40
KPX Uacute Aogonek -40
KPX Uacute Aring -40
KPX Uacute Atilde -40
KPX Uacute comma -40
KPX Uacute period -40
KPX Ucircumflex A -40
KPX Ucircumflex Aacute -40
KPX Ucircumflex Abreve -40
KPX Ucircumflex Acircumflex -40
KPX Ucircumflex Adieresis -40
KPX Ucircumflex Agrave -40
KPX Ucircumflex Amacron -40
KPX Ucircumflex Aogonek -40
KPX Ucircumflex Aring -40
KPX Ucircumflex Atilde -40
KPX Ucircumflex comma -40
KPX Ucircumflex period -40
KPX Udieresis A -40
KPX Udieresis Aacute -40
KPX Udieresis Abreve -40
KPX Udieresis Acircumflex -40
KPX Udieresis Adieresis -40
KPX Udieresis Agrave -40
KPX Udieresis Amacron -40
KPX Udieresis Aogonek -40
KPX Udieresis Aring -40
KPX Udieresis Atilde -40
KPX Udieresis comma -40
KPX Udieresis period -40
KPX Ugrave A -40
KPX Ugrave Aacute -40
KPX Ugrave Abreve -40
KPX Ugrave Acircumflex -40
KPX Ugrave Adieresis -40
KPX Ugrave Agrave -40
KPX Ugrave Amacron -40
KPX Ugrave Aogonek -40
KPX Ugrave Aring -40
KPX Ugrave Atilde -40
KPX Ugrave comma -40
KPX Ugrave period -40
KPX Uhungarumlaut A -40
KPX Uhungarumlaut Aacute -40
KPX Uhungarumlaut Abreve -40
KPX Uhungarumlaut Acircumflex -40
KPX Uhungarumlaut Adieresis -40
KPX Uhungarumlaut Agrave -40
KPX Uhungarumlaut Amacron -40
KPX Uhungarumlaut Aogonek -40
KPX Uhungarumlaut Aring -40
KPX Uhungarumlaut Atilde -40
KPX Uhungarumlaut comma -40
KPX Uhungarumlaut period -40
KPX Umacron A -40
KPX Umacron Aacute -40
KPX Umacron Abreve -40
KPX Umacron Acircumflex -40
KPX Umacron Adieresis -40
KPX Umacron Agrave -40
KPX Umacron Amacron -40
KPX Umacron Aogonek -40
KPX Umacron Aring -40
KPX Umacron Atilde -40
KPX Umacron comma -40
KPX Umacron period -40
KPX Uogonek A -40
KPX Uogonek Aacute -40
KPX Uogonek Abreve -40
KPX Uogonek Acircumflex -40
KPX Uogonek Adieresis -40
KPX Uogonek Agrave -40
KPX Uogonek Amacron -40
KPX Uogonek Aogonek -40
KPX Uogonek Aring -40
KPX Uogonek Atilde -40
KPX Uogonek comma -40
KPX Uogonek period -40
KPX Uring A -40
KPX Uring Aacute -40
KPX Uring Abreve -40
KPX Uring Acircumflex -40
KPX Uring Adieresis -40
KPX Uring Agrave -40
KPX Uring Amacron -40
KPX Uring Aogonek -40
KPX Uring Aring -40
KPX Uring Atilde -40
KPX Uring comma -40
KPX Uring period -40
KPX V A -80
KPX V Aacute -80
KPX V Abreve -80
KPX V Acircumflex -80
KPX V Adieresis -80
KPX V Agrave -80
KPX V Amacron -80
KPX V Aogonek -80
KPX V Aring -80
KPX V Atilde -80
KPX V G -40
KPX V Gbreve -40
KPX V Gcommaaccent -40
KPX V O -40
KPX V Oacute -40
KPX V Ocircumflex -40
KPX V Odieresis -40
KPX V Ograve -40
KPX V Ohungarumlaut -40
KPX V Omacron -40
KPX V Oslash -40
KPX V Otilde -40
KPX V a -70
KPX V aacute -70
KPX V abreve -70
KPX V acircumflex -70
KPX V adieresis -70
KPX V agrave -70
KPX V amacron -70
KPX V aogonek -70
KPX V aring -70
KPX V atilde -70
KPX V colon -40
KPX V comma -125
KPX V e -80
KPX V eacute -80
KPX V ecaron -80
KPX V ecircumflex -80
KPX V edieresis -80
KPX V edotaccent -80
KPX V egrave -80
KPX V emacron -80
KPX V eogonek -80
KPX V hyphen -80
KPX V o -80
KPX V oacute -80
KPX V ocircumflex -80
KPX V odieresis -80
KPX V ograve -80
KPX V ohungarumlaut -80
KPX V omacron -80
KPX V oslash -80
KPX V otilde -80
KPX V period -125
KPX V semicolon -40
KPX V u -70
KPX V uacute -70
KPX V ucircumflex -70
KPX V udieresis -70
KPX V ugrave -70
KPX V uhungarumlaut -70
KPX V umacron -70
KPX V uogonek -70
KPX V uring -70
KPX W A -50
KPX W Aacute -50
KPX W Abreve -50
KPX W Acircumflex -50
KPX W Adieresis -50
KPX W Agrave -50
KPX W Amacron -50
KPX W Aogonek -50
KPX W Aring -50
KPX W Atilde -50
KPX W O -20
KPX W Oacute -20
KPX W Ocircumflex -20
KPX W Odieresis -20
KPX W Ograve -20
KPX W Ohungarumlaut -20
KPX W Omacron -20
KPX W Oslash -20
KPX W Otilde -20
KPX W a -40
KPX W aacute -40
KPX W abreve -40
KPX W acircumflex -40
KPX W adieresis -40
KPX W agrave -40
KPX W amacron -40
KPX W aogonek -40
KPX W aring -40
KPX W atilde -40
KPX W comma -80
KPX W e -30
KPX W eacute -30
KPX W ecaron -30
KPX W ecircumflex -30
KPX W edieresis -30
KPX W edotaccent -30
KPX W egrave -30
KPX W emacron -30
KPX W eogonek -30
KPX W hyphen -40
KPX W o -30
KPX W oacute -30
KPX W ocircumflex -30
KPX W odieresis -30
KPX W ograve -30
KPX W ohungarumlaut -30
KPX W omacron -30
KPX W oslash -30
KPX W otilde -30
KPX W period -80
KPX W u -30
KPX W uacute -30
KPX W ucircumflex -30
KPX W udieresis -30
KPX W ugrave -30
KPX W uhungarumlaut -30
KPX W umacron -30
KPX W uogonek -30
KPX W uring -30
KPX W y -20
KPX W yacute -20
KPX W ydieresis -20
KPX Y A -110
KPX Y Aacute -110
KPX Y Abreve -110
KPX Y Acircumflex -110
KPX Y Adieresis -110
KPX Y Agrave -110
KPX Y Amacron -110
KPX Y Aogonek -110
KPX Y Aring -110
KPX Y Atilde -110
KPX Y O -85
KPX Y Oacute -85
KPX Y Ocircumflex -85
KPX Y Odieresis -85
KPX Y Ograve -85
KPX Y Ohungarumlaut -85
KPX Y Omacron -85
KPX Y Oslash -85
KPX Y Otilde -85
KPX Y a -140
KPX Y aacute -140
KPX Y abreve -70
KPX Y acircumflex -140
KPX Y adieresis -140
KPX Y agrave -140
KPX Y amacron -70
KPX Y aogonek -140
KPX Y aring -140
KPX Y atilde -140
KPX Y colon -60
KPX Y comma -140
KPX Y e -140
KPX Y eacute -140
KPX Y ecaron -140
KPX Y ecircumflex -140
KPX Y edieresis -140
KPX Y edotaccent -140
KPX Y egrave -140
KPX Y emacron -70
KPX Y eogonek -140
KPX Y hyphen -140
KPX Y i -20
KPX Y iacute -20
KPX Y iogonek -20
KPX Y o -140
KPX Y oacute -140
KPX Y ocircumflex -140
KPX Y odieresis -140
KPX Y ograve -140
KPX Y ohungarumlaut -140
KPX Y omacron -140
KPX Y oslash -140
KPX Y otilde -140
KPX Y period -140
KPX Y semicolon -60
KPX Y u -110
KPX Y uacute -110
KPX Y ucircumflex -110
KPX Y udieresis -110
KPX Y ugrave -110
KPX Y uhungarumlaut -110
KPX Y umacron -110
KPX Y uogonek -110
KPX Y uring -110
KPX Yacute A -110
KPX Yacute Aacute -110
KPX Yacute Abreve -110
KPX Yacute Acircumflex -110
KPX Yacute Adieresis -110
KPX Yacute Agrave -110
KPX Yacute Amacron -110
KPX Yacute Aogonek -110
KPX Yacute Aring -110
KPX Yacute Atilde -110
KPX Yacute O -85
KPX Yacute Oacute -85
KPX Yacute Ocircumflex -85
KPX Yacute Odieresis -85
KPX Yacute Ograve -85
KPX Yacute Ohungarumlaut -85
KPX Yacute Omacron -85
KPX Yacute Oslash -85
KPX Yacute Otilde -85
KPX Yacute a -140
KPX Yacute aacute -140
KPX Yacute abreve -70
KPX Yacute acircumflex -140
KPX Yacute adieresis -140
KPX Yacute agrave -140
KPX Yacute amacron -70
KPX Yacute aogonek -140
KPX Yacute aring -140
KPX Yacute atilde -70
KPX Yacute colon -60
KPX Yacute comma -140
KPX Yacute e -140
KPX Yacute eacute -140
KPX Yacute ecaron -140
KPX Yacute ecircumflex -140
KPX Yacute edieresis -140
KPX Yacute edotaccent -140
KPX Yacute egrave -140
KPX Yacute emacron -70
KPX Yacute eogonek -140
KPX Yacute hyphen -140
KPX Yacute i -20
KPX Yacute iacute -20
KPX Yacute iogonek -20
KPX Yacute o -140
KPX Yacute oacute -140
KPX Yacute ocircumflex -140
KPX Yacute odieresis -140
KPX Yacute ograve -140
KPX Yacute ohungarumlaut -140
KPX Yacute omacron -70
KPX Yacute oslash -140
KPX Yacute otilde -140
KPX Yacute period -140
KPX Yacute semicolon -60
KPX Yacute u -110
KPX Yacute uacute -110
KPX Yacute ucircumflex -110
KPX Yacute udieresis -110
KPX Yacute ugrave -110
KPX Yacute uhungarumlaut -110
KPX Yacute umacron -110
KPX Yacute uogonek -110
KPX Yacute uring -110
KPX Ydieresis A -110
KPX Ydieresis Aacute -110
KPX Ydieresis Abreve -110
KPX Ydieresis Acircumflex -110
KPX Ydieresis Adieresis -110
KPX Ydieresis Agrave -110
KPX Ydieresis Amacron -110
KPX Ydieresis Aogonek -110
KPX Ydieresis Aring -110
KPX Ydieresis Atilde -110
KPX Ydieresis O -85
KPX Ydieresis Oacute -85
KPX Ydieresis Ocircumflex -85
KPX Ydieresis Odieresis -85
KPX Ydieresis Ograve -85
KPX Ydieresis Ohungarumlaut -85
KPX Ydieresis Omacron -85
KPX Ydieresis Oslash -85
KPX Ydieresis Otilde -85
KPX Ydieresis a -140
KPX Ydieresis aacute -140
KPX Ydieresis abreve -70
KPX Ydieresis acircumflex -140
KPX Ydieresis adieresis -140
KPX Ydieresis agrave -140
KPX Ydieresis amacron -70
KPX Ydieresis aogonek -140
KPX Ydieresis aring -140
KPX Ydieresis atilde -70
KPX Ydieresis colon -60
KPX Ydieresis comma -140
KPX Ydieresis e -140
KPX Ydieresis eacute -140
KPX Ydieresis ecaron -140
KPX Ydieresis ecircumflex -140
KPX Ydieresis edieresis -140
KPX Ydieresis edotaccent -140
KPX Ydieresis egrave -140
KPX Ydieresis emacron -70
KPX Ydieresis eogonek -140
KPX Ydieresis hyphen -140
KPX Ydieresis i -20
KPX Ydieresis iacute -20
KPX Ydieresis iogonek -20
KPX Ydieresis o -140
KPX Ydieresis oacute -140
KPX Ydieresis ocircumflex -140
KPX Ydieresis odieresis -140
KPX Ydieresis ograve -140
KPX Ydieresis ohungarumlaut -140
KPX Ydieresis omacron -140
KPX Ydieresis oslash -140
KPX Ydieresis otilde -140
KPX Ydieresis period -140
KPX Ydieresis semicolon -60
KPX Ydieresis u -110
KPX Ydieresis uacute -110
KPX Ydieresis ucircumflex -110
KPX Ydieresis udieresis -110
KPX Ydieresis ugrave -110
KPX Ydieresis uhungarumlaut -110
KPX Ydieresis umacron -110
KPX Ydieresis uogonek -110
KPX Ydieresis uring -110
KPX a v -20
KPX a w -20
KPX a y -30
KPX a yacute -30
KPX a ydieresis -30
KPX aacute v -20
KPX aacute w -20
KPX aacute y -30
KPX aacute yacute -30
KPX aacute ydieresis -30
KPX abreve v -20
KPX abreve w -20
KPX abreve y -30
KPX abreve yacute -30
KPX abreve ydieresis -30
KPX acircumflex v -20
KPX acircumflex w -20
KPX acircumflex y -30
KPX acircumflex yacute -30
KPX acircumflex ydieresis -30
KPX adieresis v -20
KPX adieresis w -20
KPX adieresis y -30
KPX adieresis yacute -30
KPX adieresis ydieresis -30
KPX agrave v -20
KPX agrave w -20
KPX agrave y -30
KPX agrave yacute -30
KPX agrave ydieresis -30
KPX amacron v -20
KPX amacron w -20
KPX amacron y -30
KPX amacron yacute -30
KPX amacron ydieresis -30
KPX aogonek v -20
KPX aogonek w -20
KPX aogonek y -30
KPX aogonek yacute -30
KPX aogonek ydieresis -30
KPX aring v -20
KPX aring w -20
KPX aring y -30
KPX aring yacute -30
KPX aring ydieresis -30
KPX atilde v -20
KPX atilde w -20
KPX atilde y -30
KPX atilde yacute -30
KPX atilde ydieresis -30
KPX b b -10
KPX b comma -40
KPX b l -20
KPX b lacute -20
KPX b lcommaaccent -20
KPX b lslash -20
KPX b period -40
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX b v -20
KPX b y -20
KPX b yacute -20
KPX b ydieresis -20
KPX c comma -15
KPX c k -20
KPX c kcommaaccent -20
KPX cacute comma -15
KPX cacute k -20
KPX cacute kcommaaccent -20
KPX ccaron comma -15
KPX ccaron k -20
KPX ccaron kcommaaccent -20
KPX ccedilla comma -15
KPX ccedilla k -20
KPX ccedilla kcommaaccent -20
KPX colon space -50
KPX comma quotedblright -100
KPX comma quoteright -100
KPX e comma -15
KPX e period -15
KPX e v -30
KPX e w -20
KPX e x -30
KPX e y -20
KPX e yacute -20
KPX e ydieresis -20
KPX eacute comma -15
KPX eacute period -15
KPX eacute v -30
KPX eacute w -20
KPX eacute x -30
KPX eacute y -20
KPX eacute yacute -20
KPX eacute ydieresis -20
KPX ecaron comma -15
KPX ecaron period -15
KPX ecaron v -30
KPX ecaron w -20
KPX ecaron x -30
KPX ecaron y -20
KPX ecaron yacute -20
KPX ecaron ydieresis -20
KPX ecircumflex comma -15
KPX ecircumflex period -15
KPX ecircumflex v -30
KPX ecircumflex w -20
KPX ecircumflex x -30
KPX ecircumflex y -20
KPX ecircumflex yacute -20
KPX ecircumflex ydieresis -20
KPX edieresis comma -15
KPX edieresis period -15
KPX edieresis v -30
KPX edieresis w -20
KPX edieresis x -30
KPX edieresis y -20
KPX edieresis yacute -20
KPX edieresis ydieresis -20
KPX edotaccent comma -15
KPX edotaccent period -15
KPX edotaccent v -30
KPX edotaccent w -20
KPX edotaccent x -30
KPX edotaccent y -20
KPX edotaccent yacute -20
KPX edotaccent ydieresis -20
KPX egrave comma -15
KPX egrave period -15
KPX egrave v -30
KPX egrave w -20
KPX egrave x -30
KPX egrave y -20
KPX egrave yacute -20
KPX egrave ydieresis -20
KPX emacron comma -15
KPX emacron period -15
KPX emacron v -30
KPX emacron w -20
KPX emacron x -30
KPX emacron y -20
KPX emacron yacute -20
KPX emacron ydieresis -20
KPX eogonek comma -15
KPX eogonek period -15
KPX eogonek v -30
KPX eogonek w -20
KPX eogonek x -30
KPX eogonek y -20
KPX eogonek yacute -20
KPX eogonek ydieresis -20
KPX f a -30
KPX f aacute -30
KPX f abreve -30
KPX f acircumflex -30
KPX f adieresis -30
KPX f agrave -30
KPX f amacron -30
KPX f aogonek -30
KPX f aring -30
KPX f atilde -30
KPX f comma -30
KPX f dotlessi -28
KPX f e -30
KPX f eacute -30
KPX f ecaron -30
KPX f ecircumflex -30
KPX f edieresis -30
KPX f edotaccent -30
KPX f egrave -30
KPX f emacron -30
KPX f eogonek -30
KPX f o -30
KPX f oacute -30
KPX f ocircumflex -30
KPX f odieresis -30
KPX f ograve -30
KPX f ohungarumlaut -30
KPX f omacron -30
KPX f oslash -30
KPX f otilde -30
KPX f period -30
KPX f quotedblright 60
KPX f quoteright 50
KPX g r -10
KPX g racute -10
KPX g rcaron -10
KPX g rcommaaccent -10
KPX gbreve r -10
KPX gbreve racute -10
KPX gbreve rcaron -10
KPX gbreve rcommaaccent -10
KPX gcommaaccent r -10
KPX gcommaaccent racute -10
KPX gcommaaccent rcaron -10
KPX gcommaaccent rcommaaccent -10
KPX h y -30
KPX h yacute -30
KPX h ydieresis -30
KPX k e -20
KPX k eacute -20
KPX k ecaron -20
KPX k ecircumflex -20
KPX k edieresis -20
KPX k edotaccent -20
KPX k egrave -20
KPX k emacron -20
KPX k eogonek -20
KPX k o -20
KPX k oacute -20
KPX k ocircumflex -20
KPX k odieresis -20
KPX k ograve -20
KPX k ohungarumlaut -20
KPX k omacron -20
KPX k oslash -20
KPX k otilde -20
KPX kcommaaccent e -20
KPX kcommaaccent eacute -20
KPX kcommaaccent ecaron -20
KPX kcommaaccent ecircumflex -20
KPX kcommaaccent edieresis -20
KPX kcommaaccent edotaccent -20
KPX kcommaaccent egrave -20
KPX kcommaaccent emacron -20
KPX kcommaaccent eogonek -20
KPX kcommaaccent o -20
KPX kcommaaccent oacute -20
KPX kcommaaccent ocircumflex -20
KPX kcommaaccent odieresis -20
KPX kcommaaccent ograve -20
KPX kcommaaccent ohungarumlaut -20
KPX kcommaaccent omacron -20
KPX kcommaaccent oslash -20
KPX kcommaaccent otilde -20
KPX m u -10
KPX m uacute -10
KPX m ucircumflex -10
KPX m udieresis -10
KPX m ugrave -10
KPX m uhungarumlaut -10
KPX m umacron -10
KPX m uogonek -10
KPX m uring -10
KPX m y -15
KPX m yacute -15
KPX m ydieresis -15
KPX n u -10
KPX n uacute -10
KPX n ucircumflex -10
KPX n udieresis -10
KPX n ugrave -10
KPX n uhungarumlaut -10
KPX n umacron -10
KPX n uogonek -10
KPX n uring -10
KPX n v -20
KPX n y -15
KPX n yacute -15
KPX n ydieresis -15
KPX nacute u -10
KPX nacute uacute -10
KPX nacute ucircumflex -10
KPX nacute udieresis -10
KPX nacute ugrave -10
KPX nacute uhungarumlaut -10
KPX nacute umacron -10
KPX nacute uogonek -10
KPX nacute uring -10
KPX nacute v -20
KPX nacute y -15
KPX nacute yacute -15
KPX nacute ydieresis -15
KPX ncaron u -10
KPX ncaron uacute -10
KPX ncaron ucircumflex -10
KPX ncaron udieresis -10
KPX ncaron ugrave -10
KPX ncaron uhungarumlaut -10
KPX ncaron umacron -10
KPX ncaron uogonek -10
KPX ncaron uring -10
KPX ncaron v -20
KPX ncaron y -15
KPX ncaron yacute -15
KPX ncaron ydieresis -15
KPX ncommaaccent u -10
KPX ncommaaccent uacute -10
KPX ncommaaccent ucircumflex -10
KPX ncommaaccent udieresis -10
KPX ncommaaccent ugrave -10
KPX ncommaaccent uhungarumlaut -10
KPX ncommaaccent umacron -10
KPX ncommaaccent uogonek -10
KPX ncommaaccent uring -10
KPX ncommaaccent v -20
KPX ncommaaccent y -15
KPX ncommaaccent yacute -15
KPX ncommaaccent ydieresis -15
KPX ntilde u -10
KPX ntilde uacute -10
KPX ntilde ucircumflex -10
KPX ntilde udieresis -10
KPX ntilde ugrave -10
KPX ntilde uhungarumlaut -10
KPX ntilde umacron -10
KPX ntilde uogonek -10
KPX ntilde uring -10
KPX ntilde v -20
KPX ntilde y -15
KPX ntilde yacute -15
KPX ntilde ydieresis -15
KPX o comma -40
KPX o period -40
KPX o v -15
KPX o w -15
KPX o x -30
KPX o y -30
KPX o yacute -30
KPX o ydieresis -30
KPX oacute comma -40
KPX oacute period -40
KPX oacute v -15
KPX oacute w -15
KPX oacute x -30
KPX oacute y -30
KPX oacute yacute -30
KPX oacute ydieresis -30
KPX ocircumflex comma -40
KPX ocircumflex period -40
KPX ocircumflex v -15
KPX ocircumflex w -15
KPX ocircumflex x -30
KPX ocircumflex y -30
KPX ocircumflex yacute -30
KPX ocircumflex ydieresis -30
KPX odieresis comma -40
KPX odieresis period -40
KPX odieresis v -15
KPX odieresis w -15
KPX odieresis x -30
KPX odieresis y -30
KPX odieresis yacute -30
KPX odieresis ydieresis -30
KPX ograve comma -40
KPX ograve period -40
KPX ograve v -15
KPX ograve w -15
KPX ograve x -30
KPX ograve y -30
KPX ograve yacute -30
KPX ograve ydieresis -30
KPX ohungarumlaut comma -40
KPX ohungarumlaut period -40
KPX ohungarumlaut v -15
KPX ohungarumlaut w -15
KPX ohungarumlaut x -30
KPX ohungarumlaut y -30
KPX ohungarumlaut yacute -30
KPX ohungarumlaut ydieresis -30
KPX omacron comma -40
KPX omacron period -40
KPX omacron v -15
KPX omacron w -15
KPX omacron x -30
KPX omacron y -30
KPX omacron yacute -30
KPX omacron ydieresis -30
KPX oslash a -55
KPX oslash aacute -55
KPX oslash abreve -55
KPX oslash acircumflex -55
KPX oslash adieresis -55
KPX oslash agrave -55
KPX oslash amacron -55
KPX oslash aogonek -55
KPX oslash aring -55
KPX oslash atilde -55
KPX oslash b -55
KPX oslash c -55
KPX oslash cacute -55
KPX oslash ccaron -55
KPX oslash ccedilla -55
KPX oslash comma -95
KPX oslash d -55
KPX oslash dcroat -55
KPX oslash e -55
KPX oslash eacute -55
KPX oslash ecaron -55
KPX oslash ecircumflex -55
KPX oslash edieresis -55
KPX oslash edotaccent -55
KPX oslash egrave -55
KPX oslash emacron -55
KPX oslash eogonek -55
KPX oslash f -55
KPX oslash g -55
KPX oslash gbreve -55
KPX oslash gcommaaccent -55
KPX oslash h -55
KPX oslash i -55
KPX oslash iacute -55
KPX oslash icircumflex -55
KPX oslash idieresis -55
KPX oslash igrave -55
KPX oslash imacron -55
KPX oslash iogonek -55
KPX oslash j -55
KPX oslash k -55
KPX oslash kcommaaccent -55
KPX oslash l -55
KPX oslash lacute -55
KPX oslash lcommaaccent -55
KPX oslash lslash -55
KPX oslash m -55
KPX oslash n -55
KPX oslash nacute -55
KPX oslash ncaron -55
KPX oslash ncommaaccent -55
KPX oslash ntilde -55
KPX oslash o -55
KPX oslash oacute -55
KPX oslash ocircumflex -55
KPX oslash odieresis -55
KPX oslash ograve -55
KPX oslash ohungarumlaut -55
KPX oslash omacron -55
KPX oslash oslash -55
KPX oslash otilde -55
KPX oslash p -55
KPX oslash period -95
KPX oslash q -55
KPX oslash r -55
KPX oslash racute -55
KPX oslash rcaron -55
KPX oslash rcommaaccent -55
KPX oslash s -55
KPX oslash sacute -55
KPX oslash scaron -55
KPX oslash scedilla -55
KPX oslash scommaaccent -55
KPX oslash t -55
KPX oslash tcommaaccent -55
KPX oslash u -55
KPX oslash uacute -55
KPX oslash ucircumflex -55
KPX oslash udieresis -55
KPX oslash ugrave -55
KPX oslash uhungarumlaut -55
KPX oslash umacron -55
KPX oslash uogonek -55
KPX oslash uring -55
KPX oslash v -70
KPX oslash w -70
KPX oslash x -85
KPX oslash y -70
KPX oslash yacute -70
KPX oslash ydieresis -70
KPX oslash z -55
KPX oslash zacute -55
KPX oslash zcaron -55
KPX oslash zdotaccent -55
KPX otilde comma -40
KPX otilde period -40
KPX otilde v -15
KPX otilde w -15
KPX otilde x -30
KPX otilde y -30
KPX otilde yacute -30
KPX otilde ydieresis -30
KPX p comma -35
KPX p period -35
KPX p y -30
KPX p yacute -30
KPX p ydieresis -30
KPX period quotedblright -100
KPX period quoteright -100
KPX period space -60
KPX quotedblright space -40
KPX quoteleft quoteleft -57
KPX quoteright d -50
KPX quoteright dcroat -50
KPX quoteright quoteright -57
KPX quoteright r -50
KPX quoteright racute -50
KPX quoteright rcaron -50
KPX quoteright rcommaaccent -50
KPX quoteright s -50
KPX quoteright sacute -50
KPX quoteright scaron -50
KPX quoteright scedilla -50
KPX quoteright scommaaccent -50
KPX quoteright space -70
KPX r a -10
KPX r aacute -10
KPX r abreve -10
KPX r acircumflex -10
KPX r adieresis -10
KPX r agrave -10
KPX r amacron -10
KPX r aogonek -10
KPX r aring -10
KPX r atilde -10
KPX r colon 30
KPX r comma -50
KPX r i 15
KPX r iacute 15
KPX r icircumflex 15
KPX r idieresis 15
KPX r igrave 15
KPX r imacron 15
KPX r iogonek 15
KPX r k 15
KPX r kcommaaccent 15
KPX r l 15
KPX r lacute 15
KPX r lcommaaccent 15
KPX r lslash 15
KPX r m 25
KPX r n 25
KPX r nacute 25
KPX r ncaron 25
KPX r ncommaaccent 25
KPX r ntilde 25
KPX r p 30
KPX r period -50
KPX r semicolon 30
KPX r t 40
KPX r tcommaaccent 40
KPX r u 15
KPX r uacute 15
KPX r ucircumflex 15
KPX r udieresis 15
KPX r ugrave 15
KPX r uhungarumlaut 15
KPX r umacron 15
KPX r uogonek 15
KPX r uring 15
KPX r v 30
KPX r y 30
KPX r yacute 30
KPX r ydieresis 30
KPX racute a -10
KPX racute aacute -10
KPX racute abreve -10
KPX racute acircumflex -10
KPX racute adieresis -10
KPX racute agrave -10
KPX racute amacron -10
KPX racute aogonek -10
KPX racute aring -10
KPX racute atilde -10
KPX racute colon 30
KPX racute comma -50
KPX racute i 15
KPX racute iacute 15
KPX racute icircumflex 15
KPX racute idieresis 15
KPX racute igrave 15
KPX racute imacron 15
KPX racute iogonek 15
KPX racute k 15
KPX racute kcommaaccent 15
KPX racute l 15
KPX racute lacute 15
KPX racute lcommaaccent 15
KPX racute lslash 15
KPX racute m 25
KPX racute n 25
KPX racute nacute 25
KPX racute ncaron 25
KPX racute ncommaaccent 25
KPX racute ntilde 25
KPX racute p 30
KPX racute period -50
KPX racute semicolon 30
KPX racute t 40
KPX racute tcommaaccent 40
KPX racute u 15
KPX racute uacute 15
KPX racute ucircumflex 15
KPX racute udieresis 15
KPX racute ugrave 15
KPX racute uhungarumlaut 15
KPX racute umacron 15
KPX racute uogonek 15
KPX racute uring 15
KPX racute v 30
KPX racute y 30
KPX racute yacute 30
KPX racute ydieresis 30
KPX rcaron a -10
KPX rcaron aacute -10
KPX rcaron abreve -10
KPX rcaron acircumflex -10
KPX rcaron adieresis -10
KPX rcaron agrave -10
KPX rcaron amacron -10
KPX rcaron aogonek -10
KPX rcaron aring -10
KPX rcaron atilde -10
KPX rcaron colon 30
KPX rcaron comma -50
KPX rcaron i 15
KPX rcaron iacute 15
KPX rcaron icircumflex 15
KPX rcaron idieresis 15
KPX rcaron igrave 15
KPX rcaron imacron 15
KPX rcaron iogonek 15
KPX rcaron k 15
KPX rcaron kcommaaccent 15
KPX rcaron l 15
KPX rcaron lacute 15
KPX rcaron lcommaaccent 15
KPX rcaron lslash 15
KPX rcaron m 25
KPX rcaron n 25
KPX rcaron nacute 25
KPX rcaron ncaron 25
KPX rcaron ncommaaccent 25
KPX rcaron ntilde 25
KPX rcaron p 30
KPX rcaron period -50
KPX rcaron semicolon 30
KPX rcaron t 40
KPX rcaron tcommaaccent 40
KPX rcaron u 15
KPX rcaron uacute 15
KPX rcaron ucircumflex 15
KPX rcaron udieresis 15
KPX rcaron ugrave 15
KPX rcaron uhungarumlaut 15
KPX rcaron umacron 15
KPX rcaron uogonek 15
KPX rcaron uring 15
KPX rcaron v 30
KPX rcaron y 30
KPX rcaron yacute 30
KPX rcaron ydieresis 30
KPX rcommaaccent a -10
KPX rcommaaccent aacute -10
KPX rcommaaccent abreve -10
KPX rcommaaccent acircumflex -10
KPX rcommaaccent adieresis -10
KPX rcommaaccent agrave -10
KPX rcommaaccent amacron -10
KPX rcommaaccent aogonek -10
KPX rcommaaccent aring -10
KPX rcommaaccent atilde -10
KPX rcommaaccent colon 30
KPX rcommaaccent comma -50
KPX rcommaaccent i 15
KPX rcommaaccent iacute 15
KPX rcommaaccent icircumflex 15
KPX rcommaaccent idieresis 15
KPX rcommaaccent igrave 15
KPX rcommaaccent imacron 15
KPX rcommaaccent iogonek 15
KPX rcommaaccent k 15
KPX rcommaaccent kcommaaccent 15
KPX rcommaaccent l 15
KPX rcommaaccent lacute 15
KPX rcommaaccent lcommaaccent 15
KPX rcommaaccent lslash 15
KPX rcommaaccent m 25
KPX rcommaaccent n 25
KPX rcommaaccent nacute 25
KPX rcommaaccent ncaron 25
KPX rcommaaccent ncommaaccent 25
KPX rcommaaccent ntilde 25
KPX rcommaaccent p 30
KPX rcommaaccent period -50
KPX rcommaaccent semicolon 30
KPX rcommaaccent t 40
KPX rcommaaccent tcommaaccent 40
KPX rcommaaccent u 15
KPX rcommaaccent uacute 15
KPX rcommaaccent ucircumflex 15
KPX rcommaaccent udieresis 15
KPX rcommaaccent ugrave 15
KPX rcommaaccent uhungarumlaut 15
KPX rcommaaccent umacron 15
KPX rcommaaccent uogonek 15
KPX rcommaaccent uring 15
KPX rcommaaccent v 30
KPX rcommaaccent y 30
KPX rcommaaccent yacute 30
KPX rcommaaccent ydieresis 30
KPX s comma -15
KPX s period -15
KPX s w -30
KPX sacute comma -15
KPX sacute period -15
KPX sacute w -30
KPX scaron comma -15
KPX scaron period -15
KPX scaron w -30
KPX scedilla comma -15
KPX scedilla period -15
KPX scedilla w -30
KPX scommaaccent comma -15
KPX scommaaccent period -15
KPX scommaaccent w -30
KPX semicolon space -50
KPX space T -50
KPX space Tcaron -50
KPX space Tcommaaccent -50
KPX space V -50
KPX space W -40
KPX space Y -90
KPX space Yacute -90
KPX space Ydieresis -90
KPX space quotedblleft -30
KPX space quoteleft -60
KPX v a -25
KPX v aacute -25
KPX v abreve -25
KPX v acircumflex -25
KPX v adieresis -25
KPX v agrave -25
KPX v amacron -25
KPX v aogonek -25
KPX v aring -25
KPX v atilde -25
KPX v comma -80
KPX v e -25
KPX v eacute -25
KPX v ecaron -25
KPX v ecircumflex -25
KPX v edieresis -25
KPX v edotaccent -25
KPX v egrave -25
KPX v emacron -25
KPX v eogonek -25
KPX v o -25
KPX v oacute -25
KPX v ocircumflex -25
KPX v odieresis -25
KPX v ograve -25
KPX v ohungarumlaut -25
KPX v omacron -25
KPX v oslash -25
KPX v otilde -25
KPX v period -80
KPX w a -15
KPX w aacute -15
KPX w abreve -15
KPX w acircumflex -15
KPX w adieresis -15
KPX w agrave -15
KPX w amacron -15
KPX w aogonek -15
KPX w aring -15
KPX w atilde -15
KPX w comma -60
KPX w e -10
KPX w eacute -10
KPX w ecaron -10
KPX w ecircumflex -10
KPX w edieresis -10
KPX w edotaccent -10
KPX w egrave -10
KPX w emacron -10
KPX w eogonek -10
KPX w o -10
KPX w oacute -10
KPX w ocircumflex -10
KPX w odieresis -10
KPX w ograve -10
KPX w ohungarumlaut -10
KPX w omacron -10
KPX w oslash -10
KPX w otilde -10
KPX w period -60
KPX x e -30
KPX x eacute -30
KPX x ecaron -30
KPX x ecircumflex -30
KPX x edieresis -30
KPX x edotaccent -30
KPX x egrave -30
KPX x emacron -30
KPX x eogonek -30
KPX y a -20
KPX y aacute -20
KPX y abreve -20
KPX y acircumflex -20
KPX y adieresis -20
KPX y agrave -20
KPX y amacron -20
KPX y aogonek -20
KPX y aring -20
KPX y atilde -20
KPX y comma -100
KPX y e -20
KPX y eacute -20
KPX y ecaron -20
KPX y ecircumflex -20
KPX y edieresis -20
KPX y edotaccent -20
KPX y egrave -20
KPX y emacron -20
KPX y eogonek -20
KPX y o -20
KPX y oacute -20
KPX y ocircumflex -20
KPX y odieresis -20
KPX y ograve -20
KPX y ohungarumlaut -20
KPX y omacron -20
KPX y oslash -20
KPX y otilde -20
KPX y period -100
KPX yacute a -20
KPX yacute aacute -20
KPX yacute abreve -20
KPX yacute acircumflex -20
KPX yacute adieresis -20
KPX yacute agrave -20
KPX yacute amacron -20
KPX yacute aogonek -20
KPX yacute aring -20
KPX yacute atilde -20
KPX yacute comma -100
KPX yacute e -20
KPX yacute eacute -20
KPX yacute ecaron -20
KPX yacute ecircumflex -20
KPX yacute edieresis -20
KPX yacute edotaccent -20
KPX yacute egrave -20
KPX yacute emacron -20
KPX yacute eogonek -20
KPX yacute o -20
KPX yacute oacute -20
KPX yacute ocircumflex -20
KPX yacute odieresis -20
KPX yacute ograve -20
KPX yacute ohungarumlaut -20
KPX yacute omacron -20
KPX yacute oslash -20
KPX yacute otilde -20
KPX yacute period -100
KPX ydieresis a -20
KPX ydieresis aacute -20
KPX ydieresis abreve -20
KPX ydieresis acircumflex -20
KPX ydieresis adieresis -20
KPX ydieresis agrave -20
KPX ydieresis amacron -20
KPX ydieresis aogonek -20
KPX ydieresis aring -20
KPX ydieresis atilde -20
KPX ydieresis comma -100
KPX ydieresis e -20
KPX ydieresis eacute -20
KPX ydieresis ecaron -20
KPX ydieresis ecircumflex -20
KPX ydieresis edieresis -20
KPX ydieresis edotaccent -20
KPX ydieresis egrave -20
KPX ydieresis emacron -20
KPX ydieresis eogonek -20
KPX ydieresis o -20
KPX ydieresis oacute -20
KPX ydieresis ocircumflex -20
KPX ydieresis odieresis -20
KPX ydieresis ograve -20
KPX ydieresis ohungarumlaut -20
KPX ydieresis omacron -20
KPX ydieresis oslash -20
KPX ydieresis otilde -20
KPX ydieresis period -100
KPX z e -15
KPX z eacute -15
KPX z ecaron -15
KPX z ecircumflex -15
KPX z edieresis -15
KPX z edotaccent -15
KPX z egrave -15
KPX z emacron -15
KPX z eogonek -15
KPX z o -15
KPX z oacute -15
KPX z ocircumflex -15
KPX z odieresis -15
KPX z ograve -15
KPX z ohungarumlaut -15
KPX z omacron -15
KPX z oslash -15
KPX z otilde -15
KPX zacute e -15
KPX zacute eacute -15
KPX zacute ecaron -15
KPX zacute ecircumflex -15
KPX zacute edieresis -15
KPX zacute edotaccent -15
KPX zacute egrave -15
KPX zacute emacron -15
KPX zacute eogonek -15
KPX zacute o -15
KPX zacute oacute -15
KPX zacute ocircumflex -15
KPX zacute odieresis -15
KPX zacute ograve -15
KPX zacute ohungarumlaut -15
KPX zacute omacron -15
KPX zacute oslash -15
KPX zacute otilde -15
KPX zcaron e -15
KPX zcaron eacute -15
KPX zcaron ecaron -15
KPX zcaron ecircumflex -15
KPX zcaron edieresis -15
KPX zcaron edotaccent -15
KPX zcaron egrave -15
KPX zcaron emacron -15
KPX zcaron eogonek -15
KPX zcaron o -15
KPX zcaron oacute -15
KPX zcaron ocircumflex -15
KPX zcaron odieresis -15
KPX zcaron ograve -15
KPX zcaron ohungarumlaut -15
KPX zcaron omacron -15
KPX zcaron oslash -15
KPX zcaron otilde -15
KPX zdotaccent e -15
KPX zdotaccent eacute -15
KPX zdotaccent ecaron -15
KPX zdotaccent ecircumflex -15
KPX zdotaccent edieresis -15
KPX zdotaccent edotaccent -15
KPX zdotaccent egrave -15
KPX zdotaccent emacron -15
KPX zdotaccent eogonek -15
KPX zdotaccent o -15
KPX zdotaccent oacute -15
KPX zdotaccent ocircumflex -15
KPX zdotaccent odieresis -15
KPX zdotaccent ograve -15
KPX zdotaccent ohungarumlaut -15
KPX zdotaccent omacron -15
KPX zdotaccent oslash -15
KPX zdotaccent otilde -15
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Times-Bold.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:52:56 1997
Comment UniqueID 43065
Comment VMusage 41636 52661
FontName Times-Bold
FullName Times Bold
FamilyName Times
Weight Bold
ItalicAngle 0
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -168 -218 1000 935
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 676
XHeight 461
Ascender 683
Descender -217
StdHW 44
StdVW 139
StartCharMetrics 315
C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
C 33 ; WX 333 ; N exclam ; B 81 -13 251 691 ;
C 34 ; WX 555 ; N quotedbl ; B 83 404 472 691 ;
C 35 ; WX 500 ; N numbersign ; B 4 0 496 700 ;
C 36 ; WX 500 ; N dollar ; B 29 -99 472 750 ;
C 37 ; WX 1000 ; N percent ; B 124 -14 877 692 ;
C 38 ; WX 833 ; N ampersand ; B 62 -16 787 691 ;
C 39 ; WX 333 ; N quoteright ; B 79 356 263 691 ;
C 40 ; WX 333 ; N parenleft ; B 46 -168 306 694 ;
C 41 ; WX 333 ; N parenright ; B 27 -168 287 694 ;
C 42 ; WX 500 ; N asterisk ; B 56 255 447 691 ;
C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
C 44 ; WX 250 ; N comma ; B 39 -180 223 155 ;
C 45 ; WX 333 ; N hyphen ; B 44 171 287 287 ;
C 46 ; WX 250 ; N period ; B 41 -13 210 156 ;
C 47 ; WX 278 ; N slash ; B -24 -19 302 691 ;
C 48 ; WX 500 ; N zero ; B 24 -13 476 688 ;
C 49 ; WX 500 ; N one ; B 65 0 442 688 ;
C 50 ; WX 500 ; N two ; B 17 0 478 688 ;
C 51 ; WX 500 ; N three ; B 16 -14 468 688 ;
C 52 ; WX 500 ; N four ; B 19 0 475 688 ;
C 53 ; WX 500 ; N five ; B 22 -8 470 676 ;
C 54 ; WX 500 ; N six ; B 28 -13 475 688 ;
C 55 ; WX 500 ; N seven ; B 17 0 477 676 ;
C 56 ; WX 500 ; N eight ; B 28 -13 472 688 ;
C 57 ; WX 500 ; N nine ; B 26 -13 473 688 ;
C 58 ; WX 333 ; N colon ; B 82 -13 251 472 ;
C 59 ; WX 333 ; N semicolon ; B 82 -180 266 472 ;
C 60 ; WX 570 ; N less ; B 31 -8 539 514 ;
C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ;
C 63 ; WX 500 ; N question ; B 57 -13 445 689 ;
C 64 ; WX 930 ; N at ; B 108 -19 822 691 ;
C 65 ; WX 722 ; N A ; B 9 0 689 690 ;
C 66 ; WX 667 ; N B ; B 16 0 619 676 ;
C 67 ; WX 722 ; N C ; B 49 -19 687 691 ;
C 68 ; WX 722 ; N D ; B 14 0 690 676 ;
C 69 ; WX 667 ; N E ; B 16 0 641 676 ;
C 70 ; WX 611 ; N F ; B 16 0 583 676 ;
C 71 ; WX 778 ; N G ; B 37 -19 755 691 ;
C 72 ; WX 778 ; N H ; B 21 0 759 676 ;
C 73 ; WX 389 ; N I ; B 20 0 370 676 ;
C 74 ; WX 500 ; N J ; B 3 -96 479 676 ;
C 75 ; WX 778 ; N K ; B 30 0 769 676 ;
C 76 ; WX 667 ; N L ; B 19 0 638 676 ;
C 77 ; WX 944 ; N M ; B 14 0 921 676 ;
C 78 ; WX 722 ; N N ; B 16 -18 701 676 ;
C 79 ; WX 778 ; N O ; B 35 -19 743 691 ;
C 80 ; WX 611 ; N P ; B 16 0 600 676 ;
C 81 ; WX 778 ; N Q ; B 35 -176 743 691 ;
C 82 ; WX 722 ; N R ; B 26 0 715 676 ;
C 83 ; WX 556 ; N S ; B 35 -19 513 692 ;
C 84 ; WX 667 ; N T ; B 31 0 636 676 ;
C 85 ; WX 722 ; N U ; B 16 -19 701 676 ;
C 86 ; WX 722 ; N V ; B 16 -18 701 676 ;
C 87 ; WX 1000 ; N W ; B 19 -15 981 676 ;
C 88 ; WX 722 ; N X ; B 16 0 699 676 ;
C 89 ; WX 722 ; N Y ; B 15 0 699 676 ;
C 90 ; WX 667 ; N Z ; B 28 0 634 676 ;
C 91 ; WX 333 ; N bracketleft ; B 67 -149 301 678 ;
C 92 ; WX 278 ; N backslash ; B -25 -19 303 691 ;
C 93 ; WX 333 ; N bracketright ; B 32 -149 266 678 ;
C 94 ; WX 581 ; N asciicircum ; B 73 311 509 676 ;
C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
C 96 ; WX 333 ; N quoteleft ; B 70 356 254 691 ;
C 97 ; WX 500 ; N a ; B 25 -14 488 473 ;
C 98 ; WX 556 ; N b ; B 17 -14 521 676 ;
C 99 ; WX 444 ; N c ; B 25 -14 430 473 ;
C 100 ; WX 556 ; N d ; B 25 -14 534 676 ;
C 101 ; WX 444 ; N e ; B 25 -14 426 473 ;
C 102 ; WX 333 ; N f ; B 14 0 389 691 ; L i fi ; L l fl ;
C 103 ; WX 500 ; N g ; B 28 -206 483 473 ;
C 104 ; WX 556 ; N h ; B 16 0 534 676 ;
C 105 ; WX 278 ; N i ; B 16 0 255 691 ;
C 106 ; WX 333 ; N j ; B -57 -203 263 691 ;
C 107 ; WX 556 ; N k ; B 22 0 543 676 ;
C 108 ; WX 278 ; N l ; B 16 0 255 676 ;
C 109 ; WX 833 ; N m ; B 16 0 814 473 ;
C 110 ; WX 556 ; N n ; B 21 0 539 473 ;
C 111 ; WX 500 ; N o ; B 25 -14 476 473 ;
C 112 ; WX 556 ; N p ; B 19 -205 524 473 ;
C 113 ; WX 556 ; N q ; B 34 -205 536 473 ;
C 114 ; WX 444 ; N r ; B 29 0 434 473 ;
C 115 ; WX 389 ; N s ; B 25 -14 361 473 ;
C 116 ; WX 333 ; N t ; B 20 -12 332 630 ;
C 117 ; WX 556 ; N u ; B 16 -14 537 461 ;
C 118 ; WX 500 ; N v ; B 21 -14 485 461 ;
C 119 ; WX 722 ; N w ; B 23 -14 707 461 ;
C 120 ; WX 500 ; N x ; B 12 0 484 461 ;
C 121 ; WX 500 ; N y ; B 16 -205 480 461 ;
C 122 ; WX 444 ; N z ; B 21 0 420 461 ;
C 123 ; WX 394 ; N braceleft ; B 22 -175 340 698 ;
C 124 ; WX 220 ; N bar ; B 66 -218 154 782 ;
C 125 ; WX 394 ; N braceright ; B 54 -175 372 698 ;
C 126 ; WX 520 ; N asciitilde ; B 29 173 491 333 ;
C 161 ; WX 333 ; N exclamdown ; B 82 -203 252 501 ;
C 162 ; WX 500 ; N cent ; B 53 -140 458 588 ;
C 163 ; WX 500 ; N sterling ; B 21 -14 477 684 ;
C 164 ; WX 167 ; N fraction ; B -168 -12 329 688 ;
C 165 ; WX 500 ; N yen ; B -64 0 547 676 ;
C 166 ; WX 500 ; N florin ; B 0 -155 498 706 ;
C 167 ; WX 500 ; N section ; B 57 -132 443 691 ;
C 168 ; WX 500 ; N currency ; B -26 61 526 613 ;
C 169 ; WX 278 ; N quotesingle ; B 75 404 204 691 ;
C 170 ; WX 500 ; N quotedblleft ; B 32 356 486 691 ;
C 171 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ;
C 172 ; WX 333 ; N guilsinglleft ; B 51 36 305 415 ;
C 173 ; WX 333 ; N guilsinglright ; B 28 36 282 415 ;
C 174 ; WX 556 ; N fi ; B 14 0 536 691 ;
C 175 ; WX 556 ; N fl ; B 14 0 536 691 ;
C 177 ; WX 500 ; N endash ; B 0 181 500 271 ;
C 178 ; WX 500 ; N dagger ; B 47 -134 453 691 ;
C 179 ; WX 500 ; N daggerdbl ; B 45 -132 456 691 ;
C 180 ; WX 250 ; N periodcentered ; B 41 248 210 417 ;
C 182 ; WX 540 ; N paragraph ; B 0 -186 519 676 ;
C 183 ; WX 350 ; N bullet ; B 35 198 315 478 ;
C 184 ; WX 333 ; N quotesinglbase ; B 79 -180 263 155 ;
C 185 ; WX 500 ; N quotedblbase ; B 14 -180 468 155 ;
C 186 ; WX 500 ; N quotedblright ; B 14 356 468 691 ;
C 187 ; WX 500 ; N guillemotright ; B 27 36 477 415 ;
C 188 ; WX 1000 ; N ellipsis ; B 82 -13 917 156 ;
C 189 ; WX 1000 ; N perthousand ; B 7 -29 995 706 ;
C 191 ; WX 500 ; N questiondown ; B 55 -201 443 501 ;
C 193 ; WX 333 ; N grave ; B 8 528 246 713 ;
C 194 ; WX 333 ; N acute ; B 86 528 324 713 ;
C 195 ; WX 333 ; N circumflex ; B -2 528 335 704 ;
C 196 ; WX 333 ; N tilde ; B -16 547 349 674 ;
C 197 ; WX 333 ; N macron ; B 1 565 331 637 ;
C 198 ; WX 333 ; N breve ; B 15 528 318 691 ;
C 199 ; WX 333 ; N dotaccent ; B 103 536 258 691 ;
C 200 ; WX 333 ; N dieresis ; B -2 537 335 667 ;
C 202 ; WX 333 ; N ring ; B 60 527 273 740 ;
C 203 ; WX 333 ; N cedilla ; B 68 -218 294 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B -13 528 425 713 ;
C 206 ; WX 333 ; N ogonek ; B 90 -193 319 24 ;
C 207 ; WX 333 ; N caron ; B -2 528 335 704 ;
C 208 ; WX 1000 ; N emdash ; B 0 181 1000 271 ;
C 225 ; WX 1000 ; N AE ; B 4 0 951 676 ;
C 227 ; WX 300 ; N ordfeminine ; B -1 397 301 688 ;
C 232 ; WX 667 ; N Lslash ; B 19 0 638 676 ;
C 233 ; WX 778 ; N Oslash ; B 35 -74 743 737 ;
C 234 ; WX 1000 ; N OE ; B 22 -5 981 684 ;
C 235 ; WX 330 ; N ordmasculine ; B 18 397 312 688 ;
C 241 ; WX 722 ; N ae ; B 33 -14 693 473 ;
C 245 ; WX 278 ; N dotlessi ; B 16 0 255 461 ;
C 248 ; WX 278 ; N lslash ; B -22 0 303 676 ;
C 249 ; WX 500 ; N oslash ; B 25 -92 476 549 ;
C 250 ; WX 722 ; N oe ; B 22 -14 696 473 ;
C 251 ; WX 556 ; N germandbls ; B 19 -12 517 691 ;
C -1 ; WX 389 ; N Idieresis ; B 20 0 370 877 ;
C -1 ; WX 444 ; N eacute ; B 25 -14 426 713 ;
C -1 ; WX 500 ; N abreve ; B 25 -14 488 691 ;
C -1 ; WX 556 ; N uhungarumlaut ; B 16 -14 557 713 ;
C -1 ; WX 444 ; N ecaron ; B 25 -14 426 704 ;
C -1 ; WX 722 ; N Ydieresis ; B 15 0 699 877 ;
C -1 ; WX 570 ; N divide ; B 33 -31 537 537 ;
C -1 ; WX 722 ; N Yacute ; B 15 0 699 923 ;
C -1 ; WX 722 ; N Acircumflex ; B 9 0 689 914 ;
C -1 ; WX 500 ; N aacute ; B 25 -14 488 713 ;
C -1 ; WX 722 ; N Ucircumflex ; B 16 -19 701 914 ;
C -1 ; WX 500 ; N yacute ; B 16 -205 480 713 ;
C -1 ; WX 389 ; N scommaaccent ; B 25 -218 361 473 ;
C -1 ; WX 444 ; N ecircumflex ; B 25 -14 426 704 ;
C -1 ; WX 722 ; N Uring ; B 16 -19 701 935 ;
C -1 ; WX 722 ; N Udieresis ; B 16 -19 701 877 ;
C -1 ; WX 500 ; N aogonek ; B 25 -193 504 473 ;
C -1 ; WX 722 ; N Uacute ; B 16 -19 701 923 ;
C -1 ; WX 556 ; N uogonek ; B 16 -193 539 461 ;
C -1 ; WX 667 ; N Edieresis ; B 16 0 641 877 ;
C -1 ; WX 722 ; N Dcroat ; B 6 0 690 676 ;
C -1 ; WX 250 ; N commaaccent ; B 47 -218 203 -50 ;
C -1 ; WX 747 ; N copyright ; B 26 -19 721 691 ;
C -1 ; WX 667 ; N Emacron ; B 16 0 641 847 ;
C -1 ; WX 444 ; N ccaron ; B 25 -14 430 704 ;
C -1 ; WX 500 ; N aring ; B 25 -14 488 740 ;
C -1 ; WX 722 ; N Ncommaaccent ; B 16 -188 701 676 ;
C -1 ; WX 278 ; N lacute ; B 16 0 297 923 ;
C -1 ; WX 500 ; N agrave ; B 25 -14 488 713 ;
C -1 ; WX 667 ; N Tcommaaccent ; B 31 -218 636 676 ;
C -1 ; WX 722 ; N Cacute ; B 49 -19 687 923 ;
C -1 ; WX 500 ; N atilde ; B 25 -14 488 674 ;
C -1 ; WX 667 ; N Edotaccent ; B 16 0 641 901 ;
C -1 ; WX 389 ; N scaron ; B 25 -14 363 704 ;
C -1 ; WX 389 ; N scedilla ; B 25 -218 361 473 ;
C -1 ; WX 278 ; N iacute ; B 16 0 289 713 ;
C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ;
C -1 ; WX 722 ; N Rcaron ; B 26 0 715 914 ;
C -1 ; WX 778 ; N Gcommaaccent ; B 37 -218 755 691 ;
C -1 ; WX 556 ; N ucircumflex ; B 16 -14 537 704 ;
C -1 ; WX 500 ; N acircumflex ; B 25 -14 488 704 ;
C -1 ; WX 722 ; N Amacron ; B 9 0 689 847 ;
C -1 ; WX 444 ; N rcaron ; B 29 0 434 704 ;
C -1 ; WX 444 ; N ccedilla ; B 25 -218 430 473 ;
C -1 ; WX 667 ; N Zdotaccent ; B 28 0 634 901 ;
C -1 ; WX 611 ; N Thorn ; B 16 0 600 676 ;
C -1 ; WX 778 ; N Omacron ; B 35 -19 743 847 ;
C -1 ; WX 722 ; N Racute ; B 26 0 715 923 ;
C -1 ; WX 556 ; N Sacute ; B 35 -19 513 923 ;
C -1 ; WX 672 ; N dcaron ; B 25 -14 681 682 ;
C -1 ; WX 722 ; N Umacron ; B 16 -19 701 847 ;
C -1 ; WX 556 ; N uring ; B 16 -14 537 740 ;
C -1 ; WX 300 ; N threesuperior ; B 3 268 297 688 ;
C -1 ; WX 778 ; N Ograve ; B 35 -19 743 923 ;
C -1 ; WX 722 ; N Agrave ; B 9 0 689 923 ;
C -1 ; WX 722 ; N Abreve ; B 9 0 689 901 ;
C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
C -1 ; WX 556 ; N uacute ; B 16 -14 537 713 ;
C -1 ; WX 667 ; N Tcaron ; B 31 0 636 914 ;
C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ;
C -1 ; WX 500 ; N ydieresis ; B 16 -205 480 667 ;
C -1 ; WX 722 ; N Nacute ; B 16 -18 701 923 ;
C -1 ; WX 278 ; N icircumflex ; B -37 0 300 704 ;
C -1 ; WX 667 ; N Ecircumflex ; B 16 0 641 914 ;
C -1 ; WX 500 ; N adieresis ; B 25 -14 488 667 ;
C -1 ; WX 444 ; N edieresis ; B 25 -14 426 667 ;
C -1 ; WX 444 ; N cacute ; B 25 -14 430 713 ;
C -1 ; WX 556 ; N nacute ; B 21 0 539 713 ;
C -1 ; WX 556 ; N umacron ; B 16 -14 537 637 ;
C -1 ; WX 722 ; N Ncaron ; B 16 -18 701 914 ;
C -1 ; WX 389 ; N Iacute ; B 20 0 370 923 ;
C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ;
C -1 ; WX 220 ; N brokenbar ; B 66 -143 154 707 ;
C -1 ; WX 747 ; N registered ; B 26 -19 721 691 ;
C -1 ; WX 778 ; N Gbreve ; B 37 -19 755 901 ;
C -1 ; WX 389 ; N Idotaccent ; B 20 0 370 901 ;
C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ;
C -1 ; WX 667 ; N Egrave ; B 16 0 641 923 ;
C -1 ; WX 444 ; N racute ; B 29 0 434 713 ;
C -1 ; WX 500 ; N omacron ; B 25 -14 476 637 ;
C -1 ; WX 667 ; N Zacute ; B 28 0 634 923 ;
C -1 ; WX 667 ; N Zcaron ; B 28 0 634 914 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ;
C -1 ; WX 722 ; N Eth ; B 6 0 690 676 ;
C -1 ; WX 722 ; N Ccedilla ; B 49 -218 687 691 ;
C -1 ; WX 278 ; N lcommaaccent ; B 16 -218 255 676 ;
C -1 ; WX 416 ; N tcaron ; B 20 -12 425 815 ;
C -1 ; WX 444 ; N eogonek ; B 25 -193 426 473 ;
C -1 ; WX 722 ; N Uogonek ; B 16 -193 701 676 ;
C -1 ; WX 722 ; N Aacute ; B 9 0 689 923 ;
C -1 ; WX 722 ; N Adieresis ; B 9 0 689 877 ;
C -1 ; WX 444 ; N egrave ; B 25 -14 426 713 ;
C -1 ; WX 444 ; N zacute ; B 21 0 420 713 ;
C -1 ; WX 278 ; N iogonek ; B 16 -193 274 691 ;
C -1 ; WX 778 ; N Oacute ; B 35 -19 743 923 ;
C -1 ; WX 500 ; N oacute ; B 25 -14 476 713 ;
C -1 ; WX 500 ; N amacron ; B 25 -14 488 637 ;
C -1 ; WX 389 ; N sacute ; B 25 -14 361 713 ;
C -1 ; WX 278 ; N idieresis ; B -37 0 300 667 ;
C -1 ; WX 778 ; N Ocircumflex ; B 35 -19 743 914 ;
C -1 ; WX 722 ; N Ugrave ; B 16 -19 701 923 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 556 ; N thorn ; B 19 -205 524 676 ;
C -1 ; WX 300 ; N twosuperior ; B 0 275 300 688 ;
C -1 ; WX 778 ; N Odieresis ; B 35 -19 743 877 ;
C -1 ; WX 556 ; N mu ; B 33 -206 536 461 ;
C -1 ; WX 278 ; N igrave ; B -27 0 255 713 ;
C -1 ; WX 500 ; N ohungarumlaut ; B 25 -14 529 713 ;
C -1 ; WX 667 ; N Eogonek ; B 16 -193 644 676 ;
C -1 ; WX 556 ; N dcroat ; B 25 -14 534 676 ;
C -1 ; WX 750 ; N threequarters ; B 23 -12 733 688 ;
C -1 ; WX 556 ; N Scedilla ; B 35 -218 513 692 ;
C -1 ; WX 394 ; N lcaron ; B 16 0 412 682 ;
C -1 ; WX 778 ; N Kcommaaccent ; B 30 -218 769 676 ;
C -1 ; WX 667 ; N Lacute ; B 19 0 638 923 ;
C -1 ; WX 1000 ; N trademark ; B 24 271 977 676 ;
C -1 ; WX 444 ; N edotaccent ; B 25 -14 426 691 ;
C -1 ; WX 389 ; N Igrave ; B 20 0 370 923 ;
C -1 ; WX 389 ; N Imacron ; B 20 0 370 847 ;
C -1 ; WX 667 ; N Lcaron ; B 19 0 652 682 ;
C -1 ; WX 750 ; N onehalf ; B -7 -12 775 688 ;
C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ;
C -1 ; WX 500 ; N ocircumflex ; B 25 -14 476 704 ;
C -1 ; WX 556 ; N ntilde ; B 21 0 539 674 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 16 -19 701 923 ;
C -1 ; WX 667 ; N Eacute ; B 16 0 641 923 ;
C -1 ; WX 444 ; N emacron ; B 25 -14 426 637 ;
C -1 ; WX 500 ; N gbreve ; B 28 -206 483 691 ;
C -1 ; WX 750 ; N onequarter ; B 28 -12 743 688 ;
C -1 ; WX 556 ; N Scaron ; B 35 -19 513 914 ;
C -1 ; WX 556 ; N Scommaaccent ; B 35 -218 513 692 ;
C -1 ; WX 778 ; N Ohungarumlaut ; B 35 -19 743 923 ;
C -1 ; WX 400 ; N degree ; B 57 402 343 688 ;
C -1 ; WX 500 ; N ograve ; B 25 -14 476 713 ;
C -1 ; WX 722 ; N Ccaron ; B 49 -19 687 914 ;
C -1 ; WX 556 ; N ugrave ; B 16 -14 537 713 ;
C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ;
C -1 ; WX 722 ; N Dcaron ; B 14 0 690 914 ;
C -1 ; WX 444 ; N rcommaaccent ; B 29 -218 434 473 ;
C -1 ; WX 722 ; N Ntilde ; B 16 -18 701 884 ;
C -1 ; WX 500 ; N otilde ; B 25 -14 476 674 ;
C -1 ; WX 722 ; N Rcommaaccent ; B 26 -218 715 676 ;
C -1 ; WX 667 ; N Lcommaaccent ; B 19 -218 638 676 ;
C -1 ; WX 722 ; N Atilde ; B 9 0 689 884 ;
C -1 ; WX 722 ; N Aogonek ; B 9 -193 699 690 ;
C -1 ; WX 722 ; N Aring ; B 9 0 689 935 ;
C -1 ; WX 778 ; N Otilde ; B 35 -19 743 884 ;
C -1 ; WX 444 ; N zdotaccent ; B 21 0 420 691 ;
C -1 ; WX 667 ; N Ecaron ; B 16 0 641 914 ;
C -1 ; WX 389 ; N Iogonek ; B 20 -193 370 676 ;
C -1 ; WX 556 ; N kcommaaccent ; B 22 -218 543 676 ;
C -1 ; WX 570 ; N minus ; B 33 209 537 297 ;
C -1 ; WX 389 ; N Icircumflex ; B 20 0 370 914 ;
C -1 ; WX 556 ; N ncaron ; B 21 0 539 704 ;
C -1 ; WX 333 ; N tcommaaccent ; B 20 -218 332 630 ;
C -1 ; WX 570 ; N logicalnot ; B 33 108 537 399 ;
C -1 ; WX 500 ; N odieresis ; B 25 -14 476 667 ;
C -1 ; WX 556 ; N udieresis ; B 16 -14 537 667 ;
C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ;
C -1 ; WX 500 ; N gcommaaccent ; B 28 -206 483 829 ;
C -1 ; WX 500 ; N eth ; B 25 -14 476 691 ;
C -1 ; WX 444 ; N zcaron ; B 21 0 420 704 ;
C -1 ; WX 556 ; N ncommaaccent ; B 21 -218 539 473 ;
C -1 ; WX 300 ; N onesuperior ; B 28 275 273 688 ;
C -1 ; WX 278 ; N imacron ; B -8 0 272 637 ;
C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2242
KPX A C -55
KPX A Cacute -55
KPX A Ccaron -55
KPX A Ccedilla -55
KPX A G -55
KPX A Gbreve -55
KPX A Gcommaaccent -55
KPX A O -45
KPX A Oacute -45
KPX A Ocircumflex -45
KPX A Odieresis -45
KPX A Ograve -45
KPX A Ohungarumlaut -45
KPX A Omacron -45
KPX A Oslash -45
KPX A Otilde -45
KPX A Q -45
KPX A T -95
KPX A Tcaron -95
KPX A Tcommaaccent -95
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -145
KPX A W -130
KPX A Y -100
KPX A Yacute -100
KPX A Ydieresis -100
KPX A p -25
KPX A quoteright -74
KPX A u -50
KPX A uacute -50
KPX A ucircumflex -50
KPX A udieresis -50
KPX A ugrave -50
KPX A uhungarumlaut -50
KPX A umacron -50
KPX A uogonek -50
KPX A uring -50
KPX A v -100
KPX A w -90
KPX A y -74
KPX A yacute -74
KPX A ydieresis -74
KPX Aacute C -55
KPX Aacute Cacute -55
KPX Aacute Ccaron -55
KPX Aacute Ccedilla -55
KPX Aacute G -55
KPX Aacute Gbreve -55
KPX Aacute Gcommaaccent -55
KPX Aacute O -45
KPX Aacute Oacute -45
KPX Aacute Ocircumflex -45
KPX Aacute Odieresis -45
KPX Aacute Ograve -45
KPX Aacute Ohungarumlaut -45
KPX Aacute Omacron -45
KPX Aacute Oslash -45
KPX Aacute Otilde -45
KPX Aacute Q -45
KPX Aacute T -95
KPX Aacute Tcaron -95
KPX Aacute Tcommaaccent -95
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -145
KPX Aacute W -130
KPX Aacute Y -100
KPX Aacute Yacute -100
KPX Aacute Ydieresis -100
KPX Aacute p -25
KPX Aacute quoteright -74
KPX Aacute u -50
KPX Aacute uacute -50
KPX Aacute ucircumflex -50
KPX Aacute udieresis -50
KPX Aacute ugrave -50
KPX Aacute uhungarumlaut -50
KPX Aacute umacron -50
KPX Aacute uogonek -50
KPX Aacute uring -50
KPX Aacute v -100
KPX Aacute w -90
KPX Aacute y -74
KPX Aacute yacute -74
KPX Aacute ydieresis -74
KPX Abreve C -55
KPX Abreve Cacute -55
KPX Abreve Ccaron -55
KPX Abreve Ccedilla -55
KPX Abreve G -55
KPX Abreve Gbreve -55
KPX Abreve Gcommaaccent -55
KPX Abreve O -45
KPX Abreve Oacute -45
KPX Abreve Ocircumflex -45
KPX Abreve Odieresis -45
KPX Abreve Ograve -45
KPX Abreve Ohungarumlaut -45
KPX Abreve Omacron -45
KPX Abreve Oslash -45
KPX Abreve Otilde -45
KPX Abreve Q -45
KPX Abreve T -95
KPX Abreve Tcaron -95
KPX Abreve Tcommaaccent -95
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -145
KPX Abreve W -130
KPX Abreve Y -100
KPX Abreve Yacute -100
KPX Abreve Ydieresis -100
KPX Abreve p -25
KPX Abreve quoteright -74
KPX Abreve u -50
KPX Abreve uacute -50
KPX Abreve ucircumflex -50
KPX Abreve udieresis -50
KPX Abreve ugrave -50
KPX Abreve uhungarumlaut -50
KPX Abreve umacron -50
KPX Abreve uogonek -50
KPX Abreve uring -50
KPX Abreve v -100
KPX Abreve w -90
KPX Abreve y -74
KPX Abreve yacute -74
KPX Abreve ydieresis -74
KPX Acircumflex C -55
KPX Acircumflex Cacute -55
KPX Acircumflex Ccaron -55
KPX Acircumflex Ccedilla -55
KPX Acircumflex G -55
KPX Acircumflex Gbreve -55
KPX Acircumflex Gcommaaccent -55
KPX Acircumflex O -45
KPX Acircumflex Oacute -45
KPX Acircumflex Ocircumflex -45
KPX Acircumflex Odieresis -45
KPX Acircumflex Ograve -45
KPX Acircumflex Ohungarumlaut -45
KPX Acircumflex Omacron -45
KPX Acircumflex Oslash -45
KPX Acircumflex Otilde -45
KPX Acircumflex Q -45
KPX Acircumflex T -95
KPX Acircumflex Tcaron -95
KPX Acircumflex Tcommaaccent -95
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -145
KPX Acircumflex W -130
KPX Acircumflex Y -100
KPX Acircumflex Yacute -100
KPX Acircumflex Ydieresis -100
KPX Acircumflex p -25
KPX Acircumflex quoteright -74
KPX Acircumflex u -50
KPX Acircumflex uacute -50
KPX Acircumflex ucircumflex -50
KPX Acircumflex udieresis -50
KPX Acircumflex ugrave -50
KPX Acircumflex uhungarumlaut -50
KPX Acircumflex umacron -50
KPX Acircumflex uogonek -50
KPX Acircumflex uring -50
KPX Acircumflex v -100
KPX Acircumflex w -90
KPX Acircumflex y -74
KPX Acircumflex yacute -74
KPX Acircumflex ydieresis -74
KPX Adieresis C -55
KPX Adieresis Cacute -55
KPX Adieresis Ccaron -55
KPX Adieresis Ccedilla -55
KPX Adieresis G -55
KPX Adieresis Gbreve -55
KPX Adieresis Gcommaaccent -55
KPX Adieresis O -45
KPX Adieresis Oacute -45
KPX Adieresis Ocircumflex -45
KPX Adieresis Odieresis -45
KPX Adieresis Ograve -45
KPX Adieresis Ohungarumlaut -45
KPX Adieresis Omacron -45
KPX Adieresis Oslash -45
KPX Adieresis Otilde -45
KPX Adieresis Q -45
KPX Adieresis T -95
KPX Adieresis Tcaron -95
KPX Adieresis Tcommaaccent -95
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -145
KPX Adieresis W -130
KPX Adieresis Y -100
KPX Adieresis Yacute -100
KPX Adieresis Ydieresis -100
KPX Adieresis p -25
KPX Adieresis quoteright -74
KPX Adieresis u -50
KPX Adieresis uacute -50
KPX Adieresis ucircumflex -50
KPX Adieresis udieresis -50
KPX Adieresis ugrave -50
KPX Adieresis uhungarumlaut -50
KPX Adieresis umacron -50
KPX Adieresis uogonek -50
KPX Adieresis uring -50
KPX Adieresis v -100
KPX Adieresis w -90
KPX Adieresis y -74
KPX Adieresis yacute -74
KPX Adieresis ydieresis -74
KPX Agrave C -55
KPX Agrave Cacute -55
KPX Agrave Ccaron -55
KPX Agrave Ccedilla -55
KPX Agrave G -55
KPX Agrave Gbreve -55
KPX Agrave Gcommaaccent -55
KPX Agrave O -45
KPX Agrave Oacute -45
KPX Agrave Ocircumflex -45
KPX Agrave Odieresis -45
KPX Agrave Ograve -45
KPX Agrave Ohungarumlaut -45
KPX Agrave Omacron -45
KPX Agrave Oslash -45
KPX Agrave Otilde -45
KPX Agrave Q -45
KPX Agrave T -95
KPX Agrave Tcaron -95
KPX Agrave Tcommaaccent -95
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -145
KPX Agrave W -130
KPX Agrave Y -100
KPX Agrave Yacute -100
KPX Agrave Ydieresis -100
KPX Agrave p -25
KPX Agrave quoteright -74
KPX Agrave u -50
KPX Agrave uacute -50
KPX Agrave ucircumflex -50
KPX Agrave udieresis -50
KPX Agrave ugrave -50
KPX Agrave uhungarumlaut -50
KPX Agrave umacron -50
KPX Agrave uogonek -50
KPX Agrave uring -50
KPX Agrave v -100
KPX Agrave w -90
KPX Agrave y -74
KPX Agrave yacute -74
KPX Agrave ydieresis -74
KPX Amacron C -55
KPX Amacron Cacute -55
KPX Amacron Ccaron -55
KPX Amacron Ccedilla -55
KPX Amacron G -55
KPX Amacron Gbreve -55
KPX Amacron Gcommaaccent -55
KPX Amacron O -45
KPX Amacron Oacute -45
KPX Amacron Ocircumflex -45
KPX Amacron Odieresis -45
KPX Amacron Ograve -45
KPX Amacron Ohungarumlaut -45
KPX Amacron Omacron -45
KPX Amacron Oslash -45
KPX Amacron Otilde -45
KPX Amacron Q -45
KPX Amacron T -95
KPX Amacron Tcaron -95
KPX Amacron Tcommaaccent -95
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -145
KPX Amacron W -130
KPX Amacron Y -100
KPX Amacron Yacute -100
KPX Amacron Ydieresis -100
KPX Amacron p -25
KPX Amacron quoteright -74
KPX Amacron u -50
KPX Amacron uacute -50
KPX Amacron ucircumflex -50
KPX Amacron udieresis -50
KPX Amacron ugrave -50
KPX Amacron uhungarumlaut -50
KPX Amacron umacron -50
KPX Amacron uogonek -50
KPX Amacron uring -50
KPX Amacron v -100
KPX Amacron w -90
KPX Amacron y -74
KPX Amacron yacute -74
KPX Amacron ydieresis -74
KPX Aogonek C -55
KPX Aogonek Cacute -55
KPX Aogonek Ccaron -55
KPX Aogonek Ccedilla -55
KPX Aogonek G -55
KPX Aogonek Gbreve -55
KPX Aogonek Gcommaaccent -55
KPX Aogonek O -45
KPX Aogonek Oacute -45
KPX Aogonek Ocircumflex -45
KPX Aogonek Odieresis -45
KPX Aogonek Ograve -45
KPX Aogonek Ohungarumlaut -45
KPX Aogonek Omacron -45
KPX Aogonek Oslash -45
KPX Aogonek Otilde -45
KPX Aogonek Q -45
KPX Aogonek T -95
KPX Aogonek Tcaron -95
KPX Aogonek Tcommaaccent -95
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -145
KPX Aogonek W -130
KPX Aogonek Y -100
KPX Aogonek Yacute -100
KPX Aogonek Ydieresis -100
KPX Aogonek p -25
KPX Aogonek quoteright -74
KPX Aogonek u -50
KPX Aogonek uacute -50
KPX Aogonek ucircumflex -50
KPX Aogonek udieresis -50
KPX Aogonek ugrave -50
KPX Aogonek uhungarumlaut -50
KPX Aogonek umacron -50
KPX Aogonek uogonek -50
KPX Aogonek uring -50
KPX Aogonek v -100
KPX Aogonek w -90
KPX Aogonek y -34
KPX Aogonek yacute -34
KPX Aogonek ydieresis -34
KPX Aring C -55
KPX Aring Cacute -55
KPX Aring Ccaron -55
KPX Aring Ccedilla -55
KPX Aring G -55
KPX Aring Gbreve -55
KPX Aring Gcommaaccent -55
KPX Aring O -45
KPX Aring Oacute -45
KPX Aring Ocircumflex -45
KPX Aring Odieresis -45
KPX Aring Ograve -45
KPX Aring Ohungarumlaut -45
KPX Aring Omacron -45
KPX Aring Oslash -45
KPX Aring Otilde -45
KPX Aring Q -45
KPX Aring T -95
KPX Aring Tcaron -95
KPX Aring Tcommaaccent -95
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -145
KPX Aring W -130
KPX Aring Y -100
KPX Aring Yacute -100
KPX Aring Ydieresis -100
KPX Aring p -25
KPX Aring quoteright -74
KPX Aring u -50
KPX Aring uacute -50
KPX Aring ucircumflex -50
KPX Aring udieresis -50
KPX Aring ugrave -50
KPX Aring uhungarumlaut -50
KPX Aring umacron -50
KPX Aring uogonek -50
KPX Aring uring -50
KPX Aring v -100
KPX Aring w -90
KPX Aring y -74
KPX Aring yacute -74
KPX Aring ydieresis -74
KPX Atilde C -55
KPX Atilde Cacute -55
KPX Atilde Ccaron -55
KPX Atilde Ccedilla -55
KPX Atilde G -55
KPX Atilde Gbreve -55
KPX Atilde Gcommaaccent -55
KPX Atilde O -45
KPX Atilde Oacute -45
KPX Atilde Ocircumflex -45
KPX Atilde Odieresis -45
KPX Atilde Ograve -45
KPX Atilde Ohungarumlaut -45
KPX Atilde Omacron -45
KPX Atilde Oslash -45
KPX Atilde Otilde -45
KPX Atilde Q -45
KPX Atilde T -95
KPX Atilde Tcaron -95
KPX Atilde Tcommaaccent -95
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -145
KPX Atilde W -130
KPX Atilde Y -100
KPX Atilde Yacute -100
KPX Atilde Ydieresis -100
KPX Atilde p -25
KPX Atilde quoteright -74
KPX Atilde u -50
KPX Atilde uacute -50
KPX Atilde ucircumflex -50
KPX Atilde udieresis -50
KPX Atilde ugrave -50
KPX Atilde uhungarumlaut -50
KPX Atilde umacron -50
KPX Atilde uogonek -50
KPX Atilde uring -50
KPX Atilde v -100
KPX Atilde w -90
KPX Atilde y -74
KPX Atilde yacute -74
KPX Atilde ydieresis -74
KPX B A -30
KPX B Aacute -30
KPX B Abreve -30
KPX B Acircumflex -30
KPX B Adieresis -30
KPX B Agrave -30
KPX B Amacron -30
KPX B Aogonek -30
KPX B Aring -30
KPX B Atilde -30
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX D A -35
KPX D Aacute -35
KPX D Abreve -35
KPX D Acircumflex -35
KPX D Adieresis -35
KPX D Agrave -35
KPX D Amacron -35
KPX D Aogonek -35
KPX D Aring -35
KPX D Atilde -35
KPX D V -40
KPX D W -40
KPX D Y -40
KPX D Yacute -40
KPX D Ydieresis -40
KPX D period -20
KPX Dcaron A -35
KPX Dcaron Aacute -35
KPX Dcaron Abreve -35
KPX Dcaron Acircumflex -35
KPX Dcaron Adieresis -35
KPX Dcaron Agrave -35
KPX Dcaron Amacron -35
KPX Dcaron Aogonek -35
KPX Dcaron Aring -35
KPX Dcaron Atilde -35
KPX Dcaron V -40
KPX Dcaron W -40
KPX Dcaron Y -40
KPX Dcaron Yacute -40
KPX Dcaron Ydieresis -40
KPX Dcaron period -20
KPX Dcroat A -35
KPX Dcroat Aacute -35
KPX Dcroat Abreve -35
KPX Dcroat Acircumflex -35
KPX Dcroat Adieresis -35
KPX Dcroat Agrave -35
KPX Dcroat Amacron -35
KPX Dcroat Aogonek -35
KPX Dcroat Aring -35
KPX Dcroat Atilde -35
KPX Dcroat V -40
KPX Dcroat W -40
KPX Dcroat Y -40
KPX Dcroat Yacute -40
KPX Dcroat Ydieresis -40
KPX Dcroat period -20
KPX F A -90
KPX F Aacute -90
KPX F Abreve -90
KPX F Acircumflex -90
KPX F Adieresis -90
KPX F Agrave -90
KPX F Amacron -90
KPX F Aogonek -90
KPX F Aring -90
KPX F Atilde -90
KPX F a -25
KPX F aacute -25
KPX F abreve -25
KPX F acircumflex -25
KPX F adieresis -25
KPX F agrave -25
KPX F amacron -25
KPX F aogonek -25
KPX F aring -25
KPX F atilde -25
KPX F comma -92
KPX F e -25
KPX F eacute -25
KPX F ecaron -25
KPX F ecircumflex -25
KPX F edieresis -25
KPX F edotaccent -25
KPX F egrave -25
KPX F emacron -25
KPX F eogonek -25
KPX F o -25
KPX F oacute -25
KPX F ocircumflex -25
KPX F odieresis -25
KPX F ograve -25
KPX F ohungarumlaut -25
KPX F omacron -25
KPX F oslash -25
KPX F otilde -25
KPX F period -110
KPX J A -30
KPX J Aacute -30
KPX J Abreve -30
KPX J Acircumflex -30
KPX J Adieresis -30
KPX J Agrave -30
KPX J Amacron -30
KPX J Aogonek -30
KPX J Aring -30
KPX J Atilde -30
KPX J a -15
KPX J aacute -15
KPX J abreve -15
KPX J acircumflex -15
KPX J adieresis -15
KPX J agrave -15
KPX J amacron -15
KPX J aogonek -15
KPX J aring -15
KPX J atilde -15
KPX J e -15
KPX J eacute -15
KPX J ecaron -15
KPX J ecircumflex -15
KPX J edieresis -15
KPX J edotaccent -15
KPX J egrave -15
KPX J emacron -15
KPX J eogonek -15
KPX J o -15
KPX J oacute -15
KPX J ocircumflex -15
KPX J odieresis -15
KPX J ograve -15
KPX J ohungarumlaut -15
KPX J omacron -15
KPX J oslash -15
KPX J otilde -15
KPX J period -20
KPX J u -15
KPX J uacute -15
KPX J ucircumflex -15
KPX J udieresis -15
KPX J ugrave -15
KPX J uhungarumlaut -15
KPX J umacron -15
KPX J uogonek -15
KPX J uring -15
KPX K O -30
KPX K Oacute -30
KPX K Ocircumflex -30
KPX K Odieresis -30
KPX K Ograve -30
KPX K Ohungarumlaut -30
KPX K Omacron -30
KPX K Oslash -30
KPX K Otilde -30
KPX K e -25
KPX K eacute -25
KPX K ecaron -25
KPX K ecircumflex -25
KPX K edieresis -25
KPX K edotaccent -25
KPX K egrave -25
KPX K emacron -25
KPX K eogonek -25
KPX K o -25
KPX K oacute -25
KPX K ocircumflex -25
KPX K odieresis -25
KPX K ograve -25
KPX K ohungarumlaut -25
KPX K omacron -25
KPX K oslash -25
KPX K otilde -25
KPX K u -15
KPX K uacute -15
KPX K ucircumflex -15
KPX K udieresis -15
KPX K ugrave -15
KPX K uhungarumlaut -15
KPX K umacron -15
KPX K uogonek -15
KPX K uring -15
KPX K y -45
KPX K yacute -45
KPX K ydieresis -45
KPX Kcommaaccent O -30
KPX Kcommaaccent Oacute -30
KPX Kcommaaccent Ocircumflex -30
KPX Kcommaaccent Odieresis -30
KPX Kcommaaccent Ograve -30
KPX Kcommaaccent Ohungarumlaut -30
KPX Kcommaaccent Omacron -30
KPX Kcommaaccent Oslash -30
KPX Kcommaaccent Otilde -30
KPX Kcommaaccent e -25
KPX Kcommaaccent eacute -25
KPX Kcommaaccent ecaron -25
KPX Kcommaaccent ecircumflex -25
KPX Kcommaaccent edieresis -25
KPX Kcommaaccent edotaccent -25
KPX Kcommaaccent egrave -25
KPX Kcommaaccent emacron -25
KPX Kcommaaccent eogonek -25
KPX Kcommaaccent o -25
KPX Kcommaaccent oacute -25
KPX Kcommaaccent ocircumflex -25
KPX Kcommaaccent odieresis -25
KPX Kcommaaccent ograve -25
KPX Kcommaaccent ohungarumlaut -25
KPX Kcommaaccent omacron -25
KPX Kcommaaccent oslash -25
KPX Kcommaaccent otilde -25
KPX Kcommaaccent u -15
KPX Kcommaaccent uacute -15
KPX Kcommaaccent ucircumflex -15
KPX Kcommaaccent udieresis -15
KPX Kcommaaccent ugrave -15
KPX Kcommaaccent uhungarumlaut -15
KPX Kcommaaccent umacron -15
KPX Kcommaaccent uogonek -15
KPX Kcommaaccent uring -15
KPX Kcommaaccent y -45
KPX Kcommaaccent yacute -45
KPX Kcommaaccent ydieresis -45
KPX L T -92
KPX L Tcaron -92
KPX L Tcommaaccent -92
KPX L V -92
KPX L W -92
KPX L Y -92
KPX L Yacute -92
KPX L Ydieresis -92
KPX L quotedblright -20
KPX L quoteright -110
KPX L y -55
KPX L yacute -55
KPX L ydieresis -55
KPX Lacute T -92
KPX Lacute Tcaron -92
KPX Lacute Tcommaaccent -92
KPX Lacute V -92
KPX Lacute W -92
KPX Lacute Y -92
KPX Lacute Yacute -92
KPX Lacute Ydieresis -92
KPX Lacute quotedblright -20
KPX Lacute quoteright -110
KPX Lacute y -55
KPX Lacute yacute -55
KPX Lacute ydieresis -55
KPX Lcommaaccent T -92
KPX Lcommaaccent Tcaron -92
KPX Lcommaaccent Tcommaaccent -92
KPX Lcommaaccent V -92
KPX Lcommaaccent W -92
KPX Lcommaaccent Y -92
KPX Lcommaaccent Yacute -92
KPX Lcommaaccent Ydieresis -92
KPX Lcommaaccent quotedblright -20
KPX Lcommaaccent quoteright -110
KPX Lcommaaccent y -55
KPX Lcommaaccent yacute -55
KPX Lcommaaccent ydieresis -55
KPX Lslash T -92
KPX Lslash Tcaron -92
KPX Lslash Tcommaaccent -92
KPX Lslash V -92
KPX Lslash W -92
KPX Lslash Y -92
KPX Lslash Yacute -92
KPX Lslash Ydieresis -92
KPX Lslash quotedblright -20
KPX Lslash quoteright -110
KPX Lslash y -55
KPX Lslash yacute -55
KPX Lslash ydieresis -55
KPX N A -20
KPX N Aacute -20
KPX N Abreve -20
KPX N Acircumflex -20
KPX N Adieresis -20
KPX N Agrave -20
KPX N Amacron -20
KPX N Aogonek -20
KPX N Aring -20
KPX N Atilde -20
KPX Nacute A -20
KPX Nacute Aacute -20
KPX Nacute Abreve -20
KPX Nacute Acircumflex -20
KPX Nacute Adieresis -20
KPX Nacute Agrave -20
KPX Nacute Amacron -20
KPX Nacute Aogonek -20
KPX Nacute Aring -20
KPX Nacute Atilde -20
KPX Ncaron A -20
KPX Ncaron Aacute -20
KPX Ncaron Abreve -20
KPX Ncaron Acircumflex -20
KPX Ncaron Adieresis -20
KPX Ncaron Agrave -20
KPX Ncaron Amacron -20
KPX Ncaron Aogonek -20
KPX Ncaron Aring -20
KPX Ncaron Atilde -20
KPX Ncommaaccent A -20
KPX Ncommaaccent Aacute -20
KPX Ncommaaccent Abreve -20
KPX Ncommaaccent Acircumflex -20
KPX Ncommaaccent Adieresis -20
KPX Ncommaaccent Agrave -20
KPX Ncommaaccent Amacron -20
KPX Ncommaaccent Aogonek -20
KPX Ncommaaccent Aring -20
KPX Ncommaaccent Atilde -20
KPX Ntilde A -20
KPX Ntilde Aacute -20
KPX Ntilde Abreve -20
KPX Ntilde Acircumflex -20
KPX Ntilde Adieresis -20
KPX Ntilde Agrave -20
KPX Ntilde Amacron -20
KPX Ntilde Aogonek -20
KPX Ntilde Aring -20
KPX Ntilde Atilde -20
KPX O A -40
KPX O Aacute -40
KPX O Abreve -40
KPX O Acircumflex -40
KPX O Adieresis -40
KPX O Agrave -40
KPX O Amacron -40
KPX O Aogonek -40
KPX O Aring -40
KPX O Atilde -40
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -50
KPX O X -40
KPX O Y -50
KPX O Yacute -50
KPX O Ydieresis -50
KPX Oacute A -40
KPX Oacute Aacute -40
KPX Oacute Abreve -40
KPX Oacute Acircumflex -40
KPX Oacute Adieresis -40
KPX Oacute Agrave -40
KPX Oacute Amacron -40
KPX Oacute Aogonek -40
KPX Oacute Aring -40
KPX Oacute Atilde -40
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -50
KPX Oacute X -40
KPX Oacute Y -50
KPX Oacute Yacute -50
KPX Oacute Ydieresis -50
KPX Ocircumflex A -40
KPX Ocircumflex Aacute -40
KPX Ocircumflex Abreve -40
KPX Ocircumflex Acircumflex -40
KPX Ocircumflex Adieresis -40
KPX Ocircumflex Agrave -40
KPX Ocircumflex Amacron -40
KPX Ocircumflex Aogonek -40
KPX Ocircumflex Aring -40
KPX Ocircumflex Atilde -40
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -50
KPX Ocircumflex X -40
KPX Ocircumflex Y -50
KPX Ocircumflex Yacute -50
KPX Ocircumflex Ydieresis -50
KPX Odieresis A -40
KPX Odieresis Aacute -40
KPX Odieresis Abreve -40
KPX Odieresis Acircumflex -40
KPX Odieresis Adieresis -40
KPX Odieresis Agrave -40
KPX Odieresis Amacron -40
KPX Odieresis Aogonek -40
KPX Odieresis Aring -40
KPX Odieresis Atilde -40
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -50
KPX Odieresis X -40
KPX Odieresis Y -50
KPX Odieresis Yacute -50
KPX Odieresis Ydieresis -50
KPX Ograve A -40
KPX Ograve Aacute -40
KPX Ograve Abreve -40
KPX Ograve Acircumflex -40
KPX Ograve Adieresis -40
KPX Ograve Agrave -40
KPX Ograve Amacron -40
KPX Ograve Aogonek -40
KPX Ograve Aring -40
KPX Ograve Atilde -40
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -50
KPX Ograve X -40
KPX Ograve Y -50
KPX Ograve Yacute -50
KPX Ograve Ydieresis -50
KPX Ohungarumlaut A -40
KPX Ohungarumlaut Aacute -40
KPX Ohungarumlaut Abreve -40
KPX Ohungarumlaut Acircumflex -40
KPX Ohungarumlaut Adieresis -40
KPX Ohungarumlaut Agrave -40
KPX Ohungarumlaut Amacron -40
KPX Ohungarumlaut Aogonek -40
KPX Ohungarumlaut Aring -40
KPX Ohungarumlaut Atilde -40
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -50
KPX Ohungarumlaut X -40
KPX Ohungarumlaut Y -50
KPX Ohungarumlaut Yacute -50
KPX Ohungarumlaut Ydieresis -50
KPX Omacron A -40
KPX Omacron Aacute -40
KPX Omacron Abreve -40
KPX Omacron Acircumflex -40
KPX Omacron Adieresis -40
KPX Omacron Agrave -40
KPX Omacron Amacron -40
KPX Omacron Aogonek -40
KPX Omacron Aring -40
KPX Omacron Atilde -40
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -50
KPX Omacron X -40
KPX Omacron Y -50
KPX Omacron Yacute -50
KPX Omacron Ydieresis -50
KPX Oslash A -40
KPX Oslash Aacute -40
KPX Oslash Abreve -40
KPX Oslash Acircumflex -40
KPX Oslash Adieresis -40
KPX Oslash Agrave -40
KPX Oslash Amacron -40
KPX Oslash Aogonek -40
KPX Oslash Aring -40
KPX Oslash Atilde -40
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -50
KPX Oslash X -40
KPX Oslash Y -50
KPX Oslash Yacute -50
KPX Oslash Ydieresis -50
KPX Otilde A -40
KPX Otilde Aacute -40
KPX Otilde Abreve -40
KPX Otilde Acircumflex -40
KPX Otilde Adieresis -40
KPX Otilde Agrave -40
KPX Otilde Amacron -40
KPX Otilde Aogonek -40
KPX Otilde Aring -40
KPX Otilde Atilde -40
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -50
KPX Otilde X -40
KPX Otilde Y -50
KPX Otilde Yacute -50
KPX Otilde Ydieresis -50
KPX P A -74
KPX P Aacute -74
KPX P Abreve -74
KPX P Acircumflex -74
KPX P Adieresis -74
KPX P Agrave -74
KPX P Amacron -74
KPX P Aogonek -74
KPX P Aring -74
KPX P Atilde -74
KPX P a -10
KPX P aacute -10
KPX P abreve -10
KPX P acircumflex -10
KPX P adieresis -10
KPX P agrave -10
KPX P amacron -10
KPX P aogonek -10
KPX P aring -10
KPX P atilde -10
KPX P comma -92
KPX P e -20
KPX P eacute -20
KPX P ecaron -20
KPX P ecircumflex -20
KPX P edieresis -20
KPX P edotaccent -20
KPX P egrave -20
KPX P emacron -20
KPX P eogonek -20
KPX P o -20
KPX P oacute -20
KPX P ocircumflex -20
KPX P odieresis -20
KPX P ograve -20
KPX P ohungarumlaut -20
KPX P omacron -20
KPX P oslash -20
KPX P otilde -20
KPX P period -110
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX Q period -20
KPX R O -30
KPX R Oacute -30
KPX R Ocircumflex -30
KPX R Odieresis -30
KPX R Ograve -30
KPX R Ohungarumlaut -30
KPX R Omacron -30
KPX R Oslash -30
KPX R Otilde -30
KPX R T -40
KPX R Tcaron -40
KPX R Tcommaaccent -40
KPX R U -30
KPX R Uacute -30
KPX R Ucircumflex -30
KPX R Udieresis -30
KPX R Ugrave -30
KPX R Uhungarumlaut -30
KPX R Umacron -30
KPX R Uogonek -30
KPX R Uring -30
KPX R V -55
KPX R W -35
KPX R Y -35
KPX R Yacute -35
KPX R Ydieresis -35
KPX Racute O -30
KPX Racute Oacute -30
KPX Racute Ocircumflex -30
KPX Racute Odieresis -30
KPX Racute Ograve -30
KPX Racute Ohungarumlaut -30
KPX Racute Omacron -30
KPX Racute Oslash -30
KPX Racute Otilde -30
KPX Racute T -40
KPX Racute Tcaron -40
KPX Racute Tcommaaccent -40
KPX Racute U -30
KPX Racute Uacute -30
KPX Racute Ucircumflex -30
KPX Racute Udieresis -30
KPX Racute Ugrave -30
KPX Racute Uhungarumlaut -30
KPX Racute Umacron -30
KPX Racute Uogonek -30
KPX Racute Uring -30
KPX Racute V -55
KPX Racute W -35
KPX Racute Y -35
KPX Racute Yacute -35
KPX Racute Ydieresis -35
KPX Rcaron O -30
KPX Rcaron Oacute -30
KPX Rcaron Ocircumflex -30
KPX Rcaron Odieresis -30
KPX Rcaron Ograve -30
KPX Rcaron Ohungarumlaut -30
KPX Rcaron Omacron -30
KPX Rcaron Oslash -30
KPX Rcaron Otilde -30
KPX Rcaron T -40
KPX Rcaron Tcaron -40
KPX Rcaron Tcommaaccent -40
KPX Rcaron U -30
KPX Rcaron Uacute -30
KPX Rcaron Ucircumflex -30
KPX Rcaron Udieresis -30
KPX Rcaron Ugrave -30
KPX Rcaron Uhungarumlaut -30
KPX Rcaron Umacron -30
KPX Rcaron Uogonek -30
KPX Rcaron Uring -30
KPX Rcaron V -55
KPX Rcaron W -35
KPX Rcaron Y -35
KPX Rcaron Yacute -35
KPX Rcaron Ydieresis -35
KPX Rcommaaccent O -30
KPX Rcommaaccent Oacute -30
KPX Rcommaaccent Ocircumflex -30
KPX Rcommaaccent Odieresis -30
KPX Rcommaaccent Ograve -30
KPX Rcommaaccent Ohungarumlaut -30
KPX Rcommaaccent Omacron -30
KPX Rcommaaccent Oslash -30
KPX Rcommaaccent Otilde -30
KPX Rcommaaccent T -40
KPX Rcommaaccent Tcaron -40
KPX Rcommaaccent Tcommaaccent -40
KPX Rcommaaccent U -30
KPX Rcommaaccent Uacute -30
KPX Rcommaaccent Ucircumflex -30
KPX Rcommaaccent Udieresis -30
KPX Rcommaaccent Ugrave -30
KPX Rcommaaccent Uhungarumlaut -30
KPX Rcommaaccent Umacron -30
KPX Rcommaaccent Uogonek -30
KPX Rcommaaccent Uring -30
KPX Rcommaaccent V -55
KPX Rcommaaccent W -35
KPX Rcommaaccent Y -35
KPX Rcommaaccent Yacute -35
KPX Rcommaaccent Ydieresis -35
KPX T A -90
KPX T Aacute -90
KPX T Abreve -90
KPX T Acircumflex -90
KPX T Adieresis -90
KPX T Agrave -90
KPX T Amacron -90
KPX T Aogonek -90
KPX T Aring -90
KPX T Atilde -90
KPX T O -18
KPX T Oacute -18
KPX T Ocircumflex -18
KPX T Odieresis -18
KPX T Ograve -18
KPX T Ohungarumlaut -18
KPX T Omacron -18
KPX T Oslash -18
KPX T Otilde -18
KPX T a -92
KPX T aacute -92
KPX T abreve -52
KPX T acircumflex -52
KPX T adieresis -52
KPX T agrave -52
KPX T amacron -52
KPX T aogonek -92
KPX T aring -92
KPX T atilde -52
KPX T colon -74
KPX T comma -74
KPX T e -92
KPX T eacute -92
KPX T ecaron -92
KPX T ecircumflex -92
KPX T edieresis -52
KPX T edotaccent -92
KPX T egrave -52
KPX T emacron -52
KPX T eogonek -92
KPX T hyphen -92
KPX T i -18
KPX T iacute -18
KPX T iogonek -18
KPX T o -92
KPX T oacute -92
KPX T ocircumflex -92
KPX T odieresis -92
KPX T ograve -92
KPX T ohungarumlaut -92
KPX T omacron -92
KPX T oslash -92
KPX T otilde -92
KPX T period -90
KPX T r -74
KPX T racute -74
KPX T rcaron -74
KPX T rcommaaccent -74
KPX T semicolon -74
KPX T u -92
KPX T uacute -92
KPX T ucircumflex -92
KPX T udieresis -92
KPX T ugrave -92
KPX T uhungarumlaut -92
KPX T umacron -92
KPX T uogonek -92
KPX T uring -92
KPX T w -74
KPX T y -34
KPX T yacute -34
KPX T ydieresis -34
KPX Tcaron A -90
KPX Tcaron Aacute -90
KPX Tcaron Abreve -90
KPX Tcaron Acircumflex -90
KPX Tcaron Adieresis -90
KPX Tcaron Agrave -90
KPX Tcaron Amacron -90
KPX Tcaron Aogonek -90
KPX Tcaron Aring -90
KPX Tcaron Atilde -90
KPX Tcaron O -18
KPX Tcaron Oacute -18
KPX Tcaron Ocircumflex -18
KPX Tcaron Odieresis -18
KPX Tcaron Ograve -18
KPX Tcaron Ohungarumlaut -18
KPX Tcaron Omacron -18
KPX Tcaron Oslash -18
KPX Tcaron Otilde -18
KPX Tcaron a -92
KPX Tcaron aacute -92
KPX Tcaron abreve -52
KPX Tcaron acircumflex -52
KPX Tcaron adieresis -52
KPX Tcaron agrave -52
KPX Tcaron amacron -52
KPX Tcaron aogonek -92
KPX Tcaron aring -92
KPX Tcaron atilde -52
KPX Tcaron colon -74
KPX Tcaron comma -74
KPX Tcaron e -92
KPX Tcaron eacute -92
KPX Tcaron ecaron -92
KPX Tcaron ecircumflex -92
KPX Tcaron edieresis -52
KPX Tcaron edotaccent -92
KPX Tcaron egrave -52
KPX Tcaron emacron -52
KPX Tcaron eogonek -92
KPX Tcaron hyphen -92
KPX Tcaron i -18
KPX Tcaron iacute -18
KPX Tcaron iogonek -18
KPX Tcaron o -92
KPX Tcaron oacute -92
KPX Tcaron ocircumflex -92
KPX Tcaron odieresis -92
KPX Tcaron ograve -92
KPX Tcaron ohungarumlaut -92
KPX Tcaron omacron -92
KPX Tcaron oslash -92
KPX Tcaron otilde -92
KPX Tcaron period -90
KPX Tcaron r -74
KPX Tcaron racute -74
KPX Tcaron rcaron -74
KPX Tcaron rcommaaccent -74
KPX Tcaron semicolon -74
KPX Tcaron u -92
KPX Tcaron uacute -92
KPX Tcaron ucircumflex -92
KPX Tcaron udieresis -92
KPX Tcaron ugrave -92
KPX Tcaron uhungarumlaut -92
KPX Tcaron umacron -92
KPX Tcaron uogonek -92
KPX Tcaron uring -92
KPX Tcaron w -74
KPX Tcaron y -34
KPX Tcaron yacute -34
KPX Tcaron ydieresis -34
KPX Tcommaaccent A -90
KPX Tcommaaccent Aacute -90
KPX Tcommaaccent Abreve -90
KPX Tcommaaccent Acircumflex -90
KPX Tcommaaccent Adieresis -90
KPX Tcommaaccent Agrave -90
KPX Tcommaaccent Amacron -90
KPX Tcommaaccent Aogonek -90
KPX Tcommaaccent Aring -90
KPX Tcommaaccent Atilde -90
KPX Tcommaaccent O -18
KPX Tcommaaccent Oacute -18
KPX Tcommaaccent Ocircumflex -18
KPX Tcommaaccent Odieresis -18
KPX Tcommaaccent Ograve -18
KPX Tcommaaccent Ohungarumlaut -18
KPX Tcommaaccent Omacron -18
KPX Tcommaaccent Oslash -18
KPX Tcommaaccent Otilde -18
KPX Tcommaaccent a -92
KPX Tcommaaccent aacute -92
KPX Tcommaaccent abreve -52
KPX Tcommaaccent acircumflex -52
KPX Tcommaaccent adieresis -52
KPX Tcommaaccent agrave -52
KPX Tcommaaccent amacron -52
KPX Tcommaaccent aogonek -92
KPX Tcommaaccent aring -92
KPX Tcommaaccent atilde -52
KPX Tcommaaccent colon -74
KPX Tcommaaccent comma -74
KPX Tcommaaccent e -92
KPX Tcommaaccent eacute -92
KPX Tcommaaccent ecaron -92
KPX Tcommaaccent ecircumflex -92
KPX Tcommaaccent edieresis -52
KPX Tcommaaccent edotaccent -92
KPX Tcommaaccent egrave -52
KPX Tcommaaccent emacron -52
KPX Tcommaaccent eogonek -92
KPX Tcommaaccent hyphen -92
KPX Tcommaaccent i -18
KPX Tcommaaccent iacute -18
KPX Tcommaaccent iogonek -18
KPX Tcommaaccent o -92
KPX Tcommaaccent oacute -92
KPX Tcommaaccent ocircumflex -92
KPX Tcommaaccent odieresis -92
KPX Tcommaaccent ograve -92
KPX Tcommaaccent ohungarumlaut -92
KPX Tcommaaccent omacron -92
KPX Tcommaaccent oslash -92
KPX Tcommaaccent otilde -92
KPX Tcommaaccent period -90
KPX Tcommaaccent r -74
KPX Tcommaaccent racute -74
KPX Tcommaaccent rcaron -74
KPX Tcommaaccent rcommaaccent -74
KPX Tcommaaccent semicolon -74
KPX Tcommaaccent u -92
KPX Tcommaaccent uacute -92
KPX Tcommaaccent ucircumflex -92
KPX Tcommaaccent udieresis -92
KPX Tcommaaccent ugrave -92
KPX Tcommaaccent uhungarumlaut -92
KPX Tcommaaccent umacron -92
KPX Tcommaaccent uogonek -92
KPX Tcommaaccent uring -92
KPX Tcommaaccent w -74
KPX Tcommaaccent y -34
KPX Tcommaaccent yacute -34
KPX Tcommaaccent ydieresis -34
KPX U A -60
KPX U Aacute -60
KPX U Abreve -60
KPX U Acircumflex -60
KPX U Adieresis -60
KPX U Agrave -60
KPX U Amacron -60
KPX U Aogonek -60
KPX U Aring -60
KPX U Atilde -60
KPX U comma -50
KPX U period -50
KPX Uacute A -60
KPX Uacute Aacute -60
KPX Uacute Abreve -60
KPX Uacute Acircumflex -60
KPX Uacute Adieresis -60
KPX Uacute Agrave -60
KPX Uacute Amacron -60
KPX Uacute Aogonek -60
KPX Uacute Aring -60
KPX Uacute Atilde -60
KPX Uacute comma -50
KPX Uacute period -50
KPX Ucircumflex A -60
KPX Ucircumflex Aacute -60
KPX Ucircumflex Abreve -60
KPX Ucircumflex Acircumflex -60
KPX Ucircumflex Adieresis -60
KPX Ucircumflex Agrave -60
KPX Ucircumflex Amacron -60
KPX Ucircumflex Aogonek -60
KPX Ucircumflex Aring -60
KPX Ucircumflex Atilde -60
KPX Ucircumflex comma -50
KPX Ucircumflex period -50
KPX Udieresis A -60
KPX Udieresis Aacute -60
KPX Udieresis Abreve -60
KPX Udieresis Acircumflex -60
KPX Udieresis Adieresis -60
KPX Udieresis Agrave -60
KPX Udieresis Amacron -60
KPX Udieresis Aogonek -60
KPX Udieresis Aring -60
KPX Udieresis Atilde -60
KPX Udieresis comma -50
KPX Udieresis period -50
KPX Ugrave A -60
KPX Ugrave Aacute -60
KPX Ugrave Abreve -60
KPX Ugrave Acircumflex -60
KPX Ugrave Adieresis -60
KPX Ugrave Agrave -60
KPX Ugrave Amacron -60
KPX Ugrave Aogonek -60
KPX Ugrave Aring -60
KPX Ugrave Atilde -60
KPX Ugrave comma -50
KPX Ugrave period -50
KPX Uhungarumlaut A -60
KPX Uhungarumlaut Aacute -60
KPX Uhungarumlaut Abreve -60
KPX Uhungarumlaut Acircumflex -60
KPX Uhungarumlaut Adieresis -60
KPX Uhungarumlaut Agrave -60
KPX Uhungarumlaut Amacron -60
KPX Uhungarumlaut Aogonek -60
KPX Uhungarumlaut Aring -60
KPX Uhungarumlaut Atilde -60
KPX Uhungarumlaut comma -50
KPX Uhungarumlaut period -50
KPX Umacron A -60
KPX Umacron Aacute -60
KPX Umacron Abreve -60
KPX Umacron Acircumflex -60
KPX Umacron Adieresis -60
KPX Umacron Agrave -60
KPX Umacron Amacron -60
KPX Umacron Aogonek -60
KPX Umacron Aring -60
KPX Umacron Atilde -60
KPX Umacron comma -50
KPX Umacron period -50
KPX Uogonek A -60
KPX Uogonek Aacute -60
KPX Uogonek Abreve -60
KPX Uogonek Acircumflex -60
KPX Uogonek Adieresis -60
KPX Uogonek Agrave -60
KPX Uogonek Amacron -60
KPX Uogonek Aogonek -60
KPX Uogonek Aring -60
KPX Uogonek Atilde -60
KPX Uogonek comma -50
KPX Uogonek period -50
KPX Uring A -60
KPX Uring Aacute -60
KPX Uring Abreve -60
KPX Uring Acircumflex -60
KPX Uring Adieresis -60
KPX Uring Agrave -60
KPX Uring Amacron -60
KPX Uring Aogonek -60
KPX Uring Aring -60
KPX Uring Atilde -60
KPX Uring comma -50
KPX Uring period -50
KPX V A -135
KPX V Aacute -135
KPX V Abreve -135
KPX V Acircumflex -135
KPX V Adieresis -135
KPX V Agrave -135
KPX V Amacron -135
KPX V Aogonek -135
KPX V Aring -135
KPX V Atilde -135
KPX V G -30
KPX V Gbreve -30
KPX V Gcommaaccent -30
KPX V O -45
KPX V Oacute -45
KPX V Ocircumflex -45
KPX V Odieresis -45
KPX V Ograve -45
KPX V Ohungarumlaut -45
KPX V Omacron -45
KPX V Oslash -45
KPX V Otilde -45
KPX V a -92
KPX V aacute -92
KPX V abreve -92
KPX V acircumflex -92
KPX V adieresis -92
KPX V agrave -92
KPX V amacron -92
KPX V aogonek -92
KPX V aring -92
KPX V atilde -92
KPX V colon -92
KPX V comma -129
KPX V e -100
KPX V eacute -100
KPX V ecaron -100
KPX V ecircumflex -100
KPX V edieresis -100
KPX V edotaccent -100
KPX V egrave -100
KPX V emacron -100
KPX V eogonek -100
KPX V hyphen -74
KPX V i -37
KPX V iacute -37
KPX V icircumflex -37
KPX V idieresis -37
KPX V igrave -37
KPX V imacron -37
KPX V iogonek -37
KPX V o -100
KPX V oacute -100
KPX V ocircumflex -100
KPX V odieresis -100
KPX V ograve -100
KPX V ohungarumlaut -100
KPX V omacron -100
KPX V oslash -100
KPX V otilde -100
KPX V period -145
KPX V semicolon -92
KPX V u -92
KPX V uacute -92
KPX V ucircumflex -92
KPX V udieresis -92
KPX V ugrave -92
KPX V uhungarumlaut -92
KPX V umacron -92
KPX V uogonek -92
KPX V uring -92
KPX W A -120
KPX W Aacute -120
KPX W Abreve -120
KPX W Acircumflex -120
KPX W Adieresis -120
KPX W Agrave -120
KPX W Amacron -120
KPX W Aogonek -120
KPX W Aring -120
KPX W Atilde -120
KPX W O -10
KPX W Oacute -10
KPX W Ocircumflex -10
KPX W Odieresis -10
KPX W Ograve -10
KPX W Ohungarumlaut -10
KPX W Omacron -10
KPX W Oslash -10
KPX W Otilde -10
KPX W a -65
KPX W aacute -65
KPX W abreve -65
KPX W acircumflex -65
KPX W adieresis -65
KPX W agrave -65
KPX W amacron -65
KPX W aogonek -65
KPX W aring -65
KPX W atilde -65
KPX W colon -55
KPX W comma -92
KPX W e -65
KPX W eacute -65
KPX W ecaron -65
KPX W ecircumflex -65
KPX W edieresis -65
KPX W edotaccent -65
KPX W egrave -65
KPX W emacron -65
KPX W eogonek -65
KPX W hyphen -37
KPX W i -18
KPX W iacute -18
KPX W iogonek -18
KPX W o -75
KPX W oacute -75
KPX W ocircumflex -75
KPX W odieresis -75
KPX W ograve -75
KPX W ohungarumlaut -75
KPX W omacron -75
KPX W oslash -75
KPX W otilde -75
KPX W period -92
KPX W semicolon -55
KPX W u -50
KPX W uacute -50
KPX W ucircumflex -50
KPX W udieresis -50
KPX W ugrave -50
KPX W uhungarumlaut -50
KPX W umacron -50
KPX W uogonek -50
KPX W uring -50
KPX W y -60
KPX W yacute -60
KPX W ydieresis -60
KPX Y A -110
KPX Y Aacute -110
KPX Y Abreve -110
KPX Y Acircumflex -110
KPX Y Adieresis -110
KPX Y Agrave -110
KPX Y Amacron -110
KPX Y Aogonek -110
KPX Y Aring -110
KPX Y Atilde -110
KPX Y O -35
KPX Y Oacute -35
KPX Y Ocircumflex -35
KPX Y Odieresis -35
KPX Y Ograve -35
KPX Y Ohungarumlaut -35
KPX Y Omacron -35
KPX Y Oslash -35
KPX Y Otilde -35
KPX Y a -85
KPX Y aacute -85
KPX Y abreve -85
KPX Y acircumflex -85
KPX Y adieresis -85
KPX Y agrave -85
KPX Y amacron -85
KPX Y aogonek -85
KPX Y aring -85
KPX Y atilde -85
KPX Y colon -92
KPX Y comma -92
KPX Y e -111
KPX Y eacute -111
KPX Y ecaron -111
KPX Y ecircumflex -111
KPX Y edieresis -71
KPX Y edotaccent -111
KPX Y egrave -71
KPX Y emacron -71
KPX Y eogonek -111
KPX Y hyphen -92
KPX Y i -37
KPX Y iacute -37
KPX Y iogonek -37
KPX Y o -111
KPX Y oacute -111
KPX Y ocircumflex -111
KPX Y odieresis -111
KPX Y ograve -111
KPX Y ohungarumlaut -111
KPX Y omacron -111
KPX Y oslash -111
KPX Y otilde -111
KPX Y period -92
KPX Y semicolon -92
KPX Y u -92
KPX Y uacute -92
KPX Y ucircumflex -92
KPX Y udieresis -92
KPX Y ugrave -92
KPX Y uhungarumlaut -92
KPX Y umacron -92
KPX Y uogonek -92
KPX Y uring -92
KPX Yacute A -110
KPX Yacute Aacute -110
KPX Yacute Abreve -110
KPX Yacute Acircumflex -110
KPX Yacute Adieresis -110
KPX Yacute Agrave -110
KPX Yacute Amacron -110
KPX Yacute Aogonek -110
KPX Yacute Aring -110
KPX Yacute Atilde -110
KPX Yacute O -35
KPX Yacute Oacute -35
KPX Yacute Ocircumflex -35
KPX Yacute Odieresis -35
KPX Yacute Ograve -35
KPX Yacute Ohungarumlaut -35
KPX Yacute Omacron -35
KPX Yacute Oslash -35
KPX Yacute Otilde -35
KPX Yacute a -85
KPX Yacute aacute -85
KPX Yacute abreve -85
KPX Yacute acircumflex -85
KPX Yacute adieresis -85
KPX Yacute agrave -85
KPX Yacute amacron -85
KPX Yacute aogonek -85
KPX Yacute aring -85
KPX Yacute atilde -85
KPX Yacute colon -92
KPX Yacute comma -92
KPX Yacute e -111
KPX Yacute eacute -111
KPX Yacute ecaron -111
KPX Yacute ecircumflex -111
KPX Yacute edieresis -71
KPX Yacute edotaccent -111
KPX Yacute egrave -71
KPX Yacute emacron -71
KPX Yacute eogonek -111
KPX Yacute hyphen -92
KPX Yacute i -37
KPX Yacute iacute -37
KPX Yacute iogonek -37
KPX Yacute o -111
KPX Yacute oacute -111
KPX Yacute ocircumflex -111
KPX Yacute odieresis -111
KPX Yacute ograve -111
KPX Yacute ohungarumlaut -111
KPX Yacute omacron -111
KPX Yacute oslash -111
KPX Yacute otilde -111
KPX Yacute period -92
KPX Yacute semicolon -92
KPX Yacute u -92
KPX Yacute uacute -92
KPX Yacute ucircumflex -92
KPX Yacute udieresis -92
KPX Yacute ugrave -92
KPX Yacute uhungarumlaut -92
KPX Yacute umacron -92
KPX Yacute uogonek -92
KPX Yacute uring -92
KPX Ydieresis A -110
KPX Ydieresis Aacute -110
KPX Ydieresis Abreve -110
KPX Ydieresis Acircumflex -110
KPX Ydieresis Adieresis -110
KPX Ydieresis Agrave -110
KPX Ydieresis Amacron -110
KPX Ydieresis Aogonek -110
KPX Ydieresis Aring -110
KPX Ydieresis Atilde -110
KPX Ydieresis O -35
KPX Ydieresis Oacute -35
KPX Ydieresis Ocircumflex -35
KPX Ydieresis Odieresis -35
KPX Ydieresis Ograve -35
KPX Ydieresis Ohungarumlaut -35
KPX Ydieresis Omacron -35
KPX Ydieresis Oslash -35
KPX Ydieresis Otilde -35
KPX Ydieresis a -85
KPX Ydieresis aacute -85
KPX Ydieresis abreve -85
KPX Ydieresis acircumflex -85
KPX Ydieresis adieresis -85
KPX Ydieresis agrave -85
KPX Ydieresis amacron -85
KPX Ydieresis aogonek -85
KPX Ydieresis aring -85
KPX Ydieresis atilde -85
KPX Ydieresis colon -92
KPX Ydieresis comma -92
KPX Ydieresis e -111
KPX Ydieresis eacute -111
KPX Ydieresis ecaron -111
KPX Ydieresis ecircumflex -111
KPX Ydieresis edieresis -71
KPX Ydieresis edotaccent -111
KPX Ydieresis egrave -71
KPX Ydieresis emacron -71
KPX Ydieresis eogonek -111
KPX Ydieresis hyphen -92
KPX Ydieresis i -37
KPX Ydieresis iacute -37
KPX Ydieresis iogonek -37
KPX Ydieresis o -111
KPX Ydieresis oacute -111
KPX Ydieresis ocircumflex -111
KPX Ydieresis odieresis -111
KPX Ydieresis ograve -111
KPX Ydieresis ohungarumlaut -111
KPX Ydieresis omacron -111
KPX Ydieresis oslash -111
KPX Ydieresis otilde -111
KPX Ydieresis period -92
KPX Ydieresis semicolon -92
KPX Ydieresis u -92
KPX Ydieresis uacute -92
KPX Ydieresis ucircumflex -92
KPX Ydieresis udieresis -92
KPX Ydieresis ugrave -92
KPX Ydieresis uhungarumlaut -92
KPX Ydieresis umacron -92
KPX Ydieresis uogonek -92
KPX Ydieresis uring -92
KPX a v -25
KPX aacute v -25
KPX abreve v -25
KPX acircumflex v -25
KPX adieresis v -25
KPX agrave v -25
KPX amacron v -25
KPX aogonek v -25
KPX aring v -25
KPX atilde v -25
KPX b b -10
KPX b period -40
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX b v -15
KPX comma quotedblright -45
KPX comma quoteright -55
KPX d w -15
KPX dcroat w -15
KPX e v -15
KPX eacute v -15
KPX ecaron v -15
KPX ecircumflex v -15
KPX edieresis v -15
KPX edotaccent v -15
KPX egrave v -15
KPX emacron v -15
KPX eogonek v -15
KPX f comma -15
KPX f dotlessi -35
KPX f i -25
KPX f o -25
KPX f oacute -25
KPX f ocircumflex -25
KPX f odieresis -25
KPX f ograve -25
KPX f ohungarumlaut -25
KPX f omacron -25
KPX f oslash -25
KPX f otilde -25
KPX f period -15
KPX f quotedblright 50
KPX f quoteright 55
KPX g period -15
KPX gbreve period -15
KPX gcommaaccent period -15
KPX h y -15
KPX h yacute -15
KPX h ydieresis -15
KPX i v -10
KPX iacute v -10
KPX icircumflex v -10
KPX idieresis v -10
KPX igrave v -10
KPX imacron v -10
KPX iogonek v -10
KPX k e -10
KPX k eacute -10
KPX k ecaron -10
KPX k ecircumflex -10
KPX k edieresis -10
KPX k edotaccent -10
KPX k egrave -10
KPX k emacron -10
KPX k eogonek -10
KPX k o -15
KPX k oacute -15
KPX k ocircumflex -15
KPX k odieresis -15
KPX k ograve -15
KPX k ohungarumlaut -15
KPX k omacron -15
KPX k oslash -15
KPX k otilde -15
KPX k y -15
KPX k yacute -15
KPX k ydieresis -15
KPX kcommaaccent e -10
KPX kcommaaccent eacute -10
KPX kcommaaccent ecaron -10
KPX kcommaaccent ecircumflex -10
KPX kcommaaccent edieresis -10
KPX kcommaaccent edotaccent -10
KPX kcommaaccent egrave -10
KPX kcommaaccent emacron -10
KPX kcommaaccent eogonek -10
KPX kcommaaccent o -15
KPX kcommaaccent oacute -15
KPX kcommaaccent ocircumflex -15
KPX kcommaaccent odieresis -15
KPX kcommaaccent ograve -15
KPX kcommaaccent ohungarumlaut -15
KPX kcommaaccent omacron -15
KPX kcommaaccent oslash -15
KPX kcommaaccent otilde -15
KPX kcommaaccent y -15
KPX kcommaaccent yacute -15
KPX kcommaaccent ydieresis -15
KPX n v -40
KPX nacute v -40
KPX ncaron v -40
KPX ncommaaccent v -40
KPX ntilde v -40
KPX o v -10
KPX o w -10
KPX oacute v -10
KPX oacute w -10
KPX ocircumflex v -10
KPX ocircumflex w -10
KPX odieresis v -10
KPX odieresis w -10
KPX ograve v -10
KPX ograve w -10
KPX ohungarumlaut v -10
KPX ohungarumlaut w -10
KPX omacron v -10
KPX omacron w -10
KPX oslash v -10
KPX oslash w -10
KPX otilde v -10
KPX otilde w -10
KPX period quotedblright -55
KPX period quoteright -55
KPX quotedblleft A -10
KPX quotedblleft Aacute -10
KPX quotedblleft Abreve -10
KPX quotedblleft Acircumflex -10
KPX quotedblleft Adieresis -10
KPX quotedblleft Agrave -10
KPX quotedblleft Amacron -10
KPX quotedblleft Aogonek -10
KPX quotedblleft Aring -10
KPX quotedblleft Atilde -10
KPX quoteleft A -10
KPX quoteleft Aacute -10
KPX quoteleft Abreve -10
KPX quoteleft Acircumflex -10
KPX quoteleft Adieresis -10
KPX quoteleft Agrave -10
KPX quoteleft Amacron -10
KPX quoteleft Aogonek -10
KPX quoteleft Aring -10
KPX quoteleft Atilde -10
KPX quoteleft quoteleft -63
KPX quoteright d -20
KPX quoteright dcroat -20
KPX quoteright quoteright -63
KPX quoteright r -20
KPX quoteright racute -20
KPX quoteright rcaron -20
KPX quoteright rcommaaccent -20
KPX quoteright s -37
KPX quoteright sacute -37
KPX quoteright scaron -37
KPX quoteright scedilla -37
KPX quoteright scommaaccent -37
KPX quoteright space -74
KPX quoteright v -20
KPX r c -18
KPX r cacute -18
KPX r ccaron -18
KPX r ccedilla -18
KPX r comma -92
KPX r e -18
KPX r eacute -18
KPX r ecaron -18
KPX r ecircumflex -18
KPX r edieresis -18
KPX r edotaccent -18
KPX r egrave -18
KPX r emacron -18
KPX r eogonek -18
KPX r g -10
KPX r gbreve -10
KPX r gcommaaccent -10
KPX r hyphen -37
KPX r n -15
KPX r nacute -15
KPX r ncaron -15
KPX r ncommaaccent -15
KPX r ntilde -15
KPX r o -18
KPX r oacute -18
KPX r ocircumflex -18
KPX r odieresis -18
KPX r ograve -18
KPX r ohungarumlaut -18
KPX r omacron -18
KPX r oslash -18
KPX r otilde -18
KPX r p -10
KPX r period -100
KPX r q -18
KPX r v -10
KPX racute c -18
KPX racute cacute -18
KPX racute ccaron -18
KPX racute ccedilla -18
KPX racute comma -92
KPX racute e -18
KPX racute eacute -18
KPX racute ecaron -18
KPX racute ecircumflex -18
KPX racute edieresis -18
KPX racute edotaccent -18
KPX racute egrave -18
KPX racute emacron -18
KPX racute eogonek -18
KPX racute g -10
KPX racute gbreve -10
KPX racute gcommaaccent -10
KPX racute hyphen -37
KPX racute n -15
KPX racute nacute -15
KPX racute ncaron -15
KPX racute ncommaaccent -15
KPX racute ntilde -15
KPX racute o -18
KPX racute oacute -18
KPX racute ocircumflex -18
KPX racute odieresis -18
KPX racute ograve -18
KPX racute ohungarumlaut -18
KPX racute omacron -18
KPX racute oslash -18
KPX racute otilde -18
KPX racute p -10
KPX racute period -100
KPX racute q -18
KPX racute v -10
KPX rcaron c -18
KPX rcaron cacute -18
KPX rcaron ccaron -18
KPX rcaron ccedilla -18
KPX rcaron comma -92
KPX rcaron e -18
KPX rcaron eacute -18
KPX rcaron ecaron -18
KPX rcaron ecircumflex -18
KPX rcaron edieresis -18
KPX rcaron edotaccent -18
KPX rcaron egrave -18
KPX rcaron emacron -18
KPX rcaron eogonek -18
KPX rcaron g -10
KPX rcaron gbreve -10
KPX rcaron gcommaaccent -10
KPX rcaron hyphen -37
KPX rcaron n -15
KPX rcaron nacute -15
KPX rcaron ncaron -15
KPX rcaron ncommaaccent -15
KPX rcaron ntilde -15
KPX rcaron o -18
KPX rcaron oacute -18
KPX rcaron ocircumflex -18
KPX rcaron odieresis -18
KPX rcaron ograve -18
KPX rcaron ohungarumlaut -18
KPX rcaron omacron -18
KPX rcaron oslash -18
KPX rcaron otilde -18
KPX rcaron p -10
KPX rcaron period -100
KPX rcaron q -18
KPX rcaron v -10
KPX rcommaaccent c -18
KPX rcommaaccent cacute -18
KPX rcommaaccent ccaron -18
KPX rcommaaccent ccedilla -18
KPX rcommaaccent comma -92
KPX rcommaaccent e -18
KPX rcommaaccent eacute -18
KPX rcommaaccent ecaron -18
KPX rcommaaccent ecircumflex -18
KPX rcommaaccent edieresis -18
KPX rcommaaccent edotaccent -18
KPX rcommaaccent egrave -18
KPX rcommaaccent emacron -18
KPX rcommaaccent eogonek -18
KPX rcommaaccent g -10
KPX rcommaaccent gbreve -10
KPX rcommaaccent gcommaaccent -10
KPX rcommaaccent hyphen -37
KPX rcommaaccent n -15
KPX rcommaaccent nacute -15
KPX rcommaaccent ncaron -15
KPX rcommaaccent ncommaaccent -15
KPX rcommaaccent ntilde -15
KPX rcommaaccent o -18
KPX rcommaaccent oacute -18
KPX rcommaaccent ocircumflex -18
KPX rcommaaccent odieresis -18
KPX rcommaaccent ograve -18
KPX rcommaaccent ohungarumlaut -18
KPX rcommaaccent omacron -18
KPX rcommaaccent oslash -18
KPX rcommaaccent otilde -18
KPX rcommaaccent p -10
KPX rcommaaccent period -100
KPX rcommaaccent q -18
KPX rcommaaccent v -10
KPX space A -55
KPX space Aacute -55
KPX space Abreve -55
KPX space Acircumflex -55
KPX space Adieresis -55
KPX space Agrave -55
KPX space Amacron -55
KPX space Aogonek -55
KPX space Aring -55
KPX space Atilde -55
KPX space T -30
KPX space Tcaron -30
KPX space Tcommaaccent -30
KPX space V -45
KPX space W -30
KPX space Y -55
KPX space Yacute -55
KPX space Ydieresis -55
KPX v a -10
KPX v aacute -10
KPX v abreve -10
KPX v acircumflex -10
KPX v adieresis -10
KPX v agrave -10
KPX v amacron -10
KPX v aogonek -10
KPX v aring -10
KPX v atilde -10
KPX v comma -55
KPX v e -10
KPX v eacute -10
KPX v ecaron -10
KPX v ecircumflex -10
KPX v edieresis -10
KPX v edotaccent -10
KPX v egrave -10
KPX v emacron -10
KPX v eogonek -10
KPX v o -10
KPX v oacute -10
KPX v ocircumflex -10
KPX v odieresis -10
KPX v ograve -10
KPX v ohungarumlaut -10
KPX v omacron -10
KPX v oslash -10
KPX v otilde -10
KPX v period -70
KPX w comma -55
KPX w o -10
KPX w oacute -10
KPX w ocircumflex -10
KPX w odieresis -10
KPX w ograve -10
KPX w ohungarumlaut -10
KPX w omacron -10
KPX w oslash -10
KPX w otilde -10
KPX w period -70
KPX y comma -55
KPX y e -10
KPX y eacute -10
KPX y ecaron -10
KPX y ecircumflex -10
KPX y edieresis -10
KPX y edotaccent -10
KPX y egrave -10
KPX y emacron -10
KPX y eogonek -10
KPX y o -25
KPX y oacute -25
KPX y ocircumflex -25
KPX y odieresis -25
KPX y ograve -25
KPX y ohungarumlaut -25
KPX y omacron -25
KPX y oslash -25
KPX y otilde -25
KPX y period -70
KPX yacute comma -55
KPX yacute e -10
KPX yacute eacute -10
KPX yacute ecaron -10
KPX yacute ecircumflex -10
KPX yacute edieresis -10
KPX yacute edotaccent -10
KPX yacute egrave -10
KPX yacute emacron -10
KPX yacute eogonek -10
KPX yacute o -25
KPX yacute oacute -25
KPX yacute ocircumflex -25
KPX yacute odieresis -25
KPX yacute ograve -25
KPX yacute ohungarumlaut -25
KPX yacute omacron -25
KPX yacute oslash -25
KPX yacute otilde -25
KPX yacute period -70
KPX ydieresis comma -55
KPX ydieresis e -10
KPX ydieresis eacute -10
KPX ydieresis ecaron -10
KPX ydieresis ecircumflex -10
KPX ydieresis edieresis -10
KPX ydieresis edotaccent -10
KPX ydieresis egrave -10
KPX ydieresis emacron -10
KPX ydieresis eogonek -10
KPX ydieresis o -25
KPX ydieresis oacute -25
KPX ydieresis ocircumflex -25
KPX ydieresis odieresis -25
KPX ydieresis ograve -25
KPX ydieresis ohungarumlaut -25
KPX ydieresis omacron -25
KPX ydieresis oslash -25
KPX ydieresis otilde -25
KPX ydieresis period -70
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Times-BoldItalic.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 13:04:06 1997
Comment UniqueID 43066
Comment VMusage 45874 56899
FontName Times-BoldItalic
FullName Times Bold Italic
FamilyName Times
Weight Bold
ItalicAngle -15
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -200 -218 996 921
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 669
XHeight 462
Ascender 683
Descender -217
StdHW 42
StdVW 121
StartCharMetrics 315
C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
C 33 ; WX 389 ; N exclam ; B 67 -13 370 684 ;
C 34 ; WX 555 ; N quotedbl ; B 136 398 536 685 ;
C 35 ; WX 500 ; N numbersign ; B -33 0 533 700 ;
C 36 ; WX 500 ; N dollar ; B -20 -100 497 733 ;
C 37 ; WX 833 ; N percent ; B 39 -10 793 692 ;
C 38 ; WX 778 ; N ampersand ; B 5 -19 699 682 ;
C 39 ; WX 333 ; N quoteright ; B 98 369 302 685 ;
C 40 ; WX 333 ; N parenleft ; B 28 -179 344 685 ;
C 41 ; WX 333 ; N parenright ; B -44 -179 271 685 ;
C 42 ; WX 500 ; N asterisk ; B 65 249 456 685 ;
C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
C 44 ; WX 250 ; N comma ; B -60 -182 144 134 ;
C 45 ; WX 333 ; N hyphen ; B 2 166 271 282 ;
C 46 ; WX 250 ; N period ; B -9 -13 139 135 ;
C 47 ; WX 278 ; N slash ; B -64 -18 342 685 ;
C 48 ; WX 500 ; N zero ; B 17 -14 477 683 ;
C 49 ; WX 500 ; N one ; B 5 0 419 683 ;
C 50 ; WX 500 ; N two ; B -27 0 446 683 ;
C 51 ; WX 500 ; N three ; B -15 -13 450 683 ;
C 52 ; WX 500 ; N four ; B -15 0 503 683 ;
C 53 ; WX 500 ; N five ; B -11 -13 487 669 ;
C 54 ; WX 500 ; N six ; B 23 -15 509 679 ;
C 55 ; WX 500 ; N seven ; B 52 0 525 669 ;
C 56 ; WX 500 ; N eight ; B 3 -13 476 683 ;
C 57 ; WX 500 ; N nine ; B -12 -10 475 683 ;
C 58 ; WX 333 ; N colon ; B 23 -13 264 459 ;
C 59 ; WX 333 ; N semicolon ; B -25 -183 264 459 ;
C 60 ; WX 570 ; N less ; B 31 -8 539 514 ;
C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ;
C 63 ; WX 500 ; N question ; B 79 -13 470 684 ;
C 64 ; WX 832 ; N at ; B 63 -18 770 685 ;
C 65 ; WX 667 ; N A ; B -67 0 593 683 ;
C 66 ; WX 667 ; N B ; B -24 0 624 669 ;
C 67 ; WX 667 ; N C ; B 32 -18 677 685 ;
C 68 ; WX 722 ; N D ; B -46 0 685 669 ;
C 69 ; WX 667 ; N E ; B -27 0 653 669 ;
C 70 ; WX 667 ; N F ; B -13 0 660 669 ;
C 71 ; WX 722 ; N G ; B 21 -18 706 685 ;
C 72 ; WX 778 ; N H ; B -24 0 799 669 ;
C 73 ; WX 389 ; N I ; B -32 0 406 669 ;
C 74 ; WX 500 ; N J ; B -46 -99 524 669 ;
C 75 ; WX 667 ; N K ; B -21 0 702 669 ;
C 76 ; WX 611 ; N L ; B -22 0 590 669 ;
C 77 ; WX 889 ; N M ; B -29 -12 917 669 ;
C 78 ; WX 722 ; N N ; B -27 -15 748 669 ;
C 79 ; WX 722 ; N O ; B 27 -18 691 685 ;
C 80 ; WX 611 ; N P ; B -27 0 613 669 ;
C 81 ; WX 722 ; N Q ; B 27 -208 691 685 ;
C 82 ; WX 667 ; N R ; B -29 0 623 669 ;
C 83 ; WX 556 ; N S ; B 2 -18 526 685 ;
C 84 ; WX 611 ; N T ; B 50 0 650 669 ;
C 85 ; WX 722 ; N U ; B 67 -18 744 669 ;
C 86 ; WX 667 ; N V ; B 65 -18 715 669 ;
C 87 ; WX 889 ; N W ; B 65 -18 940 669 ;
C 88 ; WX 667 ; N X ; B -24 0 694 669 ;
C 89 ; WX 611 ; N Y ; B 73 0 659 669 ;
C 90 ; WX 611 ; N Z ; B -11 0 590 669 ;
C 91 ; WX 333 ; N bracketleft ; B -37 -159 362 674 ;
C 92 ; WX 278 ; N backslash ; B -1 -18 279 685 ;
C 93 ; WX 333 ; N bracketright ; B -56 -157 343 674 ;
C 94 ; WX 570 ; N asciicircum ; B 67 304 503 669 ;
C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
C 96 ; WX 333 ; N quoteleft ; B 128 369 332 685 ;
C 97 ; WX 500 ; N a ; B -21 -14 455 462 ;
C 98 ; WX 500 ; N b ; B -14 -13 444 699 ;
C 99 ; WX 444 ; N c ; B -5 -13 392 462 ;
C 100 ; WX 500 ; N d ; B -21 -13 517 699 ;
C 101 ; WX 444 ; N e ; B 5 -13 398 462 ;
C 102 ; WX 333 ; N f ; B -169 -205 446 698 ; L i fi ; L l fl ;
C 103 ; WX 500 ; N g ; B -52 -203 478 462 ;
C 104 ; WX 556 ; N h ; B -13 -9 498 699 ;
C 105 ; WX 278 ; N i ; B 2 -9 263 684 ;
C 106 ; WX 278 ; N j ; B -189 -207 279 684 ;
C 107 ; WX 500 ; N k ; B -23 -8 483 699 ;
C 108 ; WX 278 ; N l ; B 2 -9 290 699 ;
C 109 ; WX 778 ; N m ; B -14 -9 722 462 ;
C 110 ; WX 556 ; N n ; B -6 -9 493 462 ;
C 111 ; WX 500 ; N o ; B -3 -13 441 462 ;
C 112 ; WX 500 ; N p ; B -120 -205 446 462 ;
C 113 ; WX 500 ; N q ; B 1 -205 471 462 ;
C 114 ; WX 389 ; N r ; B -21 0 389 462 ;
C 115 ; WX 389 ; N s ; B -19 -13 333 462 ;
C 116 ; WX 278 ; N t ; B -11 -9 281 594 ;
C 117 ; WX 556 ; N u ; B 15 -9 492 462 ;
C 118 ; WX 444 ; N v ; B 16 -13 401 462 ;
C 119 ; WX 667 ; N w ; B 16 -13 614 462 ;
C 120 ; WX 500 ; N x ; B -46 -13 469 462 ;
C 121 ; WX 444 ; N y ; B -94 -205 392 462 ;
C 122 ; WX 389 ; N z ; B -43 -78 368 449 ;
C 123 ; WX 348 ; N braceleft ; B 5 -187 436 686 ;
C 124 ; WX 220 ; N bar ; B 66 -218 154 782 ;
C 125 ; WX 348 ; N braceright ; B -129 -187 302 686 ;
C 126 ; WX 570 ; N asciitilde ; B 54 173 516 333 ;
C 161 ; WX 389 ; N exclamdown ; B 19 -205 322 492 ;
C 162 ; WX 500 ; N cent ; B 42 -143 439 576 ;
C 163 ; WX 500 ; N sterling ; B -32 -12 510 683 ;
C 164 ; WX 167 ; N fraction ; B -169 -14 324 683 ;
C 165 ; WX 500 ; N yen ; B 33 0 628 669 ;
C 166 ; WX 500 ; N florin ; B -87 -156 537 707 ;
C 167 ; WX 500 ; N section ; B 36 -143 459 685 ;
C 168 ; WX 500 ; N currency ; B -26 34 526 586 ;
C 169 ; WX 278 ; N quotesingle ; B 128 398 268 685 ;
C 170 ; WX 500 ; N quotedblleft ; B 53 369 513 685 ;
C 171 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ;
C 172 ; WX 333 ; N guilsinglleft ; B 32 32 303 415 ;
C 173 ; WX 333 ; N guilsinglright ; B 10 32 281 415 ;
C 174 ; WX 556 ; N fi ; B -188 -205 514 703 ;
C 175 ; WX 556 ; N fl ; B -186 -205 553 704 ;
C 177 ; WX 500 ; N endash ; B -40 178 477 269 ;
C 178 ; WX 500 ; N dagger ; B 91 -145 494 685 ;
C 179 ; WX 500 ; N daggerdbl ; B 10 -139 493 685 ;
C 180 ; WX 250 ; N periodcentered ; B 51 257 199 405 ;
C 182 ; WX 500 ; N paragraph ; B -57 -193 562 669 ;
C 183 ; WX 350 ; N bullet ; B 0 175 350 525 ;
C 184 ; WX 333 ; N quotesinglbase ; B -5 -182 199 134 ;
C 185 ; WX 500 ; N quotedblbase ; B -57 -182 403 134 ;
C 186 ; WX 500 ; N quotedblright ; B 53 369 513 685 ;
C 187 ; WX 500 ; N guillemotright ; B 12 32 468 415 ;
C 188 ; WX 1000 ; N ellipsis ; B 40 -13 852 135 ;
C 189 ; WX 1000 ; N perthousand ; B 7 -29 996 706 ;
C 191 ; WX 500 ; N questiondown ; B 30 -205 421 492 ;
C 193 ; WX 333 ; N grave ; B 85 516 297 697 ;
C 194 ; WX 333 ; N acute ; B 139 516 379 697 ;
C 195 ; WX 333 ; N circumflex ; B 40 516 367 690 ;
C 196 ; WX 333 ; N tilde ; B 48 536 407 655 ;
C 197 ; WX 333 ; N macron ; B 51 553 393 623 ;
C 198 ; WX 333 ; N breve ; B 71 516 387 678 ;
C 199 ; WX 333 ; N dotaccent ; B 163 550 298 684 ;
C 200 ; WX 333 ; N dieresis ; B 55 550 402 684 ;
C 202 ; WX 333 ; N ring ; B 127 516 340 729 ;
C 203 ; WX 333 ; N cedilla ; B -80 -218 156 5 ;
C 205 ; WX 333 ; N hungarumlaut ; B 69 516 498 697 ;
C 206 ; WX 333 ; N ogonek ; B 15 -183 244 34 ;
C 207 ; WX 333 ; N caron ; B 79 516 411 690 ;
C 208 ; WX 1000 ; N emdash ; B -40 178 977 269 ;
C 225 ; WX 944 ; N AE ; B -64 0 918 669 ;
C 227 ; WX 266 ; N ordfeminine ; B 16 399 330 685 ;
C 232 ; WX 611 ; N Lslash ; B -22 0 590 669 ;
C 233 ; WX 722 ; N Oslash ; B 27 -125 691 764 ;
C 234 ; WX 944 ; N OE ; B 23 -8 946 677 ;
C 235 ; WX 300 ; N ordmasculine ; B 56 400 347 685 ;
C 241 ; WX 722 ; N ae ; B -5 -13 673 462 ;
C 245 ; WX 278 ; N dotlessi ; B 2 -9 238 462 ;
C 248 ; WX 278 ; N lslash ; B -7 -9 307 699 ;
C 249 ; WX 500 ; N oslash ; B -3 -119 441 560 ;
C 250 ; WX 722 ; N oe ; B 6 -13 674 462 ;
C 251 ; WX 500 ; N germandbls ; B -200 -200 473 705 ;
C -1 ; WX 389 ; N Idieresis ; B -32 0 450 862 ;
C -1 ; WX 444 ; N eacute ; B 5 -13 435 697 ;
C -1 ; WX 500 ; N abreve ; B -21 -14 471 678 ;
C -1 ; WX 556 ; N uhungarumlaut ; B 15 -9 610 697 ;
C -1 ; WX 444 ; N ecaron ; B 5 -13 467 690 ;
C -1 ; WX 611 ; N Ydieresis ; B 73 0 659 862 ;
C -1 ; WX 570 ; N divide ; B 33 -29 537 535 ;
C -1 ; WX 611 ; N Yacute ; B 73 0 659 904 ;
C -1 ; WX 667 ; N Acircumflex ; B -67 0 593 897 ;
C -1 ; WX 500 ; N aacute ; B -21 -14 463 697 ;
C -1 ; WX 722 ; N Ucircumflex ; B 67 -18 744 897 ;
C -1 ; WX 444 ; N yacute ; B -94 -205 435 697 ;
C -1 ; WX 389 ; N scommaaccent ; B -19 -218 333 462 ;
C -1 ; WX 444 ; N ecircumflex ; B 5 -13 423 690 ;
C -1 ; WX 722 ; N Uring ; B 67 -18 744 921 ;
C -1 ; WX 722 ; N Udieresis ; B 67 -18 744 862 ;
C -1 ; WX 500 ; N aogonek ; B -21 -183 455 462 ;
C -1 ; WX 722 ; N Uacute ; B 67 -18 744 904 ;
C -1 ; WX 556 ; N uogonek ; B 15 -183 492 462 ;
C -1 ; WX 667 ; N Edieresis ; B -27 0 653 862 ;
C -1 ; WX 722 ; N Dcroat ; B -31 0 700 669 ;
C -1 ; WX 250 ; N commaaccent ; B -36 -218 131 -50 ;
C -1 ; WX 747 ; N copyright ; B 30 -18 718 685 ;
C -1 ; WX 667 ; N Emacron ; B -27 0 653 830 ;
C -1 ; WX 444 ; N ccaron ; B -5 -13 467 690 ;
C -1 ; WX 500 ; N aring ; B -21 -14 455 729 ;
C -1 ; WX 722 ; N Ncommaaccent ; B -27 -218 748 669 ;
C -1 ; WX 278 ; N lacute ; B 2 -9 392 904 ;
C -1 ; WX 500 ; N agrave ; B -21 -14 455 697 ;
C -1 ; WX 611 ; N Tcommaaccent ; B 50 -218 650 669 ;
C -1 ; WX 667 ; N Cacute ; B 32 -18 677 904 ;
C -1 ; WX 500 ; N atilde ; B -21 -14 491 655 ;
C -1 ; WX 667 ; N Edotaccent ; B -27 0 653 862 ;
C -1 ; WX 389 ; N scaron ; B -19 -13 424 690 ;
C -1 ; WX 389 ; N scedilla ; B -19 -218 333 462 ;
C -1 ; WX 278 ; N iacute ; B 2 -9 352 697 ;
C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ;
C -1 ; WX 667 ; N Rcaron ; B -29 0 623 897 ;
C -1 ; WX 722 ; N Gcommaaccent ; B 21 -218 706 685 ;
C -1 ; WX 556 ; N ucircumflex ; B 15 -9 492 690 ;
C -1 ; WX 500 ; N acircumflex ; B -21 -14 455 690 ;
C -1 ; WX 667 ; N Amacron ; B -67 0 593 830 ;
C -1 ; WX 389 ; N rcaron ; B -21 0 424 690 ;
C -1 ; WX 444 ; N ccedilla ; B -5 -218 392 462 ;
C -1 ; WX 611 ; N Zdotaccent ; B -11 0 590 862 ;
C -1 ; WX 611 ; N Thorn ; B -27 0 573 669 ;
C -1 ; WX 722 ; N Omacron ; B 27 -18 691 830 ;
C -1 ; WX 667 ; N Racute ; B -29 0 623 904 ;
C -1 ; WX 556 ; N Sacute ; B 2 -18 531 904 ;
C -1 ; WX 608 ; N dcaron ; B -21 -13 675 708 ;
C -1 ; WX 722 ; N Umacron ; B 67 -18 744 830 ;
C -1 ; WX 556 ; N uring ; B 15 -9 492 729 ;
C -1 ; WX 300 ; N threesuperior ; B 17 265 321 683 ;
C -1 ; WX 722 ; N Ograve ; B 27 -18 691 904 ;
C -1 ; WX 667 ; N Agrave ; B -67 0 593 904 ;
C -1 ; WX 667 ; N Abreve ; B -67 0 593 885 ;
C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
C -1 ; WX 556 ; N uacute ; B 15 -9 492 697 ;
C -1 ; WX 611 ; N Tcaron ; B 50 0 650 897 ;
C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ;
C -1 ; WX 444 ; N ydieresis ; B -94 -205 443 655 ;
C -1 ; WX 722 ; N Nacute ; B -27 -15 748 904 ;
C -1 ; WX 278 ; N icircumflex ; B -3 -9 324 690 ;
C -1 ; WX 667 ; N Ecircumflex ; B -27 0 653 897 ;
C -1 ; WX 500 ; N adieresis ; B -21 -14 476 655 ;
C -1 ; WX 444 ; N edieresis ; B 5 -13 448 655 ;
C -1 ; WX 444 ; N cacute ; B -5 -13 435 697 ;
C -1 ; WX 556 ; N nacute ; B -6 -9 493 697 ;
C -1 ; WX 556 ; N umacron ; B 15 -9 492 623 ;
C -1 ; WX 722 ; N Ncaron ; B -27 -15 748 897 ;
C -1 ; WX 389 ; N Iacute ; B -32 0 432 904 ;
C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ;
C -1 ; WX 220 ; N brokenbar ; B 66 -143 154 707 ;
C -1 ; WX 747 ; N registered ; B 30 -18 718 685 ;
C -1 ; WX 722 ; N Gbreve ; B 21 -18 706 885 ;
C -1 ; WX 389 ; N Idotaccent ; B -32 0 406 862 ;
C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ;
C -1 ; WX 667 ; N Egrave ; B -27 0 653 904 ;
C -1 ; WX 389 ; N racute ; B -21 0 407 697 ;
C -1 ; WX 500 ; N omacron ; B -3 -13 462 623 ;
C -1 ; WX 611 ; N Zacute ; B -11 0 590 904 ;
C -1 ; WX 611 ; N Zcaron ; B -11 0 590 897 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ;
C -1 ; WX 722 ; N Eth ; B -31 0 700 669 ;
C -1 ; WX 667 ; N Ccedilla ; B 32 -218 677 685 ;
C -1 ; WX 278 ; N lcommaaccent ; B -42 -218 290 699 ;
C -1 ; WX 366 ; N tcaron ; B -11 -9 434 754 ;
C -1 ; WX 444 ; N eogonek ; B 5 -183 398 462 ;
C -1 ; WX 722 ; N Uogonek ; B 67 -183 744 669 ;
C -1 ; WX 667 ; N Aacute ; B -67 0 593 904 ;
C -1 ; WX 667 ; N Adieresis ; B -67 0 593 862 ;
C -1 ; WX 444 ; N egrave ; B 5 -13 398 697 ;
C -1 ; WX 389 ; N zacute ; B -43 -78 407 697 ;
C -1 ; WX 278 ; N iogonek ; B -20 -183 263 684 ;
C -1 ; WX 722 ; N Oacute ; B 27 -18 691 904 ;
C -1 ; WX 500 ; N oacute ; B -3 -13 463 697 ;
C -1 ; WX 500 ; N amacron ; B -21 -14 467 623 ;
C -1 ; WX 389 ; N sacute ; B -19 -13 407 697 ;
C -1 ; WX 278 ; N idieresis ; B 2 -9 364 655 ;
C -1 ; WX 722 ; N Ocircumflex ; B 27 -18 691 897 ;
C -1 ; WX 722 ; N Ugrave ; B 67 -18 744 904 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 500 ; N thorn ; B -120 -205 446 699 ;
C -1 ; WX 300 ; N twosuperior ; B 2 274 313 683 ;
C -1 ; WX 722 ; N Odieresis ; B 27 -18 691 862 ;
C -1 ; WX 576 ; N mu ; B -60 -207 516 449 ;
C -1 ; WX 278 ; N igrave ; B 2 -9 259 697 ;
C -1 ; WX 500 ; N ohungarumlaut ; B -3 -13 582 697 ;
C -1 ; WX 667 ; N Eogonek ; B -27 -183 653 669 ;
C -1 ; WX 500 ; N dcroat ; B -21 -13 552 699 ;
C -1 ; WX 750 ; N threequarters ; B 7 -14 726 683 ;
C -1 ; WX 556 ; N Scedilla ; B 2 -218 526 685 ;
C -1 ; WX 382 ; N lcaron ; B 2 -9 448 708 ;
C -1 ; WX 667 ; N Kcommaaccent ; B -21 -218 702 669 ;
C -1 ; WX 611 ; N Lacute ; B -22 0 590 904 ;
C -1 ; WX 1000 ; N trademark ; B 32 263 968 669 ;
C -1 ; WX 444 ; N edotaccent ; B 5 -13 398 655 ;
C -1 ; WX 389 ; N Igrave ; B -32 0 406 904 ;
C -1 ; WX 389 ; N Imacron ; B -32 0 461 830 ;
C -1 ; WX 611 ; N Lcaron ; B -22 0 671 718 ;
C -1 ; WX 750 ; N onehalf ; B -9 -14 723 683 ;
C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ;
C -1 ; WX 500 ; N ocircumflex ; B -3 -13 451 690 ;
C -1 ; WX 556 ; N ntilde ; B -6 -9 504 655 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 67 -18 744 904 ;
C -1 ; WX 667 ; N Eacute ; B -27 0 653 904 ;
C -1 ; WX 444 ; N emacron ; B 5 -13 439 623 ;
C -1 ; WX 500 ; N gbreve ; B -52 -203 478 678 ;
C -1 ; WX 750 ; N onequarter ; B 7 -14 721 683 ;
C -1 ; WX 556 ; N Scaron ; B 2 -18 553 897 ;
C -1 ; WX 556 ; N Scommaaccent ; B 2 -218 526 685 ;
C -1 ; WX 722 ; N Ohungarumlaut ; B 27 -18 723 904 ;
C -1 ; WX 400 ; N degree ; B 83 397 369 683 ;
C -1 ; WX 500 ; N ograve ; B -3 -13 441 697 ;
C -1 ; WX 667 ; N Ccaron ; B 32 -18 677 897 ;
C -1 ; WX 556 ; N ugrave ; B 15 -9 492 697 ;
C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ;
C -1 ; WX 722 ; N Dcaron ; B -46 0 685 897 ;
C -1 ; WX 389 ; N rcommaaccent ; B -67 -218 389 462 ;
C -1 ; WX 722 ; N Ntilde ; B -27 -15 748 862 ;
C -1 ; WX 500 ; N otilde ; B -3 -13 491 655 ;
C -1 ; WX 667 ; N Rcommaaccent ; B -29 -218 623 669 ;
C -1 ; WX 611 ; N Lcommaaccent ; B -22 -218 590 669 ;
C -1 ; WX 667 ; N Atilde ; B -67 0 593 862 ;
C -1 ; WX 667 ; N Aogonek ; B -67 -183 604 683 ;
C -1 ; WX 667 ; N Aring ; B -67 0 593 921 ;
C -1 ; WX 722 ; N Otilde ; B 27 -18 691 862 ;
C -1 ; WX 389 ; N zdotaccent ; B -43 -78 368 655 ;
C -1 ; WX 667 ; N Ecaron ; B -27 0 653 897 ;
C -1 ; WX 389 ; N Iogonek ; B -32 -183 406 669 ;
C -1 ; WX 500 ; N kcommaaccent ; B -23 -218 483 699 ;
C -1 ; WX 606 ; N minus ; B 51 209 555 297 ;
C -1 ; WX 389 ; N Icircumflex ; B -32 0 450 897 ;
C -1 ; WX 556 ; N ncaron ; B -6 -9 523 690 ;
C -1 ; WX 278 ; N tcommaaccent ; B -62 -218 281 594 ;
C -1 ; WX 606 ; N logicalnot ; B 51 108 555 399 ;
C -1 ; WX 500 ; N odieresis ; B -3 -13 471 655 ;
C -1 ; WX 556 ; N udieresis ; B 15 -9 499 655 ;
C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ;
C -1 ; WX 500 ; N gcommaaccent ; B -52 -203 478 767 ;
C -1 ; WX 500 ; N eth ; B -3 -13 454 699 ;
C -1 ; WX 389 ; N zcaron ; B -43 -78 424 690 ;
C -1 ; WX 556 ; N ncommaaccent ; B -6 -218 493 462 ;
C -1 ; WX 300 ; N onesuperior ; B 30 274 301 683 ;
C -1 ; WX 278 ; N imacron ; B 2 -9 294 623 ;
C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2038
KPX A C -65
KPX A Cacute -65
KPX A Ccaron -65
KPX A Ccedilla -65
KPX A G -60
KPX A Gbreve -60
KPX A Gcommaaccent -60
KPX A O -50
KPX A Oacute -50
KPX A Ocircumflex -50
KPX A Odieresis -50
KPX A Ograve -50
KPX A Ohungarumlaut -50
KPX A Omacron -50
KPX A Oslash -50
KPX A Otilde -50
KPX A Q -55
KPX A T -55
KPX A Tcaron -55
KPX A Tcommaaccent -55
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -95
KPX A W -100
KPX A Y -70
KPX A Yacute -70
KPX A Ydieresis -70
KPX A quoteright -74
KPX A u -30
KPX A uacute -30
KPX A ucircumflex -30
KPX A udieresis -30
KPX A ugrave -30
KPX A uhungarumlaut -30
KPX A umacron -30
KPX A uogonek -30
KPX A uring -30
KPX A v -74
KPX A w -74
KPX A y -74
KPX A yacute -74
KPX A ydieresis -74
KPX Aacute C -65
KPX Aacute Cacute -65
KPX Aacute Ccaron -65
KPX Aacute Ccedilla -65
KPX Aacute G -60
KPX Aacute Gbreve -60
KPX Aacute Gcommaaccent -60
KPX Aacute O -50
KPX Aacute Oacute -50
KPX Aacute Ocircumflex -50
KPX Aacute Odieresis -50
KPX Aacute Ograve -50
KPX Aacute Ohungarumlaut -50
KPX Aacute Omacron -50
KPX Aacute Oslash -50
KPX Aacute Otilde -50
KPX Aacute Q -55
KPX Aacute T -55
KPX Aacute Tcaron -55
KPX Aacute Tcommaaccent -55
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -95
KPX Aacute W -100
KPX Aacute Y -70
KPX Aacute Yacute -70
KPX Aacute Ydieresis -70
KPX Aacute quoteright -74
KPX Aacute u -30
KPX Aacute uacute -30
KPX Aacute ucircumflex -30
KPX Aacute udieresis -30
KPX Aacute ugrave -30
KPX Aacute uhungarumlaut -30
KPX Aacute umacron -30
KPX Aacute uogonek -30
KPX Aacute uring -30
KPX Aacute v -74
KPX Aacute w -74
KPX Aacute y -74
KPX Aacute yacute -74
KPX Aacute ydieresis -74
KPX Abreve C -65
KPX Abreve Cacute -65
KPX Abreve Ccaron -65
KPX Abreve Ccedilla -65
KPX Abreve G -60
KPX Abreve Gbreve -60
KPX Abreve Gcommaaccent -60
KPX Abreve O -50
KPX Abreve Oacute -50
KPX Abreve Ocircumflex -50
KPX Abreve Odieresis -50
KPX Abreve Ograve -50
KPX Abreve Ohungarumlaut -50
KPX Abreve Omacron -50
KPX Abreve Oslash -50
KPX Abreve Otilde -50
KPX Abreve Q -55
KPX Abreve T -55
KPX Abreve Tcaron -55
KPX Abreve Tcommaaccent -55
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -95
KPX Abreve W -100
KPX Abreve Y -70
KPX Abreve Yacute -70
KPX Abreve Ydieresis -70
KPX Abreve quoteright -74
KPX Abreve u -30
KPX Abreve uacute -30
KPX Abreve ucircumflex -30
KPX Abreve udieresis -30
KPX Abreve ugrave -30
KPX Abreve uhungarumlaut -30
KPX Abreve umacron -30
KPX Abreve uogonek -30
KPX Abreve uring -30
KPX Abreve v -74
KPX Abreve w -74
KPX Abreve y -74
KPX Abreve yacute -74
KPX Abreve ydieresis -74
KPX Acircumflex C -65
KPX Acircumflex Cacute -65
KPX Acircumflex Ccaron -65
KPX Acircumflex Ccedilla -65
KPX Acircumflex G -60
KPX Acircumflex Gbreve -60
KPX Acircumflex Gcommaaccent -60
KPX Acircumflex O -50
KPX Acircumflex Oacute -50
KPX Acircumflex Ocircumflex -50
KPX Acircumflex Odieresis -50
KPX Acircumflex Ograve -50
KPX Acircumflex Ohungarumlaut -50
KPX Acircumflex Omacron -50
KPX Acircumflex Oslash -50
KPX Acircumflex Otilde -50
KPX Acircumflex Q -55
KPX Acircumflex T -55
KPX Acircumflex Tcaron -55
KPX Acircumflex Tcommaaccent -55
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -95
KPX Acircumflex W -100
KPX Acircumflex Y -70
KPX Acircumflex Yacute -70
KPX Acircumflex Ydieresis -70
KPX Acircumflex quoteright -74
KPX Acircumflex u -30
KPX Acircumflex uacute -30
KPX Acircumflex ucircumflex -30
KPX Acircumflex udieresis -30
KPX Acircumflex ugrave -30
KPX Acircumflex uhungarumlaut -30
KPX Acircumflex umacron -30
KPX Acircumflex uogonek -30
KPX Acircumflex uring -30
KPX Acircumflex v -74
KPX Acircumflex w -74
KPX Acircumflex y -74
KPX Acircumflex yacute -74
KPX Acircumflex ydieresis -74
KPX Adieresis C -65
KPX Adieresis Cacute -65
KPX Adieresis Ccaron -65
KPX Adieresis Ccedilla -65
KPX Adieresis G -60
KPX Adieresis Gbreve -60
KPX Adieresis Gcommaaccent -60
KPX Adieresis O -50
KPX Adieresis Oacute -50
KPX Adieresis Ocircumflex -50
KPX Adieresis Odieresis -50
KPX Adieresis Ograve -50
KPX Adieresis Ohungarumlaut -50
KPX Adieresis Omacron -50
KPX Adieresis Oslash -50
KPX Adieresis Otilde -50
KPX Adieresis Q -55
KPX Adieresis T -55
KPX Adieresis Tcaron -55
KPX Adieresis Tcommaaccent -55
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -95
KPX Adieresis W -100
KPX Adieresis Y -70
KPX Adieresis Yacute -70
KPX Adieresis Ydieresis -70
KPX Adieresis quoteright -74
KPX Adieresis u -30
KPX Adieresis uacute -30
KPX Adieresis ucircumflex -30
KPX Adieresis udieresis -30
KPX Adieresis ugrave -30
KPX Adieresis uhungarumlaut -30
KPX Adieresis umacron -30
KPX Adieresis uogonek -30
KPX Adieresis uring -30
KPX Adieresis v -74
KPX Adieresis w -74
KPX Adieresis y -74
KPX Adieresis yacute -74
KPX Adieresis ydieresis -74
KPX Agrave C -65
KPX Agrave Cacute -65
KPX Agrave Ccaron -65
KPX Agrave Ccedilla -65
KPX Agrave G -60
KPX Agrave Gbreve -60
KPX Agrave Gcommaaccent -60
KPX Agrave O -50
KPX Agrave Oacute -50
KPX Agrave Ocircumflex -50
KPX Agrave Odieresis -50
KPX Agrave Ograve -50
KPX Agrave Ohungarumlaut -50
KPX Agrave Omacron -50
KPX Agrave Oslash -50
KPX Agrave Otilde -50
KPX Agrave Q -55
KPX Agrave T -55
KPX Agrave Tcaron -55
KPX Agrave Tcommaaccent -55
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -95
KPX Agrave W -100
KPX Agrave Y -70
KPX Agrave Yacute -70
KPX Agrave Ydieresis -70
KPX Agrave quoteright -74
KPX Agrave u -30
KPX Agrave uacute -30
KPX Agrave ucircumflex -30
KPX Agrave udieresis -30
KPX Agrave ugrave -30
KPX Agrave uhungarumlaut -30
KPX Agrave umacron -30
KPX Agrave uogonek -30
KPX Agrave uring -30
KPX Agrave v -74
KPX Agrave w -74
KPX Agrave y -74
KPX Agrave yacute -74
KPX Agrave ydieresis -74
KPX Amacron C -65
KPX Amacron Cacute -65
KPX Amacron Ccaron -65
KPX Amacron Ccedilla -65
KPX Amacron G -60
KPX Amacron Gbreve -60
KPX Amacron Gcommaaccent -60
KPX Amacron O -50
KPX Amacron Oacute -50
KPX Amacron Ocircumflex -50
KPX Amacron Odieresis -50
KPX Amacron Ograve -50
KPX Amacron Ohungarumlaut -50
KPX Amacron Omacron -50
KPX Amacron Oslash -50
KPX Amacron Otilde -50
KPX Amacron Q -55
KPX Amacron T -55
KPX Amacron Tcaron -55
KPX Amacron Tcommaaccent -55
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -95
KPX Amacron W -100
KPX Amacron Y -70
KPX Amacron Yacute -70
KPX Amacron Ydieresis -70
KPX Amacron quoteright -74
KPX Amacron u -30
KPX Amacron uacute -30
KPX Amacron ucircumflex -30
KPX Amacron udieresis -30
KPX Amacron ugrave -30
KPX Amacron uhungarumlaut -30
KPX Amacron umacron -30
KPX Amacron uogonek -30
KPX Amacron uring -30
KPX Amacron v -74
KPX Amacron w -74
KPX Amacron y -74
KPX Amacron yacute -74
KPX Amacron ydieresis -74
KPX Aogonek C -65
KPX Aogonek Cacute -65
KPX Aogonek Ccaron -65
KPX Aogonek Ccedilla -65
KPX Aogonek G -60
KPX Aogonek Gbreve -60
KPX Aogonek Gcommaaccent -60
KPX Aogonek O -50
KPX Aogonek Oacute -50
KPX Aogonek Ocircumflex -50
KPX Aogonek Odieresis -50
KPX Aogonek Ograve -50
KPX Aogonek Ohungarumlaut -50
KPX Aogonek Omacron -50
KPX Aogonek Oslash -50
KPX Aogonek Otilde -50
KPX Aogonek Q -55
KPX Aogonek T -55
KPX Aogonek Tcaron -55
KPX Aogonek Tcommaaccent -55
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -95
KPX Aogonek W -100
KPX Aogonek Y -70
KPX Aogonek Yacute -70
KPX Aogonek Ydieresis -70
KPX Aogonek quoteright -74
KPX Aogonek u -30
KPX Aogonek uacute -30
KPX Aogonek ucircumflex -30
KPX Aogonek udieresis -30
KPX Aogonek ugrave -30
KPX Aogonek uhungarumlaut -30
KPX Aogonek umacron -30
KPX Aogonek uogonek -30
KPX Aogonek uring -30
KPX Aogonek v -74
KPX Aogonek w -74
KPX Aogonek y -34
KPX Aogonek yacute -34
KPX Aogonek ydieresis -34
KPX Aring C -65
KPX Aring Cacute -65
KPX Aring Ccaron -65
KPX Aring Ccedilla -65
KPX Aring G -60
KPX Aring Gbreve -60
KPX Aring Gcommaaccent -60
KPX Aring O -50
KPX Aring Oacute -50
KPX Aring Ocircumflex -50
KPX Aring Odieresis -50
KPX Aring Ograve -50
KPX Aring Ohungarumlaut -50
KPX Aring Omacron -50
KPX Aring Oslash -50
KPX Aring Otilde -50
KPX Aring Q -55
KPX Aring T -55
KPX Aring Tcaron -55
KPX Aring Tcommaaccent -55
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -95
KPX Aring W -100
KPX Aring Y -70
KPX Aring Yacute -70
KPX Aring Ydieresis -70
KPX Aring quoteright -74
KPX Aring u -30
KPX Aring uacute -30
KPX Aring ucircumflex -30
KPX Aring udieresis -30
KPX Aring ugrave -30
KPX Aring uhungarumlaut -30
KPX Aring umacron -30
KPX Aring uogonek -30
KPX Aring uring -30
KPX Aring v -74
KPX Aring w -74
KPX Aring y -74
KPX Aring yacute -74
KPX Aring ydieresis -74
KPX Atilde C -65
KPX Atilde Cacute -65
KPX Atilde Ccaron -65
KPX Atilde Ccedilla -65
KPX Atilde G -60
KPX Atilde Gbreve -60
KPX Atilde Gcommaaccent -60
KPX Atilde O -50
KPX Atilde Oacute -50
KPX Atilde Ocircumflex -50
KPX Atilde Odieresis -50
KPX Atilde Ograve -50
KPX Atilde Ohungarumlaut -50
KPX Atilde Omacron -50
KPX Atilde Oslash -50
KPX Atilde Otilde -50
KPX Atilde Q -55
KPX Atilde T -55
KPX Atilde Tcaron -55
KPX Atilde Tcommaaccent -55
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -95
KPX Atilde W -100
KPX Atilde Y -70
KPX Atilde Yacute -70
KPX Atilde Ydieresis -70
KPX Atilde quoteright -74
KPX Atilde u -30
KPX Atilde uacute -30
KPX Atilde ucircumflex -30
KPX Atilde udieresis -30
KPX Atilde ugrave -30
KPX Atilde uhungarumlaut -30
KPX Atilde umacron -30
KPX Atilde uogonek -30
KPX Atilde uring -30
KPX Atilde v -74
KPX Atilde w -74
KPX Atilde y -74
KPX Atilde yacute -74
KPX Atilde ydieresis -74
KPX B A -25
KPX B Aacute -25
KPX B Abreve -25
KPX B Acircumflex -25
KPX B Adieresis -25
KPX B Agrave -25
KPX B Amacron -25
KPX B Aogonek -25
KPX B Aring -25
KPX B Atilde -25
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX D A -25
KPX D Aacute -25
KPX D Abreve -25
KPX D Acircumflex -25
KPX D Adieresis -25
KPX D Agrave -25
KPX D Amacron -25
KPX D Aogonek -25
KPX D Aring -25
KPX D Atilde -25
KPX D V -50
KPX D W -40
KPX D Y -50
KPX D Yacute -50
KPX D Ydieresis -50
KPX Dcaron A -25
KPX Dcaron Aacute -25
KPX Dcaron Abreve -25
KPX Dcaron Acircumflex -25
KPX Dcaron Adieresis -25
KPX Dcaron Agrave -25
KPX Dcaron Amacron -25
KPX Dcaron Aogonek -25
KPX Dcaron Aring -25
KPX Dcaron Atilde -25
KPX Dcaron V -50
KPX Dcaron W -40
KPX Dcaron Y -50
KPX Dcaron Yacute -50
KPX Dcaron Ydieresis -50
KPX Dcroat A -25
KPX Dcroat Aacute -25
KPX Dcroat Abreve -25
KPX Dcroat Acircumflex -25
KPX Dcroat Adieresis -25
KPX Dcroat Agrave -25
KPX Dcroat Amacron -25
KPX Dcroat Aogonek -25
KPX Dcroat Aring -25
KPX Dcroat Atilde -25
KPX Dcroat V -50
KPX Dcroat W -40
KPX Dcroat Y -50
KPX Dcroat Yacute -50
KPX Dcroat Ydieresis -50
KPX F A -100
KPX F Aacute -100
KPX F Abreve -100
KPX F Acircumflex -100
KPX F Adieresis -100
KPX F Agrave -100
KPX F Amacron -100
KPX F Aogonek -100
KPX F Aring -100
KPX F Atilde -100
KPX F a -95
KPX F aacute -95
KPX F abreve -95
KPX F acircumflex -95
KPX F adieresis -95
KPX F agrave -95
KPX F amacron -95
KPX F aogonek -95
KPX F aring -95
KPX F atilde -95
KPX F comma -129
KPX F e -100
KPX F eacute -100
KPX F ecaron -100
KPX F ecircumflex -100
KPX F edieresis -100
KPX F edotaccent -100
KPX F egrave -100
KPX F emacron -100
KPX F eogonek -100
KPX F i -40
KPX F iacute -40
KPX F icircumflex -40
KPX F idieresis -40
KPX F igrave -40
KPX F imacron -40
KPX F iogonek -40
KPX F o -70
KPX F oacute -70
KPX F ocircumflex -70
KPX F odieresis -70
KPX F ograve -70
KPX F ohungarumlaut -70
KPX F omacron -70
KPX F oslash -70
KPX F otilde -70
KPX F period -129
KPX F r -50
KPX F racute -50
KPX F rcaron -50
KPX F rcommaaccent -50
KPX J A -25
KPX J Aacute -25
KPX J Abreve -25
KPX J Acircumflex -25
KPX J Adieresis -25
KPX J Agrave -25
KPX J Amacron -25
KPX J Aogonek -25
KPX J Aring -25
KPX J Atilde -25
KPX J a -40
KPX J aacute -40
KPX J abreve -40
KPX J acircumflex -40
KPX J adieresis -40
KPX J agrave -40
KPX J amacron -40
KPX J aogonek -40
KPX J aring -40
KPX J atilde -40
KPX J comma -10
KPX J e -40
KPX J eacute -40
KPX J ecaron -40
KPX J ecircumflex -40
KPX J edieresis -40
KPX J edotaccent -40
KPX J egrave -40
KPX J emacron -40
KPX J eogonek -40
KPX J o -40
KPX J oacute -40
KPX J ocircumflex -40
KPX J odieresis -40
KPX J ograve -40
KPX J ohungarumlaut -40
KPX J omacron -40
KPX J oslash -40
KPX J otilde -40
KPX J period -10
KPX J u -40
KPX J uacute -40
KPX J ucircumflex -40
KPX J udieresis -40
KPX J ugrave -40
KPX J uhungarumlaut -40
KPX J umacron -40
KPX J uogonek -40
KPX J uring -40
KPX K O -30
KPX K Oacute -30
KPX K Ocircumflex -30
KPX K Odieresis -30
KPX K Ograve -30
KPX K Ohungarumlaut -30
KPX K Omacron -30
KPX K Oslash -30
KPX K Otilde -30
KPX K e -25
KPX K eacute -25
KPX K ecaron -25
KPX K ecircumflex -25
KPX K edieresis -25
KPX K edotaccent -25
KPX K egrave -25
KPX K emacron -25
KPX K eogonek -25
KPX K o -25
KPX K oacute -25
KPX K ocircumflex -25
KPX K odieresis -25
KPX K ograve -25
KPX K ohungarumlaut -25
KPX K omacron -25
KPX K oslash -25
KPX K otilde -25
KPX K u -20
KPX K uacute -20
KPX K ucircumflex -20
KPX K udieresis -20
KPX K ugrave -20
KPX K uhungarumlaut -20
KPX K umacron -20
KPX K uogonek -20
KPX K uring -20
KPX K y -20
KPX K yacute -20
KPX K ydieresis -20
KPX Kcommaaccent O -30
KPX Kcommaaccent Oacute -30
KPX Kcommaaccent Ocircumflex -30
KPX Kcommaaccent Odieresis -30
KPX Kcommaaccent Ograve -30
KPX Kcommaaccent Ohungarumlaut -30
KPX Kcommaaccent Omacron -30
KPX Kcommaaccent Oslash -30
KPX Kcommaaccent Otilde -30
KPX Kcommaaccent e -25
KPX Kcommaaccent eacute -25
KPX Kcommaaccent ecaron -25
KPX Kcommaaccent ecircumflex -25
KPX Kcommaaccent edieresis -25
KPX Kcommaaccent edotaccent -25
KPX Kcommaaccent egrave -25
KPX Kcommaaccent emacron -25
KPX Kcommaaccent eogonek -25
KPX Kcommaaccent o -25
KPX Kcommaaccent oacute -25
KPX Kcommaaccent ocircumflex -25
KPX Kcommaaccent odieresis -25
KPX Kcommaaccent ograve -25
KPX Kcommaaccent ohungarumlaut -25
KPX Kcommaaccent omacron -25
KPX Kcommaaccent oslash -25
KPX Kcommaaccent otilde -25
KPX Kcommaaccent u -20
KPX Kcommaaccent uacute -20
KPX Kcommaaccent ucircumflex -20
KPX Kcommaaccent udieresis -20
KPX Kcommaaccent ugrave -20
KPX Kcommaaccent uhungarumlaut -20
KPX Kcommaaccent umacron -20
KPX Kcommaaccent uogonek -20
KPX Kcommaaccent uring -20
KPX Kcommaaccent y -20
KPX Kcommaaccent yacute -20
KPX Kcommaaccent ydieresis -20
KPX L T -18
KPX L Tcaron -18
KPX L Tcommaaccent -18
KPX L V -37
KPX L W -37
KPX L Y -37
KPX L Yacute -37
KPX L Ydieresis -37
KPX L quoteright -55
KPX L y -37
KPX L yacute -37
KPX L ydieresis -37
KPX Lacute T -18
KPX Lacute Tcaron -18
KPX Lacute Tcommaaccent -18
KPX Lacute V -37
KPX Lacute W -37
KPX Lacute Y -37
KPX Lacute Yacute -37
KPX Lacute Ydieresis -37
KPX Lacute quoteright -55
KPX Lacute y -37
KPX Lacute yacute -37
KPX Lacute ydieresis -37
KPX Lcommaaccent T -18
KPX Lcommaaccent Tcaron -18
KPX Lcommaaccent Tcommaaccent -18
KPX Lcommaaccent V -37
KPX Lcommaaccent W -37
KPX Lcommaaccent Y -37
KPX Lcommaaccent Yacute -37
KPX Lcommaaccent Ydieresis -37
KPX Lcommaaccent quoteright -55
KPX Lcommaaccent y -37
KPX Lcommaaccent yacute -37
KPX Lcommaaccent ydieresis -37
KPX Lslash T -18
KPX Lslash Tcaron -18
KPX Lslash Tcommaaccent -18
KPX Lslash V -37
KPX Lslash W -37
KPX Lslash Y -37
KPX Lslash Yacute -37
KPX Lslash Ydieresis -37
KPX Lslash quoteright -55
KPX Lslash y -37
KPX Lslash yacute -37
KPX Lslash ydieresis -37
KPX N A -30
KPX N Aacute -30
KPX N Abreve -30
KPX N Acircumflex -30
KPX N Adieresis -30
KPX N Agrave -30
KPX N Amacron -30
KPX N Aogonek -30
KPX N Aring -30
KPX N Atilde -30
KPX Nacute A -30
KPX Nacute Aacute -30
KPX Nacute Abreve -30
KPX Nacute Acircumflex -30
KPX Nacute Adieresis -30
KPX Nacute Agrave -30
KPX Nacute Amacron -30
KPX Nacute Aogonek -30
KPX Nacute Aring -30
KPX Nacute Atilde -30
KPX Ncaron A -30
KPX Ncaron Aacute -30
KPX Ncaron Abreve -30
KPX Ncaron Acircumflex -30
KPX Ncaron Adieresis -30
KPX Ncaron Agrave -30
KPX Ncaron Amacron -30
KPX Ncaron Aogonek -30
KPX Ncaron Aring -30
KPX Ncaron Atilde -30
KPX Ncommaaccent A -30
KPX Ncommaaccent Aacute -30
KPX Ncommaaccent Abreve -30
KPX Ncommaaccent Acircumflex -30
KPX Ncommaaccent Adieresis -30
KPX Ncommaaccent Agrave -30
KPX Ncommaaccent Amacron -30
KPX Ncommaaccent Aogonek -30
KPX Ncommaaccent Aring -30
KPX Ncommaaccent Atilde -30
KPX Ntilde A -30
KPX Ntilde Aacute -30
KPX Ntilde Abreve -30
KPX Ntilde Acircumflex -30
KPX Ntilde Adieresis -30
KPX Ntilde Agrave -30
KPX Ntilde Amacron -30
KPX Ntilde Aogonek -30
KPX Ntilde Aring -30
KPX Ntilde Atilde -30
KPX O A -40
KPX O Aacute -40
KPX O Abreve -40
KPX O Acircumflex -40
KPX O Adieresis -40
KPX O Agrave -40
KPX O Amacron -40
KPX O Aogonek -40
KPX O Aring -40
KPX O Atilde -40
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -50
KPX O X -40
KPX O Y -50
KPX O Yacute -50
KPX O Ydieresis -50
KPX Oacute A -40
KPX Oacute Aacute -40
KPX Oacute Abreve -40
KPX Oacute Acircumflex -40
KPX Oacute Adieresis -40
KPX Oacute Agrave -40
KPX Oacute Amacron -40
KPX Oacute Aogonek -40
KPX Oacute Aring -40
KPX Oacute Atilde -40
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -50
KPX Oacute X -40
KPX Oacute Y -50
KPX Oacute Yacute -50
KPX Oacute Ydieresis -50
KPX Ocircumflex A -40
KPX Ocircumflex Aacute -40
KPX Ocircumflex Abreve -40
KPX Ocircumflex Acircumflex -40
KPX Ocircumflex Adieresis -40
KPX Ocircumflex Agrave -40
KPX Ocircumflex Amacron -40
KPX Ocircumflex Aogonek -40
KPX Ocircumflex Aring -40
KPX Ocircumflex Atilde -40
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -50
KPX Ocircumflex X -40
KPX Ocircumflex Y -50
KPX Ocircumflex Yacute -50
KPX Ocircumflex Ydieresis -50
KPX Odieresis A -40
KPX Odieresis Aacute -40
KPX Odieresis Abreve -40
KPX Odieresis Acircumflex -40
KPX Odieresis Adieresis -40
KPX Odieresis Agrave -40
KPX Odieresis Amacron -40
KPX Odieresis Aogonek -40
KPX Odieresis Aring -40
KPX Odieresis Atilde -40
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -50
KPX Odieresis X -40
KPX Odieresis Y -50
KPX Odieresis Yacute -50
KPX Odieresis Ydieresis -50
KPX Ograve A -40
KPX Ograve Aacute -40
KPX Ograve Abreve -40
KPX Ograve Acircumflex -40
KPX Ograve Adieresis -40
KPX Ograve Agrave -40
KPX Ograve Amacron -40
KPX Ograve Aogonek -40
KPX Ograve Aring -40
KPX Ograve Atilde -40
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -50
KPX Ograve X -40
KPX Ograve Y -50
KPX Ograve Yacute -50
KPX Ograve Ydieresis -50
KPX Ohungarumlaut A -40
KPX Ohungarumlaut Aacute -40
KPX Ohungarumlaut Abreve -40
KPX Ohungarumlaut Acircumflex -40
KPX Ohungarumlaut Adieresis -40
KPX Ohungarumlaut Agrave -40
KPX Ohungarumlaut Amacron -40
KPX Ohungarumlaut Aogonek -40
KPX Ohungarumlaut Aring -40
KPX Ohungarumlaut Atilde -40
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -50
KPX Ohungarumlaut X -40
KPX Ohungarumlaut Y -50
KPX Ohungarumlaut Yacute -50
KPX Ohungarumlaut Ydieresis -50
KPX Omacron A -40
KPX Omacron Aacute -40
KPX Omacron Abreve -40
KPX Omacron Acircumflex -40
KPX Omacron Adieresis -40
KPX Omacron Agrave -40
KPX Omacron Amacron -40
KPX Omacron Aogonek -40
KPX Omacron Aring -40
KPX Omacron Atilde -40
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -50
KPX Omacron X -40
KPX Omacron Y -50
KPX Omacron Yacute -50
KPX Omacron Ydieresis -50
KPX Oslash A -40
KPX Oslash Aacute -40
KPX Oslash Abreve -40
KPX Oslash Acircumflex -40
KPX Oslash Adieresis -40
KPX Oslash Agrave -40
KPX Oslash Amacron -40
KPX Oslash Aogonek -40
KPX Oslash Aring -40
KPX Oslash Atilde -40
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -50
KPX Oslash X -40
KPX Oslash Y -50
KPX Oslash Yacute -50
KPX Oslash Ydieresis -50
KPX Otilde A -40
KPX Otilde Aacute -40
KPX Otilde Abreve -40
KPX Otilde Acircumflex -40
KPX Otilde Adieresis -40
KPX Otilde Agrave -40
KPX Otilde Amacron -40
KPX Otilde Aogonek -40
KPX Otilde Aring -40
KPX Otilde Atilde -40
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -50
KPX Otilde X -40
KPX Otilde Y -50
KPX Otilde Yacute -50
KPX Otilde Ydieresis -50
KPX P A -85
KPX P Aacute -85
KPX P Abreve -85
KPX P Acircumflex -85
KPX P Adieresis -85
KPX P Agrave -85
KPX P Amacron -85
KPX P Aogonek -85
KPX P Aring -85
KPX P Atilde -85
KPX P a -40
KPX P aacute -40
KPX P abreve -40
KPX P acircumflex -40
KPX P adieresis -40
KPX P agrave -40
KPX P amacron -40
KPX P aogonek -40
KPX P aring -40
KPX P atilde -40
KPX P comma -129
KPX P e -50
KPX P eacute -50
KPX P ecaron -50
KPX P ecircumflex -50
KPX P edieresis -50
KPX P edotaccent -50
KPX P egrave -50
KPX P emacron -50
KPX P eogonek -50
KPX P o -55
KPX P oacute -55
KPX P ocircumflex -55
KPX P odieresis -55
KPX P ograve -55
KPX P ohungarumlaut -55
KPX P omacron -55
KPX P oslash -55
KPX P otilde -55
KPX P period -129
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX R O -40
KPX R Oacute -40
KPX R Ocircumflex -40
KPX R Odieresis -40
KPX R Ograve -40
KPX R Ohungarumlaut -40
KPX R Omacron -40
KPX R Oslash -40
KPX R Otilde -40
KPX R T -30
KPX R Tcaron -30
KPX R Tcommaaccent -30
KPX R U -40
KPX R Uacute -40
KPX R Ucircumflex -40
KPX R Udieresis -40
KPX R Ugrave -40
KPX R Uhungarumlaut -40
KPX R Umacron -40
KPX R Uogonek -40
KPX R Uring -40
KPX R V -18
KPX R W -18
KPX R Y -18
KPX R Yacute -18
KPX R Ydieresis -18
KPX Racute O -40
KPX Racute Oacute -40
KPX Racute Ocircumflex -40
KPX Racute Odieresis -40
KPX Racute Ograve -40
KPX Racute Ohungarumlaut -40
KPX Racute Omacron -40
KPX Racute Oslash -40
KPX Racute Otilde -40
KPX Racute T -30
KPX Racute Tcaron -30
KPX Racute Tcommaaccent -30
KPX Racute U -40
KPX Racute Uacute -40
KPX Racute Ucircumflex -40
KPX Racute Udieresis -40
KPX Racute Ugrave -40
KPX Racute Uhungarumlaut -40
KPX Racute Umacron -40
KPX Racute Uogonek -40
KPX Racute Uring -40
KPX Racute V -18
KPX Racute W -18
KPX Racute Y -18
KPX Racute Yacute -18
KPX Racute Ydieresis -18
KPX Rcaron O -40
KPX Rcaron Oacute -40
KPX Rcaron Ocircumflex -40
KPX Rcaron Odieresis -40
KPX Rcaron Ograve -40
KPX Rcaron Ohungarumlaut -40
KPX Rcaron Omacron -40
KPX Rcaron Oslash -40
KPX Rcaron Otilde -40
KPX Rcaron T -30
KPX Rcaron Tcaron -30
KPX Rcaron Tcommaaccent -30
KPX Rcaron U -40
KPX Rcaron Uacute -40
KPX Rcaron Ucircumflex -40
KPX Rcaron Udieresis -40
KPX Rcaron Ugrave -40
KPX Rcaron Uhungarumlaut -40
KPX Rcaron Umacron -40
KPX Rcaron Uogonek -40
KPX Rcaron Uring -40
KPX Rcaron V -18
KPX Rcaron W -18
KPX Rcaron Y -18
KPX Rcaron Yacute -18
KPX Rcaron Ydieresis -18
KPX Rcommaaccent O -40
KPX Rcommaaccent Oacute -40
KPX Rcommaaccent Ocircumflex -40
KPX Rcommaaccent Odieresis -40
KPX Rcommaaccent Ograve -40
KPX Rcommaaccent Ohungarumlaut -40
KPX Rcommaaccent Omacron -40
KPX Rcommaaccent Oslash -40
KPX Rcommaaccent Otilde -40
KPX Rcommaaccent T -30
KPX Rcommaaccent Tcaron -30
KPX Rcommaaccent Tcommaaccent -30
KPX Rcommaaccent U -40
KPX Rcommaaccent Uacute -40
KPX Rcommaaccent Ucircumflex -40
KPX Rcommaaccent Udieresis -40
KPX Rcommaaccent Ugrave -40
KPX Rcommaaccent Uhungarumlaut -40
KPX Rcommaaccent Umacron -40
KPX Rcommaaccent Uogonek -40
KPX Rcommaaccent Uring -40
KPX Rcommaaccent V -18
KPX Rcommaaccent W -18
KPX Rcommaaccent Y -18
KPX Rcommaaccent Yacute -18
KPX Rcommaaccent Ydieresis -18
KPX T A -55
KPX T Aacute -55
KPX T Abreve -55
KPX T Acircumflex -55
KPX T Adieresis -55
KPX T Agrave -55
KPX T Amacron -55
KPX T Aogonek -55
KPX T Aring -55
KPX T Atilde -55
KPX T O -18
KPX T Oacute -18
KPX T Ocircumflex -18
KPX T Odieresis -18
KPX T Ograve -18
KPX T Ohungarumlaut -18
KPX T Omacron -18
KPX T Oslash -18
KPX T Otilde -18
KPX T a -92
KPX T aacute -92
KPX T abreve -92
KPX T acircumflex -92
KPX T adieresis -92
KPX T agrave -92
KPX T amacron -92
KPX T aogonek -92
KPX T aring -92
KPX T atilde -92
KPX T colon -74
KPX T comma -92
KPX T e -92
KPX T eacute -92
KPX T ecaron -92
KPX T ecircumflex -92
KPX T edieresis -52
KPX T edotaccent -92
KPX T egrave -52
KPX T emacron -52
KPX T eogonek -92
KPX T hyphen -92
KPX T i -37
KPX T iacute -37
KPX T iogonek -37
KPX T o -95
KPX T oacute -95
KPX T ocircumflex -95
KPX T odieresis -95
KPX T ograve -95
KPX T ohungarumlaut -95
KPX T omacron -95
KPX T oslash -95
KPX T otilde -95
KPX T period -92
KPX T r -37
KPX T racute -37
KPX T rcaron -37
KPX T rcommaaccent -37
KPX T semicolon -74
KPX T u -37
KPX T uacute -37
KPX T ucircumflex -37
KPX T udieresis -37
KPX T ugrave -37
KPX T uhungarumlaut -37
KPX T umacron -37
KPX T uogonek -37
KPX T uring -37
KPX T w -37
KPX T y -37
KPX T yacute -37
KPX T ydieresis -37
KPX Tcaron A -55
KPX Tcaron Aacute -55
KPX Tcaron Abreve -55
KPX Tcaron Acircumflex -55
KPX Tcaron Adieresis -55
KPX Tcaron Agrave -55
KPX Tcaron Amacron -55
KPX Tcaron Aogonek -55
KPX Tcaron Aring -55
KPX Tcaron Atilde -55
KPX Tcaron O -18
KPX Tcaron Oacute -18
KPX Tcaron Ocircumflex -18
KPX Tcaron Odieresis -18
KPX Tcaron Ograve -18
KPX Tcaron Ohungarumlaut -18
KPX Tcaron Omacron -18
KPX Tcaron Oslash -18
KPX Tcaron Otilde -18
KPX Tcaron a -92
KPX Tcaron aacute -92
KPX Tcaron abreve -92
KPX Tcaron acircumflex -92
KPX Tcaron adieresis -92
KPX Tcaron agrave -92
KPX Tcaron amacron -92
KPX Tcaron aogonek -92
KPX Tcaron aring -92
KPX Tcaron atilde -92
KPX Tcaron colon -74
KPX Tcaron comma -92
KPX Tcaron e -92
KPX Tcaron eacute -92
KPX Tcaron ecaron -92
KPX Tcaron ecircumflex -92
KPX Tcaron edieresis -52
KPX Tcaron edotaccent -92
KPX Tcaron egrave -52
KPX Tcaron emacron -52
KPX Tcaron eogonek -92
KPX Tcaron hyphen -92
KPX Tcaron i -37
KPX Tcaron iacute -37
KPX Tcaron iogonek -37
KPX Tcaron o -95
KPX Tcaron oacute -95
KPX Tcaron ocircumflex -95
KPX Tcaron odieresis -95
KPX Tcaron ograve -95
KPX Tcaron ohungarumlaut -95
KPX Tcaron omacron -95
KPX Tcaron oslash -95
KPX Tcaron otilde -95
KPX Tcaron period -92
KPX Tcaron r -37
KPX Tcaron racute -37
KPX Tcaron rcaron -37
KPX Tcaron rcommaaccent -37
KPX Tcaron semicolon -74
KPX Tcaron u -37
KPX Tcaron uacute -37
KPX Tcaron ucircumflex -37
KPX Tcaron udieresis -37
KPX Tcaron ugrave -37
KPX Tcaron uhungarumlaut -37
KPX Tcaron umacron -37
KPX Tcaron uogonek -37
KPX Tcaron uring -37
KPX Tcaron w -37
KPX Tcaron y -37
KPX Tcaron yacute -37
KPX Tcaron ydieresis -37
KPX Tcommaaccent A -55
KPX Tcommaaccent Aacute -55
KPX Tcommaaccent Abreve -55
KPX Tcommaaccent Acircumflex -55
KPX Tcommaaccent Adieresis -55
KPX Tcommaaccent Agrave -55
KPX Tcommaaccent Amacron -55
KPX Tcommaaccent Aogonek -55
KPX Tcommaaccent Aring -55
KPX Tcommaaccent Atilde -55
KPX Tcommaaccent O -18
KPX Tcommaaccent Oacute -18
KPX Tcommaaccent Ocircumflex -18
KPX Tcommaaccent Odieresis -18
KPX Tcommaaccent Ograve -18
KPX Tcommaaccent Ohungarumlaut -18
KPX Tcommaaccent Omacron -18
KPX Tcommaaccent Oslash -18
KPX Tcommaaccent Otilde -18
KPX Tcommaaccent a -92
KPX Tcommaaccent aacute -92
KPX Tcommaaccent abreve -92
KPX Tcommaaccent acircumflex -92
KPX Tcommaaccent adieresis -92
KPX Tcommaaccent agrave -92
KPX Tcommaaccent amacron -92
KPX Tcommaaccent aogonek -92
KPX Tcommaaccent aring -92
KPX Tcommaaccent atilde -92
KPX Tcommaaccent colon -74
KPX Tcommaaccent comma -92
KPX Tcommaaccent e -92
KPX Tcommaaccent eacute -92
KPX Tcommaaccent ecaron -92
KPX Tcommaaccent ecircumflex -92
KPX Tcommaaccent edieresis -52
KPX Tcommaaccent edotaccent -92
KPX Tcommaaccent egrave -52
KPX Tcommaaccent emacron -52
KPX Tcommaaccent eogonek -92
KPX Tcommaaccent hyphen -92
KPX Tcommaaccent i -37
KPX Tcommaaccent iacute -37
KPX Tcommaaccent iogonek -37
KPX Tcommaaccent o -95
KPX Tcommaaccent oacute -95
KPX Tcommaaccent ocircumflex -95
KPX Tcommaaccent odieresis -95
KPX Tcommaaccent ograve -95
KPX Tcommaaccent ohungarumlaut -95
KPX Tcommaaccent omacron -95
KPX Tcommaaccent oslash -95
KPX Tcommaaccent otilde -95
KPX Tcommaaccent period -92
KPX Tcommaaccent r -37
KPX Tcommaaccent racute -37
KPX Tcommaaccent rcaron -37
KPX Tcommaaccent rcommaaccent -37
KPX Tcommaaccent semicolon -74
KPX Tcommaaccent u -37
KPX Tcommaaccent uacute -37
KPX Tcommaaccent ucircumflex -37
KPX Tcommaaccent udieresis -37
KPX Tcommaaccent ugrave -37
KPX Tcommaaccent uhungarumlaut -37
KPX Tcommaaccent umacron -37
KPX Tcommaaccent uogonek -37
KPX Tcommaaccent uring -37
KPX Tcommaaccent w -37
KPX Tcommaaccent y -37
KPX Tcommaaccent yacute -37
KPX Tcommaaccent ydieresis -37
KPX U A -45
KPX U Aacute -45
KPX U Abreve -45
KPX U Acircumflex -45
KPX U Adieresis -45
KPX U Agrave -45
KPX U Amacron -45
KPX U Aogonek -45
KPX U Aring -45
KPX U Atilde -45
KPX Uacute A -45
KPX Uacute Aacute -45
KPX Uacute Abreve -45
KPX Uacute Acircumflex -45
KPX Uacute Adieresis -45
KPX Uacute Agrave -45
KPX Uacute Amacron -45
KPX Uacute Aogonek -45
KPX Uacute Aring -45
KPX Uacute Atilde -45
KPX Ucircumflex A -45
KPX Ucircumflex Aacute -45
KPX Ucircumflex Abreve -45
KPX Ucircumflex Acircumflex -45
KPX Ucircumflex Adieresis -45
KPX Ucircumflex Agrave -45
KPX Ucircumflex Amacron -45
KPX Ucircumflex Aogonek -45
KPX Ucircumflex Aring -45
KPX Ucircumflex Atilde -45
KPX Udieresis A -45
KPX Udieresis Aacute -45
KPX Udieresis Abreve -45
KPX Udieresis Acircumflex -45
KPX Udieresis Adieresis -45
KPX Udieresis Agrave -45
KPX Udieresis Amacron -45
KPX Udieresis Aogonek -45
KPX Udieresis Aring -45
KPX Udieresis Atilde -45
KPX Ugrave A -45
KPX Ugrave Aacute -45
KPX Ugrave Abreve -45
KPX Ugrave Acircumflex -45
KPX Ugrave Adieresis -45
KPX Ugrave Agrave -45
KPX Ugrave Amacron -45
KPX Ugrave Aogonek -45
KPX Ugrave Aring -45
KPX Ugrave Atilde -45
KPX Uhungarumlaut A -45
KPX Uhungarumlaut Aacute -45
KPX Uhungarumlaut Abreve -45
KPX Uhungarumlaut Acircumflex -45
KPX Uhungarumlaut Adieresis -45
KPX Uhungarumlaut Agrave -45
KPX Uhungarumlaut Amacron -45
KPX Uhungarumlaut Aogonek -45
KPX Uhungarumlaut Aring -45
KPX Uhungarumlaut Atilde -45
KPX Umacron A -45
KPX Umacron Aacute -45
KPX Umacron Abreve -45
KPX Umacron Acircumflex -45
KPX Umacron Adieresis -45
KPX Umacron Agrave -45
KPX Umacron Amacron -45
KPX Umacron Aogonek -45
KPX Umacron Aring -45
KPX Umacron Atilde -45
KPX Uogonek A -45
KPX Uogonek Aacute -45
KPX Uogonek Abreve -45
KPX Uogonek Acircumflex -45
KPX Uogonek Adieresis -45
KPX Uogonek Agrave -45
KPX Uogonek Amacron -45
KPX Uogonek Aogonek -45
KPX Uogonek Aring -45
KPX Uogonek Atilde -45
KPX Uring A -45
KPX Uring Aacute -45
KPX Uring Abreve -45
KPX Uring Acircumflex -45
KPX Uring Adieresis -45
KPX Uring Agrave -45
KPX Uring Amacron -45
KPX Uring Aogonek -45
KPX Uring Aring -45
KPX Uring Atilde -45
KPX V A -85
KPX V Aacute -85
KPX V Abreve -85
KPX V Acircumflex -85
KPX V Adieresis -85
KPX V Agrave -85
KPX V Amacron -85
KPX V Aogonek -85
KPX V Aring -85
KPX V Atilde -85
KPX V G -10
KPX V Gbreve -10
KPX V Gcommaaccent -10
KPX V O -30
KPX V Oacute -30
KPX V Ocircumflex -30
KPX V Odieresis -30
KPX V Ograve -30
KPX V Ohungarumlaut -30
KPX V Omacron -30
KPX V Oslash -30
KPX V Otilde -30
KPX V a -111
KPX V aacute -111
KPX V abreve -111
KPX V acircumflex -111
KPX V adieresis -111
KPX V agrave -111
KPX V amacron -111
KPX V aogonek -111
KPX V aring -111
KPX V atilde -111
KPX V colon -74
KPX V comma -129
KPX V e -111
KPX V eacute -111
KPX V ecaron -111
KPX V ecircumflex -111
KPX V edieresis -71
KPX V edotaccent -111
KPX V egrave -71
KPX V emacron -71
KPX V eogonek -111
KPX V hyphen -70
KPX V i -55
KPX V iacute -55
KPX V iogonek -55
KPX V o -111
KPX V oacute -111
KPX V ocircumflex -111
KPX V odieresis -111
KPX V ograve -111
KPX V ohungarumlaut -111
KPX V omacron -111
KPX V oslash -111
KPX V otilde -111
KPX V period -129
KPX V semicolon -74
KPX V u -55
KPX V uacute -55
KPX V ucircumflex -55
KPX V udieresis -55
KPX V ugrave -55
KPX V uhungarumlaut -55
KPX V umacron -55
KPX V uogonek -55
KPX V uring -55
KPX W A -74
KPX W Aacute -74
KPX W Abreve -74
KPX W Acircumflex -74
KPX W Adieresis -74
KPX W Agrave -74
KPX W Amacron -74
KPX W Aogonek -74
KPX W Aring -74
KPX W Atilde -74
KPX W O -15
KPX W Oacute -15
KPX W Ocircumflex -15
KPX W Odieresis -15
KPX W Ograve -15
KPX W Ohungarumlaut -15
KPX W Omacron -15
KPX W Oslash -15
KPX W Otilde -15
KPX W a -85
KPX W aacute -85
KPX W abreve -85
KPX W acircumflex -85
KPX W adieresis -85
KPX W agrave -85
KPX W amacron -85
KPX W aogonek -85
KPX W aring -85
KPX W atilde -85
KPX W colon -55
KPX W comma -74
KPX W e -90
KPX W eacute -90
KPX W ecaron -90
KPX W ecircumflex -90
KPX W edieresis -50
KPX W edotaccent -90
KPX W egrave -50
KPX W emacron -50
KPX W eogonek -90
KPX W hyphen -50
KPX W i -37
KPX W iacute -37
KPX W iogonek -37
KPX W o -80
KPX W oacute -80
KPX W ocircumflex -80
KPX W odieresis -80
KPX W ograve -80
KPX W ohungarumlaut -80
KPX W omacron -80
KPX W oslash -80
KPX W otilde -80
KPX W period -74
KPX W semicolon -55
KPX W u -55
KPX W uacute -55
KPX W ucircumflex -55
KPX W udieresis -55
KPX W ugrave -55
KPX W uhungarumlaut -55
KPX W umacron -55
KPX W uogonek -55
KPX W uring -55
KPX W y -55
KPX W yacute -55
KPX W ydieresis -55
KPX Y A -74
KPX Y Aacute -74
KPX Y Abreve -74
KPX Y Acircumflex -74
KPX Y Adieresis -74
KPX Y Agrave -74
KPX Y Amacron -74
KPX Y Aogonek -74
KPX Y Aring -74
KPX Y Atilde -74
KPX Y O -25
KPX Y Oacute -25
KPX Y Ocircumflex -25
KPX Y Odieresis -25
KPX Y Ograve -25
KPX Y Ohungarumlaut -25
KPX Y Omacron -25
KPX Y Oslash -25
KPX Y Otilde -25
KPX Y a -92
KPX Y aacute -92
KPX Y abreve -92
KPX Y acircumflex -92
KPX Y adieresis -92
KPX Y agrave -92
KPX Y amacron -92
KPX Y aogonek -92
KPX Y aring -92
KPX Y atilde -92
KPX Y colon -92
KPX Y comma -92
KPX Y e -111
KPX Y eacute -111
KPX Y ecaron -111
KPX Y ecircumflex -71
KPX Y edieresis -71
KPX Y edotaccent -111
KPX Y egrave -71
KPX Y emacron -71
KPX Y eogonek -111
KPX Y hyphen -92
KPX Y i -55
KPX Y iacute -55
KPX Y iogonek -55
KPX Y o -111
KPX Y oacute -111
KPX Y ocircumflex -111
KPX Y odieresis -111
KPX Y ograve -111
KPX Y ohungarumlaut -111
KPX Y omacron -111
KPX Y oslash -111
KPX Y otilde -111
KPX Y period -74
KPX Y semicolon -92
KPX Y u -92
KPX Y uacute -92
KPX Y ucircumflex -92
KPX Y udieresis -92
KPX Y ugrave -92
KPX Y uhungarumlaut -92
KPX Y umacron -92
KPX Y uogonek -92
KPX Y uring -92
KPX Yacute A -74
KPX Yacute Aacute -74
KPX Yacute Abreve -74
KPX Yacute Acircumflex -74
KPX Yacute Adieresis -74
KPX Yacute Agrave -74
KPX Yacute Amacron -74
KPX Yacute Aogonek -74
KPX Yacute Aring -74
KPX Yacute Atilde -74
KPX Yacute O -25
KPX Yacute Oacute -25
KPX Yacute Ocircumflex -25
KPX Yacute Odieresis -25
KPX Yacute Ograve -25
KPX Yacute Ohungarumlaut -25
KPX Yacute Omacron -25
KPX Yacute Oslash -25
KPX Yacute Otilde -25
KPX Yacute a -92
KPX Yacute aacute -92
KPX Yacute abreve -92
KPX Yacute acircumflex -92
KPX Yacute adieresis -92
KPX Yacute agrave -92
KPX Yacute amacron -92
KPX Yacute aogonek -92
KPX Yacute aring -92
KPX Yacute atilde -92
KPX Yacute colon -92
KPX Yacute comma -92
KPX Yacute e -111
KPX Yacute eacute -111
KPX Yacute ecaron -111
KPX Yacute ecircumflex -71
KPX Yacute edieresis -71
KPX Yacute edotaccent -111
KPX Yacute egrave -71
KPX Yacute emacron -71
KPX Yacute eogonek -111
KPX Yacute hyphen -92
KPX Yacute i -55
KPX Yacute iacute -55
KPX Yacute iogonek -55
KPX Yacute o -111
KPX Yacute oacute -111
KPX Yacute ocircumflex -111
KPX Yacute odieresis -111
KPX Yacute ograve -111
KPX Yacute ohungarumlaut -111
KPX Yacute omacron -111
KPX Yacute oslash -111
KPX Yacute otilde -111
KPX Yacute period -74
KPX Yacute semicolon -92
KPX Yacute u -92
KPX Yacute uacute -92
KPX Yacute ucircumflex -92
KPX Yacute udieresis -92
KPX Yacute ugrave -92
KPX Yacute uhungarumlaut -92
KPX Yacute umacron -92
KPX Yacute uogonek -92
KPX Yacute uring -92
KPX Ydieresis A -74
KPX Ydieresis Aacute -74
KPX Ydieresis Abreve -74
KPX Ydieresis Acircumflex -74
KPX Ydieresis Adieresis -74
KPX Ydieresis Agrave -74
KPX Ydieresis Amacron -74
KPX Ydieresis Aogonek -74
KPX Ydieresis Aring -74
KPX Ydieresis Atilde -74
KPX Ydieresis O -25
KPX Ydieresis Oacute -25
KPX Ydieresis Ocircumflex -25
KPX Ydieresis Odieresis -25
KPX Ydieresis Ograve -25
KPX Ydieresis Ohungarumlaut -25
KPX Ydieresis Omacron -25
KPX Ydieresis Oslash -25
KPX Ydieresis Otilde -25
KPX Ydieresis a -92
KPX Ydieresis aacute -92
KPX Ydieresis abreve -92
KPX Ydieresis acircumflex -92
KPX Ydieresis adieresis -92
KPX Ydieresis agrave -92
KPX Ydieresis amacron -92
KPX Ydieresis aogonek -92
KPX Ydieresis aring -92
KPX Ydieresis atilde -92
KPX Ydieresis colon -92
KPX Ydieresis comma -92
KPX Ydieresis e -111
KPX Ydieresis eacute -111
KPX Ydieresis ecaron -111
KPX Ydieresis ecircumflex -71
KPX Ydieresis edieresis -71
KPX Ydieresis edotaccent -111
KPX Ydieresis egrave -71
KPX Ydieresis emacron -71
KPX Ydieresis eogonek -111
KPX Ydieresis hyphen -92
KPX Ydieresis i -55
KPX Ydieresis iacute -55
KPX Ydieresis iogonek -55
KPX Ydieresis o -111
KPX Ydieresis oacute -111
KPX Ydieresis ocircumflex -111
KPX Ydieresis odieresis -111
KPX Ydieresis ograve -111
KPX Ydieresis ohungarumlaut -111
KPX Ydieresis omacron -111
KPX Ydieresis oslash -111
KPX Ydieresis otilde -111
KPX Ydieresis period -74
KPX Ydieresis semicolon -92
KPX Ydieresis u -92
KPX Ydieresis uacute -92
KPX Ydieresis ucircumflex -92
KPX Ydieresis udieresis -92
KPX Ydieresis ugrave -92
KPX Ydieresis uhungarumlaut -92
KPX Ydieresis umacron -92
KPX Ydieresis uogonek -92
KPX Ydieresis uring -92
KPX b b -10
KPX b period -40
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX c h -10
KPX c k -10
KPX c kcommaaccent -10
KPX cacute h -10
KPX cacute k -10
KPX cacute kcommaaccent -10
KPX ccaron h -10
KPX ccaron k -10
KPX ccaron kcommaaccent -10
KPX ccedilla h -10
KPX ccedilla k -10
KPX ccedilla kcommaaccent -10
KPX comma quotedblright -95
KPX comma quoteright -95
KPX e b -10
KPX eacute b -10
KPX ecaron b -10
KPX ecircumflex b -10
KPX edieresis b -10
KPX edotaccent b -10
KPX egrave b -10
KPX emacron b -10
KPX eogonek b -10
KPX f comma -10
KPX f dotlessi -30
KPX f e -10
KPX f eacute -10
KPX f edotaccent -10
KPX f eogonek -10
KPX f f -18
KPX f o -10
KPX f oacute -10
KPX f ocircumflex -10
KPX f ograve -10
KPX f ohungarumlaut -10
KPX f oslash -10
KPX f otilde -10
KPX f period -10
KPX f quoteright 55
KPX k e -30
KPX k eacute -30
KPX k ecaron -30
KPX k ecircumflex -30
KPX k edieresis -30
KPX k edotaccent -30
KPX k egrave -30
KPX k emacron -30
KPX k eogonek -30
KPX k o -10
KPX k oacute -10
KPX k ocircumflex -10
KPX k odieresis -10
KPX k ograve -10
KPX k ohungarumlaut -10
KPX k omacron -10
KPX k oslash -10
KPX k otilde -10
KPX kcommaaccent e -30
KPX kcommaaccent eacute -30
KPX kcommaaccent ecaron -30
KPX kcommaaccent ecircumflex -30
KPX kcommaaccent edieresis -30
KPX kcommaaccent edotaccent -30
KPX kcommaaccent egrave -30
KPX kcommaaccent emacron -30
KPX kcommaaccent eogonek -30
KPX kcommaaccent o -10
KPX kcommaaccent oacute -10
KPX kcommaaccent ocircumflex -10
KPX kcommaaccent odieresis -10
KPX kcommaaccent ograve -10
KPX kcommaaccent ohungarumlaut -10
KPX kcommaaccent omacron -10
KPX kcommaaccent oslash -10
KPX kcommaaccent otilde -10
KPX n v -40
KPX nacute v -40
KPX ncaron v -40
KPX ncommaaccent v -40
KPX ntilde v -40
KPX o v -15
KPX o w -25
KPX o x -10
KPX o y -10
KPX o yacute -10
KPX o ydieresis -10
KPX oacute v -15
KPX oacute w -25
KPX oacute x -10
KPX oacute y -10
KPX oacute yacute -10
KPX oacute ydieresis -10
KPX ocircumflex v -15
KPX ocircumflex w -25
KPX ocircumflex x -10
KPX ocircumflex y -10
KPX ocircumflex yacute -10
KPX ocircumflex ydieresis -10
KPX odieresis v -15
KPX odieresis w -25
KPX odieresis x -10
KPX odieresis y -10
KPX odieresis yacute -10
KPX odieresis ydieresis -10
KPX ograve v -15
KPX ograve w -25
KPX ograve x -10
KPX ograve y -10
KPX ograve yacute -10
KPX ograve ydieresis -10
KPX ohungarumlaut v -15
KPX ohungarumlaut w -25
KPX ohungarumlaut x -10
KPX ohungarumlaut y -10
KPX ohungarumlaut yacute -10
KPX ohungarumlaut ydieresis -10
KPX omacron v -15
KPX omacron w -25
KPX omacron x -10
KPX omacron y -10
KPX omacron yacute -10
KPX omacron ydieresis -10
KPX oslash v -15
KPX oslash w -25
KPX oslash x -10
KPX oslash y -10
KPX oslash yacute -10
KPX oslash ydieresis -10
KPX otilde v -15
KPX otilde w -25
KPX otilde x -10
KPX otilde y -10
KPX otilde yacute -10
KPX otilde ydieresis -10
KPX period quotedblright -95
KPX period quoteright -95
KPX quoteleft quoteleft -74
KPX quoteright d -15
KPX quoteright dcroat -15
KPX quoteright quoteright -74
KPX quoteright r -15
KPX quoteright racute -15
KPX quoteright rcaron -15
KPX quoteright rcommaaccent -15
KPX quoteright s -74
KPX quoteright sacute -74
KPX quoteright scaron -74
KPX quoteright scedilla -74
KPX quoteright scommaaccent -74
KPX quoteright space -74
KPX quoteright t -37
KPX quoteright tcommaaccent -37
KPX quoteright v -15
KPX r comma -65
KPX r period -65
KPX racute comma -65
KPX racute period -65
KPX rcaron comma -65
KPX rcaron period -65
KPX rcommaaccent comma -65
KPX rcommaaccent period -65
KPX space A -37
KPX space Aacute -37
KPX space Abreve -37
KPX space Acircumflex -37
KPX space Adieresis -37
KPX space Agrave -37
KPX space Amacron -37
KPX space Aogonek -37
KPX space Aring -37
KPX space Atilde -37
KPX space V -70
KPX space W -70
KPX space Y -70
KPX space Yacute -70
KPX space Ydieresis -70
KPX v comma -37
KPX v e -15
KPX v eacute -15
KPX v ecaron -15
KPX v ecircumflex -15
KPX v edieresis -15
KPX v edotaccent -15
KPX v egrave -15
KPX v emacron -15
KPX v eogonek -15
KPX v o -15
KPX v oacute -15
KPX v ocircumflex -15
KPX v odieresis -15
KPX v ograve -15
KPX v ohungarumlaut -15
KPX v omacron -15
KPX v oslash -15
KPX v otilde -15
KPX v period -37
KPX w a -10
KPX w aacute -10
KPX w abreve -10
KPX w acircumflex -10
KPX w adieresis -10
KPX w agrave -10
KPX w amacron -10
KPX w aogonek -10
KPX w aring -10
KPX w atilde -10
KPX w comma -37
KPX w e -10
KPX w eacute -10
KPX w ecaron -10
KPX w ecircumflex -10
KPX w edieresis -10
KPX w edotaccent -10
KPX w egrave -10
KPX w emacron -10
KPX w eogonek -10
KPX w o -15
KPX w oacute -15
KPX w ocircumflex -15
KPX w odieresis -15
KPX w ograve -15
KPX w ohungarumlaut -15
KPX w omacron -15
KPX w oslash -15
KPX w otilde -15
KPX w period -37
KPX x e -10
KPX x eacute -10
KPX x ecaron -10
KPX x ecircumflex -10
KPX x edieresis -10
KPX x edotaccent -10
KPX x egrave -10
KPX x emacron -10
KPX x eogonek -10
KPX y comma -37
KPX y period -37
KPX yacute comma -37
KPX yacute period -37
KPX ydieresis comma -37
KPX ydieresis period -37
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Times-Italic.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:56:55 1997
Comment UniqueID 43067
Comment VMusage 47727 58752
FontName Times-Italic
FullName Times Italic
FamilyName Times
Weight Medium
ItalicAngle -15.5
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -169 -217 1010 883
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 653
XHeight 441
Ascender 683
Descender -217
StdHW 32
StdVW 76
StartCharMetrics 315
C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
C 33 ; WX 333 ; N exclam ; B 39 -11 302 667 ;
C 34 ; WX 420 ; N quotedbl ; B 144 421 432 666 ;
C 35 ; WX 500 ; N numbersign ; B 2 0 540 676 ;
C 36 ; WX 500 ; N dollar ; B 31 -89 497 731 ;
C 37 ; WX 833 ; N percent ; B 79 -13 790 676 ;
C 38 ; WX 778 ; N ampersand ; B 76 -18 723 666 ;
C 39 ; WX 333 ; N quoteright ; B 151 436 290 666 ;
C 40 ; WX 333 ; N parenleft ; B 42 -181 315 669 ;
C 41 ; WX 333 ; N parenright ; B 16 -180 289 669 ;
C 42 ; WX 500 ; N asterisk ; B 128 255 492 666 ;
C 43 ; WX 675 ; N plus ; B 86 0 590 506 ;
C 44 ; WX 250 ; N comma ; B -4 -129 135 101 ;
C 45 ; WX 333 ; N hyphen ; B 49 192 282 255 ;
C 46 ; WX 250 ; N period ; B 27 -11 138 100 ;
C 47 ; WX 278 ; N slash ; B -65 -18 386 666 ;
C 48 ; WX 500 ; N zero ; B 32 -7 497 676 ;
C 49 ; WX 500 ; N one ; B 49 0 409 676 ;
C 50 ; WX 500 ; N two ; B 12 0 452 676 ;
C 51 ; WX 500 ; N three ; B 15 -7 465 676 ;
C 52 ; WX 500 ; N four ; B 1 0 479 676 ;
C 53 ; WX 500 ; N five ; B 15 -7 491 666 ;
C 54 ; WX 500 ; N six ; B 30 -7 521 686 ;
C 55 ; WX 500 ; N seven ; B 75 -8 537 666 ;
C 56 ; WX 500 ; N eight ; B 30 -7 493 676 ;
C 57 ; WX 500 ; N nine ; B 23 -17 492 676 ;
C 58 ; WX 333 ; N colon ; B 50 -11 261 441 ;
C 59 ; WX 333 ; N semicolon ; B 27 -129 261 441 ;
C 60 ; WX 675 ; N less ; B 84 -8 592 514 ;
C 61 ; WX 675 ; N equal ; B 86 120 590 386 ;
C 62 ; WX 675 ; N greater ; B 84 -8 592 514 ;
C 63 ; WX 500 ; N question ; B 132 -12 472 664 ;
C 64 ; WX 920 ; N at ; B 118 -18 806 666 ;
C 65 ; WX 611 ; N A ; B -51 0 564 668 ;
C 66 ; WX 611 ; N B ; B -8 0 588 653 ;
C 67 ; WX 667 ; N C ; B 66 -18 689 666 ;
C 68 ; WX 722 ; N D ; B -8 0 700 653 ;
C 69 ; WX 611 ; N E ; B -1 0 634 653 ;
C 70 ; WX 611 ; N F ; B 8 0 645 653 ;
C 71 ; WX 722 ; N G ; B 52 -18 722 666 ;
C 72 ; WX 722 ; N H ; B -8 0 767 653 ;
C 73 ; WX 333 ; N I ; B -8 0 384 653 ;
C 74 ; WX 444 ; N J ; B -6 -18 491 653 ;
C 75 ; WX 667 ; N K ; B 7 0 722 653 ;
C 76 ; WX 556 ; N L ; B -8 0 559 653 ;
C 77 ; WX 833 ; N M ; B -18 0 873 653 ;
C 78 ; WX 667 ; N N ; B -20 -15 727 653 ;
C 79 ; WX 722 ; N O ; B 60 -18 699 666 ;
C 80 ; WX 611 ; N P ; B 0 0 605 653 ;
C 81 ; WX 722 ; N Q ; B 59 -182 699 666 ;
C 82 ; WX 611 ; N R ; B -13 0 588 653 ;
C 83 ; WX 500 ; N S ; B 17 -18 508 667 ;
C 84 ; WX 556 ; N T ; B 59 0 633 653 ;
C 85 ; WX 722 ; N U ; B 102 -18 765 653 ;
C 86 ; WX 611 ; N V ; B 76 -18 688 653 ;
C 87 ; WX 833 ; N W ; B 71 -18 906 653 ;
C 88 ; WX 611 ; N X ; B -29 0 655 653 ;
C 89 ; WX 556 ; N Y ; B 78 0 633 653 ;
C 90 ; WX 556 ; N Z ; B -6 0 606 653 ;
C 91 ; WX 389 ; N bracketleft ; B 21 -153 391 663 ;
C 92 ; WX 278 ; N backslash ; B -41 -18 319 666 ;
C 93 ; WX 389 ; N bracketright ; B 12 -153 382 663 ;
C 94 ; WX 422 ; N asciicircum ; B 0 301 422 666 ;
C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
C 96 ; WX 333 ; N quoteleft ; B 171 436 310 666 ;
C 97 ; WX 500 ; N a ; B 17 -11 476 441 ;
C 98 ; WX 500 ; N b ; B 23 -11 473 683 ;
C 99 ; WX 444 ; N c ; B 30 -11 425 441 ;
C 100 ; WX 500 ; N d ; B 15 -13 527 683 ;
C 101 ; WX 444 ; N e ; B 31 -11 412 441 ;
C 102 ; WX 278 ; N f ; B -147 -207 424 678 ; L i fi ; L l fl ;
C 103 ; WX 500 ; N g ; B 8 -206 472 441 ;
C 104 ; WX 500 ; N h ; B 19 -9 478 683 ;
C 105 ; WX 278 ; N i ; B 49 -11 264 654 ;
C 106 ; WX 278 ; N j ; B -124 -207 276 654 ;
C 107 ; WX 444 ; N k ; B 14 -11 461 683 ;
C 108 ; WX 278 ; N l ; B 41 -11 279 683 ;
C 109 ; WX 722 ; N m ; B 12 -9 704 441 ;
C 110 ; WX 500 ; N n ; B 14 -9 474 441 ;
C 111 ; WX 500 ; N o ; B 27 -11 468 441 ;
C 112 ; WX 500 ; N p ; B -75 -205 469 441 ;
C 113 ; WX 500 ; N q ; B 25 -209 483 441 ;
C 114 ; WX 389 ; N r ; B 45 0 412 441 ;
C 115 ; WX 389 ; N s ; B 16 -13 366 442 ;
C 116 ; WX 278 ; N t ; B 37 -11 296 546 ;
C 117 ; WX 500 ; N u ; B 42 -11 475 441 ;
C 118 ; WX 444 ; N v ; B 21 -18 426 441 ;
C 119 ; WX 667 ; N w ; B 16 -18 648 441 ;
C 120 ; WX 444 ; N x ; B -27 -11 447 441 ;
C 121 ; WX 444 ; N y ; B -24 -206 426 441 ;
C 122 ; WX 389 ; N z ; B -2 -81 380 428 ;
C 123 ; WX 400 ; N braceleft ; B 51 -177 407 687 ;
C 124 ; WX 275 ; N bar ; B 105 -217 171 783 ;
C 125 ; WX 400 ; N braceright ; B -7 -177 349 687 ;
C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;
C 161 ; WX 389 ; N exclamdown ; B 59 -205 322 473 ;
C 162 ; WX 500 ; N cent ; B 77 -143 472 560 ;
C 163 ; WX 500 ; N sterling ; B 10 -6 517 670 ;
C 164 ; WX 167 ; N fraction ; B -169 -10 337 676 ;
C 165 ; WX 500 ; N yen ; B 27 0 603 653 ;
C 166 ; WX 500 ; N florin ; B 25 -182 507 682 ;
C 167 ; WX 500 ; N section ; B 53 -162 461 666 ;
C 168 ; WX 500 ; N currency ; B -22 53 522 597 ;
C 169 ; WX 214 ; N quotesingle ; B 132 421 241 666 ;
C 170 ; WX 556 ; N quotedblleft ; B 166 436 514 666 ;
C 171 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ;
C 172 ; WX 333 ; N guilsinglleft ; B 51 37 281 403 ;
C 173 ; WX 333 ; N guilsinglright ; B 52 37 282 403 ;
C 174 ; WX 500 ; N fi ; B -141 -207 481 681 ;
C 175 ; WX 500 ; N fl ; B -141 -204 518 682 ;
C 177 ; WX 500 ; N endash ; B -6 197 505 243 ;
C 178 ; WX 500 ; N dagger ; B 101 -159 488 666 ;
C 179 ; WX 500 ; N daggerdbl ; B 22 -143 491 666 ;
C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
C 182 ; WX 523 ; N paragraph ; B 55 -123 616 653 ;
C 183 ; WX 350 ; N bullet ; B 40 191 310 461 ;
C 184 ; WX 333 ; N quotesinglbase ; B 44 -129 183 101 ;
C 185 ; WX 556 ; N quotedblbase ; B 57 -129 405 101 ;
C 186 ; WX 556 ; N quotedblright ; B 151 436 499 666 ;
C 187 ; WX 500 ; N guillemotright ; B 55 37 447 403 ;
C 188 ; WX 889 ; N ellipsis ; B 57 -11 762 100 ;
C 189 ; WX 1000 ; N perthousand ; B 25 -19 1010 706 ;
C 191 ; WX 500 ; N questiondown ; B 28 -205 368 471 ;
C 193 ; WX 333 ; N grave ; B 121 492 311 664 ;
C 194 ; WX 333 ; N acute ; B 180 494 403 664 ;
C 195 ; WX 333 ; N circumflex ; B 91 492 385 661 ;
C 196 ; WX 333 ; N tilde ; B 100 517 427 624 ;
C 197 ; WX 333 ; N macron ; B 99 532 411 583 ;
C 198 ; WX 333 ; N breve ; B 117 492 418 650 ;
C 199 ; WX 333 ; N dotaccent ; B 207 548 305 646 ;
C 200 ; WX 333 ; N dieresis ; B 107 548 405 646 ;
C 202 ; WX 333 ; N ring ; B 155 492 355 691 ;
C 203 ; WX 333 ; N cedilla ; B -30 -217 182 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B 93 494 486 664 ;
C 206 ; WX 333 ; N ogonek ; B 20 -169 203 40 ;
C 207 ; WX 333 ; N caron ; B 121 492 426 661 ;
C 208 ; WX 889 ; N emdash ; B -6 197 894 243 ;
C 225 ; WX 889 ; N AE ; B -27 0 911 653 ;
C 227 ; WX 276 ; N ordfeminine ; B 42 406 352 676 ;
C 232 ; WX 556 ; N Lslash ; B -8 0 559 653 ;
C 233 ; WX 722 ; N Oslash ; B 60 -105 699 722 ;
C 234 ; WX 944 ; N OE ; B 49 -8 964 666 ;
C 235 ; WX 310 ; N ordmasculine ; B 67 406 362 676 ;
C 241 ; WX 667 ; N ae ; B 23 -11 640 441 ;
C 245 ; WX 278 ; N dotlessi ; B 49 -11 235 441 ;
C 248 ; WX 278 ; N lslash ; B 41 -11 312 683 ;
C 249 ; WX 500 ; N oslash ; B 28 -135 469 554 ;
C 250 ; WX 667 ; N oe ; B 20 -12 646 441 ;
C 251 ; WX 500 ; N germandbls ; B -168 -207 493 679 ;
C -1 ; WX 333 ; N Idieresis ; B -8 0 435 818 ;
C -1 ; WX 444 ; N eacute ; B 31 -11 459 664 ;
C -1 ; WX 500 ; N abreve ; B 17 -11 502 650 ;
C -1 ; WX 500 ; N uhungarumlaut ; B 42 -11 580 664 ;
C -1 ; WX 444 ; N ecaron ; B 31 -11 482 661 ;
C -1 ; WX 556 ; N Ydieresis ; B 78 0 633 818 ;
C -1 ; WX 675 ; N divide ; B 86 -11 590 517 ;
C -1 ; WX 556 ; N Yacute ; B 78 0 633 876 ;
C -1 ; WX 611 ; N Acircumflex ; B -51 0 564 873 ;
C -1 ; WX 500 ; N aacute ; B 17 -11 487 664 ;
C -1 ; WX 722 ; N Ucircumflex ; B 102 -18 765 873 ;
C -1 ; WX 444 ; N yacute ; B -24 -206 459 664 ;
C -1 ; WX 389 ; N scommaaccent ; B 16 -217 366 442 ;
C -1 ; WX 444 ; N ecircumflex ; B 31 -11 441 661 ;
C -1 ; WX 722 ; N Uring ; B 102 -18 765 883 ;
C -1 ; WX 722 ; N Udieresis ; B 102 -18 765 818 ;
C -1 ; WX 500 ; N aogonek ; B 17 -169 476 441 ;
C -1 ; WX 722 ; N Uacute ; B 102 -18 765 876 ;
C -1 ; WX 500 ; N uogonek ; B 42 -169 477 441 ;
C -1 ; WX 611 ; N Edieresis ; B -1 0 634 818 ;
C -1 ; WX 722 ; N Dcroat ; B -8 0 700 653 ;
C -1 ; WX 250 ; N commaaccent ; B 8 -217 133 -50 ;
C -1 ; WX 760 ; N copyright ; B 41 -18 719 666 ;
C -1 ; WX 611 ; N Emacron ; B -1 0 634 795 ;
C -1 ; WX 444 ; N ccaron ; B 30 -11 482 661 ;
C -1 ; WX 500 ; N aring ; B 17 -11 476 691 ;
C -1 ; WX 667 ; N Ncommaaccent ; B -20 -187 727 653 ;
C -1 ; WX 278 ; N lacute ; B 41 -11 395 876 ;
C -1 ; WX 500 ; N agrave ; B 17 -11 476 664 ;
C -1 ; WX 556 ; N Tcommaaccent ; B 59 -217 633 653 ;
C -1 ; WX 667 ; N Cacute ; B 66 -18 690 876 ;
C -1 ; WX 500 ; N atilde ; B 17 -11 511 624 ;
C -1 ; WX 611 ; N Edotaccent ; B -1 0 634 818 ;
C -1 ; WX 389 ; N scaron ; B 16 -13 454 661 ;
C -1 ; WX 389 ; N scedilla ; B 16 -217 366 442 ;
C -1 ; WX 278 ; N iacute ; B 49 -11 355 664 ;
C -1 ; WX 471 ; N lozenge ; B 13 0 459 724 ;
C -1 ; WX 611 ; N Rcaron ; B -13 0 588 873 ;
C -1 ; WX 722 ; N Gcommaaccent ; B 52 -217 722 666 ;
C -1 ; WX 500 ; N ucircumflex ; B 42 -11 475 661 ;
C -1 ; WX 500 ; N acircumflex ; B 17 -11 476 661 ;
C -1 ; WX 611 ; N Amacron ; B -51 0 564 795 ;
C -1 ; WX 389 ; N rcaron ; B 45 0 434 661 ;
C -1 ; WX 444 ; N ccedilla ; B 30 -217 425 441 ;
C -1 ; WX 556 ; N Zdotaccent ; B -6 0 606 818 ;
C -1 ; WX 611 ; N Thorn ; B 0 0 569 653 ;
C -1 ; WX 722 ; N Omacron ; B 60 -18 699 795 ;
C -1 ; WX 611 ; N Racute ; B -13 0 588 876 ;
C -1 ; WX 500 ; N Sacute ; B 17 -18 508 876 ;
C -1 ; WX 544 ; N dcaron ; B 15 -13 658 683 ;
C -1 ; WX 722 ; N Umacron ; B 102 -18 765 795 ;
C -1 ; WX 500 ; N uring ; B 42 -11 475 691 ;
C -1 ; WX 300 ; N threesuperior ; B 43 268 339 676 ;
C -1 ; WX 722 ; N Ograve ; B 60 -18 699 876 ;
C -1 ; WX 611 ; N Agrave ; B -51 0 564 876 ;
C -1 ; WX 611 ; N Abreve ; B -51 0 564 862 ;
C -1 ; WX 675 ; N multiply ; B 93 8 582 497 ;
C -1 ; WX 500 ; N uacute ; B 42 -11 477 664 ;
C -1 ; WX 556 ; N Tcaron ; B 59 0 633 873 ;
C -1 ; WX 476 ; N partialdiff ; B 17 -38 459 710 ;
C -1 ; WX 444 ; N ydieresis ; B -24 -206 441 606 ;
C -1 ; WX 667 ; N Nacute ; B -20 -15 727 876 ;
C -1 ; WX 278 ; N icircumflex ; B 33 -11 327 661 ;
C -1 ; WX 611 ; N Ecircumflex ; B -1 0 634 873 ;
C -1 ; WX 500 ; N adieresis ; B 17 -11 489 606 ;
C -1 ; WX 444 ; N edieresis ; B 31 -11 451 606 ;
C -1 ; WX 444 ; N cacute ; B 30 -11 459 664 ;
C -1 ; WX 500 ; N nacute ; B 14 -9 477 664 ;
C -1 ; WX 500 ; N umacron ; B 42 -11 485 583 ;
C -1 ; WX 667 ; N Ncaron ; B -20 -15 727 873 ;
C -1 ; WX 333 ; N Iacute ; B -8 0 433 876 ;
C -1 ; WX 675 ; N plusminus ; B 86 0 590 506 ;
C -1 ; WX 275 ; N brokenbar ; B 105 -142 171 708 ;
C -1 ; WX 760 ; N registered ; B 41 -18 719 666 ;
C -1 ; WX 722 ; N Gbreve ; B 52 -18 722 862 ;
C -1 ; WX 333 ; N Idotaccent ; B -8 0 384 818 ;
C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ;
C -1 ; WX 611 ; N Egrave ; B -1 0 634 876 ;
C -1 ; WX 389 ; N racute ; B 45 0 431 664 ;
C -1 ; WX 500 ; N omacron ; B 27 -11 495 583 ;
C -1 ; WX 556 ; N Zacute ; B -6 0 606 876 ;
C -1 ; WX 556 ; N Zcaron ; B -6 0 606 873 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 523 658 ;
C -1 ; WX 722 ; N Eth ; B -8 0 700 653 ;
C -1 ; WX 667 ; N Ccedilla ; B 66 -217 689 666 ;
C -1 ; WX 278 ; N lcommaaccent ; B 22 -217 279 683 ;
C -1 ; WX 300 ; N tcaron ; B 37 -11 407 681 ;
C -1 ; WX 444 ; N eogonek ; B 31 -169 412 441 ;
C -1 ; WX 722 ; N Uogonek ; B 102 -184 765 653 ;
C -1 ; WX 611 ; N Aacute ; B -51 0 564 876 ;
C -1 ; WX 611 ; N Adieresis ; B -51 0 564 818 ;
C -1 ; WX 444 ; N egrave ; B 31 -11 412 664 ;
C -1 ; WX 389 ; N zacute ; B -2 -81 431 664 ;
C -1 ; WX 278 ; N iogonek ; B 49 -169 264 654 ;
C -1 ; WX 722 ; N Oacute ; B 60 -18 699 876 ;
C -1 ; WX 500 ; N oacute ; B 27 -11 487 664 ;
C -1 ; WX 500 ; N amacron ; B 17 -11 495 583 ;
C -1 ; WX 389 ; N sacute ; B 16 -13 431 664 ;
C -1 ; WX 278 ; N idieresis ; B 49 -11 352 606 ;
C -1 ; WX 722 ; N Ocircumflex ; B 60 -18 699 873 ;
C -1 ; WX 722 ; N Ugrave ; B 102 -18 765 876 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 500 ; N thorn ; B -75 -205 469 683 ;
C -1 ; WX 300 ; N twosuperior ; B 33 271 324 676 ;
C -1 ; WX 722 ; N Odieresis ; B 60 -18 699 818 ;
C -1 ; WX 500 ; N mu ; B -30 -209 497 428 ;
C -1 ; WX 278 ; N igrave ; B 49 -11 284 664 ;
C -1 ; WX 500 ; N ohungarumlaut ; B 27 -11 590 664 ;
C -1 ; WX 611 ; N Eogonek ; B -1 -169 634 653 ;
C -1 ; WX 500 ; N dcroat ; B 15 -13 572 683 ;
C -1 ; WX 750 ; N threequarters ; B 23 -10 736 676 ;
C -1 ; WX 500 ; N Scedilla ; B 17 -217 508 667 ;
C -1 ; WX 300 ; N lcaron ; B 41 -11 407 683 ;
C -1 ; WX 667 ; N Kcommaaccent ; B 7 -217 722 653 ;
C -1 ; WX 556 ; N Lacute ; B -8 0 559 876 ;
C -1 ; WX 980 ; N trademark ; B 30 247 957 653 ;
C -1 ; WX 444 ; N edotaccent ; B 31 -11 412 606 ;
C -1 ; WX 333 ; N Igrave ; B -8 0 384 876 ;
C -1 ; WX 333 ; N Imacron ; B -8 0 441 795 ;
C -1 ; WX 611 ; N Lcaron ; B -8 0 586 653 ;
C -1 ; WX 750 ; N onehalf ; B 34 -10 749 676 ;
C -1 ; WX 549 ; N lessequal ; B 26 0 523 658 ;
C -1 ; WX 500 ; N ocircumflex ; B 27 -11 468 661 ;
C -1 ; WX 500 ; N ntilde ; B 14 -9 476 624 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 102 -18 765 876 ;
C -1 ; WX 611 ; N Eacute ; B -1 0 634 876 ;
C -1 ; WX 444 ; N emacron ; B 31 -11 457 583 ;
C -1 ; WX 500 ; N gbreve ; B 8 -206 487 650 ;
C -1 ; WX 750 ; N onequarter ; B 33 -10 736 676 ;
C -1 ; WX 500 ; N Scaron ; B 17 -18 520 873 ;
C -1 ; WX 500 ; N Scommaaccent ; B 17 -217 508 667 ;
C -1 ; WX 722 ; N Ohungarumlaut ; B 60 -18 699 876 ;
C -1 ; WX 400 ; N degree ; B 101 390 387 676 ;
C -1 ; WX 500 ; N ograve ; B 27 -11 468 664 ;
C -1 ; WX 667 ; N Ccaron ; B 66 -18 689 873 ;
C -1 ; WX 500 ; N ugrave ; B 42 -11 475 664 ;
C -1 ; WX 453 ; N radical ; B 2 -60 452 768 ;
C -1 ; WX 722 ; N Dcaron ; B -8 0 700 873 ;
C -1 ; WX 389 ; N rcommaaccent ; B -3 -217 412 441 ;
C -1 ; WX 667 ; N Ntilde ; B -20 -15 727 836 ;
C -1 ; WX 500 ; N otilde ; B 27 -11 496 624 ;
C -1 ; WX 611 ; N Rcommaaccent ; B -13 -187 588 653 ;
C -1 ; WX 556 ; N Lcommaaccent ; B -8 -217 559 653 ;
C -1 ; WX 611 ; N Atilde ; B -51 0 566 836 ;
C -1 ; WX 611 ; N Aogonek ; B -51 -169 566 668 ;
C -1 ; WX 611 ; N Aring ; B -51 0 564 883 ;
C -1 ; WX 722 ; N Otilde ; B 60 -18 699 836 ;
C -1 ; WX 389 ; N zdotaccent ; B -2 -81 380 606 ;
C -1 ; WX 611 ; N Ecaron ; B -1 0 634 873 ;
C -1 ; WX 333 ; N Iogonek ; B -8 -169 384 653 ;
C -1 ; WX 444 ; N kcommaaccent ; B 14 -187 461 683 ;
C -1 ; WX 675 ; N minus ; B 86 220 590 286 ;
C -1 ; WX 333 ; N Icircumflex ; B -8 0 425 873 ;
C -1 ; WX 500 ; N ncaron ; B 14 -9 510 661 ;
C -1 ; WX 278 ; N tcommaaccent ; B 2 -217 296 546 ;
C -1 ; WX 675 ; N logicalnot ; B 86 108 590 386 ;
C -1 ; WX 500 ; N odieresis ; B 27 -11 489 606 ;
C -1 ; WX 500 ; N udieresis ; B 42 -11 479 606 ;
C -1 ; WX 549 ; N notequal ; B 12 -29 537 541 ;
C -1 ; WX 500 ; N gcommaaccent ; B 8 -206 472 706 ;
C -1 ; WX 500 ; N eth ; B 27 -11 482 683 ;
C -1 ; WX 389 ; N zcaron ; B -2 -81 434 661 ;
C -1 ; WX 500 ; N ncommaaccent ; B 14 -187 474 441 ;
C -1 ; WX 300 ; N onesuperior ; B 43 271 284 676 ;
C -1 ; WX 278 ; N imacron ; B 46 -11 311 583 ;
C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2321
KPX A C -30
KPX A Cacute -30
KPX A Ccaron -30
KPX A Ccedilla -30
KPX A G -35
KPX A Gbreve -35
KPX A Gcommaaccent -35
KPX A O -40
KPX A Oacute -40
KPX A Ocircumflex -40
KPX A Odieresis -40
KPX A Ograve -40
KPX A Ohungarumlaut -40
KPX A Omacron -40
KPX A Oslash -40
KPX A Otilde -40
KPX A Q -40
KPX A T -37
KPX A Tcaron -37
KPX A Tcommaaccent -37
KPX A U -50
KPX A Uacute -50
KPX A Ucircumflex -50
KPX A Udieresis -50
KPX A Ugrave -50
KPX A Uhungarumlaut -50
KPX A Umacron -50
KPX A Uogonek -50
KPX A Uring -50
KPX A V -105
KPX A W -95
KPX A Y -55
KPX A Yacute -55
KPX A Ydieresis -55
KPX A quoteright -37
KPX A u -20
KPX A uacute -20
KPX A ucircumflex -20
KPX A udieresis -20
KPX A ugrave -20
KPX A uhungarumlaut -20
KPX A umacron -20
KPX A uogonek -20
KPX A uring -20
KPX A v -55
KPX A w -55
KPX A y -55
KPX A yacute -55
KPX A ydieresis -55
KPX Aacute C -30
KPX Aacute Cacute -30
KPX Aacute Ccaron -30
KPX Aacute Ccedilla -30
KPX Aacute G -35
KPX Aacute Gbreve -35
KPX Aacute Gcommaaccent -35
KPX Aacute O -40
KPX Aacute Oacute -40
KPX Aacute Ocircumflex -40
KPX Aacute Odieresis -40
KPX Aacute Ograve -40
KPX Aacute Ohungarumlaut -40
KPX Aacute Omacron -40
KPX Aacute Oslash -40
KPX Aacute Otilde -40
KPX Aacute Q -40
KPX Aacute T -37
KPX Aacute Tcaron -37
KPX Aacute Tcommaaccent -37
KPX Aacute U -50
KPX Aacute Uacute -50
KPX Aacute Ucircumflex -50
KPX Aacute Udieresis -50
KPX Aacute Ugrave -50
KPX Aacute Uhungarumlaut -50
KPX Aacute Umacron -50
KPX Aacute Uogonek -50
KPX Aacute Uring -50
KPX Aacute V -105
KPX Aacute W -95
KPX Aacute Y -55
KPX Aacute Yacute -55
KPX Aacute Ydieresis -55
KPX Aacute quoteright -37
KPX Aacute u -20
KPX Aacute uacute -20
KPX Aacute ucircumflex -20
KPX Aacute udieresis -20
KPX Aacute ugrave -20
KPX Aacute uhungarumlaut -20
KPX Aacute umacron -20
KPX Aacute uogonek -20
KPX Aacute uring -20
KPX Aacute v -55
KPX Aacute w -55
KPX Aacute y -55
KPX Aacute yacute -55
KPX Aacute ydieresis -55
KPX Abreve C -30
KPX Abreve Cacute -30
KPX Abreve Ccaron -30
KPX Abreve Ccedilla -30
KPX Abreve G -35
KPX Abreve Gbreve -35
KPX Abreve Gcommaaccent -35
KPX Abreve O -40
KPX Abreve Oacute -40
KPX Abreve Ocircumflex -40
KPX Abreve Odieresis -40
KPX Abreve Ograve -40
KPX Abreve Ohungarumlaut -40
KPX Abreve Omacron -40
KPX Abreve Oslash -40
KPX Abreve Otilde -40
KPX Abreve Q -40
KPX Abreve T -37
KPX Abreve Tcaron -37
KPX Abreve Tcommaaccent -37
KPX Abreve U -50
KPX Abreve Uacute -50
KPX Abreve Ucircumflex -50
KPX Abreve Udieresis -50
KPX Abreve Ugrave -50
KPX Abreve Uhungarumlaut -50
KPX Abreve Umacron -50
KPX Abreve Uogonek -50
KPX Abreve Uring -50
KPX Abreve V -105
KPX Abreve W -95
KPX Abreve Y -55
KPX Abreve Yacute -55
KPX Abreve Ydieresis -55
KPX Abreve quoteright -37
KPX Abreve u -20
KPX Abreve uacute -20
KPX Abreve ucircumflex -20
KPX Abreve udieresis -20
KPX Abreve ugrave -20
KPX Abreve uhungarumlaut -20
KPX Abreve umacron -20
KPX Abreve uogonek -20
KPX Abreve uring -20
KPX Abreve v -55
KPX Abreve w -55
KPX Abreve y -55
KPX Abreve yacute -55
KPX Abreve ydieresis -55
KPX Acircumflex C -30
KPX Acircumflex Cacute -30
KPX Acircumflex Ccaron -30
KPX Acircumflex Ccedilla -30
KPX Acircumflex G -35
KPX Acircumflex Gbreve -35
KPX Acircumflex Gcommaaccent -35
KPX Acircumflex O -40
KPX Acircumflex Oacute -40
KPX Acircumflex Ocircumflex -40
KPX Acircumflex Odieresis -40
KPX Acircumflex Ograve -40
KPX Acircumflex Ohungarumlaut -40
KPX Acircumflex Omacron -40
KPX Acircumflex Oslash -40
KPX Acircumflex Otilde -40
KPX Acircumflex Q -40
KPX Acircumflex T -37
KPX Acircumflex Tcaron -37
KPX Acircumflex Tcommaaccent -37
KPX Acircumflex U -50
KPX Acircumflex Uacute -50
KPX Acircumflex Ucircumflex -50
KPX Acircumflex Udieresis -50
KPX Acircumflex Ugrave -50
KPX Acircumflex Uhungarumlaut -50
KPX Acircumflex Umacron -50
KPX Acircumflex Uogonek -50
KPX Acircumflex Uring -50
KPX Acircumflex V -105
KPX Acircumflex W -95
KPX Acircumflex Y -55
KPX Acircumflex Yacute -55
KPX Acircumflex Ydieresis -55
KPX Acircumflex quoteright -37
KPX Acircumflex u -20
KPX Acircumflex uacute -20
KPX Acircumflex ucircumflex -20
KPX Acircumflex udieresis -20
KPX Acircumflex ugrave -20
KPX Acircumflex uhungarumlaut -20
KPX Acircumflex umacron -20
KPX Acircumflex uogonek -20
KPX Acircumflex uring -20
KPX Acircumflex v -55
KPX Acircumflex w -55
KPX Acircumflex y -55
KPX Acircumflex yacute -55
KPX Acircumflex ydieresis -55
KPX Adieresis C -30
KPX Adieresis Cacute -30
KPX Adieresis Ccaron -30
KPX Adieresis Ccedilla -30
KPX Adieresis G -35
KPX Adieresis Gbreve -35
KPX Adieresis Gcommaaccent -35
KPX Adieresis O -40
KPX Adieresis Oacute -40
KPX Adieresis Ocircumflex -40
KPX Adieresis Odieresis -40
KPX Adieresis Ograve -40
KPX Adieresis Ohungarumlaut -40
KPX Adieresis Omacron -40
KPX Adieresis Oslash -40
KPX Adieresis Otilde -40
KPX Adieresis Q -40
KPX Adieresis T -37
KPX Adieresis Tcaron -37
KPX Adieresis Tcommaaccent -37
KPX Adieresis U -50
KPX Adieresis Uacute -50
KPX Adieresis Ucircumflex -50
KPX Adieresis Udieresis -50
KPX Adieresis Ugrave -50
KPX Adieresis Uhungarumlaut -50
KPX Adieresis Umacron -50
KPX Adieresis Uogonek -50
KPX Adieresis Uring -50
KPX Adieresis V -105
KPX Adieresis W -95
KPX Adieresis Y -55
KPX Adieresis Yacute -55
KPX Adieresis Ydieresis -55
KPX Adieresis quoteright -37
KPX Adieresis u -20
KPX Adieresis uacute -20
KPX Adieresis ucircumflex -20
KPX Adieresis udieresis -20
KPX Adieresis ugrave -20
KPX Adieresis uhungarumlaut -20
KPX Adieresis umacron -20
KPX Adieresis uogonek -20
KPX Adieresis uring -20
KPX Adieresis v -55
KPX Adieresis w -55
KPX Adieresis y -55
KPX Adieresis yacute -55
KPX Adieresis ydieresis -55
KPX Agrave C -30
KPX Agrave Cacute -30
KPX Agrave Ccaron -30
KPX Agrave Ccedilla -30
KPX Agrave G -35
KPX Agrave Gbreve -35
KPX Agrave Gcommaaccent -35
KPX Agrave O -40
KPX Agrave Oacute -40
KPX Agrave Ocircumflex -40
KPX Agrave Odieresis -40
KPX Agrave Ograve -40
KPX Agrave Ohungarumlaut -40
KPX Agrave Omacron -40
KPX Agrave Oslash -40
KPX Agrave Otilde -40
KPX Agrave Q -40
KPX Agrave T -37
KPX Agrave Tcaron -37
KPX Agrave Tcommaaccent -37
KPX Agrave U -50
KPX Agrave Uacute -50
KPX Agrave Ucircumflex -50
KPX Agrave Udieresis -50
KPX Agrave Ugrave -50
KPX Agrave Uhungarumlaut -50
KPX Agrave Umacron -50
KPX Agrave Uogonek -50
KPX Agrave Uring -50
KPX Agrave V -105
KPX Agrave W -95
KPX Agrave Y -55
KPX Agrave Yacute -55
KPX Agrave Ydieresis -55
KPX Agrave quoteright -37
KPX Agrave u -20
KPX Agrave uacute -20
KPX Agrave ucircumflex -20
KPX Agrave udieresis -20
KPX Agrave ugrave -20
KPX Agrave uhungarumlaut -20
KPX Agrave umacron -20
KPX Agrave uogonek -20
KPX Agrave uring -20
KPX Agrave v -55
KPX Agrave w -55
KPX Agrave y -55
KPX Agrave yacute -55
KPX Agrave ydieresis -55
KPX Amacron C -30
KPX Amacron Cacute -30
KPX Amacron Ccaron -30
KPX Amacron Ccedilla -30
KPX Amacron G -35
KPX Amacron Gbreve -35
KPX Amacron Gcommaaccent -35
KPX Amacron O -40
KPX Amacron Oacute -40
KPX Amacron Ocircumflex -40
KPX Amacron Odieresis -40
KPX Amacron Ograve -40
KPX Amacron Ohungarumlaut -40
KPX Amacron Omacron -40
KPX Amacron Oslash -40
KPX Amacron Otilde -40
KPX Amacron Q -40
KPX Amacron T -37
KPX Amacron Tcaron -37
KPX Amacron Tcommaaccent -37
KPX Amacron U -50
KPX Amacron Uacute -50
KPX Amacron Ucircumflex -50
KPX Amacron Udieresis -50
KPX Amacron Ugrave -50
KPX Amacron Uhungarumlaut -50
KPX Amacron Umacron -50
KPX Amacron Uogonek -50
KPX Amacron Uring -50
KPX Amacron V -105
KPX Amacron W -95
KPX Amacron Y -55
KPX Amacron Yacute -55
KPX Amacron Ydieresis -55
KPX Amacron quoteright -37
KPX Amacron u -20
KPX Amacron uacute -20
KPX Amacron ucircumflex -20
KPX Amacron udieresis -20
KPX Amacron ugrave -20
KPX Amacron uhungarumlaut -20
KPX Amacron umacron -20
KPX Amacron uogonek -20
KPX Amacron uring -20
KPX Amacron v -55
KPX Amacron w -55
KPX Amacron y -55
KPX Amacron yacute -55
KPX Amacron ydieresis -55
KPX Aogonek C -30
KPX Aogonek Cacute -30
KPX Aogonek Ccaron -30
KPX Aogonek Ccedilla -30
KPX Aogonek G -35
KPX Aogonek Gbreve -35
KPX Aogonek Gcommaaccent -35
KPX Aogonek O -40
KPX Aogonek Oacute -40
KPX Aogonek Ocircumflex -40
KPX Aogonek Odieresis -40
KPX Aogonek Ograve -40
KPX Aogonek Ohungarumlaut -40
KPX Aogonek Omacron -40
KPX Aogonek Oslash -40
KPX Aogonek Otilde -40
KPX Aogonek Q -40
KPX Aogonek T -37
KPX Aogonek Tcaron -37
KPX Aogonek Tcommaaccent -37
KPX Aogonek U -50
KPX Aogonek Uacute -50
KPX Aogonek Ucircumflex -50
KPX Aogonek Udieresis -50
KPX Aogonek Ugrave -50
KPX Aogonek Uhungarumlaut -50
KPX Aogonek Umacron -50
KPX Aogonek Uogonek -50
KPX Aogonek Uring -50
KPX Aogonek V -105
KPX Aogonek W -95
KPX Aogonek Y -55
KPX Aogonek Yacute -55
KPX Aogonek Ydieresis -55
KPX Aogonek quoteright -37
KPX Aogonek u -20
KPX Aogonek uacute -20
KPX Aogonek ucircumflex -20
KPX Aogonek udieresis -20
KPX Aogonek ugrave -20
KPX Aogonek uhungarumlaut -20
KPX Aogonek umacron -20
KPX Aogonek uogonek -20
KPX Aogonek uring -20
KPX Aogonek v -55
KPX Aogonek w -55
KPX Aogonek y -55
KPX Aogonek yacute -55
KPX Aogonek ydieresis -55
KPX Aring C -30
KPX Aring Cacute -30
KPX Aring Ccaron -30
KPX Aring Ccedilla -30
KPX Aring G -35
KPX Aring Gbreve -35
KPX Aring Gcommaaccent -35
KPX Aring O -40
KPX Aring Oacute -40
KPX Aring Ocircumflex -40
KPX Aring Odieresis -40
KPX Aring Ograve -40
KPX Aring Ohungarumlaut -40
KPX Aring Omacron -40
KPX Aring Oslash -40
KPX Aring Otilde -40
KPX Aring Q -40
KPX Aring T -37
KPX Aring Tcaron -37
KPX Aring Tcommaaccent -37
KPX Aring U -50
KPX Aring Uacute -50
KPX Aring Ucircumflex -50
KPX Aring Udieresis -50
KPX Aring Ugrave -50
KPX Aring Uhungarumlaut -50
KPX Aring Umacron -50
KPX Aring Uogonek -50
KPX Aring Uring -50
KPX Aring V -105
KPX Aring W -95
KPX Aring Y -55
KPX Aring Yacute -55
KPX Aring Ydieresis -55
KPX Aring quoteright -37
KPX Aring u -20
KPX Aring uacute -20
KPX Aring ucircumflex -20
KPX Aring udieresis -20
KPX Aring ugrave -20
KPX Aring uhungarumlaut -20
KPX Aring umacron -20
KPX Aring uogonek -20
KPX Aring uring -20
KPX Aring v -55
KPX Aring w -55
KPX Aring y -55
KPX Aring yacute -55
KPX Aring ydieresis -55
KPX Atilde C -30
KPX Atilde Cacute -30
KPX Atilde Ccaron -30
KPX Atilde Ccedilla -30
KPX Atilde G -35
KPX Atilde Gbreve -35
KPX Atilde Gcommaaccent -35
KPX Atilde O -40
KPX Atilde Oacute -40
KPX Atilde Ocircumflex -40
KPX Atilde Odieresis -40
KPX Atilde Ograve -40
KPX Atilde Ohungarumlaut -40
KPX Atilde Omacron -40
KPX Atilde Oslash -40
KPX Atilde Otilde -40
KPX Atilde Q -40
KPX Atilde T -37
KPX Atilde Tcaron -37
KPX Atilde Tcommaaccent -37
KPX Atilde U -50
KPX Atilde Uacute -50
KPX Atilde Ucircumflex -50
KPX Atilde Udieresis -50
KPX Atilde Ugrave -50
KPX Atilde Uhungarumlaut -50
KPX Atilde Umacron -50
KPX Atilde Uogonek -50
KPX Atilde Uring -50
KPX Atilde V -105
KPX Atilde W -95
KPX Atilde Y -55
KPX Atilde Yacute -55
KPX Atilde Ydieresis -55
KPX Atilde quoteright -37
KPX Atilde u -20
KPX Atilde uacute -20
KPX Atilde ucircumflex -20
KPX Atilde udieresis -20
KPX Atilde ugrave -20
KPX Atilde uhungarumlaut -20
KPX Atilde umacron -20
KPX Atilde uogonek -20
KPX Atilde uring -20
KPX Atilde v -55
KPX Atilde w -55
KPX Atilde y -55
KPX Atilde yacute -55
KPX Atilde ydieresis -55
KPX B A -25
KPX B Aacute -25
KPX B Abreve -25
KPX B Acircumflex -25
KPX B Adieresis -25
KPX B Agrave -25
KPX B Amacron -25
KPX B Aogonek -25
KPX B Aring -25
KPX B Atilde -25
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX D A -35
KPX D Aacute -35
KPX D Abreve -35
KPX D Acircumflex -35
KPX D Adieresis -35
KPX D Agrave -35
KPX D Amacron -35
KPX D Aogonek -35
KPX D Aring -35
KPX D Atilde -35
KPX D V -40
KPX D W -40
KPX D Y -40
KPX D Yacute -40
KPX D Ydieresis -40
KPX Dcaron A -35
KPX Dcaron Aacute -35
KPX Dcaron Abreve -35
KPX Dcaron Acircumflex -35
KPX Dcaron Adieresis -35
KPX Dcaron Agrave -35
KPX Dcaron Amacron -35
KPX Dcaron Aogonek -35
KPX Dcaron Aring -35
KPX Dcaron Atilde -35
KPX Dcaron V -40
KPX Dcaron W -40
KPX Dcaron Y -40
KPX Dcaron Yacute -40
KPX Dcaron Ydieresis -40
KPX Dcroat A -35
KPX Dcroat Aacute -35
KPX Dcroat Abreve -35
KPX Dcroat Acircumflex -35
KPX Dcroat Adieresis -35
KPX Dcroat Agrave -35
KPX Dcroat Amacron -35
KPX Dcroat Aogonek -35
KPX Dcroat Aring -35
KPX Dcroat Atilde -35
KPX Dcroat V -40
KPX Dcroat W -40
KPX Dcroat Y -40
KPX Dcroat Yacute -40
KPX Dcroat Ydieresis -40
KPX F A -115
KPX F Aacute -115
KPX F Abreve -115
KPX F Acircumflex -115
KPX F Adieresis -115
KPX F Agrave -115
KPX F Amacron -115
KPX F Aogonek -115
KPX F Aring -115
KPX F Atilde -115
KPX F a -75
KPX F aacute -75
KPX F abreve -75
KPX F acircumflex -75
KPX F adieresis -75
KPX F agrave -75
KPX F amacron -75
KPX F aogonek -75
KPX F aring -75
KPX F atilde -75
KPX F comma -135
KPX F e -75
KPX F eacute -75
KPX F ecaron -75
KPX F ecircumflex -75
KPX F edieresis -75
KPX F edotaccent -75
KPX F egrave -75
KPX F emacron -75
KPX F eogonek -75
KPX F i -45
KPX F iacute -45
KPX F icircumflex -45
KPX F idieresis -45
KPX F igrave -45
KPX F imacron -45
KPX F iogonek -45
KPX F o -105
KPX F oacute -105
KPX F ocircumflex -105
KPX F odieresis -105
KPX F ograve -105
KPX F ohungarumlaut -105
KPX F omacron -105
KPX F oslash -105
KPX F otilde -105
KPX F period -135
KPX F r -55
KPX F racute -55
KPX F rcaron -55
KPX F rcommaaccent -55
KPX J A -40
KPX J Aacute -40
KPX J Abreve -40
KPX J Acircumflex -40
KPX J Adieresis -40
KPX J Agrave -40
KPX J Amacron -40
KPX J Aogonek -40
KPX J Aring -40
KPX J Atilde -40
KPX J a -35
KPX J aacute -35
KPX J abreve -35
KPX J acircumflex -35
KPX J adieresis -35
KPX J agrave -35
KPX J amacron -35
KPX J aogonek -35
KPX J aring -35
KPX J atilde -35
KPX J comma -25
KPX J e -25
KPX J eacute -25
KPX J ecaron -25
KPX J ecircumflex -25
KPX J edieresis -25
KPX J edotaccent -25
KPX J egrave -25
KPX J emacron -25
KPX J eogonek -25
KPX J o -25
KPX J oacute -25
KPX J ocircumflex -25
KPX J odieresis -25
KPX J ograve -25
KPX J ohungarumlaut -25
KPX J omacron -25
KPX J oslash -25
KPX J otilde -25
KPX J period -25
KPX J u -35
KPX J uacute -35
KPX J ucircumflex -35
KPX J udieresis -35
KPX J ugrave -35
KPX J uhungarumlaut -35
KPX J umacron -35
KPX J uogonek -35
KPX J uring -35
KPX K O -50
KPX K Oacute -50
KPX K Ocircumflex -50
KPX K Odieresis -50
KPX K Ograve -50
KPX K Ohungarumlaut -50
KPX K Omacron -50
KPX K Oslash -50
KPX K Otilde -50
KPX K e -35
KPX K eacute -35
KPX K ecaron -35
KPX K ecircumflex -35
KPX K edieresis -35
KPX K edotaccent -35
KPX K egrave -35
KPX K emacron -35
KPX K eogonek -35
KPX K o -40
KPX K oacute -40
KPX K ocircumflex -40
KPX K odieresis -40
KPX K ograve -40
KPX K ohungarumlaut -40
KPX K omacron -40
KPX K oslash -40
KPX K otilde -40
KPX K u -40
KPX K uacute -40
KPX K ucircumflex -40
KPX K udieresis -40
KPX K ugrave -40
KPX K uhungarumlaut -40
KPX K umacron -40
KPX K uogonek -40
KPX K uring -40
KPX K y -40
KPX K yacute -40
KPX K ydieresis -40
KPX Kcommaaccent O -50
KPX Kcommaaccent Oacute -50
KPX Kcommaaccent Ocircumflex -50
KPX Kcommaaccent Odieresis -50
KPX Kcommaaccent Ograve -50
KPX Kcommaaccent Ohungarumlaut -50
KPX Kcommaaccent Omacron -50
KPX Kcommaaccent Oslash -50
KPX Kcommaaccent Otilde -50
KPX Kcommaaccent e -35
KPX Kcommaaccent eacute -35
KPX Kcommaaccent ecaron -35
KPX Kcommaaccent ecircumflex -35
KPX Kcommaaccent edieresis -35
KPX Kcommaaccent edotaccent -35
KPX Kcommaaccent egrave -35
KPX Kcommaaccent emacron -35
KPX Kcommaaccent eogonek -35
KPX Kcommaaccent o -40
KPX Kcommaaccent oacute -40
KPX Kcommaaccent ocircumflex -40
KPX Kcommaaccent odieresis -40
KPX Kcommaaccent ograve -40
KPX Kcommaaccent ohungarumlaut -40
KPX Kcommaaccent omacron -40
KPX Kcommaaccent oslash -40
KPX Kcommaaccent otilde -40
KPX Kcommaaccent u -40
KPX Kcommaaccent uacute -40
KPX Kcommaaccent ucircumflex -40
KPX Kcommaaccent udieresis -40
KPX Kcommaaccent ugrave -40
KPX Kcommaaccent uhungarumlaut -40
KPX Kcommaaccent umacron -40
KPX Kcommaaccent uogonek -40
KPX Kcommaaccent uring -40
KPX Kcommaaccent y -40
KPX Kcommaaccent yacute -40
KPX Kcommaaccent ydieresis -40
KPX L T -20
KPX L Tcaron -20
KPX L Tcommaaccent -20
KPX L V -55
KPX L W -55
KPX L Y -20
KPX L Yacute -20
KPX L Ydieresis -20
KPX L quoteright -37
KPX L y -30
KPX L yacute -30
KPX L ydieresis -30
KPX Lacute T -20
KPX Lacute Tcaron -20
KPX Lacute Tcommaaccent -20
KPX Lacute V -55
KPX Lacute W -55
KPX Lacute Y -20
KPX Lacute Yacute -20
KPX Lacute Ydieresis -20
KPX Lacute quoteright -37
KPX Lacute y -30
KPX Lacute yacute -30
KPX Lacute ydieresis -30
KPX Lcommaaccent T -20
KPX Lcommaaccent Tcaron -20
KPX Lcommaaccent Tcommaaccent -20
KPX Lcommaaccent V -55
KPX Lcommaaccent W -55
KPX Lcommaaccent Y -20
KPX Lcommaaccent Yacute -20
KPX Lcommaaccent Ydieresis -20
KPX Lcommaaccent quoteright -37
KPX Lcommaaccent y -30
KPX Lcommaaccent yacute -30
KPX Lcommaaccent ydieresis -30
KPX Lslash T -20
KPX Lslash Tcaron -20
KPX Lslash Tcommaaccent -20
KPX Lslash V -55
KPX Lslash W -55
KPX Lslash Y -20
KPX Lslash Yacute -20
KPX Lslash Ydieresis -20
KPX Lslash quoteright -37
KPX Lslash y -30
KPX Lslash yacute -30
KPX Lslash ydieresis -30
KPX N A -27
KPX N Aacute -27
KPX N Abreve -27
KPX N Acircumflex -27
KPX N Adieresis -27
KPX N Agrave -27
KPX N Amacron -27
KPX N Aogonek -27
KPX N Aring -27
KPX N Atilde -27
KPX Nacute A -27
KPX Nacute Aacute -27
KPX Nacute Abreve -27
KPX Nacute Acircumflex -27
KPX Nacute Adieresis -27
KPX Nacute Agrave -27
KPX Nacute Amacron -27
KPX Nacute Aogonek -27
KPX Nacute Aring -27
KPX Nacute Atilde -27
KPX Ncaron A -27
KPX Ncaron Aacute -27
KPX Ncaron Abreve -27
KPX Ncaron Acircumflex -27
KPX Ncaron Adieresis -27
KPX Ncaron Agrave -27
KPX Ncaron Amacron -27
KPX Ncaron Aogonek -27
KPX Ncaron Aring -27
KPX Ncaron Atilde -27
KPX Ncommaaccent A -27
KPX Ncommaaccent Aacute -27
KPX Ncommaaccent Abreve -27
KPX Ncommaaccent Acircumflex -27
KPX Ncommaaccent Adieresis -27
KPX Ncommaaccent Agrave -27
KPX Ncommaaccent Amacron -27
KPX Ncommaaccent Aogonek -27
KPX Ncommaaccent Aring -27
KPX Ncommaaccent Atilde -27
KPX Ntilde A -27
KPX Ntilde Aacute -27
KPX Ntilde Abreve -27
KPX Ntilde Acircumflex -27
KPX Ntilde Adieresis -27
KPX Ntilde Agrave -27
KPX Ntilde Amacron -27
KPX Ntilde Aogonek -27
KPX Ntilde Aring -27
KPX Ntilde Atilde -27
KPX O A -55
KPX O Aacute -55
KPX O Abreve -55
KPX O Acircumflex -55
KPX O Adieresis -55
KPX O Agrave -55
KPX O Amacron -55
KPX O Aogonek -55
KPX O Aring -55
KPX O Atilde -55
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -50
KPX O X -40
KPX O Y -50
KPX O Yacute -50
KPX O Ydieresis -50
KPX Oacute A -55
KPX Oacute Aacute -55
KPX Oacute Abreve -55
KPX Oacute Acircumflex -55
KPX Oacute Adieresis -55
KPX Oacute Agrave -55
KPX Oacute Amacron -55
KPX Oacute Aogonek -55
KPX Oacute Aring -55
KPX Oacute Atilde -55
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -50
KPX Oacute X -40
KPX Oacute Y -50
KPX Oacute Yacute -50
KPX Oacute Ydieresis -50
KPX Ocircumflex A -55
KPX Ocircumflex Aacute -55
KPX Ocircumflex Abreve -55
KPX Ocircumflex Acircumflex -55
KPX Ocircumflex Adieresis -55
KPX Ocircumflex Agrave -55
KPX Ocircumflex Amacron -55
KPX Ocircumflex Aogonek -55
KPX Ocircumflex Aring -55
KPX Ocircumflex Atilde -55
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -50
KPX Ocircumflex X -40
KPX Ocircumflex Y -50
KPX Ocircumflex Yacute -50
KPX Ocircumflex Ydieresis -50
KPX Odieresis A -55
KPX Odieresis Aacute -55
KPX Odieresis Abreve -55
KPX Odieresis Acircumflex -55
KPX Odieresis Adieresis -55
KPX Odieresis Agrave -55
KPX Odieresis Amacron -55
KPX Odieresis Aogonek -55
KPX Odieresis Aring -55
KPX Odieresis Atilde -55
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -50
KPX Odieresis X -40
KPX Odieresis Y -50
KPX Odieresis Yacute -50
KPX Odieresis Ydieresis -50
KPX Ograve A -55
KPX Ograve Aacute -55
KPX Ograve Abreve -55
KPX Ograve Acircumflex -55
KPX Ograve Adieresis -55
KPX Ograve Agrave -55
KPX Ograve Amacron -55
KPX Ograve Aogonek -55
KPX Ograve Aring -55
KPX Ograve Atilde -55
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -50
KPX Ograve X -40
KPX Ograve Y -50
KPX Ograve Yacute -50
KPX Ograve Ydieresis -50
KPX Ohungarumlaut A -55
KPX Ohungarumlaut Aacute -55
KPX Ohungarumlaut Abreve -55
KPX Ohungarumlaut Acircumflex -55
KPX Ohungarumlaut Adieresis -55
KPX Ohungarumlaut Agrave -55
KPX Ohungarumlaut Amacron -55
KPX Ohungarumlaut Aogonek -55
KPX Ohungarumlaut Aring -55
KPX Ohungarumlaut Atilde -55
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -50
KPX Ohungarumlaut X -40
KPX Ohungarumlaut Y -50
KPX Ohungarumlaut Yacute -50
KPX Ohungarumlaut Ydieresis -50
KPX Omacron A -55
KPX Omacron Aacute -55
KPX Omacron Abreve -55
KPX Omacron Acircumflex -55
KPX Omacron Adieresis -55
KPX Omacron Agrave -55
KPX Omacron Amacron -55
KPX Omacron Aogonek -55
KPX Omacron Aring -55
KPX Omacron Atilde -55
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -50
KPX Omacron X -40
KPX Omacron Y -50
KPX Omacron Yacute -50
KPX Omacron Ydieresis -50
KPX Oslash A -55
KPX Oslash Aacute -55
KPX Oslash Abreve -55
KPX Oslash Acircumflex -55
KPX Oslash Adieresis -55
KPX Oslash Agrave -55
KPX Oslash Amacron -55
KPX Oslash Aogonek -55
KPX Oslash Aring -55
KPX Oslash Atilde -55
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -50
KPX Oslash X -40
KPX Oslash Y -50
KPX Oslash Yacute -50
KPX Oslash Ydieresis -50
KPX Otilde A -55
KPX Otilde Aacute -55
KPX Otilde Abreve -55
KPX Otilde Acircumflex -55
KPX Otilde Adieresis -55
KPX Otilde Agrave -55
KPX Otilde Amacron -55
KPX Otilde Aogonek -55
KPX Otilde Aring -55
KPX Otilde Atilde -55
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -50
KPX Otilde X -40
KPX Otilde Y -50
KPX Otilde Yacute -50
KPX Otilde Ydieresis -50
KPX P A -90
KPX P Aacute -90
KPX P Abreve -90
KPX P Acircumflex -90
KPX P Adieresis -90
KPX P Agrave -90
KPX P Amacron -90
KPX P Aogonek -90
KPX P Aring -90
KPX P Atilde -90
KPX P a -80
KPX P aacute -80
KPX P abreve -80
KPX P acircumflex -80
KPX P adieresis -80
KPX P agrave -80
KPX P amacron -80
KPX P aogonek -80
KPX P aring -80
KPX P atilde -80
KPX P comma -135
KPX P e -80
KPX P eacute -80
KPX P ecaron -80
KPX P ecircumflex -80
KPX P edieresis -80
KPX P edotaccent -80
KPX P egrave -80
KPX P emacron -80
KPX P eogonek -80
KPX P o -80
KPX P oacute -80
KPX P ocircumflex -80
KPX P odieresis -80
KPX P ograve -80
KPX P ohungarumlaut -80
KPX P omacron -80
KPX P oslash -80
KPX P otilde -80
KPX P period -135
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX R O -40
KPX R Oacute -40
KPX R Ocircumflex -40
KPX R Odieresis -40
KPX R Ograve -40
KPX R Ohungarumlaut -40
KPX R Omacron -40
KPX R Oslash -40
KPX R Otilde -40
KPX R U -40
KPX R Uacute -40
KPX R Ucircumflex -40
KPX R Udieresis -40
KPX R Ugrave -40
KPX R Uhungarumlaut -40
KPX R Umacron -40
KPX R Uogonek -40
KPX R Uring -40
KPX R V -18
KPX R W -18
KPX R Y -18
KPX R Yacute -18
KPX R Ydieresis -18
KPX Racute O -40
KPX Racute Oacute -40
KPX Racute Ocircumflex -40
KPX Racute Odieresis -40
KPX Racute Ograve -40
KPX Racute Ohungarumlaut -40
KPX Racute Omacron -40
KPX Racute Oslash -40
KPX Racute Otilde -40
KPX Racute U -40
KPX Racute Uacute -40
KPX Racute Ucircumflex -40
KPX Racute Udieresis -40
KPX Racute Ugrave -40
KPX Racute Uhungarumlaut -40
KPX Racute Umacron -40
KPX Racute Uogonek -40
KPX Racute Uring -40
KPX Racute V -18
KPX Racute W -18
KPX Racute Y -18
KPX Racute Yacute -18
KPX Racute Ydieresis -18
KPX Rcaron O -40
KPX Rcaron Oacute -40
KPX Rcaron Ocircumflex -40
KPX Rcaron Odieresis -40
KPX Rcaron Ograve -40
KPX Rcaron Ohungarumlaut -40
KPX Rcaron Omacron -40
KPX Rcaron Oslash -40
KPX Rcaron Otilde -40
KPX Rcaron U -40
KPX Rcaron Uacute -40
KPX Rcaron Ucircumflex -40
KPX Rcaron Udieresis -40
KPX Rcaron Ugrave -40
KPX Rcaron Uhungarumlaut -40
KPX Rcaron Umacron -40
KPX Rcaron Uogonek -40
KPX Rcaron Uring -40
KPX Rcaron V -18
KPX Rcaron W -18
KPX Rcaron Y -18
KPX Rcaron Yacute -18
KPX Rcaron Ydieresis -18
KPX Rcommaaccent O -40
KPX Rcommaaccent Oacute -40
KPX Rcommaaccent Ocircumflex -40
KPX Rcommaaccent Odieresis -40
KPX Rcommaaccent Ograve -40
KPX Rcommaaccent Ohungarumlaut -40
KPX Rcommaaccent Omacron -40
KPX Rcommaaccent Oslash -40
KPX Rcommaaccent Otilde -40
KPX Rcommaaccent U -40
KPX Rcommaaccent Uacute -40
KPX Rcommaaccent Ucircumflex -40
KPX Rcommaaccent Udieresis -40
KPX Rcommaaccent Ugrave -40
KPX Rcommaaccent Uhungarumlaut -40
KPX Rcommaaccent Umacron -40
KPX Rcommaaccent Uogonek -40
KPX Rcommaaccent Uring -40
KPX Rcommaaccent V -18
KPX Rcommaaccent W -18
KPX Rcommaaccent Y -18
KPX Rcommaaccent Yacute -18
KPX Rcommaaccent Ydieresis -18
KPX T A -50
KPX T Aacute -50
KPX T Abreve -50
KPX T Acircumflex -50
KPX T Adieresis -50
KPX T Agrave -50
KPX T Amacron -50
KPX T Aogonek -50
KPX T Aring -50
KPX T Atilde -50
KPX T O -18
KPX T Oacute -18
KPX T Ocircumflex -18
KPX T Odieresis -18
KPX T Ograve -18
KPX T Ohungarumlaut -18
KPX T Omacron -18
KPX T Oslash -18
KPX T Otilde -18
KPX T a -92
KPX T aacute -92
KPX T abreve -92
KPX T acircumflex -92
KPX T adieresis -92
KPX T agrave -92
KPX T amacron -92
KPX T aogonek -92
KPX T aring -92
KPX T atilde -92
KPX T colon -55
KPX T comma -74
KPX T e -92
KPX T eacute -92
KPX T ecaron -92
KPX T ecircumflex -52
KPX T edieresis -52
KPX T edotaccent -92
KPX T egrave -52
KPX T emacron -52
KPX T eogonek -92
KPX T hyphen -74
KPX T i -55
KPX T iacute -55
KPX T iogonek -55
KPX T o -92
KPX T oacute -92
KPX T ocircumflex -92
KPX T odieresis -92
KPX T ograve -92
KPX T ohungarumlaut -92
KPX T omacron -92
KPX T oslash -92
KPX T otilde -92
KPX T period -74
KPX T r -55
KPX T racute -55
KPX T rcaron -55
KPX T rcommaaccent -55
KPX T semicolon -65
KPX T u -55
KPX T uacute -55
KPX T ucircumflex -55
KPX T udieresis -55
KPX T ugrave -55
KPX T uhungarumlaut -55
KPX T umacron -55
KPX T uogonek -55
KPX T uring -55
KPX T w -74
KPX T y -74
KPX T yacute -74
KPX T ydieresis -34
KPX Tcaron A -50
KPX Tcaron Aacute -50
KPX Tcaron Abreve -50
KPX Tcaron Acircumflex -50
KPX Tcaron Adieresis -50
KPX Tcaron Agrave -50
KPX Tcaron Amacron -50
KPX Tcaron Aogonek -50
KPX Tcaron Aring -50
KPX Tcaron Atilde -50
KPX Tcaron O -18
KPX Tcaron Oacute -18
KPX Tcaron Ocircumflex -18
KPX Tcaron Odieresis -18
KPX Tcaron Ograve -18
KPX Tcaron Ohungarumlaut -18
KPX Tcaron Omacron -18
KPX Tcaron Oslash -18
KPX Tcaron Otilde -18
KPX Tcaron a -92
KPX Tcaron aacute -92
KPX Tcaron abreve -92
KPX Tcaron acircumflex -92
KPX Tcaron adieresis -92
KPX Tcaron agrave -92
KPX Tcaron amacron -92
KPX Tcaron aogonek -92
KPX Tcaron aring -92
KPX Tcaron atilde -92
KPX Tcaron colon -55
KPX Tcaron comma -74
KPX Tcaron e -92
KPX Tcaron eacute -92
KPX Tcaron ecaron -92
KPX Tcaron ecircumflex -52
KPX Tcaron edieresis -52
KPX Tcaron edotaccent -92
KPX Tcaron egrave -52
KPX Tcaron emacron -52
KPX Tcaron eogonek -92
KPX Tcaron hyphen -74
KPX Tcaron i -55
KPX Tcaron iacute -55
KPX Tcaron iogonek -55
KPX Tcaron o -92
KPX Tcaron oacute -92
KPX Tcaron ocircumflex -92
KPX Tcaron odieresis -92
KPX Tcaron ograve -92
KPX Tcaron ohungarumlaut -92
KPX Tcaron omacron -92
KPX Tcaron oslash -92
KPX Tcaron otilde -92
KPX Tcaron period -74
KPX Tcaron r -55
KPX Tcaron racute -55
KPX Tcaron rcaron -55
KPX Tcaron rcommaaccent -55
KPX Tcaron semicolon -65
KPX Tcaron u -55
KPX Tcaron uacute -55
KPX Tcaron ucircumflex -55
KPX Tcaron udieresis -55
KPX Tcaron ugrave -55
KPX Tcaron uhungarumlaut -55
KPX Tcaron umacron -55
KPX Tcaron uogonek -55
KPX Tcaron uring -55
KPX Tcaron w -74
KPX Tcaron y -74
KPX Tcaron yacute -74
KPX Tcaron ydieresis -34
KPX Tcommaaccent A -50
KPX Tcommaaccent Aacute -50
KPX Tcommaaccent Abreve -50
KPX Tcommaaccent Acircumflex -50
KPX Tcommaaccent Adieresis -50
KPX Tcommaaccent Agrave -50
KPX Tcommaaccent Amacron -50
KPX Tcommaaccent Aogonek -50
KPX Tcommaaccent Aring -50
KPX Tcommaaccent Atilde -50
KPX Tcommaaccent O -18
KPX Tcommaaccent Oacute -18
KPX Tcommaaccent Ocircumflex -18
KPX Tcommaaccent Odieresis -18
KPX Tcommaaccent Ograve -18
KPX Tcommaaccent Ohungarumlaut -18
KPX Tcommaaccent Omacron -18
KPX Tcommaaccent Oslash -18
KPX Tcommaaccent Otilde -18
KPX Tcommaaccent a -92
KPX Tcommaaccent aacute -92
KPX Tcommaaccent abreve -92
KPX Tcommaaccent acircumflex -92
KPX Tcommaaccent adieresis -92
KPX Tcommaaccent agrave -92
KPX Tcommaaccent amacron -92
KPX Tcommaaccent aogonek -92
KPX Tcommaaccent aring -92
KPX Tcommaaccent atilde -92
KPX Tcommaaccent colon -55
KPX Tcommaaccent comma -74
KPX Tcommaaccent e -92
KPX Tcommaaccent eacute -92
KPX Tcommaaccent ecaron -92
KPX Tcommaaccent ecircumflex -52
KPX Tcommaaccent edieresis -52
KPX Tcommaaccent edotaccent -92
KPX Tcommaaccent egrave -52
KPX Tcommaaccent emacron -52
KPX Tcommaaccent eogonek -92
KPX Tcommaaccent hyphen -74
KPX Tcommaaccent i -55
KPX Tcommaaccent iacute -55
KPX Tcommaaccent iogonek -55
KPX Tcommaaccent o -92
KPX Tcommaaccent oacute -92
KPX Tcommaaccent ocircumflex -92
KPX Tcommaaccent odieresis -92
KPX Tcommaaccent ograve -92
KPX Tcommaaccent ohungarumlaut -92
KPX Tcommaaccent omacron -92
KPX Tcommaaccent oslash -92
KPX Tcommaaccent otilde -92
KPX Tcommaaccent period -74
KPX Tcommaaccent r -55
KPX Tcommaaccent racute -55
KPX Tcommaaccent rcaron -55
KPX Tcommaaccent rcommaaccent -55
KPX Tcommaaccent semicolon -65
KPX Tcommaaccent u -55
KPX Tcommaaccent uacute -55
KPX Tcommaaccent ucircumflex -55
KPX Tcommaaccent udieresis -55
KPX Tcommaaccent ugrave -55
KPX Tcommaaccent uhungarumlaut -55
KPX Tcommaaccent umacron -55
KPX Tcommaaccent uogonek -55
KPX Tcommaaccent uring -55
KPX Tcommaaccent w -74
KPX Tcommaaccent y -74
KPX Tcommaaccent yacute -74
KPX Tcommaaccent ydieresis -34
KPX U A -40
KPX U Aacute -40
KPX U Abreve -40
KPX U Acircumflex -40
KPX U Adieresis -40
KPX U Agrave -40
KPX U Amacron -40
KPX U Aogonek -40
KPX U Aring -40
KPX U Atilde -40
KPX U comma -25
KPX U period -25
KPX Uacute A -40
KPX Uacute Aacute -40
KPX Uacute Abreve -40
KPX Uacute Acircumflex -40
KPX Uacute Adieresis -40
KPX Uacute Agrave -40
KPX Uacute Amacron -40
KPX Uacute Aogonek -40
KPX Uacute Aring -40
KPX Uacute Atilde -40
KPX Uacute comma -25
KPX Uacute period -25
KPX Ucircumflex A -40
KPX Ucircumflex Aacute -40
KPX Ucircumflex Abreve -40
KPX Ucircumflex Acircumflex -40
KPX Ucircumflex Adieresis -40
KPX Ucircumflex Agrave -40
KPX Ucircumflex Amacron -40
KPX Ucircumflex Aogonek -40
KPX Ucircumflex Aring -40
KPX Ucircumflex Atilde -40
KPX Ucircumflex comma -25
KPX Ucircumflex period -25
KPX Udieresis A -40
KPX Udieresis Aacute -40
KPX Udieresis Abreve -40
KPX Udieresis Acircumflex -40
KPX Udieresis Adieresis -40
KPX Udieresis Agrave -40
KPX Udieresis Amacron -40
KPX Udieresis Aogonek -40
KPX Udieresis Aring -40
KPX Udieresis Atilde -40
KPX Udieresis comma -25
KPX Udieresis period -25
KPX Ugrave A -40
KPX Ugrave Aacute -40
KPX Ugrave Abreve -40
KPX Ugrave Acircumflex -40
KPX Ugrave Adieresis -40
KPX Ugrave Agrave -40
KPX Ugrave Amacron -40
KPX Ugrave Aogonek -40
KPX Ugrave Aring -40
KPX Ugrave Atilde -40
KPX Ugrave comma -25
KPX Ugrave period -25
KPX Uhungarumlaut A -40
KPX Uhungarumlaut Aacute -40
KPX Uhungarumlaut Abreve -40
KPX Uhungarumlaut Acircumflex -40
KPX Uhungarumlaut Adieresis -40
KPX Uhungarumlaut Agrave -40
KPX Uhungarumlaut Amacron -40
KPX Uhungarumlaut Aogonek -40
KPX Uhungarumlaut Aring -40
KPX Uhungarumlaut Atilde -40
KPX Uhungarumlaut comma -25
KPX Uhungarumlaut period -25
KPX Umacron A -40
KPX Umacron Aacute -40
KPX Umacron Abreve -40
KPX Umacron Acircumflex -40
KPX Umacron Adieresis -40
KPX Umacron Agrave -40
KPX Umacron Amacron -40
KPX Umacron Aogonek -40
KPX Umacron Aring -40
KPX Umacron Atilde -40
KPX Umacron comma -25
KPX Umacron period -25
KPX Uogonek A -40
KPX Uogonek Aacute -40
KPX Uogonek Abreve -40
KPX Uogonek Acircumflex -40
KPX Uogonek Adieresis -40
KPX Uogonek Agrave -40
KPX Uogonek Amacron -40
KPX Uogonek Aogonek -40
KPX Uogonek Aring -40
KPX Uogonek Atilde -40
KPX Uogonek comma -25
KPX Uogonek period -25
KPX Uring A -40
KPX Uring Aacute -40
KPX Uring Abreve -40
KPX Uring Acircumflex -40
KPX Uring Adieresis -40
KPX Uring Agrave -40
KPX Uring Amacron -40
KPX Uring Aogonek -40
KPX Uring Aring -40
KPX Uring Atilde -40
KPX Uring comma -25
KPX Uring period -25
KPX V A -60
KPX V Aacute -60
KPX V Abreve -60
KPX V Acircumflex -60
KPX V Adieresis -60
KPX V Agrave -60
KPX V Amacron -60
KPX V Aogonek -60
KPX V Aring -60
KPX V Atilde -60
KPX V O -30
KPX V Oacute -30
KPX V Ocircumflex -30
KPX V Odieresis -30
KPX V Ograve -30
KPX V Ohungarumlaut -30
KPX V Omacron -30
KPX V Oslash -30
KPX V Otilde -30
KPX V a -111
KPX V aacute -111
KPX V abreve -111
KPX V acircumflex -111
KPX V adieresis -111
KPX V agrave -111
KPX V amacron -111
KPX V aogonek -111
KPX V aring -111
KPX V atilde -111
KPX V colon -65
KPX V comma -129
KPX V e -111
KPX V eacute -111
KPX V ecaron -111
KPX V ecircumflex -111
KPX V edieresis -71
KPX V edotaccent -111
KPX V egrave -71
KPX V emacron -71
KPX V eogonek -111
KPX V hyphen -55
KPX V i -74
KPX V iacute -74
KPX V icircumflex -34
KPX V idieresis -34
KPX V igrave -34
KPX V imacron -34
KPX V iogonek -74
KPX V o -111
KPX V oacute -111
KPX V ocircumflex -111
KPX V odieresis -111
KPX V ograve -111
KPX V ohungarumlaut -111
KPX V omacron -111
KPX V oslash -111
KPX V otilde -111
KPX V period -129
KPX V semicolon -74
KPX V u -74
KPX V uacute -74
KPX V ucircumflex -74
KPX V udieresis -74
KPX V ugrave -74
KPX V uhungarumlaut -74
KPX V umacron -74
KPX V uogonek -74
KPX V uring -74
KPX W A -60
KPX W Aacute -60
KPX W Abreve -60
KPX W Acircumflex -60
KPX W Adieresis -60
KPX W Agrave -60
KPX W Amacron -60
KPX W Aogonek -60
KPX W Aring -60
KPX W Atilde -60
KPX W O -25
KPX W Oacute -25
KPX W Ocircumflex -25
KPX W Odieresis -25
KPX W Ograve -25
KPX W Ohungarumlaut -25
KPX W Omacron -25
KPX W Oslash -25
KPX W Otilde -25
KPX W a -92
KPX W aacute -92
KPX W abreve -92
KPX W acircumflex -92
KPX W adieresis -92
KPX W agrave -92
KPX W amacron -92
KPX W aogonek -92
KPX W aring -92
KPX W atilde -92
KPX W colon -65
KPX W comma -92
KPX W e -92
KPX W eacute -92
KPX W ecaron -92
KPX W ecircumflex -92
KPX W edieresis -52
KPX W edotaccent -92
KPX W egrave -52
KPX W emacron -52
KPX W eogonek -92
KPX W hyphen -37
KPX W i -55
KPX W iacute -55
KPX W iogonek -55
KPX W o -92
KPX W oacute -92
KPX W ocircumflex -92
KPX W odieresis -92
KPX W ograve -92
KPX W ohungarumlaut -92
KPX W omacron -92
KPX W oslash -92
KPX W otilde -92
KPX W period -92
KPX W semicolon -65
KPX W u -55
KPX W uacute -55
KPX W ucircumflex -55
KPX W udieresis -55
KPX W ugrave -55
KPX W uhungarumlaut -55
KPX W umacron -55
KPX W uogonek -55
KPX W uring -55
KPX W y -70
KPX W yacute -70
KPX W ydieresis -70
KPX Y A -50
KPX Y Aacute -50
KPX Y Abreve -50
KPX Y Acircumflex -50
KPX Y Adieresis -50
KPX Y Agrave -50
KPX Y Amacron -50
KPX Y Aogonek -50
KPX Y Aring -50
KPX Y Atilde -50
KPX Y O -15
KPX Y Oacute -15
KPX Y Ocircumflex -15
KPX Y Odieresis -15
KPX Y Ograve -15
KPX Y Ohungarumlaut -15
KPX Y Omacron -15
KPX Y Oslash -15
KPX Y Otilde -15
KPX Y a -92
KPX Y aacute -92
KPX Y abreve -92
KPX Y acircumflex -92
KPX Y adieresis -92
KPX Y agrave -92
KPX Y amacron -92
KPX Y aogonek -92
KPX Y aring -92
KPX Y atilde -92
KPX Y colon -65
KPX Y comma -92
KPX Y e -92
KPX Y eacute -92
KPX Y ecaron -92
KPX Y ecircumflex -92
KPX Y edieresis -52
KPX Y edotaccent -92
KPX Y egrave -52
KPX Y emacron -52
KPX Y eogonek -92
KPX Y hyphen -74
KPX Y i -74
KPX Y iacute -74
KPX Y icircumflex -34
KPX Y idieresis -34
KPX Y igrave -34
KPX Y imacron -34
KPX Y iogonek -74
KPX Y o -92
KPX Y oacute -92
KPX Y ocircumflex -92
KPX Y odieresis -92
KPX Y ograve -92
KPX Y ohungarumlaut -92
KPX Y omacron -92
KPX Y oslash -92
KPX Y otilde -92
KPX Y period -92
KPX Y semicolon -65
KPX Y u -92
KPX Y uacute -92
KPX Y ucircumflex -92
KPX Y udieresis -92
KPX Y ugrave -92
KPX Y uhungarumlaut -92
KPX Y umacron -92
KPX Y uogonek -92
KPX Y uring -92
KPX Yacute A -50
KPX Yacute Aacute -50
KPX Yacute Abreve -50
KPX Yacute Acircumflex -50
KPX Yacute Adieresis -50
KPX Yacute Agrave -50
KPX Yacute Amacron -50
KPX Yacute Aogonek -50
KPX Yacute Aring -50
KPX Yacute Atilde -50
KPX Yacute O -15
KPX Yacute Oacute -15
KPX Yacute Ocircumflex -15
KPX Yacute Odieresis -15
KPX Yacute Ograve -15
KPX Yacute Ohungarumlaut -15
KPX Yacute Omacron -15
KPX Yacute Oslash -15
KPX Yacute Otilde -15
KPX Yacute a -92
KPX Yacute aacute -92
KPX Yacute abreve -92
KPX Yacute acircumflex -92
KPX Yacute adieresis -92
KPX Yacute agrave -92
KPX Yacute amacron -92
KPX Yacute aogonek -92
KPX Yacute aring -92
KPX Yacute atilde -92
KPX Yacute colon -65
KPX Yacute comma -92
KPX Yacute e -92
KPX Yacute eacute -92
KPX Yacute ecaron -92
KPX Yacute ecircumflex -92
KPX Yacute edieresis -52
KPX Yacute edotaccent -92
KPX Yacute egrave -52
KPX Yacute emacron -52
KPX Yacute eogonek -92
KPX Yacute hyphen -74
KPX Yacute i -74
KPX Yacute iacute -74
KPX Yacute icircumflex -34
KPX Yacute idieresis -34
KPX Yacute igrave -34
KPX Yacute imacron -34
KPX Yacute iogonek -74
KPX Yacute o -92
KPX Yacute oacute -92
KPX Yacute ocircumflex -92
KPX Yacute odieresis -92
KPX Yacute ograve -92
KPX Yacute ohungarumlaut -92
KPX Yacute omacron -92
KPX Yacute oslash -92
KPX Yacute otilde -92
KPX Yacute period -92
KPX Yacute semicolon -65
KPX Yacute u -92
KPX Yacute uacute -92
KPX Yacute ucircumflex -92
KPX Yacute udieresis -92
KPX Yacute ugrave -92
KPX Yacute uhungarumlaut -92
KPX Yacute umacron -92
KPX Yacute uogonek -92
KPX Yacute uring -92
KPX Ydieresis A -50
KPX Ydieresis Aacute -50
KPX Ydieresis Abreve -50
KPX Ydieresis Acircumflex -50
KPX Ydieresis Adieresis -50
KPX Ydieresis Agrave -50
KPX Ydieresis Amacron -50
KPX Ydieresis Aogonek -50
KPX Ydieresis Aring -50
KPX Ydieresis Atilde -50
KPX Ydieresis O -15
KPX Ydieresis Oacute -15
KPX Ydieresis Ocircumflex -15
KPX Ydieresis Odieresis -15
KPX Ydieresis Ograve -15
KPX Ydieresis Ohungarumlaut -15
KPX Ydieresis Omacron -15
KPX Ydieresis Oslash -15
KPX Ydieresis Otilde -15
KPX Ydieresis a -92
KPX Ydieresis aacute -92
KPX Ydieresis abreve -92
KPX Ydieresis acircumflex -92
KPX Ydieresis adieresis -92
KPX Ydieresis agrave -92
KPX Ydieresis amacron -92
KPX Ydieresis aogonek -92
KPX Ydieresis aring -92
KPX Ydieresis atilde -92
KPX Ydieresis colon -65
KPX Ydieresis comma -92
KPX Ydieresis e -92
KPX Ydieresis eacute -92
KPX Ydieresis ecaron -92
KPX Ydieresis ecircumflex -92
KPX Ydieresis edieresis -52
KPX Ydieresis edotaccent -92
KPX Ydieresis egrave -52
KPX Ydieresis emacron -52
KPX Ydieresis eogonek -92
KPX Ydieresis hyphen -74
KPX Ydieresis i -74
KPX Ydieresis iacute -74
KPX Ydieresis icircumflex -34
KPX Ydieresis idieresis -34
KPX Ydieresis igrave -34
KPX Ydieresis imacron -34
KPX Ydieresis iogonek -74
KPX Ydieresis o -92
KPX Ydieresis oacute -92
KPX Ydieresis ocircumflex -92
KPX Ydieresis odieresis -92
KPX Ydieresis ograve -92
KPX Ydieresis ohungarumlaut -92
KPX Ydieresis omacron -92
KPX Ydieresis oslash -92
KPX Ydieresis otilde -92
KPX Ydieresis period -92
KPX Ydieresis semicolon -65
KPX Ydieresis u -92
KPX Ydieresis uacute -92
KPX Ydieresis ucircumflex -92
KPX Ydieresis udieresis -92
KPX Ydieresis ugrave -92
KPX Ydieresis uhungarumlaut -92
KPX Ydieresis umacron -92
KPX Ydieresis uogonek -92
KPX Ydieresis uring -92
KPX a g -10
KPX a gbreve -10
KPX a gcommaaccent -10
KPX aacute g -10
KPX aacute gbreve -10
KPX aacute gcommaaccent -10
KPX abreve g -10
KPX abreve gbreve -10
KPX abreve gcommaaccent -10
KPX acircumflex g -10
KPX acircumflex gbreve -10
KPX acircumflex gcommaaccent -10
KPX adieresis g -10
KPX adieresis gbreve -10
KPX adieresis gcommaaccent -10
KPX agrave g -10
KPX agrave gbreve -10
KPX agrave gcommaaccent -10
KPX amacron g -10
KPX amacron gbreve -10
KPX amacron gcommaaccent -10
KPX aogonek g -10
KPX aogonek gbreve -10
KPX aogonek gcommaaccent -10
KPX aring g -10
KPX aring gbreve -10
KPX aring gcommaaccent -10
KPX atilde g -10
KPX atilde gbreve -10
KPX atilde gcommaaccent -10
KPX b period -40
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX c h -15
KPX c k -20
KPX c kcommaaccent -20
KPX cacute h -15
KPX cacute k -20
KPX cacute kcommaaccent -20
KPX ccaron h -15
KPX ccaron k -20
KPX ccaron kcommaaccent -20
KPX ccedilla h -15
KPX ccedilla k -20
KPX ccedilla kcommaaccent -20
KPX comma quotedblright -140
KPX comma quoteright -140
KPX e comma -10
KPX e g -40
KPX e gbreve -40
KPX e gcommaaccent -40
KPX e period -15
KPX e v -15
KPX e w -15
KPX e x -20
KPX e y -30
KPX e yacute -30
KPX e ydieresis -30
KPX eacute comma -10
KPX eacute g -40
KPX eacute gbreve -40
KPX eacute gcommaaccent -40
KPX eacute period -15
KPX eacute v -15
KPX eacute w -15
KPX eacute x -20
KPX eacute y -30
KPX eacute yacute -30
KPX eacute ydieresis -30
KPX ecaron comma -10
KPX ecaron g -40
KPX ecaron gbreve -40
KPX ecaron gcommaaccent -40
KPX ecaron period -15
KPX ecaron v -15
KPX ecaron w -15
KPX ecaron x -20
KPX ecaron y -30
KPX ecaron yacute -30
KPX ecaron ydieresis -30
KPX ecircumflex comma -10
KPX ecircumflex g -40
KPX ecircumflex gbreve -40
KPX ecircumflex gcommaaccent -40
KPX ecircumflex period -15
KPX ecircumflex v -15
KPX ecircumflex w -15
KPX ecircumflex x -20
KPX ecircumflex y -30
KPX ecircumflex yacute -30
KPX ecircumflex ydieresis -30
KPX edieresis comma -10
KPX edieresis g -40
KPX edieresis gbreve -40
KPX edieresis gcommaaccent -40
KPX edieresis period -15
KPX edieresis v -15
KPX edieresis w -15
KPX edieresis x -20
KPX edieresis y -30
KPX edieresis yacute -30
KPX edieresis ydieresis -30
KPX edotaccent comma -10
KPX edotaccent g -40
KPX edotaccent gbreve -40
KPX edotaccent gcommaaccent -40
KPX edotaccent period -15
KPX edotaccent v -15
KPX edotaccent w -15
KPX edotaccent x -20
KPX edotaccent y -30
KPX edotaccent yacute -30
KPX edotaccent ydieresis -30
KPX egrave comma -10
KPX egrave g -40
KPX egrave gbreve -40
KPX egrave gcommaaccent -40
KPX egrave period -15
KPX egrave v -15
KPX egrave w -15
KPX egrave x -20
KPX egrave y -30
KPX egrave yacute -30
KPX egrave ydieresis -30
KPX emacron comma -10
KPX emacron g -40
KPX emacron gbreve -40
KPX emacron gcommaaccent -40
KPX emacron period -15
KPX emacron v -15
KPX emacron w -15
KPX emacron x -20
KPX emacron y -30
KPX emacron yacute -30
KPX emacron ydieresis -30
KPX eogonek comma -10
KPX eogonek g -40
KPX eogonek gbreve -40
KPX eogonek gcommaaccent -40
KPX eogonek period -15
KPX eogonek v -15
KPX eogonek w -15
KPX eogonek x -20
KPX eogonek y -30
KPX eogonek yacute -30
KPX eogonek ydieresis -30
KPX f comma -10
KPX f dotlessi -60
KPX f f -18
KPX f i -20
KPX f iogonek -20
KPX f period -15
KPX f quoteright 92
KPX g comma -10
KPX g e -10
KPX g eacute -10
KPX g ecaron -10
KPX g ecircumflex -10
KPX g edieresis -10
KPX g edotaccent -10
KPX g egrave -10
KPX g emacron -10
KPX g eogonek -10
KPX g g -10
KPX g gbreve -10
KPX g gcommaaccent -10
KPX g period -15
KPX gbreve comma -10
KPX gbreve e -10
KPX gbreve eacute -10
KPX gbreve ecaron -10
KPX gbreve ecircumflex -10
KPX gbreve edieresis -10
KPX gbreve edotaccent -10
KPX gbreve egrave -10
KPX gbreve emacron -10
KPX gbreve eogonek -10
KPX gbreve g -10
KPX gbreve gbreve -10
KPX gbreve gcommaaccent -10
KPX gbreve period -15
KPX gcommaaccent comma -10
KPX gcommaaccent e -10
KPX gcommaaccent eacute -10
KPX gcommaaccent ecaron -10
KPX gcommaaccent ecircumflex -10
KPX gcommaaccent edieresis -10
KPX gcommaaccent edotaccent -10
KPX gcommaaccent egrave -10
KPX gcommaaccent emacron -10
KPX gcommaaccent eogonek -10
KPX gcommaaccent g -10
KPX gcommaaccent gbreve -10
KPX gcommaaccent gcommaaccent -10
KPX gcommaaccent period -15
KPX k e -10
KPX k eacute -10
KPX k ecaron -10
KPX k ecircumflex -10
KPX k edieresis -10
KPX k edotaccent -10
KPX k egrave -10
KPX k emacron -10
KPX k eogonek -10
KPX k o -10
KPX k oacute -10
KPX k ocircumflex -10
KPX k odieresis -10
KPX k ograve -10
KPX k ohungarumlaut -10
KPX k omacron -10
KPX k oslash -10
KPX k otilde -10
KPX k y -10
KPX k yacute -10
KPX k ydieresis -10
KPX kcommaaccent e -10
KPX kcommaaccent eacute -10
KPX kcommaaccent ecaron -10
KPX kcommaaccent ecircumflex -10
KPX kcommaaccent edieresis -10
KPX kcommaaccent edotaccent -10
KPX kcommaaccent egrave -10
KPX kcommaaccent emacron -10
KPX kcommaaccent eogonek -10
KPX kcommaaccent o -10
KPX kcommaaccent oacute -10
KPX kcommaaccent ocircumflex -10
KPX kcommaaccent odieresis -10
KPX kcommaaccent ograve -10
KPX kcommaaccent ohungarumlaut -10
KPX kcommaaccent omacron -10
KPX kcommaaccent oslash -10
KPX kcommaaccent otilde -10
KPX kcommaaccent y -10
KPX kcommaaccent yacute -10
KPX kcommaaccent ydieresis -10
KPX n v -40
KPX nacute v -40
KPX ncaron v -40
KPX ncommaaccent v -40
KPX ntilde v -40
KPX o g -10
KPX o gbreve -10
KPX o gcommaaccent -10
KPX o v -10
KPX oacute g -10
KPX oacute gbreve -10
KPX oacute gcommaaccent -10
KPX oacute v -10
KPX ocircumflex g -10
KPX ocircumflex gbreve -10
KPX ocircumflex gcommaaccent -10
KPX ocircumflex v -10
KPX odieresis g -10
KPX odieresis gbreve -10
KPX odieresis gcommaaccent -10
KPX odieresis v -10
KPX ograve g -10
KPX ograve gbreve -10
KPX ograve gcommaaccent -10
KPX ograve v -10
KPX ohungarumlaut g -10
KPX ohungarumlaut gbreve -10
KPX ohungarumlaut gcommaaccent -10
KPX ohungarumlaut v -10
KPX omacron g -10
KPX omacron gbreve -10
KPX omacron gcommaaccent -10
KPX omacron v -10
KPX oslash g -10
KPX oslash gbreve -10
KPX oslash gcommaaccent -10
KPX oslash v -10
KPX otilde g -10
KPX otilde gbreve -10
KPX otilde gcommaaccent -10
KPX otilde v -10
KPX period quotedblright -140
KPX period quoteright -140
KPX quoteleft quoteleft -111
KPX quoteright d -25
KPX quoteright dcroat -25
KPX quoteright quoteright -111
KPX quoteright r -25
KPX quoteright racute -25
KPX quoteright rcaron -25
KPX quoteright rcommaaccent -25
KPX quoteright s -40
KPX quoteright sacute -40
KPX quoteright scaron -40
KPX quoteright scedilla -40
KPX quoteright scommaaccent -40
KPX quoteright space -111
KPX quoteright t -30
KPX quoteright tcommaaccent -30
KPX quoteright v -10
KPX r a -15
KPX r aacute -15
KPX r abreve -15
KPX r acircumflex -15
KPX r adieresis -15
KPX r agrave -15
KPX r amacron -15
KPX r aogonek -15
KPX r aring -15
KPX r atilde -15
KPX r c -37
KPX r cacute -37
KPX r ccaron -37
KPX r ccedilla -37
KPX r comma -111
KPX r d -37
KPX r dcroat -37
KPX r e -37
KPX r eacute -37
KPX r ecaron -37
KPX r ecircumflex -37
KPX r edieresis -37
KPX r edotaccent -37
KPX r egrave -37
KPX r emacron -37
KPX r eogonek -37
KPX r g -37
KPX r gbreve -37
KPX r gcommaaccent -37
KPX r hyphen -20
KPX r o -45
KPX r oacute -45
KPX r ocircumflex -45
KPX r odieresis -45
KPX r ograve -45
KPX r ohungarumlaut -45
KPX r omacron -45
KPX r oslash -45
KPX r otilde -45
KPX r period -111
KPX r q -37
KPX r s -10
KPX r sacute -10
KPX r scaron -10
KPX r scedilla -10
KPX r scommaaccent -10
KPX racute a -15
KPX racute aacute -15
KPX racute abreve -15
KPX racute acircumflex -15
KPX racute adieresis -15
KPX racute agrave -15
KPX racute amacron -15
KPX racute aogonek -15
KPX racute aring -15
KPX racute atilde -15
KPX racute c -37
KPX racute cacute -37
KPX racute ccaron -37
KPX racute ccedilla -37
KPX racute comma -111
KPX racute d -37
KPX racute dcroat -37
KPX racute e -37
KPX racute eacute -37
KPX racute ecaron -37
KPX racute ecircumflex -37
KPX racute edieresis -37
KPX racute edotaccent -37
KPX racute egrave -37
KPX racute emacron -37
KPX racute eogonek -37
KPX racute g -37
KPX racute gbreve -37
KPX racute gcommaaccent -37
KPX racute hyphen -20
KPX racute o -45
KPX racute oacute -45
KPX racute ocircumflex -45
KPX racute odieresis -45
KPX racute ograve -45
KPX racute ohungarumlaut -45
KPX racute omacron -45
KPX racute oslash -45
KPX racute otilde -45
KPX racute period -111
KPX racute q -37
KPX racute s -10
KPX racute sacute -10
KPX racute scaron -10
KPX racute scedilla -10
KPX racute scommaaccent -10
KPX rcaron a -15
KPX rcaron aacute -15
KPX rcaron abreve -15
KPX rcaron acircumflex -15
KPX rcaron adieresis -15
KPX rcaron agrave -15
KPX rcaron amacron -15
KPX rcaron aogonek -15
KPX rcaron aring -15
KPX rcaron atilde -15
KPX rcaron c -37
KPX rcaron cacute -37
KPX rcaron ccaron -37
KPX rcaron ccedilla -37
KPX rcaron comma -111
KPX rcaron d -37
KPX rcaron dcroat -37
KPX rcaron e -37
KPX rcaron eacute -37
KPX rcaron ecaron -37
KPX rcaron ecircumflex -37
KPX rcaron edieresis -37
KPX rcaron edotaccent -37
KPX rcaron egrave -37
KPX rcaron emacron -37
KPX rcaron eogonek -37
KPX rcaron g -37
KPX rcaron gbreve -37
KPX rcaron gcommaaccent -37
KPX rcaron hyphen -20
KPX rcaron o -45
KPX rcaron oacute -45
KPX rcaron ocircumflex -45
KPX rcaron odieresis -45
KPX rcaron ograve -45
KPX rcaron ohungarumlaut -45
KPX rcaron omacron -45
KPX rcaron oslash -45
KPX rcaron otilde -45
KPX rcaron period -111
KPX rcaron q -37
KPX rcaron s -10
KPX rcaron sacute -10
KPX rcaron scaron -10
KPX rcaron scedilla -10
KPX rcaron scommaaccent -10
KPX rcommaaccent a -15
KPX rcommaaccent aacute -15
KPX rcommaaccent abreve -15
KPX rcommaaccent acircumflex -15
KPX rcommaaccent adieresis -15
KPX rcommaaccent agrave -15
KPX rcommaaccent amacron -15
KPX rcommaaccent aogonek -15
KPX rcommaaccent aring -15
KPX rcommaaccent atilde -15
KPX rcommaaccent c -37
KPX rcommaaccent cacute -37
KPX rcommaaccent ccaron -37
KPX rcommaaccent ccedilla -37
KPX rcommaaccent comma -111
KPX rcommaaccent d -37
KPX rcommaaccent dcroat -37
KPX rcommaaccent e -37
KPX rcommaaccent eacute -37
KPX rcommaaccent ecaron -37
KPX rcommaaccent ecircumflex -37
KPX rcommaaccent edieresis -37
KPX rcommaaccent edotaccent -37
KPX rcommaaccent egrave -37
KPX rcommaaccent emacron -37
KPX rcommaaccent eogonek -37
KPX rcommaaccent g -37
KPX rcommaaccent gbreve -37
KPX rcommaaccent gcommaaccent -37
KPX rcommaaccent hyphen -20
KPX rcommaaccent o -45
KPX rcommaaccent oacute -45
KPX rcommaaccent ocircumflex -45
KPX rcommaaccent odieresis -45
KPX rcommaaccent ograve -45
KPX rcommaaccent ohungarumlaut -45
KPX rcommaaccent omacron -45
KPX rcommaaccent oslash -45
KPX rcommaaccent otilde -45
KPX rcommaaccent period -111
KPX rcommaaccent q -37
KPX rcommaaccent s -10
KPX rcommaaccent sacute -10
KPX rcommaaccent scaron -10
KPX rcommaaccent scedilla -10
KPX rcommaaccent scommaaccent -10
KPX space A -18
KPX space Aacute -18
KPX space Abreve -18
KPX space Acircumflex -18
KPX space Adieresis -18
KPX space Agrave -18
KPX space Amacron -18
KPX space Aogonek -18
KPX space Aring -18
KPX space Atilde -18
KPX space T -18
KPX space Tcaron -18
KPX space Tcommaaccent -18
KPX space V -35
KPX space W -40
KPX space Y -75
KPX space Yacute -75
KPX space Ydieresis -75
KPX v comma -74
KPX v period -74
KPX w comma -74
KPX w period -74
KPX y comma -55
KPX y period -55
KPX yacute comma -55
KPX yacute period -55
KPX ydieresis comma -55
KPX ydieresis period -55
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/Times-Roman.afm
================================================
StartFontMetrics 4.1
Comment Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
Comment Creation Date: Thu May 1 12:49:17 1997
Comment UniqueID 43068
Comment VMusage 43909 54934
FontName Times-Roman
FullName Times Roman
FamilyName Times
Weight Roman
ItalicAngle 0
IsFixedPitch false
CharacterSet ExtendedRoman
FontBBox -168 -218 1000 898
UnderlinePosition -100
UnderlineThickness 50
Version 002.000
Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries.
EncodingScheme AdobeStandardEncoding
CapHeight 662
XHeight 450
Ascender 683
Descender -217
StdHW 28
StdVW 84
StartCharMetrics 315
C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
C 33 ; WX 333 ; N exclam ; B 130 -9 238 676 ;
C 34 ; WX 408 ; N quotedbl ; B 77 431 331 676 ;
C 35 ; WX 500 ; N numbersign ; B 5 0 496 662 ;
C 36 ; WX 500 ; N dollar ; B 44 -87 457 727 ;
C 37 ; WX 833 ; N percent ; B 61 -13 772 676 ;
C 38 ; WX 778 ; N ampersand ; B 42 -13 750 676 ;
C 39 ; WX 333 ; N quoteright ; B 79 433 218 676 ;
C 40 ; WX 333 ; N parenleft ; B 48 -177 304 676 ;
C 41 ; WX 333 ; N parenright ; B 29 -177 285 676 ;
C 42 ; WX 500 ; N asterisk ; B 69 265 432 676 ;
C 43 ; WX 564 ; N plus ; B 30 0 534 506 ;
C 44 ; WX 250 ; N comma ; B 56 -141 195 102 ;
C 45 ; WX 333 ; N hyphen ; B 39 194 285 257 ;
C 46 ; WX 250 ; N period ; B 70 -11 181 100 ;
C 47 ; WX 278 ; N slash ; B -9 -14 287 676 ;
C 48 ; WX 500 ; N zero ; B 24 -14 476 676 ;
C 49 ; WX 500 ; N one ; B 111 0 394 676 ;
C 50 ; WX 500 ; N two ; B 30 0 475 676 ;
C 51 ; WX 500 ; N three ; B 43 -14 431 676 ;
C 52 ; WX 500 ; N four ; B 12 0 472 676 ;
C 53 ; WX 500 ; N five ; B 32 -14 438 688 ;
C 54 ; WX 500 ; N six ; B 34 -14 468 684 ;
C 55 ; WX 500 ; N seven ; B 20 -8 449 662 ;
C 56 ; WX 500 ; N eight ; B 56 -14 445 676 ;
C 57 ; WX 500 ; N nine ; B 30 -22 459 676 ;
C 58 ; WX 278 ; N colon ; B 81 -11 192 459 ;
C 59 ; WX 278 ; N semicolon ; B 80 -141 219 459 ;
C 60 ; WX 564 ; N less ; B 28 -8 536 514 ;
C 61 ; WX 564 ; N equal ; B 30 120 534 386 ;
C 62 ; WX 564 ; N greater ; B 28 -8 536 514 ;
C 63 ; WX 444 ; N question ; B 68 -8 414 676 ;
C 64 ; WX 921 ; N at ; B 116 -14 809 676 ;
C 65 ; WX 722 ; N A ; B 15 0 706 674 ;
C 66 ; WX 667 ; N B ; B 17 0 593 662 ;
C 67 ; WX 667 ; N C ; B 28 -14 633 676 ;
C 68 ; WX 722 ; N D ; B 16 0 685 662 ;
C 69 ; WX 611 ; N E ; B 12 0 597 662 ;
C 70 ; WX 556 ; N F ; B 12 0 546 662 ;
C 71 ; WX 722 ; N G ; B 32 -14 709 676 ;
C 72 ; WX 722 ; N H ; B 19 0 702 662 ;
C 73 ; WX 333 ; N I ; B 18 0 315 662 ;
C 74 ; WX 389 ; N J ; B 10 -14 370 662 ;
C 75 ; WX 722 ; N K ; B 34 0 723 662 ;
C 76 ; WX 611 ; N L ; B 12 0 598 662 ;
C 77 ; WX 889 ; N M ; B 12 0 863 662 ;
C 78 ; WX 722 ; N N ; B 12 -11 707 662 ;
C 79 ; WX 722 ; N O ; B 34 -14 688 676 ;
C 80 ; WX 556 ; N P ; B 16 0 542 662 ;
C 81 ; WX 722 ; N Q ; B 34 -178 701 676 ;
C 82 ; WX 667 ; N R ; B 17 0 659 662 ;
C 83 ; WX 556 ; N S ; B 42 -14 491 676 ;
C 84 ; WX 611 ; N T ; B 17 0 593 662 ;
C 85 ; WX 722 ; N U ; B 14 -14 705 662 ;
C 86 ; WX 722 ; N V ; B 16 -11 697 662 ;
C 87 ; WX 944 ; N W ; B 5 -11 932 662 ;
C 88 ; WX 722 ; N X ; B 10 0 704 662 ;
C 89 ; WX 722 ; N Y ; B 22 0 703 662 ;
C 90 ; WX 611 ; N Z ; B 9 0 597 662 ;
C 91 ; WX 333 ; N bracketleft ; B 88 -156 299 662 ;
C 92 ; WX 278 ; N backslash ; B -9 -14 287 676 ;
C 93 ; WX 333 ; N bracketright ; B 34 -156 245 662 ;
C 94 ; WX 469 ; N asciicircum ; B 24 297 446 662 ;
C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
C 96 ; WX 333 ; N quoteleft ; B 115 433 254 676 ;
C 97 ; WX 444 ; N a ; B 37 -10 442 460 ;
C 98 ; WX 500 ; N b ; B 3 -10 468 683 ;
C 99 ; WX 444 ; N c ; B 25 -10 412 460 ;
C 100 ; WX 500 ; N d ; B 27 -10 491 683 ;
C 101 ; WX 444 ; N e ; B 25 -10 424 460 ;
C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L i fi ; L l fl ;
C 103 ; WX 500 ; N g ; B 28 -218 470 460 ;
C 104 ; WX 500 ; N h ; B 9 0 487 683 ;
C 105 ; WX 278 ; N i ; B 16 0 253 683 ;
C 106 ; WX 278 ; N j ; B -70 -218 194 683 ;
C 107 ; WX 500 ; N k ; B 7 0 505 683 ;
C 108 ; WX 278 ; N l ; B 19 0 257 683 ;
C 109 ; WX 778 ; N m ; B 16 0 775 460 ;
C 110 ; WX 500 ; N n ; B 16 0 485 460 ;
C 111 ; WX 500 ; N o ; B 29 -10 470 460 ;
C 112 ; WX 500 ; N p ; B 5 -217 470 460 ;
C 113 ; WX 500 ; N q ; B 24 -217 488 460 ;
C 114 ; WX 333 ; N r ; B 5 0 335 460 ;
C 115 ; WX 389 ; N s ; B 51 -10 348 460 ;
C 116 ; WX 278 ; N t ; B 13 -10 279 579 ;
C 117 ; WX 500 ; N u ; B 9 -10 479 450 ;
C 118 ; WX 500 ; N v ; B 19 -14 477 450 ;
C 119 ; WX 722 ; N w ; B 21 -14 694 450 ;
C 120 ; WX 500 ; N x ; B 17 0 479 450 ;
C 121 ; WX 500 ; N y ; B 14 -218 475 450 ;
C 122 ; WX 444 ; N z ; B 27 0 418 450 ;
C 123 ; WX 480 ; N braceleft ; B 100 -181 350 680 ;
C 124 ; WX 200 ; N bar ; B 67 -218 133 782 ;
C 125 ; WX 480 ; N braceright ; B 130 -181 380 680 ;
C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;
C 161 ; WX 333 ; N exclamdown ; B 97 -218 205 467 ;
C 162 ; WX 500 ; N cent ; B 53 -138 448 579 ;
C 163 ; WX 500 ; N sterling ; B 12 -8 490 676 ;
C 164 ; WX 167 ; N fraction ; B -168 -14 331 676 ;
C 165 ; WX 500 ; N yen ; B -53 0 512 662 ;
C 166 ; WX 500 ; N florin ; B 7 -189 490 676 ;
C 167 ; WX 500 ; N section ; B 70 -148 426 676 ;
C 168 ; WX 500 ; N currency ; B -22 58 522 602 ;
C 169 ; WX 180 ; N quotesingle ; B 48 431 133 676 ;
C 170 ; WX 444 ; N quotedblleft ; B 43 433 414 676 ;
C 171 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ;
C 172 ; WX 333 ; N guilsinglleft ; B 63 33 285 416 ;
C 173 ; WX 333 ; N guilsinglright ; B 48 33 270 416 ;
C 174 ; WX 556 ; N fi ; B 31 0 521 683 ;
C 175 ; WX 556 ; N fl ; B 32 0 521 683 ;
C 177 ; WX 500 ; N endash ; B 0 201 500 250 ;
C 178 ; WX 500 ; N dagger ; B 59 -149 442 676 ;
C 179 ; WX 500 ; N daggerdbl ; B 58 -153 442 676 ;
C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
C 182 ; WX 453 ; N paragraph ; B -22 -154 450 662 ;
C 183 ; WX 350 ; N bullet ; B 40 196 310 466 ;
C 184 ; WX 333 ; N quotesinglbase ; B 79 -141 218 102 ;
C 185 ; WX 444 ; N quotedblbase ; B 45 -141 416 102 ;
C 186 ; WX 444 ; N quotedblright ; B 30 433 401 676 ;
C 187 ; WX 500 ; N guillemotright ; B 44 33 458 416 ;
C 188 ; WX 1000 ; N ellipsis ; B 111 -11 888 100 ;
C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 706 ;
C 191 ; WX 444 ; N questiondown ; B 30 -218 376 466 ;
C 193 ; WX 333 ; N grave ; B 19 507 242 678 ;
C 194 ; WX 333 ; N acute ; B 93 507 317 678 ;
C 195 ; WX 333 ; N circumflex ; B 11 507 322 674 ;
C 196 ; WX 333 ; N tilde ; B 1 532 331 638 ;
C 197 ; WX 333 ; N macron ; B 11 547 322 601 ;
C 198 ; WX 333 ; N breve ; B 26 507 307 664 ;
C 199 ; WX 333 ; N dotaccent ; B 118 581 216 681 ;
C 200 ; WX 333 ; N dieresis ; B 18 581 315 681 ;
C 202 ; WX 333 ; N ring ; B 67 512 266 711 ;
C 203 ; WX 333 ; N cedilla ; B 52 -215 261 0 ;
C 205 ; WX 333 ; N hungarumlaut ; B -3 507 377 678 ;
C 206 ; WX 333 ; N ogonek ; B 62 -165 243 0 ;
C 207 ; WX 333 ; N caron ; B 11 507 322 674 ;
C 208 ; WX 1000 ; N emdash ; B 0 201 1000 250 ;
C 225 ; WX 889 ; N AE ; B 0 0 863 662 ;
C 227 ; WX 276 ; N ordfeminine ; B 4 394 270 676 ;
C 232 ; WX 611 ; N Lslash ; B 12 0 598 662 ;
C 233 ; WX 722 ; N Oslash ; B 34 -80 688 734 ;
C 234 ; WX 889 ; N OE ; B 30 -6 885 668 ;
C 235 ; WX 310 ; N ordmasculine ; B 6 394 304 676 ;
C 241 ; WX 667 ; N ae ; B 38 -10 632 460 ;
C 245 ; WX 278 ; N dotlessi ; B 16 0 253 460 ;
C 248 ; WX 278 ; N lslash ; B 19 0 259 683 ;
C 249 ; WX 500 ; N oslash ; B 29 -112 470 551 ;
C 250 ; WX 722 ; N oe ; B 30 -10 690 460 ;
C 251 ; WX 500 ; N germandbls ; B 12 -9 468 683 ;
C -1 ; WX 333 ; N Idieresis ; B 18 0 315 835 ;
C -1 ; WX 444 ; N eacute ; B 25 -10 424 678 ;
C -1 ; WX 444 ; N abreve ; B 37 -10 442 664 ;
C -1 ; WX 500 ; N uhungarumlaut ; B 9 -10 501 678 ;
C -1 ; WX 444 ; N ecaron ; B 25 -10 424 674 ;
C -1 ; WX 722 ; N Ydieresis ; B 22 0 703 835 ;
C -1 ; WX 564 ; N divide ; B 30 -10 534 516 ;
C -1 ; WX 722 ; N Yacute ; B 22 0 703 890 ;
C -1 ; WX 722 ; N Acircumflex ; B 15 0 706 886 ;
C -1 ; WX 444 ; N aacute ; B 37 -10 442 678 ;
C -1 ; WX 722 ; N Ucircumflex ; B 14 -14 705 886 ;
C -1 ; WX 500 ; N yacute ; B 14 -218 475 678 ;
C -1 ; WX 389 ; N scommaaccent ; B 51 -218 348 460 ;
C -1 ; WX 444 ; N ecircumflex ; B 25 -10 424 674 ;
C -1 ; WX 722 ; N Uring ; B 14 -14 705 898 ;
C -1 ; WX 722 ; N Udieresis ; B 14 -14 705 835 ;
C -1 ; WX 444 ; N aogonek ; B 37 -165 469 460 ;
C -1 ; WX 722 ; N Uacute ; B 14 -14 705 890 ;
C -1 ; WX 500 ; N uogonek ; B 9 -155 487 450 ;
C -1 ; WX 611 ; N Edieresis ; B 12 0 597 835 ;
C -1 ; WX 722 ; N Dcroat ; B 16 0 685 662 ;
C -1 ; WX 250 ; N commaaccent ; B 59 -218 184 -50 ;
C -1 ; WX 760 ; N copyright ; B 38 -14 722 676 ;
C -1 ; WX 611 ; N Emacron ; B 12 0 597 813 ;
C -1 ; WX 444 ; N ccaron ; B 25 -10 412 674 ;
C -1 ; WX 444 ; N aring ; B 37 -10 442 711 ;
C -1 ; WX 722 ; N Ncommaaccent ; B 12 -198 707 662 ;
C -1 ; WX 278 ; N lacute ; B 19 0 290 890 ;
C -1 ; WX 444 ; N agrave ; B 37 -10 442 678 ;
C -1 ; WX 611 ; N Tcommaaccent ; B 17 -218 593 662 ;
C -1 ; WX 667 ; N Cacute ; B 28 -14 633 890 ;
C -1 ; WX 444 ; N atilde ; B 37 -10 442 638 ;
C -1 ; WX 611 ; N Edotaccent ; B 12 0 597 835 ;
C -1 ; WX 389 ; N scaron ; B 39 -10 350 674 ;
C -1 ; WX 389 ; N scedilla ; B 51 -215 348 460 ;
C -1 ; WX 278 ; N iacute ; B 16 0 290 678 ;
C -1 ; WX 471 ; N lozenge ; B 13 0 459 724 ;
C -1 ; WX 667 ; N Rcaron ; B 17 0 659 886 ;
C -1 ; WX 722 ; N Gcommaaccent ; B 32 -218 709 676 ;
C -1 ; WX 500 ; N ucircumflex ; B 9 -10 479 674 ;
C -1 ; WX 444 ; N acircumflex ; B 37 -10 442 674 ;
C -1 ; WX 722 ; N Amacron ; B 15 0 706 813 ;
C -1 ; WX 333 ; N rcaron ; B 5 0 335 674 ;
C -1 ; WX 444 ; N ccedilla ; B 25 -215 412 460 ;
C -1 ; WX 611 ; N Zdotaccent ; B 9 0 597 835 ;
C -1 ; WX 556 ; N Thorn ; B 16 0 542 662 ;
C -1 ; WX 722 ; N Omacron ; B 34 -14 688 813 ;
C -1 ; WX 667 ; N Racute ; B 17 0 659 890 ;
C -1 ; WX 556 ; N Sacute ; B 42 -14 491 890 ;
C -1 ; WX 588 ; N dcaron ; B 27 -10 589 695 ;
C -1 ; WX 722 ; N Umacron ; B 14 -14 705 813 ;
C -1 ; WX 500 ; N uring ; B 9 -10 479 711 ;
C -1 ; WX 300 ; N threesuperior ; B 15 262 291 676 ;
C -1 ; WX 722 ; N Ograve ; B 34 -14 688 890 ;
C -1 ; WX 722 ; N Agrave ; B 15 0 706 890 ;
C -1 ; WX 722 ; N Abreve ; B 15 0 706 876 ;
C -1 ; WX 564 ; N multiply ; B 38 8 527 497 ;
C -1 ; WX 500 ; N uacute ; B 9 -10 479 678 ;
C -1 ; WX 611 ; N Tcaron ; B 17 0 593 886 ;
C -1 ; WX 476 ; N partialdiff ; B 17 -38 459 710 ;
C -1 ; WX 500 ; N ydieresis ; B 14 -218 475 623 ;
C -1 ; WX 722 ; N Nacute ; B 12 -11 707 890 ;
C -1 ; WX 278 ; N icircumflex ; B -16 0 295 674 ;
C -1 ; WX 611 ; N Ecircumflex ; B 12 0 597 886 ;
C -1 ; WX 444 ; N adieresis ; B 37 -10 442 623 ;
C -1 ; WX 444 ; N edieresis ; B 25 -10 424 623 ;
C -1 ; WX 444 ; N cacute ; B 25 -10 413 678 ;
C -1 ; WX 500 ; N nacute ; B 16 0 485 678 ;
C -1 ; WX 500 ; N umacron ; B 9 -10 479 601 ;
C -1 ; WX 722 ; N Ncaron ; B 12 -11 707 886 ;
C -1 ; WX 333 ; N Iacute ; B 18 0 317 890 ;
C -1 ; WX 564 ; N plusminus ; B 30 0 534 506 ;
C -1 ; WX 200 ; N brokenbar ; B 67 -143 133 707 ;
C -1 ; WX 760 ; N registered ; B 38 -14 722 676 ;
C -1 ; WX 722 ; N Gbreve ; B 32 -14 709 876 ;
C -1 ; WX 333 ; N Idotaccent ; B 18 0 315 835 ;
C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ;
C -1 ; WX 611 ; N Egrave ; B 12 0 597 890 ;
C -1 ; WX 333 ; N racute ; B 5 0 335 678 ;
C -1 ; WX 500 ; N omacron ; B 29 -10 470 601 ;
C -1 ; WX 611 ; N Zacute ; B 9 0 597 890 ;
C -1 ; WX 611 ; N Zcaron ; B 9 0 597 886 ;
C -1 ; WX 549 ; N greaterequal ; B 26 0 523 666 ;
C -1 ; WX 722 ; N Eth ; B 16 0 685 662 ;
C -1 ; WX 667 ; N Ccedilla ; B 28 -215 633 676 ;
C -1 ; WX 278 ; N lcommaaccent ; B 19 -218 257 683 ;
C -1 ; WX 326 ; N tcaron ; B 13 -10 318 722 ;
C -1 ; WX 444 ; N eogonek ; B 25 -165 424 460 ;
C -1 ; WX 722 ; N Uogonek ; B 14 -165 705 662 ;
C -1 ; WX 722 ; N Aacute ; B 15 0 706 890 ;
C -1 ; WX 722 ; N Adieresis ; B 15 0 706 835 ;
C -1 ; WX 444 ; N egrave ; B 25 -10 424 678 ;
C -1 ; WX 444 ; N zacute ; B 27 0 418 678 ;
C -1 ; WX 278 ; N iogonek ; B 16 -165 265 683 ;
C -1 ; WX 722 ; N Oacute ; B 34 -14 688 890 ;
C -1 ; WX 500 ; N oacute ; B 29 -10 470 678 ;
C -1 ; WX 444 ; N amacron ; B 37 -10 442 601 ;
C -1 ; WX 389 ; N sacute ; B 51 -10 348 678 ;
C -1 ; WX 278 ; N idieresis ; B -9 0 288 623 ;
C -1 ; WX 722 ; N Ocircumflex ; B 34 -14 688 886 ;
C -1 ; WX 722 ; N Ugrave ; B 14 -14 705 890 ;
C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ;
C -1 ; WX 500 ; N thorn ; B 5 -217 470 683 ;
C -1 ; WX 300 ; N twosuperior ; B 1 270 296 676 ;
C -1 ; WX 722 ; N Odieresis ; B 34 -14 688 835 ;
C -1 ; WX 500 ; N mu ; B 36 -218 512 450 ;
C -1 ; WX 278 ; N igrave ; B -8 0 253 678 ;
C -1 ; WX 500 ; N ohungarumlaut ; B 29 -10 491 678 ;
C -1 ; WX 611 ; N Eogonek ; B 12 -165 597 662 ;
C -1 ; WX 500 ; N dcroat ; B 27 -10 500 683 ;
C -1 ; WX 750 ; N threequarters ; B 15 -14 718 676 ;
C -1 ; WX 556 ; N Scedilla ; B 42 -215 491 676 ;
C -1 ; WX 344 ; N lcaron ; B 19 0 347 695 ;
C -1 ; WX 722 ; N Kcommaaccent ; B 34 -198 723 662 ;
C -1 ; WX 611 ; N Lacute ; B 12 0 598 890 ;
C -1 ; WX 980 ; N trademark ; B 30 256 957 662 ;
C -1 ; WX 444 ; N edotaccent ; B 25 -10 424 623 ;
C -1 ; WX 333 ; N Igrave ; B 18 0 315 890 ;
C -1 ; WX 333 ; N Imacron ; B 11 0 322 813 ;
C -1 ; WX 611 ; N Lcaron ; B 12 0 598 676 ;
C -1 ; WX 750 ; N onehalf ; B 31 -14 746 676 ;
C -1 ; WX 549 ; N lessequal ; B 26 0 523 666 ;
C -1 ; WX 500 ; N ocircumflex ; B 29 -10 470 674 ;
C -1 ; WX 500 ; N ntilde ; B 16 0 485 638 ;
C -1 ; WX 722 ; N Uhungarumlaut ; B 14 -14 705 890 ;
C -1 ; WX 611 ; N Eacute ; B 12 0 597 890 ;
C -1 ; WX 444 ; N emacron ; B 25 -10 424 601 ;
C -1 ; WX 500 ; N gbreve ; B 28 -218 470 664 ;
C -1 ; WX 750 ; N onequarter ; B 37 -14 718 676 ;
C -1 ; WX 556 ; N Scaron ; B 42 -14 491 886 ;
C -1 ; WX 556 ; N Scommaaccent ; B 42 -218 491 676 ;
C -1 ; WX 722 ; N Ohungarumlaut ; B 34 -14 688 890 ;
C -1 ; WX 400 ; N degree ; B 57 390 343 676 ;
C -1 ; WX 500 ; N ograve ; B 29 -10 470 678 ;
C -1 ; WX 667 ; N Ccaron ; B 28 -14 633 886 ;
C -1 ; WX 500 ; N ugrave ; B 9 -10 479 678 ;
C -1 ; WX 453 ; N radical ; B 2 -60 452 768 ;
C -1 ; WX 722 ; N Dcaron ; B 16 0 685 886 ;
C -1 ; WX 333 ; N rcommaaccent ; B 5 -218 335 460 ;
C -1 ; WX 722 ; N Ntilde ; B 12 -11 707 850 ;
C -1 ; WX 500 ; N otilde ; B 29 -10 470 638 ;
C -1 ; WX 667 ; N Rcommaaccent ; B 17 -198 659 662 ;
C -1 ; WX 611 ; N Lcommaaccent ; B 12 -218 598 662 ;
C -1 ; WX 722 ; N Atilde ; B 15 0 706 850 ;
C -1 ; WX 722 ; N Aogonek ; B 15 -165 738 674 ;
C -1 ; WX 722 ; N Aring ; B 15 0 706 898 ;
C -1 ; WX 722 ; N Otilde ; B 34 -14 688 850 ;
C -1 ; WX 444 ; N zdotaccent ; B 27 0 418 623 ;
C -1 ; WX 611 ; N Ecaron ; B 12 0 597 886 ;
C -1 ; WX 333 ; N Iogonek ; B 18 -165 315 662 ;
C -1 ; WX 500 ; N kcommaaccent ; B 7 -218 505 683 ;
C -1 ; WX 564 ; N minus ; B 30 220 534 286 ;
C -1 ; WX 333 ; N Icircumflex ; B 11 0 322 886 ;
C -1 ; WX 500 ; N ncaron ; B 16 0 485 674 ;
C -1 ; WX 278 ; N tcommaaccent ; B 13 -218 279 579 ;
C -1 ; WX 564 ; N logicalnot ; B 30 108 534 386 ;
C -1 ; WX 500 ; N odieresis ; B 29 -10 470 623 ;
C -1 ; WX 500 ; N udieresis ; B 9 -10 479 623 ;
C -1 ; WX 549 ; N notequal ; B 12 -31 537 547 ;
C -1 ; WX 500 ; N gcommaaccent ; B 28 -218 470 749 ;
C -1 ; WX 500 ; N eth ; B 29 -10 471 686 ;
C -1 ; WX 444 ; N zcaron ; B 27 0 418 674 ;
C -1 ; WX 500 ; N ncommaaccent ; B 16 -218 485 460 ;
C -1 ; WX 300 ; N onesuperior ; B 57 270 248 676 ;
C -1 ; WX 278 ; N imacron ; B 6 0 271 601 ;
C -1 ; WX 500 ; N Euro ; B 0 0 0 0 ;
EndCharMetrics
StartKernData
StartKernPairs 2073
KPX A C -40
KPX A Cacute -40
KPX A Ccaron -40
KPX A Ccedilla -40
KPX A G -40
KPX A Gbreve -40
KPX A Gcommaaccent -40
KPX A O -55
KPX A Oacute -55
KPX A Ocircumflex -55
KPX A Odieresis -55
KPX A Ograve -55
KPX A Ohungarumlaut -55
KPX A Omacron -55
KPX A Oslash -55
KPX A Otilde -55
KPX A Q -55
KPX A T -111
KPX A Tcaron -111
KPX A Tcommaaccent -111
KPX A U -55
KPX A Uacute -55
KPX A Ucircumflex -55
KPX A Udieresis -55
KPX A Ugrave -55
KPX A Uhungarumlaut -55
KPX A Umacron -55
KPX A Uogonek -55
KPX A Uring -55
KPX A V -135
KPX A W -90
KPX A Y -105
KPX A Yacute -105
KPX A Ydieresis -105
KPX A quoteright -111
KPX A v -74
KPX A w -92
KPX A y -92
KPX A yacute -92
KPX A ydieresis -92
KPX Aacute C -40
KPX Aacute Cacute -40
KPX Aacute Ccaron -40
KPX Aacute Ccedilla -40
KPX Aacute G -40
KPX Aacute Gbreve -40
KPX Aacute Gcommaaccent -40
KPX Aacute O -55
KPX Aacute Oacute -55
KPX Aacute Ocircumflex -55
KPX Aacute Odieresis -55
KPX Aacute Ograve -55
KPX Aacute Ohungarumlaut -55
KPX Aacute Omacron -55
KPX Aacute Oslash -55
KPX Aacute Otilde -55
KPX Aacute Q -55
KPX Aacute T -111
KPX Aacute Tcaron -111
KPX Aacute Tcommaaccent -111
KPX Aacute U -55
KPX Aacute Uacute -55
KPX Aacute Ucircumflex -55
KPX Aacute Udieresis -55
KPX Aacute Ugrave -55
KPX Aacute Uhungarumlaut -55
KPX Aacute Umacron -55
KPX Aacute Uogonek -55
KPX Aacute Uring -55
KPX Aacute V -135
KPX Aacute W -90
KPX Aacute Y -105
KPX Aacute Yacute -105
KPX Aacute Ydieresis -105
KPX Aacute quoteright -111
KPX Aacute v -74
KPX Aacute w -92
KPX Aacute y -92
KPX Aacute yacute -92
KPX Aacute ydieresis -92
KPX Abreve C -40
KPX Abreve Cacute -40
KPX Abreve Ccaron -40
KPX Abreve Ccedilla -40
KPX Abreve G -40
KPX Abreve Gbreve -40
KPX Abreve Gcommaaccent -40
KPX Abreve O -55
KPX Abreve Oacute -55
KPX Abreve Ocircumflex -55
KPX Abreve Odieresis -55
KPX Abreve Ograve -55
KPX Abreve Ohungarumlaut -55
KPX Abreve Omacron -55
KPX Abreve Oslash -55
KPX Abreve Otilde -55
KPX Abreve Q -55
KPX Abreve T -111
KPX Abreve Tcaron -111
KPX Abreve Tcommaaccent -111
KPX Abreve U -55
KPX Abreve Uacute -55
KPX Abreve Ucircumflex -55
KPX Abreve Udieresis -55
KPX Abreve Ugrave -55
KPX Abreve Uhungarumlaut -55
KPX Abreve Umacron -55
KPX Abreve Uogonek -55
KPX Abreve Uring -55
KPX Abreve V -135
KPX Abreve W -90
KPX Abreve Y -105
KPX Abreve Yacute -105
KPX Abreve Ydieresis -105
KPX Abreve quoteright -111
KPX Abreve v -74
KPX Abreve w -92
KPX Abreve y -92
KPX Abreve yacute -92
KPX Abreve ydieresis -92
KPX Acircumflex C -40
KPX Acircumflex Cacute -40
KPX Acircumflex Ccaron -40
KPX Acircumflex Ccedilla -40
KPX Acircumflex G -40
KPX Acircumflex Gbreve -40
KPX Acircumflex Gcommaaccent -40
KPX Acircumflex O -55
KPX Acircumflex Oacute -55
KPX Acircumflex Ocircumflex -55
KPX Acircumflex Odieresis -55
KPX Acircumflex Ograve -55
KPX Acircumflex Ohungarumlaut -55
KPX Acircumflex Omacron -55
KPX Acircumflex Oslash -55
KPX Acircumflex Otilde -55
KPX Acircumflex Q -55
KPX Acircumflex T -111
KPX Acircumflex Tcaron -111
KPX Acircumflex Tcommaaccent -111
KPX Acircumflex U -55
KPX Acircumflex Uacute -55
KPX Acircumflex Ucircumflex -55
KPX Acircumflex Udieresis -55
KPX Acircumflex Ugrave -55
KPX Acircumflex Uhungarumlaut -55
KPX Acircumflex Umacron -55
KPX Acircumflex Uogonek -55
KPX Acircumflex Uring -55
KPX Acircumflex V -135
KPX Acircumflex W -90
KPX Acircumflex Y -105
KPX Acircumflex Yacute -105
KPX Acircumflex Ydieresis -105
KPX Acircumflex quoteright -111
KPX Acircumflex v -74
KPX Acircumflex w -92
KPX Acircumflex y -92
KPX Acircumflex yacute -92
KPX Acircumflex ydieresis -92
KPX Adieresis C -40
KPX Adieresis Cacute -40
KPX Adieresis Ccaron -40
KPX Adieresis Ccedilla -40
KPX Adieresis G -40
KPX Adieresis Gbreve -40
KPX Adieresis Gcommaaccent -40
KPX Adieresis O -55
KPX Adieresis Oacute -55
KPX Adieresis Ocircumflex -55
KPX Adieresis Odieresis -55
KPX Adieresis Ograve -55
KPX Adieresis Ohungarumlaut -55
KPX Adieresis Omacron -55
KPX Adieresis Oslash -55
KPX Adieresis Otilde -55
KPX Adieresis Q -55
KPX Adieresis T -111
KPX Adieresis Tcaron -111
KPX Adieresis Tcommaaccent -111
KPX Adieresis U -55
KPX Adieresis Uacute -55
KPX Adieresis Ucircumflex -55
KPX Adieresis Udieresis -55
KPX Adieresis Ugrave -55
KPX Adieresis Uhungarumlaut -55
KPX Adieresis Umacron -55
KPX Adieresis Uogonek -55
KPX Adieresis Uring -55
KPX Adieresis V -135
KPX Adieresis W -90
KPX Adieresis Y -105
KPX Adieresis Yacute -105
KPX Adieresis Ydieresis -105
KPX Adieresis quoteright -111
KPX Adieresis v -74
KPX Adieresis w -92
KPX Adieresis y -92
KPX Adieresis yacute -92
KPX Adieresis ydieresis -92
KPX Agrave C -40
KPX Agrave Cacute -40
KPX Agrave Ccaron -40
KPX Agrave Ccedilla -40
KPX Agrave G -40
KPX Agrave Gbreve -40
KPX Agrave Gcommaaccent -40
KPX Agrave O -55
KPX Agrave Oacute -55
KPX Agrave Ocircumflex -55
KPX Agrave Odieresis -55
KPX Agrave Ograve -55
KPX Agrave Ohungarumlaut -55
KPX Agrave Omacron -55
KPX Agrave Oslash -55
KPX Agrave Otilde -55
KPX Agrave Q -55
KPX Agrave T -111
KPX Agrave Tcaron -111
KPX Agrave Tcommaaccent -111
KPX Agrave U -55
KPX Agrave Uacute -55
KPX Agrave Ucircumflex -55
KPX Agrave Udieresis -55
KPX Agrave Ugrave -55
KPX Agrave Uhungarumlaut -55
KPX Agrave Umacron -55
KPX Agrave Uogonek -55
KPX Agrave Uring -55
KPX Agrave V -135
KPX Agrave W -90
KPX Agrave Y -105
KPX Agrave Yacute -105
KPX Agrave Ydieresis -105
KPX Agrave quoteright -111
KPX Agrave v -74
KPX Agrave w -92
KPX Agrave y -92
KPX Agrave yacute -92
KPX Agrave ydieresis -92
KPX Amacron C -40
KPX Amacron Cacute -40
KPX Amacron Ccaron -40
KPX Amacron Ccedilla -40
KPX Amacron G -40
KPX Amacron Gbreve -40
KPX Amacron Gcommaaccent -40
KPX Amacron O -55
KPX Amacron Oacute -55
KPX Amacron Ocircumflex -55
KPX Amacron Odieresis -55
KPX Amacron Ograve -55
KPX Amacron Ohungarumlaut -55
KPX Amacron Omacron -55
KPX Amacron Oslash -55
KPX Amacron Otilde -55
KPX Amacron Q -55
KPX Amacron T -111
KPX Amacron Tcaron -111
KPX Amacron Tcommaaccent -111
KPX Amacron U -55
KPX Amacron Uacute -55
KPX Amacron Ucircumflex -55
KPX Amacron Udieresis -55
KPX Amacron Ugrave -55
KPX Amacron Uhungarumlaut -55
KPX Amacron Umacron -55
KPX Amacron Uogonek -55
KPX Amacron Uring -55
KPX Amacron V -135
KPX Amacron W -90
KPX Amacron Y -105
KPX Amacron Yacute -105
KPX Amacron Ydieresis -105
KPX Amacron quoteright -111
KPX Amacron v -74
KPX Amacron w -92
KPX Amacron y -92
KPX Amacron yacute -92
KPX Amacron ydieresis -92
KPX Aogonek C -40
KPX Aogonek Cacute -40
KPX Aogonek Ccaron -40
KPX Aogonek Ccedilla -40
KPX Aogonek G -40
KPX Aogonek Gbreve -40
KPX Aogonek Gcommaaccent -40
KPX Aogonek O -55
KPX Aogonek Oacute -55
KPX Aogonek Ocircumflex -55
KPX Aogonek Odieresis -55
KPX Aogonek Ograve -55
KPX Aogonek Ohungarumlaut -55
KPX Aogonek Omacron -55
KPX Aogonek Oslash -55
KPX Aogonek Otilde -55
KPX Aogonek Q -55
KPX Aogonek T -111
KPX Aogonek Tcaron -111
KPX Aogonek Tcommaaccent -111
KPX Aogonek U -55
KPX Aogonek Uacute -55
KPX Aogonek Ucircumflex -55
KPX Aogonek Udieresis -55
KPX Aogonek Ugrave -55
KPX Aogonek Uhungarumlaut -55
KPX Aogonek Umacron -55
KPX Aogonek Uogonek -55
KPX Aogonek Uring -55
KPX Aogonek V -135
KPX Aogonek W -90
KPX Aogonek Y -105
KPX Aogonek Yacute -105
KPX Aogonek Ydieresis -105
KPX Aogonek quoteright -111
KPX Aogonek v -74
KPX Aogonek w -52
KPX Aogonek y -52
KPX Aogonek yacute -52
KPX Aogonek ydieresis -52
KPX Aring C -40
KPX Aring Cacute -40
KPX Aring Ccaron -40
KPX Aring Ccedilla -40
KPX Aring G -40
KPX Aring Gbreve -40
KPX Aring Gcommaaccent -40
KPX Aring O -55
KPX Aring Oacute -55
KPX Aring Ocircumflex -55
KPX Aring Odieresis -55
KPX Aring Ograve -55
KPX Aring Ohungarumlaut -55
KPX Aring Omacron -55
KPX Aring Oslash -55
KPX Aring Otilde -55
KPX Aring Q -55
KPX Aring T -111
KPX Aring Tcaron -111
KPX Aring Tcommaaccent -111
KPX Aring U -55
KPX Aring Uacute -55
KPX Aring Ucircumflex -55
KPX Aring Udieresis -55
KPX Aring Ugrave -55
KPX Aring Uhungarumlaut -55
KPX Aring Umacron -55
KPX Aring Uogonek -55
KPX Aring Uring -55
KPX Aring V -135
KPX Aring W -90
KPX Aring Y -105
KPX Aring Yacute -105
KPX Aring Ydieresis -105
KPX Aring quoteright -111
KPX Aring v -74
KPX Aring w -92
KPX Aring y -92
KPX Aring yacute -92
KPX Aring ydieresis -92
KPX Atilde C -40
KPX Atilde Cacute -40
KPX Atilde Ccaron -40
KPX Atilde Ccedilla -40
KPX Atilde G -40
KPX Atilde Gbreve -40
KPX Atilde Gcommaaccent -40
KPX Atilde O -55
KPX Atilde Oacute -55
KPX Atilde Ocircumflex -55
KPX Atilde Odieresis -55
KPX Atilde Ograve -55
KPX Atilde Ohungarumlaut -55
KPX Atilde Omacron -55
KPX Atilde Oslash -55
KPX Atilde Otilde -55
KPX Atilde Q -55
KPX Atilde T -111
KPX Atilde Tcaron -111
KPX Atilde Tcommaaccent -111
KPX Atilde U -55
KPX Atilde Uacute -55
KPX Atilde Ucircumflex -55
KPX Atilde Udieresis -55
KPX Atilde Ugrave -55
KPX Atilde Uhungarumlaut -55
KPX Atilde Umacron -55
KPX Atilde Uogonek -55
KPX Atilde Uring -55
KPX Atilde V -135
KPX Atilde W -90
KPX Atilde Y -105
KPX Atilde Yacute -105
KPX Atilde Ydieresis -105
KPX Atilde quoteright -111
KPX Atilde v -74
KPX Atilde w -92
KPX Atilde y -92
KPX Atilde yacute -92
KPX Atilde ydieresis -92
KPX B A -35
KPX B Aacute -35
KPX B Abreve -35
KPX B Acircumflex -35
KPX B Adieresis -35
KPX B Agrave -35
KPX B Amacron -35
KPX B Aogonek -35
KPX B Aring -35
KPX B Atilde -35
KPX B U -10
KPX B Uacute -10
KPX B Ucircumflex -10
KPX B Udieresis -10
KPX B Ugrave -10
KPX B Uhungarumlaut -10
KPX B Umacron -10
KPX B Uogonek -10
KPX B Uring -10
KPX D A -40
KPX D Aacute -40
KPX D Abreve -40
KPX D Acircumflex -40
KPX D Adieresis -40
KPX D Agrave -40
KPX D Amacron -40
KPX D Aogonek -40
KPX D Aring -40
KPX D Atilde -40
KPX D V -40
KPX D W -30
KPX D Y -55
KPX D Yacute -55
KPX D Ydieresis -55
KPX Dcaron A -40
KPX Dcaron Aacute -40
KPX Dcaron Abreve -40
KPX Dcaron Acircumflex -40
KPX Dcaron Adieresis -40
KPX Dcaron Agrave -40
KPX Dcaron Amacron -40
KPX Dcaron Aogonek -40
KPX Dcaron Aring -40
KPX Dcaron Atilde -40
KPX Dcaron V -40
KPX Dcaron W -30
KPX Dcaron Y -55
KPX Dcaron Yacute -55
KPX Dcaron Ydieresis -55
KPX Dcroat A -40
KPX Dcroat Aacute -40
KPX Dcroat Abreve -40
KPX Dcroat Acircumflex -40
KPX Dcroat Adieresis -40
KPX Dcroat Agrave -40
KPX Dcroat Amacron -40
KPX Dcroat Aogonek -40
KPX Dcroat Aring -40
KPX Dcroat Atilde -40
KPX Dcroat V -40
KPX Dcroat W -30
KPX Dcroat Y -55
KPX Dcroat Yacute -55
KPX Dcroat Ydieresis -55
KPX F A -74
KPX F Aacute -74
KPX F Abreve -74
KPX F Acircumflex -74
KPX F Adieresis -74
KPX F Agrave -74
KPX F Amacron -74
KPX F Aogonek -74
KPX F Aring -74
KPX F Atilde -74
KPX F a -15
KPX F aacute -15
KPX F abreve -15
KPX F acircumflex -15
KPX F adieresis -15
KPX F agrave -15
KPX F amacron -15
KPX F aogonek -15
KPX F aring -15
KPX F atilde -15
KPX F comma -80
KPX F o -15
KPX F oacute -15
KPX F ocircumflex -15
KPX F odieresis -15
KPX F ograve -15
KPX F ohungarumlaut -15
KPX F omacron -15
KPX F oslash -15
KPX F otilde -15
KPX F period -80
KPX J A -60
KPX J Aacute -60
KPX J Abreve -60
KPX J Acircumflex -60
KPX J Adieresis -60
KPX J Agrave -60
KPX J Amacron -60
KPX J Aogonek -60
KPX J Aring -60
KPX J Atilde -60
KPX K O -30
KPX K Oacute -30
KPX K Ocircumflex -30
KPX K Odieresis -30
KPX K Ograve -30
KPX K Ohungarumlaut -30
KPX K Omacron -30
KPX K Oslash -30
KPX K Otilde -30
KPX K e -25
KPX K eacute -25
KPX K ecaron -25
KPX K ecircumflex -25
KPX K edieresis -25
KPX K edotaccent -25
KPX K egrave -25
KPX K emacron -25
KPX K eogonek -25
KPX K o -35
KPX K oacute -35
KPX K ocircumflex -35
KPX K odieresis -35
KPX K ograve -35
KPX K ohungarumlaut -35
KPX K omacron -35
KPX K oslash -35
KPX K otilde -35
KPX K u -15
KPX K uacute -15
KPX K ucircumflex -15
KPX K udieresis -15
KPX K ugrave -15
KPX K uhungarumlaut -15
KPX K umacron -15
KPX K uogonek -15
KPX K uring -15
KPX K y -25
KPX K yacute -25
KPX K ydieresis -25
KPX Kcommaaccent O -30
KPX Kcommaaccent Oacute -30
KPX Kcommaaccent Ocircumflex -30
KPX Kcommaaccent Odieresis -30
KPX Kcommaaccent Ograve -30
KPX Kcommaaccent Ohungarumlaut -30
KPX Kcommaaccent Omacron -30
KPX Kcommaaccent Oslash -30
KPX Kcommaaccent Otilde -30
KPX Kcommaaccent e -25
KPX Kcommaaccent eacute -25
KPX Kcommaaccent ecaron -25
KPX Kcommaaccent ecircumflex -25
KPX Kcommaaccent edieresis -25
KPX Kcommaaccent edotaccent -25
KPX Kcommaaccent egrave -25
KPX Kcommaaccent emacron -25
KPX Kcommaaccent eogonek -25
KPX Kcommaaccent o -35
KPX Kcommaaccent oacute -35
KPX Kcommaaccent ocircumflex -35
KPX Kcommaaccent odieresis -35
KPX Kcommaaccent ograve -35
KPX Kcommaaccent ohungarumlaut -35
KPX Kcommaaccent omacron -35
KPX Kcommaaccent oslash -35
KPX Kcommaaccent otilde -35
KPX Kcommaaccent u -15
KPX Kcommaaccent uacute -15
KPX Kcommaaccent ucircumflex -15
KPX Kcommaaccent udieresis -15
KPX Kcommaaccent ugrave -15
KPX Kcommaaccent uhungarumlaut -15
KPX Kcommaaccent umacron -15
KPX Kcommaaccent uogonek -15
KPX Kcommaaccent uring -15
KPX Kcommaaccent y -25
KPX Kcommaaccent yacute -25
KPX Kcommaaccent ydieresis -25
KPX L T -92
KPX L Tcaron -92
KPX L Tcommaaccent -92
KPX L V -100
KPX L W -74
KPX L Y -100
KPX L Yacute -100
KPX L Ydieresis -100
KPX L quoteright -92
KPX L y -55
KPX L yacute -55
KPX L ydieresis -55
KPX Lacute T -92
KPX Lacute Tcaron -92
KPX Lacute Tcommaaccent -92
KPX Lacute V -100
KPX Lacute W -74
KPX Lacute Y -100
KPX Lacute Yacute -100
KPX Lacute Ydieresis -100
KPX Lacute quoteright -92
KPX Lacute y -55
KPX Lacute yacute -55
KPX Lacute ydieresis -55
KPX Lcaron quoteright -92
KPX Lcaron y -55
KPX Lcaron yacute -55
KPX Lcaron ydieresis -55
KPX Lcommaaccent T -92
KPX Lcommaaccent Tcaron -92
KPX Lcommaaccent Tcommaaccent -92
KPX Lcommaaccent V -100
KPX Lcommaaccent W -74
KPX Lcommaaccent Y -100
KPX Lcommaaccent Yacute -100
KPX Lcommaaccent Ydieresis -100
KPX Lcommaaccent quoteright -92
KPX Lcommaaccent y -55
KPX Lcommaaccent yacute -55
KPX Lcommaaccent ydieresis -55
KPX Lslash T -92
KPX Lslash Tcaron -92
KPX Lslash Tcommaaccent -92
KPX Lslash V -100
KPX Lslash W -74
KPX Lslash Y -100
KPX Lslash Yacute -100
KPX Lslash Ydieresis -100
KPX Lslash quoteright -92
KPX Lslash y -55
KPX Lslash yacute -55
KPX Lslash ydieresis -55
KPX N A -35
KPX N Aacute -35
KPX N Abreve -35
KPX N Acircumflex -35
KPX N Adieresis -35
KPX N Agrave -35
KPX N Amacron -35
KPX N Aogonek -35
KPX N Aring -35
KPX N Atilde -35
KPX Nacute A -35
KPX Nacute Aacute -35
KPX Nacute Abreve -35
KPX Nacute Acircumflex -35
KPX Nacute Adieresis -35
KPX Nacute Agrave -35
KPX Nacute Amacron -35
KPX Nacute Aogonek -35
KPX Nacute Aring -35
KPX Nacute Atilde -35
KPX Ncaron A -35
KPX Ncaron Aacute -35
KPX Ncaron Abreve -35
KPX Ncaron Acircumflex -35
KPX Ncaron Adieresis -35
KPX Ncaron Agrave -35
KPX Ncaron Amacron -35
KPX Ncaron Aogonek -35
KPX Ncaron Aring -35
KPX Ncaron Atilde -35
KPX Ncommaaccent A -35
KPX Ncommaaccent Aacute -35
KPX Ncommaaccent Abreve -35
KPX Ncommaaccent Acircumflex -35
KPX Ncommaaccent Adieresis -35
KPX Ncommaaccent Agrave -35
KPX Ncommaaccent Amacron -35
KPX Ncommaaccent Aogonek -35
KPX Ncommaaccent Aring -35
KPX Ncommaaccent Atilde -35
KPX Ntilde A -35
KPX Ntilde Aacute -35
KPX Ntilde Abreve -35
KPX Ntilde Acircumflex -35
KPX Ntilde Adieresis -35
KPX Ntilde Agrave -35
KPX Ntilde Amacron -35
KPX Ntilde Aogonek -35
KPX Ntilde Aring -35
KPX Ntilde Atilde -35
KPX O A -35
KPX O Aacute -35
KPX O Abreve -35
KPX O Acircumflex -35
KPX O Adieresis -35
KPX O Agrave -35
KPX O Amacron -35
KPX O Aogonek -35
KPX O Aring -35
KPX O Atilde -35
KPX O T -40
KPX O Tcaron -40
KPX O Tcommaaccent -40
KPX O V -50
KPX O W -35
KPX O X -40
KPX O Y -50
KPX O Yacute -50
KPX O Ydieresis -50
KPX Oacute A -35
KPX Oacute Aacute -35
KPX Oacute Abreve -35
KPX Oacute Acircumflex -35
KPX Oacute Adieresis -35
KPX Oacute Agrave -35
KPX Oacute Amacron -35
KPX Oacute Aogonek -35
KPX Oacute Aring -35
KPX Oacute Atilde -35
KPX Oacute T -40
KPX Oacute Tcaron -40
KPX Oacute Tcommaaccent -40
KPX Oacute V -50
KPX Oacute W -35
KPX Oacute X -40
KPX Oacute Y -50
KPX Oacute Yacute -50
KPX Oacute Ydieresis -50
KPX Ocircumflex A -35
KPX Ocircumflex Aacute -35
KPX Ocircumflex Abreve -35
KPX Ocircumflex Acircumflex -35
KPX Ocircumflex Adieresis -35
KPX Ocircumflex Agrave -35
KPX Ocircumflex Amacron -35
KPX Ocircumflex Aogonek -35
KPX Ocircumflex Aring -35
KPX Ocircumflex Atilde -35
KPX Ocircumflex T -40
KPX Ocircumflex Tcaron -40
KPX Ocircumflex Tcommaaccent -40
KPX Ocircumflex V -50
KPX Ocircumflex W -35
KPX Ocircumflex X -40
KPX Ocircumflex Y -50
KPX Ocircumflex Yacute -50
KPX Ocircumflex Ydieresis -50
KPX Odieresis A -35
KPX Odieresis Aacute -35
KPX Odieresis Abreve -35
KPX Odieresis Acircumflex -35
KPX Odieresis Adieresis -35
KPX Odieresis Agrave -35
KPX Odieresis Amacron -35
KPX Odieresis Aogonek -35
KPX Odieresis Aring -35
KPX Odieresis Atilde -35
KPX Odieresis T -40
KPX Odieresis Tcaron -40
KPX Odieresis Tcommaaccent -40
KPX Odieresis V -50
KPX Odieresis W -35
KPX Odieresis X -40
KPX Odieresis Y -50
KPX Odieresis Yacute -50
KPX Odieresis Ydieresis -50
KPX Ograve A -35
KPX Ograve Aacute -35
KPX Ograve Abreve -35
KPX Ograve Acircumflex -35
KPX Ograve Adieresis -35
KPX Ograve Agrave -35
KPX Ograve Amacron -35
KPX Ograve Aogonek -35
KPX Ograve Aring -35
KPX Ograve Atilde -35
KPX Ograve T -40
KPX Ograve Tcaron -40
KPX Ograve Tcommaaccent -40
KPX Ograve V -50
KPX Ograve W -35
KPX Ograve X -40
KPX Ograve Y -50
KPX Ograve Yacute -50
KPX Ograve Ydieresis -50
KPX Ohungarumlaut A -35
KPX Ohungarumlaut Aacute -35
KPX Ohungarumlaut Abreve -35
KPX Ohungarumlaut Acircumflex -35
KPX Ohungarumlaut Adieresis -35
KPX Ohungarumlaut Agrave -35
KPX Ohungarumlaut Amacron -35
KPX Ohungarumlaut Aogonek -35
KPX Ohungarumlaut Aring -35
KPX Ohungarumlaut Atilde -35
KPX Ohungarumlaut T -40
KPX Ohungarumlaut Tcaron -40
KPX Ohungarumlaut Tcommaaccent -40
KPX Ohungarumlaut V -50
KPX Ohungarumlaut W -35
KPX Ohungarumlaut X -40
KPX Ohungarumlaut Y -50
KPX Ohungarumlaut Yacute -50
KPX Ohungarumlaut Ydieresis -50
KPX Omacron A -35
KPX Omacron Aacute -35
KPX Omacron Abreve -35
KPX Omacron Acircumflex -35
KPX Omacron Adieresis -35
KPX Omacron Agrave -35
KPX Omacron Amacron -35
KPX Omacron Aogonek -35
KPX Omacron Aring -35
KPX Omacron Atilde -35
KPX Omacron T -40
KPX Omacron Tcaron -40
KPX Omacron Tcommaaccent -40
KPX Omacron V -50
KPX Omacron W -35
KPX Omacron X -40
KPX Omacron Y -50
KPX Omacron Yacute -50
KPX Omacron Ydieresis -50
KPX Oslash A -35
KPX Oslash Aacute -35
KPX Oslash Abreve -35
KPX Oslash Acircumflex -35
KPX Oslash Adieresis -35
KPX Oslash Agrave -35
KPX Oslash Amacron -35
KPX Oslash Aogonek -35
KPX Oslash Aring -35
KPX Oslash Atilde -35
KPX Oslash T -40
KPX Oslash Tcaron -40
KPX Oslash Tcommaaccent -40
KPX Oslash V -50
KPX Oslash W -35
KPX Oslash X -40
KPX Oslash Y -50
KPX Oslash Yacute -50
KPX Oslash Ydieresis -50
KPX Otilde A -35
KPX Otilde Aacute -35
KPX Otilde Abreve -35
KPX Otilde Acircumflex -35
KPX Otilde Adieresis -35
KPX Otilde Agrave -35
KPX Otilde Amacron -35
KPX Otilde Aogonek -35
KPX Otilde Aring -35
KPX Otilde Atilde -35
KPX Otilde T -40
KPX Otilde Tcaron -40
KPX Otilde Tcommaaccent -40
KPX Otilde V -50
KPX Otilde W -35
KPX Otilde X -40
KPX Otilde Y -50
KPX Otilde Yacute -50
KPX Otilde Ydieresis -50
KPX P A -92
KPX P Aacute -92
KPX P Abreve -92
KPX P Acircumflex -92
KPX P Adieresis -92
KPX P Agrave -92
KPX P Amacron -92
KPX P Aogonek -92
KPX P Aring -92
KPX P Atilde -92
KPX P a -15
KPX P aacute -15
KPX P abreve -15
KPX P acircumflex -15
KPX P adieresis -15
KPX P agrave -15
KPX P amacron -15
KPX P aogonek -15
KPX P aring -15
KPX P atilde -15
KPX P comma -111
KPX P period -111
KPX Q U -10
KPX Q Uacute -10
KPX Q Ucircumflex -10
KPX Q Udieresis -10
KPX Q Ugrave -10
KPX Q Uhungarumlaut -10
KPX Q Umacron -10
KPX Q Uogonek -10
KPX Q Uring -10
KPX R O -40
KPX R Oacute -40
KPX R Ocircumflex -40
KPX R Odieresis -40
KPX R Ograve -40
KPX R Ohungarumlaut -40
KPX R Omacron -40
KPX R Oslash -40
KPX R Otilde -40
KPX R T -60
KPX R Tcaron -60
KPX R Tcommaaccent -60
KPX R U -40
KPX R Uacute -40
KPX R Ucircumflex -40
KPX R Udieresis -40
KPX R Ugrave -40
KPX R Uhungarumlaut -40
KPX R Umacron -40
KPX R Uogonek -40
KPX R Uring -40
KPX R V -80
KPX R W -55
KPX R Y -65
KPX R Yacute -65
KPX R Ydieresis -65
KPX Racute O -40
KPX Racute Oacute -40
KPX Racute Ocircumflex -40
KPX Racute Odieresis -40
KPX Racute Ograve -40
KPX Racute Ohungarumlaut -40
KPX Racute Omacron -40
KPX Racute Oslash -40
KPX Racute Otilde -40
KPX Racute T -60
KPX Racute Tcaron -60
KPX Racute Tcommaaccent -60
KPX Racute U -40
KPX Racute Uacute -40
KPX Racute Ucircumflex -40
KPX Racute Udieresis -40
KPX Racute Ugrave -40
KPX Racute Uhungarumlaut -40
KPX Racute Umacron -40
KPX Racute Uogonek -40
KPX Racute Uring -40
KPX Racute V -80
KPX Racute W -55
KPX Racute Y -65
KPX Racute Yacute -65
KPX Racute Ydieresis -65
KPX Rcaron O -40
KPX Rcaron Oacute -40
KPX Rcaron Ocircumflex -40
KPX Rcaron Odieresis -40
KPX Rcaron Ograve -40
KPX Rcaron Ohungarumlaut -40
KPX Rcaron Omacron -40
KPX Rcaron Oslash -40
KPX Rcaron Otilde -40
KPX Rcaron T -60
KPX Rcaron Tcaron -60
KPX Rcaron Tcommaaccent -60
KPX Rcaron U -40
KPX Rcaron Uacute -40
KPX Rcaron Ucircumflex -40
KPX Rcaron Udieresis -40
KPX Rcaron Ugrave -40
KPX Rcaron Uhungarumlaut -40
KPX Rcaron Umacron -40
KPX Rcaron Uogonek -40
KPX Rcaron Uring -40
KPX Rcaron V -80
KPX Rcaron W -55
KPX Rcaron Y -65
KPX Rcaron Yacute -65
KPX Rcaron Ydieresis -65
KPX Rcommaaccent O -40
KPX Rcommaaccent Oacute -40
KPX Rcommaaccent Ocircumflex -40
KPX Rcommaaccent Odieresis -40
KPX Rcommaaccent Ograve -40
KPX Rcommaaccent Ohungarumlaut -40
KPX Rcommaaccent Omacron -40
KPX Rcommaaccent Oslash -40
KPX Rcommaaccent Otilde -40
KPX Rcommaaccent T -60
KPX Rcommaaccent Tcaron -60
KPX Rcommaaccent Tcommaaccent -60
KPX Rcommaaccent U -40
KPX Rcommaaccent Uacute -40
KPX Rcommaaccent Ucircumflex -40
KPX Rcommaaccent Udieresis -40
KPX Rcommaaccent Ugrave -40
KPX Rcommaaccent Uhungarumlaut -40
KPX Rcommaaccent Umacron -40
KPX Rcommaaccent Uogonek -40
KPX Rcommaaccent Uring -40
KPX Rcommaaccent V -80
KPX Rcommaaccent W -55
KPX Rcommaaccent Y -65
KPX Rcommaaccent Yacute -65
KPX Rcommaaccent Ydieresis -65
KPX T A -93
KPX T Aacute -93
KPX T Abreve -93
KPX T Acircumflex -93
KPX T Adieresis -93
KPX T Agrave -93
KPX T Amacron -93
KPX T Aogonek -93
KPX T Aring -93
KPX T Atilde -93
KPX T O -18
KPX T Oacute -18
KPX T Ocircumflex -18
KPX T Odieresis -18
KPX T Ograve -18
KPX T Ohungarumlaut -18
KPX T Omacron -18
KPX T Oslash -18
KPX T Otilde -18
KPX T a -80
KPX T aacute -80
KPX T abreve -80
KPX T acircumflex -80
KPX T adieresis -40
KPX T agrave -40
KPX T amacron -40
KPX T aogonek -80
KPX T aring -80
KPX T atilde -40
KPX T colon -50
KPX T comma -74
KPX T e -70
KPX T eacute -70
KPX T ecaron -70
KPX T ecircumflex -70
KPX T edieresis -30
KPX T edotaccent -70
KPX T egrave -70
KPX T emacron -30
KPX T eogonek -70
KPX T hyphen -92
KPX T i -35
KPX T iacute -35
KPX T iogonek -35
KPX T o -80
KPX T oacute -80
KPX T ocircumflex -80
KPX T odieresis -80
KPX T ograve -80
KPX T ohungarumlaut -80
KPX T omacron -80
KPX T oslash -80
KPX T otilde -80
KPX T period -74
KPX T r -35
KPX T racute -35
KPX T rcaron -35
KPX T rcommaaccent -35
KPX T semicolon -55
KPX T u -45
KPX T uacute -45
KPX T ucircumflex -45
KPX T udieresis -45
KPX T ugrave -45
KPX T uhungarumlaut -45
KPX T umacron -45
KPX T uogonek -45
KPX T uring -45
KPX T w -80
KPX T y -80
KPX T yacute -80
KPX T ydieresis -80
KPX Tcaron A -93
KPX Tcaron Aacute -93
KPX Tcaron Abreve -93
KPX Tcaron Acircumflex -93
KPX Tcaron Adieresis -93
KPX Tcaron Agrave -93
KPX Tcaron Amacron -93
KPX Tcaron Aogonek -93
KPX Tcaron Aring -93
KPX Tcaron Atilde -93
KPX Tcaron O -18
KPX Tcaron Oacute -18
KPX Tcaron Ocircumflex -18
KPX Tcaron Odieresis -18
KPX Tcaron Ograve -18
KPX Tcaron Ohungarumlaut -18
KPX Tcaron Omacron -18
KPX Tcaron Oslash -18
KPX Tcaron Otilde -18
KPX Tcaron a -80
KPX Tcaron aacute -80
KPX Tcaron abreve -80
KPX Tcaron acircumflex -80
KPX Tcaron adieresis -40
KPX Tcaron agrave -40
KPX Tcaron amacron -40
KPX Tcaron aogonek -80
KPX Tcaron aring -80
KPX Tcaron atilde -40
KPX Tcaron colon -50
KPX Tcaron comma -74
KPX Tcaron e -70
KPX Tcaron eacute -70
KPX Tcaron ecaron -70
KPX Tcaron ecircumflex -30
KPX Tcaron edieresis -30
KPX Tcaron edotaccent -70
KPX Tcaron egrave -70
KPX Tcaron emacron -30
KPX Tcaron eogonek -70
KPX Tcaron hyphen -92
KPX Tcaron i -35
KPX Tcaron iacute -35
KPX Tcaron iogonek -35
KPX Tcaron o -80
KPX Tcaron oacute -80
KPX Tcaron ocircumflex -80
KPX Tcaron odieresis -80
KPX Tcaron ograve -80
KPX Tcaron ohungarumlaut -80
KPX Tcaron omacron -80
KPX Tcaron oslash -80
KPX Tcaron otilde -80
KPX Tcaron period -74
KPX Tcaron r -35
KPX Tcaron racute -35
KPX Tcaron rcaron -35
KPX Tcaron rcommaaccent -35
KPX Tcaron semicolon -55
KPX Tcaron u -45
KPX Tcaron uacute -45
KPX Tcaron ucircumflex -45
KPX Tcaron udieresis -45
KPX Tcaron ugrave -45
KPX Tcaron uhungarumlaut -45
KPX Tcaron umacron -45
KPX Tcaron uogonek -45
KPX Tcaron uring -45
KPX Tcaron w -80
KPX Tcaron y -80
KPX Tcaron yacute -80
KPX Tcaron ydieresis -80
KPX Tcommaaccent A -93
KPX Tcommaaccent Aacute -93
KPX Tcommaaccent Abreve -93
KPX Tcommaaccent Acircumflex -93
KPX Tcommaaccent Adieresis -93
KPX Tcommaaccent Agrave -93
KPX Tcommaaccent Amacron -93
KPX Tcommaaccent Aogonek -93
KPX Tcommaaccent Aring -93
KPX Tcommaaccent Atilde -93
KPX Tcommaaccent O -18
KPX Tcommaaccent Oacute -18
KPX Tcommaaccent Ocircumflex -18
KPX Tcommaaccent Odieresis -18
KPX Tcommaaccent Ograve -18
KPX Tcommaaccent Ohungarumlaut -18
KPX Tcommaaccent Omacron -18
KPX Tcommaaccent Oslash -18
KPX Tcommaaccent Otilde -18
KPX Tcommaaccent a -80
KPX Tcommaaccent aacute -80
KPX Tcommaaccent abreve -80
KPX Tcommaaccent acircumflex -80
KPX Tcommaaccent adieresis -40
KPX Tcommaaccent agrave -40
KPX Tcommaaccent amacron -40
KPX Tcommaaccent aogonek -80
KPX Tcommaaccent aring -80
KPX Tcommaaccent atilde -40
KPX Tcommaaccent colon -50
KPX Tcommaaccent comma -74
KPX Tcommaaccent e -70
KPX Tcommaaccent eacute -70
KPX Tcommaaccent ecaron -70
KPX Tcommaaccent ecircumflex -30
KPX Tcommaaccent edieresis -30
KPX Tcommaaccent edotaccent -70
KPX Tcommaaccent egrave -30
KPX Tcommaaccent emacron -70
KPX Tcommaaccent eogonek -70
KPX Tcommaaccent hyphen -92
KPX Tcommaaccent i -35
KPX Tcommaaccent iacute -35
KPX Tcommaaccent iogonek -35
KPX Tcommaaccent o -80
KPX Tcommaaccent oacute -80
KPX Tcommaaccent ocircumflex -80
KPX Tcommaaccent odieresis -80
KPX Tcommaaccent ograve -80
KPX Tcommaaccent ohungarumlaut -80
KPX Tcommaaccent omacron -80
KPX Tcommaaccent oslash -80
KPX Tcommaaccent otilde -80
KPX Tcommaaccent period -74
KPX Tcommaaccent r -35
KPX Tcommaaccent racute -35
KPX Tcommaaccent rcaron -35
KPX Tcommaaccent rcommaaccent -35
KPX Tcommaaccent semicolon -55
KPX Tcommaaccent u -45
KPX Tcommaaccent uacute -45
KPX Tcommaaccent ucircumflex -45
KPX Tcommaaccent udieresis -45
KPX Tcommaaccent ugrave -45
KPX Tcommaaccent uhungarumlaut -45
KPX Tcommaaccent umacron -45
KPX Tcommaaccent uogonek -45
KPX Tcommaaccent uring -45
KPX Tcommaaccent w -80
KPX Tcommaaccent y -80
KPX Tcommaaccent yacute -80
KPX Tcommaaccent ydieresis -80
KPX U A -40
KPX U Aacute -40
KPX U Abreve -40
KPX U Acircumflex -40
KPX U Adieresis -40
KPX U Agrave -40
KPX U Amacron -40
KPX U Aogonek -40
KPX U Aring -40
KPX U Atilde -40
KPX Uacute A -40
KPX Uacute Aacute -40
KPX Uacute Abreve -40
KPX Uacute Acircumflex -40
KPX Uacute Adieresis -40
KPX Uacute Agrave -40
KPX Uacute Amacron -40
KPX Uacute Aogonek -40
KPX Uacute Aring -40
KPX Uacute Atilde -40
KPX Ucircumflex A -40
KPX Ucircumflex Aacute -40
KPX Ucircumflex Abreve -40
KPX Ucircumflex Acircumflex -40
KPX Ucircumflex Adieresis -40
KPX Ucircumflex Agrave -40
KPX Ucircumflex Amacron -40
KPX Ucircumflex Aogonek -40
KPX Ucircumflex Aring -40
KPX Ucircumflex Atilde -40
KPX Udieresis A -40
KPX Udieresis Aacute -40
KPX Udieresis Abreve -40
KPX Udieresis Acircumflex -40
KPX Udieresis Adieresis -40
KPX Udieresis Agrave -40
KPX Udieresis Amacron -40
KPX Udieresis Aogonek -40
KPX Udieresis Aring -40
KPX Udieresis Atilde -40
KPX Ugrave A -40
KPX Ugrave Aacute -40
KPX Ugrave Abreve -40
KPX Ugrave Acircumflex -40
KPX Ugrave Adieresis -40
KPX Ugrave Agrave -40
KPX Ugrave Amacron -40
KPX Ugrave Aogonek -40
KPX Ugrave Aring -40
KPX Ugrave Atilde -40
KPX Uhungarumlaut A -40
KPX Uhungarumlaut Aacute -40
KPX Uhungarumlaut Abreve -40
KPX Uhungarumlaut Acircumflex -40
KPX Uhungarumlaut Adieresis -40
KPX Uhungarumlaut Agrave -40
KPX Uhungarumlaut Amacron -40
KPX Uhungarumlaut Aogonek -40
KPX Uhungarumlaut Aring -40
KPX Uhungarumlaut Atilde -40
KPX Umacron A -40
KPX Umacron Aacute -40
KPX Umacron Abreve -40
KPX Umacron Acircumflex -40
KPX Umacron Adieresis -40
KPX Umacron Agrave -40
KPX Umacron Amacron -40
KPX Umacron Aogonek -40
KPX Umacron Aring -40
KPX Umacron Atilde -40
KPX Uogonek A -40
KPX Uogonek Aacute -40
KPX Uogonek Abreve -40
KPX Uogonek Acircumflex -40
KPX Uogonek Adieresis -40
KPX Uogonek Agrave -40
KPX Uogonek Amacron -40
KPX Uogonek Aogonek -40
KPX Uogonek Aring -40
KPX Uogonek Atilde -40
KPX Uring A -40
KPX Uring Aacute -40
KPX Uring Abreve -40
KPX Uring Acircumflex -40
KPX Uring Adieresis -40
KPX Uring Agrave -40
KPX Uring Amacron -40
KPX Uring Aogonek -40
KPX Uring Aring -40
KPX Uring Atilde -40
KPX V A -135
KPX V Aacute -135
KPX V Abreve -135
KPX V Acircumflex -135
KPX V Adieresis -135
KPX V Agrave -135
KPX V Amacron -135
KPX V Aogonek -135
KPX V Aring -135
KPX V Atilde -135
KPX V G -15
KPX V Gbreve -15
KPX V Gcommaaccent -15
KPX V O -40
KPX V Oacute -40
KPX V Ocircumflex -40
KPX V Odieresis -40
KPX V Ograve -40
KPX V Ohungarumlaut -40
KPX V Omacron -40
KPX V Oslash -40
KPX V Otilde -40
KPX V a -111
KPX V aacute -111
KPX V abreve -111
KPX V acircumflex -71
KPX V adieresis -71
KPX V agrave -71
KPX V amacron -71
KPX V aogonek -111
KPX V aring -111
KPX V atilde -71
KPX V colon -74
KPX V comma -129
KPX V e -111
KPX V eacute -111
KPX V ecaron -71
KPX V ecircumflex -71
KPX V edieresis -71
KPX V edotaccent -111
KPX V egrave -71
KPX V emacron -71
KPX V eogonek -111
KPX V hyphen -100
KPX V i -60
KPX V iacute -60
KPX V icircumflex -20
KPX V idieresis -20
KPX V igrave -20
KPX V imacron -20
KPX V iogonek -60
KPX V o -129
KPX V oacute -129
KPX V ocircumflex -129
KPX V odieresis -89
KPX V ograve -89
KPX V ohungarumlaut -129
KPX V omacron -89
KPX V oslash -129
KPX V otilde -89
KPX V period -129
KPX V semicolon -74
KPX V u -75
KPX V uacute -75
KPX V ucircumflex -75
KPX V udieresis -75
KPX V ugrave -75
KPX V uhungarumlaut -75
KPX V umacron -75
KPX V uogonek -75
KPX V uring -75
KPX W A -120
KPX W Aacute -120
KPX W Abreve -120
KPX W Acircumflex -120
KPX W Adieresis -120
KPX W Agrave -120
KPX W Amacron -120
KPX W Aogonek -120
KPX W Aring -120
KPX W Atilde -120
KPX W O -10
KPX W Oacute -10
KPX W Ocircumflex -10
KPX W Odieresis -10
KPX W Ograve -10
KPX W Ohungarumlaut -10
KPX W Omacron -10
KPX W Oslash -10
KPX W Otilde -10
KPX W a -80
KPX W aacute -80
KPX W abreve -80
KPX W acircumflex -80
KPX W adieresis -80
KPX W agrave -80
KPX W amacron -80
KPX W aogonek -80
KPX W aring -80
KPX W atilde -80
KPX W colon -37
KPX W comma -92
KPX W e -80
KPX W eacute -80
KPX W ecaron -80
KPX W ecircumflex -80
KPX W edieresis -40
KPX W edotaccent -80
KPX W egrave -40
KPX W emacron -40
KPX W eogonek -80
KPX W hyphen -65
KPX W i -40
KPX W iacute -40
KPX W iogonek -40
KPX W o -80
KPX W oacute -80
KPX W ocircumflex -80
KPX W odieresis -80
KPX W ograve -80
KPX W ohungarumlaut -80
KPX W omacron -80
KPX W oslash -80
KPX W otilde -80
KPX W period -92
KPX W semicolon -37
KPX W u -50
KPX W uacute -50
KPX W ucircumflex -50
KPX W udieresis -50
KPX W ugrave -50
KPX W uhungarumlaut -50
KPX W umacron -50
KPX W uogonek -50
KPX W uring -50
KPX W y -73
KPX W yacute -73
KPX W ydieresis -73
KPX Y A -120
KPX Y Aacute -120
KPX Y Abreve -120
KPX Y Acircumflex -120
KPX Y Adieresis -120
KPX Y Agrave -120
KPX Y Amacron -120
KPX Y Aogonek -120
KPX Y Aring -120
KPX Y Atilde -120
KPX Y O -30
KPX Y Oacute -30
KPX Y Ocircumflex -30
KPX Y Odieresis -30
KPX Y Ograve -30
KPX Y Ohungarumlaut -30
KPX Y Omacron -30
KPX Y Oslash -30
KPX Y Otilde -30
KPX Y a -100
KPX Y aacute -100
KPX Y abreve -100
KPX Y acircumflex -100
KPX Y adieresis -60
KPX Y agrave -60
KPX Y amacron -60
KPX Y aogonek -100
KPX Y aring -100
KPX Y atilde -60
KPX Y colon -92
KPX Y comma -129
KPX Y e -100
KPX Y eacute -100
KPX Y ecaron -100
KPX Y ecircumflex -100
KPX Y edieresis -60
KPX Y edotaccent -100
KPX Y egrave -60
KPX Y emacron -60
KPX Y eogonek -100
KPX Y hyphen -111
KPX Y i -55
KPX Y iacute -55
KPX Y iogonek -55
KPX Y o -110
KPX Y oacute -110
KPX Y ocircumflex -110
KPX Y odieresis -70
KPX Y ograve -70
KPX Y ohungarumlaut -110
KPX Y omacron -70
KPX Y oslash -110
KPX Y otilde -70
KPX Y period -129
KPX Y semicolon -92
KPX Y u -111
KPX Y uacute -111
KPX Y ucircumflex -111
KPX Y udieresis -71
KPX Y ugrave -71
KPX Y uhungarumlaut -111
KPX Y umacron -71
KPX Y uogonek -111
KPX Y uring -111
KPX Yacute A -120
KPX Yacute Aacute -120
KPX Yacute Abreve -120
KPX Yacute Acircumflex -120
KPX Yacute Adieresis -120
KPX Yacute Agrave -120
KPX Yacute Amacron -120
KPX Yacute Aogonek -120
KPX Yacute Aring -120
KPX Yacute Atilde -120
KPX Yacute O -30
KPX Yacute Oacute -30
KPX Yacute Ocircumflex -30
KPX Yacute Odieresis -30
KPX Yacute Ograve -30
KPX Yacute Ohungarumlaut -30
KPX Yacute Omacron -30
KPX Yacute Oslash -30
KPX Yacute Otilde -30
KPX Yacute a -100
KPX Yacute aacute -100
KPX Yacute abreve -100
KPX Yacute acircumflex -100
KPX Yacute adieresis -60
KPX Yacute agrave -60
KPX Yacute amacron -60
KPX Yacute aogonek -100
KPX Yacute aring -100
KPX Yacute atilde -60
KPX Yacute colon -92
KPX Yacute comma -129
KPX Yacute e -100
KPX Yacute eacute -100
KPX Yacute ecaron -100
KPX Yacute ecircumflex -100
KPX Yacute edieresis -60
KPX Yacute edotaccent -100
KPX Yacute egrave -60
KPX Yacute emacron -60
KPX Yacute eogonek -100
KPX Yacute hyphen -111
KPX Yacute i -55
KPX Yacute iacute -55
KPX Yacute iogonek -55
KPX Yacute o -110
KPX Yacute oacute -110
KPX Yacute ocircumflex -110
KPX Yacute odieresis -70
KPX Yacute ograve -70
KPX Yacute ohungarumlaut -110
KPX Yacute omacron -70
KPX Yacute oslash -110
KPX Yacute otilde -70
KPX Yacute period -129
KPX Yacute semicolon -92
KPX Yacute u -111
KPX Yacute uacute -111
KPX Yacute ucircumflex -111
KPX Yacute udieresis -71
KPX Yacute ugrave -71
KPX Yacute uhungarumlaut -111
KPX Yacute umacron -71
KPX Yacute uogonek -111
KPX Yacute uring -111
KPX Ydieresis A -120
KPX Ydieresis Aacute -120
KPX Ydieresis Abreve -120
KPX Ydieresis Acircumflex -120
KPX Ydieresis Adieresis -120
KPX Ydieresis Agrave -120
KPX Ydieresis Amacron -120
KPX Ydieresis Aogonek -120
KPX Ydieresis Aring -120
KPX Ydieresis Atilde -120
KPX Ydieresis O -30
KPX Ydieresis Oacute -30
KPX Ydieresis Ocircumflex -30
KPX Ydieresis Odieresis -30
KPX Ydieresis Ograve -30
KPX Ydieresis Ohungarumlaut -30
KPX Ydieresis Omacron -30
KPX Ydieresis Oslash -30
KPX Ydieresis Otilde -30
KPX Ydieresis a -100
KPX Ydieresis aacute -100
KPX Ydieresis abreve -100
KPX Ydieresis acircumflex -100
KPX Ydieresis adieresis -60
KPX Ydieresis agrave -60
KPX Ydieresis amacron -60
KPX Ydieresis aogonek -100
KPX Ydieresis aring -100
KPX Ydieresis atilde -100
KPX Ydieresis colon -92
KPX Ydieresis comma -129
KPX Ydieresis e -100
KPX Ydieresis eacute -100
KPX Ydieresis ecaron -100
KPX Ydieresis ecircumflex -100
KPX Ydieresis edieresis -60
KPX Ydieresis edotaccent -100
KPX Ydieresis egrave -60
KPX Ydieresis emacron -60
KPX Ydieresis eogonek -100
KPX Ydieresis hyphen -111
KPX Ydieresis i -55
KPX Ydieresis iacute -55
KPX Ydieresis iogonek -55
KPX Ydieresis o -110
KPX Ydieresis oacute -110
KPX Ydieresis ocircumflex -110
KPX Ydieresis odieresis -70
KPX Ydieresis ograve -70
KPX Ydieresis ohungarumlaut -110
KPX Ydieresis omacron -70
KPX Ydieresis oslash -110
KPX Ydieresis otilde -70
KPX Ydieresis period -129
KPX Ydieresis semicolon -92
KPX Ydieresis u -111
KPX Ydieresis uacute -111
KPX Ydieresis ucircumflex -111
KPX Ydieresis udieresis -71
KPX Ydieresis ugrave -71
KPX Ydieresis uhungarumlaut -111
KPX Ydieresis umacron -71
KPX Ydieresis uogonek -111
KPX Ydieresis uring -111
KPX a v -20
KPX a w -15
KPX aacute v -20
KPX aacute w -15
KPX abreve v -20
KPX abreve w -15
KPX acircumflex v -20
KPX acircumflex w -15
KPX adieresis v -20
KPX adieresis w -15
KPX agrave v -20
KPX agrave w -15
KPX amacron v -20
KPX amacron w -15
KPX aogonek v -20
KPX aogonek w -15
KPX aring v -20
KPX aring w -15
KPX atilde v -20
KPX atilde w -15
KPX b period -40
KPX b u -20
KPX b uacute -20
KPX b ucircumflex -20
KPX b udieresis -20
KPX b ugrave -20
KPX b uhungarumlaut -20
KPX b umacron -20
KPX b uogonek -20
KPX b uring -20
KPX b v -15
KPX c y -15
KPX c yacute -15
KPX c ydieresis -15
KPX cacute y -15
KPX cacute yacute -15
KPX cacute ydieresis -15
KPX ccaron y -15
KPX ccaron yacute -15
KPX ccaron ydieresis -15
KPX ccedilla y -15
KPX ccedilla yacute -15
KPX ccedilla ydieresis -15
KPX comma quotedblright -70
KPX comma quoteright -70
KPX e g -15
KPX e gbreve -15
KPX e gcommaaccent -15
KPX e v -25
KPX e w -25
KPX e x -15
KPX e y -15
KPX e yacute -15
KPX e ydieresis -15
KPX eacute g -15
KPX eacute gbreve -15
KPX eacute gcommaaccent -15
KPX eacute v -25
KPX eacute w -25
KPX eacute x -15
KPX eacute y -15
KPX eacute yacute -15
KPX eacute ydieresis -15
KPX ecaron g -15
KPX ecaron gbreve -15
KPX ecaron gcommaaccent -15
KPX ecaron v -25
KPX ecaron w -25
KPX ecaron x -15
KPX ecaron y -15
KPX ecaron yacute -15
KPX ecaron ydieresis -15
KPX ecircumflex g -15
KPX ecircumflex gbreve -15
KPX ecircumflex gcommaaccent -15
KPX ecircumflex v -25
KPX ecircumflex w -25
KPX ecircumflex x -15
KPX ecircumflex y -15
KPX ecircumflex yacute -15
KPX ecircumflex ydieresis -15
KPX edieresis g -15
KPX edieresis gbreve -15
KPX edieresis gcommaaccent -15
KPX edieresis v -25
KPX edieresis w -25
KPX edieresis x -15
KPX edieresis y -15
KPX edieresis yacute -15
KPX edieresis ydieresis -15
KPX edotaccent g -15
KPX edotaccent gbreve -15
KPX edotaccent gcommaaccent -15
KPX edotaccent v -25
KPX edotaccent w -25
KPX edotaccent x -15
KPX edotaccent y -15
KPX edotaccent yacute -15
KPX edotaccent ydieresis -15
KPX egrave g -15
KPX egrave gbreve -15
KPX egrave gcommaaccent -15
KPX egrave v -25
KPX egrave w -25
KPX egrave x -15
KPX egrave y -15
KPX egrave yacute -15
KPX egrave ydieresis -15
KPX emacron g -15
KPX emacron gbreve -15
KPX emacron gcommaaccent -15
KPX emacron v -25
KPX emacron w -25
KPX emacron x -15
KPX emacron y -15
KPX emacron yacute -15
KPX emacron ydieresis -15
KPX eogonek g -15
KPX eogonek gbreve -15
KPX eogonek gcommaaccent -15
KPX eogonek v -25
KPX eogonek w -25
KPX eogonek x -15
KPX eogonek y -15
KPX eogonek yacute -15
KPX eogonek ydieresis -15
KPX f a -10
KPX f aacute -10
KPX f abreve -10
KPX f acircumflex -10
KPX f adieresis -10
KPX f agrave -10
KPX f amacron -10
KPX f aogonek -10
KPX f aring -10
KPX f atilde -10
KPX f dotlessi -50
KPX f f -25
KPX f i -20
KPX f iacute -20
KPX f quoteright 55
KPX g a -5
KPX g aacute -5
KPX g abreve -5
KPX g acircumflex -5
KPX g adieresis -5
KPX g agrave -5
KPX g amacron -5
KPX g aogonek -5
KPX g aring -5
KPX g atilde -5
KPX gbreve a -5
KPX gbreve aacute -5
KPX gbreve abreve -5
KPX gbreve acircumflex -5
KPX gbreve adieresis -5
KPX gbreve agrave -5
KPX gbreve amacron -5
KPX gbreve aogonek -5
KPX gbreve aring -5
KPX gbreve atilde -5
KPX gcommaaccent a -5
KPX gcommaaccent aacute -5
KPX gcommaaccent abreve -5
KPX gcommaaccent acircumflex -5
KPX gcommaaccent adieresis -5
KPX gcommaaccent agrave -5
KPX gcommaaccent amacron -5
KPX gcommaaccent aogonek -5
KPX gcommaaccent aring -5
KPX gcommaaccent atilde -5
KPX h y -5
KPX h yacute -5
KPX h ydieresis -5
KPX i v -25
KPX iacute v -25
KPX icircumflex v -25
KPX idieresis v -25
KPX igrave v -25
KPX imacron v -25
KPX iogonek v -25
KPX k e -10
KPX k eacute -10
KPX k ecaron -10
KPX k ecircumflex -10
KPX k edieresis -10
KPX k edotaccent -10
KPX k egrave -10
KPX k emacron -10
KPX k eogonek -10
KPX k o -10
KPX k oacute -10
KPX k ocircumflex -10
KPX k odieresis -10
KPX k ograve -10
KPX k ohungarumlaut -10
KPX k omacron -10
KPX k oslash -10
KPX k otilde -10
KPX k y -15
KPX k yacute -15
KPX k ydieresis -15
KPX kcommaaccent e -10
KPX kcommaaccent eacute -10
KPX kcommaaccent ecaron -10
KPX kcommaaccent ecircumflex -10
KPX kcommaaccent edieresis -10
KPX kcommaaccent edotaccent -10
KPX kcommaaccent egrave -10
KPX kcommaaccent emacron -10
KPX kcommaaccent eogonek -10
KPX kcommaaccent o -10
KPX kcommaaccent oacute -10
KPX kcommaaccent ocircumflex -10
KPX kcommaaccent odieresis -10
KPX kcommaaccent ograve -10
KPX kcommaaccent ohungarumlaut -10
KPX kcommaaccent omacron -10
KPX kcommaaccent oslash -10
KPX kcommaaccent otilde -10
KPX kcommaaccent y -15
KPX kcommaaccent yacute -15
KPX kcommaaccent ydieresis -15
KPX l w -10
KPX lacute w -10
KPX lcommaaccent w -10
KPX lslash w -10
KPX n v -40
KPX n y -15
KPX n yacute -15
KPX n ydieresis -15
KPX nacute v -40
KPX nacute y -15
KPX nacute yacute -15
KPX nacute ydieresis -15
KPX ncaron v -40
KPX ncaron y -15
KPX ncaron yacute -15
KPX ncaron ydieresis -15
KPX ncommaaccent v -40
KPX ncommaaccent y -15
KPX ncommaaccent yacute -15
KPX ncommaaccent ydieresis -15
KPX ntilde v -40
KPX ntilde y -15
KPX ntilde yacute -15
KPX ntilde ydieresis -15
KPX o v -15
KPX o w -25
KPX o y -10
KPX o yacute -10
KPX o ydieresis -10
KPX oacute v -15
KPX oacute w -25
KPX oacute y -10
KPX oacute yacute -10
KPX oacute ydieresis -10
KPX ocircumflex v -15
KPX ocircumflex w -25
KPX ocircumflex y -10
KPX ocircumflex yacute -10
KPX ocircumflex ydieresis -10
KPX odieresis v -15
KPX odieresis w -25
KPX odieresis y -10
KPX odieresis yacute -10
KPX odieresis ydieresis -10
KPX ograve v -15
KPX ograve w -25
KPX ograve y -10
KPX ograve yacute -10
KPX ograve ydieresis -10
KPX ohungarumlaut v -15
KPX ohungarumlaut w -25
KPX ohungarumlaut y -10
KPX ohungarumlaut yacute -10
KPX ohungarumlaut ydieresis -10
KPX omacron v -15
KPX omacron w -25
KPX omacron y -10
KPX omacron yacute -10
KPX omacron ydieresis -10
KPX oslash v -15
KPX oslash w -25
KPX oslash y -10
KPX oslash yacute -10
KPX oslash ydieresis -10
KPX otilde v -15
KPX otilde w -25
KPX otilde y -10
KPX otilde yacute -10
KPX otilde ydieresis -10
KPX p y -10
KPX p yacute -10
KPX p ydieresis -10
KPX period quotedblright -70
KPX period quoteright -70
KPX quotedblleft A -80
KPX quotedblleft Aacute -80
KPX quotedblleft Abreve -80
KPX quotedblleft Acircumflex -80
KPX quotedblleft Adieresis -80
KPX quotedblleft Agrave -80
KPX quotedblleft Amacron -80
KPX quotedblleft Aogonek -80
KPX quotedblleft Aring -80
KPX quotedblleft Atilde -80
KPX quoteleft A -80
KPX quoteleft Aacute -80
KPX quoteleft Abreve -80
KPX quoteleft Acircumflex -80
KPX quoteleft Adieresis -80
KPX quoteleft Agrave -80
KPX quoteleft Amacron -80
KPX quoteleft Aogonek -80
KPX quoteleft Aring -80
KPX quoteleft Atilde -80
KPX quoteleft quoteleft -74
KPX quoteright d -50
KPX quoteright dcroat -50
KPX quoteright l -10
KPX quoteright lacute -10
KPX quoteright lcommaaccent -10
KPX quoteright lslash -10
KPX quoteright quoteright -74
KPX quoteright r -50
KPX quoteright racute -50
KPX quoteright rcaron -50
KPX quoteright rcommaaccent -50
KPX quoteright s -55
KPX quoteright sacute -55
KPX quoteright scaron -55
KPX quoteright scedilla -55
KPX quoteright scommaaccent -55
KPX quoteright space -74
KPX quoteright t -18
KPX quoteright tcommaaccent -18
KPX quoteright v -50
KPX r comma -40
KPX r g -18
KPX r gbreve -18
KPX r gcommaaccent -18
KPX r hyphen -20
KPX r period -55
KPX racute comma -40
KPX racute g -18
KPX racute gbreve -18
KPX racute gcommaaccent -18
KPX racute hyphen -20
KPX racute period -55
KPX rcaron comma -40
KPX rcaron g -18
KPX rcaron gbreve -18
KPX rcaron gcommaaccent -18
KPX rcaron hyphen -20
KPX rcaron period -55
KPX rcommaaccent comma -40
KPX rcommaaccent g -18
KPX rcommaaccent gbreve -18
KPX rcommaaccent gcommaaccent -18
KPX rcommaaccent hyphen -20
KPX rcommaaccent period -55
KPX space A -55
KPX space Aacute -55
KPX space Abreve -55
KPX space Acircumflex -55
KPX space Adieresis -55
KPX space Agrave -55
KPX space Amacron -55
KPX space Aogonek -55
KPX space Aring -55
KPX space Atilde -55
KPX space T -18
KPX space Tcaron -18
KPX space Tcommaaccent -18
KPX space V -50
KPX space W -30
KPX space Y -90
KPX space Yacute -90
KPX space Ydieresis -90
KPX v a -25
KPX v aacute -25
KPX v abreve -25
KPX v acircumflex -25
KPX v adieresis -25
KPX v agrave -25
KPX v amacron -25
KPX v aogonek -25
KPX v aring -25
KPX v atilde -25
KPX v comma -65
KPX v e -15
KPX v eacute -15
KPX v ecaron -15
KPX v ecircumflex -15
KPX v edieresis -15
KPX v edotaccent -15
KPX v egrave -15
KPX v emacron -15
KPX v eogonek -15
KPX v o -20
KPX v oacute -20
KPX v ocircumflex -20
KPX v odieresis -20
KPX v ograve -20
KPX v ohungarumlaut -20
KPX v omacron -20
KPX v oslash -20
KPX v otilde -20
KPX v period -65
KPX w a -10
KPX w aacute -10
KPX w abreve -10
KPX w acircumflex -10
KPX w adieresis -10
KPX w agrave -10
KPX w amacron -10
KPX w aogonek -10
KPX w aring -10
KPX w atilde -10
KPX w comma -65
KPX w o -10
KPX w oacute -10
KPX w ocircumflex -10
KPX w odieresis -10
KPX w ograve -10
KPX w ohungarumlaut -10
KPX w omacron -10
KPX w oslash -10
KPX w otilde -10
KPX w period -65
KPX x e -15
KPX x eacute -15
KPX x ecaron -15
KPX x ecircumflex -15
KPX x edieresis -15
KPX x edotaccent -15
KPX x egrave -15
KPX x emacron -15
KPX x eogonek -15
KPX y comma -65
KPX y period -65
KPX yacute comma -65
KPX yacute period -65
KPX ydieresis comma -65
KPX ydieresis period -65
EndKernPairs
EndKernData
EndFontMetrics
================================================
FILE: packages/pdfkit/src/font/data/compressData.js
================================================
import fs from 'fs';
import url from 'url';
import { basename, extname } from 'path';
import { parse } from '../afm.js';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const generateJsonFiles = () => {
const files = fs.readdirSync(__dirname);
const afmFiles = files.filter((file) => file.match(/.afm$/));
afmFiles.forEach((file) => {
const fontName = basename(file).replace(extname(file), '');
const data = fs.readFileSync(__dirname + '/' + file, 'utf8');
const parsed = parse(data);
fs.writeFileSync(
__dirname + '/' + fontName + '.json',
JSON.stringify(parsed)
);
});
};
// Order is designed to produce the smaller size possible
const COMPRESS_ORDER = ['Helvetica', 'Times', 'Courier'];
const readJson = (file) => {
const data = fs.readFileSync(__dirname + '/' + file, 'utf8');
return JSON.parse(data);
};
const sortFiles = (a, b) => {
const indexA = COMPRESS_ORDER.indexOf(a.attributes.FamilyName);
const indexB = COMPRESS_ORDER.indexOf(b.attributes.FamilyName);
return indexA - indexB;
};
const fillWithZeros = (array) => {
const res = [];
for (let i = 0; i < array.length; i++) {
res[i] = array[i] || 0;
}
return res;
};
const compressJsonFiles = () => {
const attributes = [];
const glyphWidths = {};
const kernPairs = {};
const files = fs.readdirSync(__dirname);
const jsonFiles = files.filter((file) => file.match(/.json$/));
const filesContent = jsonFiles.map(readJson);
const sortedFiles = filesContent.sort(sortFiles);
sortedFiles.forEach((content, index) => {
attributes.push(content.attributes);
Object.keys(content.glyphWidths).forEach((key) => {
if (!glyphWidths[key]) glyphWidths[key] = [];
glyphWidths[key][index] = content.glyphWidths[key];
});
Object.keys(content.kernPairs).forEach((key) => {
if (!kernPairs[key]) kernPairs[key] = [];
kernPairs[key][index] = content.kernPairs[key];
});
});
// Cheaper to store nulls as 0s
Object.keys(glyphWidths).forEach((key) => {
glyphWidths[key] = fillWithZeros(glyphWidths[key]);
});
Object.keys(kernPairs).forEach((key) => {
kernPairs[key] = fillWithZeros(kernPairs[key]);
});
const parsed = { attributes, glyphWidths, kernPairs };
fs.writeFileSync(__dirname + '/index.json', JSON.stringify(parsed));
};
generateJsonFiles();
compressJsonFiles();
================================================
FILE: packages/pdfkit/src/font/data/expandData.js
================================================
const initFont = (font) => {
return [font.FontName, { attributes: font, glyphWidths: {}, kernPairs: {} }];
};
const expandData = (data) => {
const { attributes, glyphWidths, kernPairs } = data;
const fonts = attributes.map(initFont);
Object.keys(glyphWidths).forEach((key) => {
glyphWidths[key].forEach((value, index) => {
if (value) fonts[index][1].glyphWidths[key] = value;
});
});
Object.keys(kernPairs).forEach((key) => {
kernPairs[key].forEach((value, index) => {
if (value) fonts[index][1].kernPairs[key] = value;
});
});
return Object.fromEntries(fonts);
};
export default expandData;
================================================
FILE: packages/pdfkit/src/font/embedded.js
================================================
const toHex = function (...codePoints) {
const codes = Array.from(codePoints).map((code) =>
`0000${code.toString(16)}`.slice(-4)
);
return codes.join('');
};
const createEmbeddedFont = (PDFFont) =>
class EmbeddedFont extends PDFFont {
constructor(document, font, id) {
super();
this.document = document;
this.font = font;
this.id = id;
this.subset = this.font.createSubset();
this.unicode = [[0]];
this.widths = [this.font.getGlyph(0).advanceWidth];
this.name = this.font.postscriptName;
this.scale = 1000 / this.font.unitsPerEm;
this.ascender = this.font.ascent * this.scale;
this.descender = this.font.descent * this.scale;
this.xHeight = this.font.xHeight * this.scale;
this.capHeight = this.font.capHeight * this.scale;
this.lineGap = this.font.lineGap * this.scale;
this.bbox = this.font.bbox;
this.layoutCache = Object.create(null);
}
layoutRun(text, features) {
// passing LTR To force fontkit to not reverse the string
const run = this.font.layout(text, features, undefined, undefined, 'ltr');
// Normalize position values
for (let i = 0; i < run.positions.length; i++) {
const position = run.positions[i];
for (let key in position) {
position[key] *= this.scale;
}
position.advanceWidth = run.glyphs[i].advanceWidth * this.scale;
}
return run;
}
layoutCached(text) {
let cached;
if ((cached = this.layoutCache[text])) {
return cached;
}
const run = this.layoutRun(text);
this.layoutCache[text] = run;
return run;
}
layout(text, features, onlyWidth) {
// Skip the cache if any user defined features are applied
if (onlyWidth == null) {
onlyWidth = false;
}
if (features) {
return this.layoutRun(text, features);
}
const glyphs = onlyWidth ? null : [];
const positions = onlyWidth ? null : [];
let advanceWidth = 0;
// Split the string by words to increase cache efficiency.
// For this purpose, spaces and tabs are a good enough delimeter.
let last = 0;
let index = 0;
while (index <= text.length) {
let needle;
if (
(index === text.length && last < index) ||
((needle = text.charAt(index)), [' ', '\t'].includes(needle))
) {
const run = this.layoutCached(text.slice(last, ++index));
if (!onlyWidth) {
glyphs.push(...Array.from(run.glyphs || []));
positions.push(...Array.from(run.positions || []));
}
advanceWidth += run.advanceWidth;
last = index;
} else {
index++;
}
}
return { glyphs, positions, advanceWidth };
}
encode(text, features) {
const { glyphs, positions } = this.layout(text, features);
const res = [];
for (let i = 0; i < glyphs.length; i++) {
const glyph = glyphs[i];
const gid = this.subset.includeGlyph(glyph.id);
res.push(`0000${gid.toString(16)}`.slice(-4));
if (this.widths[gid] == null) {
this.widths[gid] = glyph.advanceWidth * this.scale;
}
if (this.unicode[gid] == null) {
this.unicode[gid] = glyph.codePoints;
}
}
return [res, positions];
}
encodeGlyphs(glyphs) {
const res = [];
for (let i = 0; i < glyphs.length; i++) {
const glyph = glyphs[i];
const gid = this.subset.includeGlyph(glyph.id);
res.push(`0000${gid.toString(16)}`.slice(-4));
if (this.widths[gid] == null) {
this.widths[gid] = glyph.advanceWidth * this.scale;
}
if (this.unicode[gid] == null) {
this.unicode[gid] = glyph.codePoints;
}
}
return res;
}
widthOfString(string, size, features) {
const width = this.layout(string, features, true).advanceWidth;
const scale = size / 1000;
return width * scale;
}
embed() {
const isCFF = this.subset.cff != null;
const fontFile = this.document.ref();
if (isCFF) {
fontFile.data.Subtype = 'CIDFontType0C';
}
fontFile.end(this.subset.encode());
const familyClass =
((this.font['OS/2'] != null
? this.font['OS/2'].sFamilyClass
: undefined) || 0) >> 8;
let flags = 0;
if (this.font.post.isFixedPitch) {
flags |= 1 << 0;
}
if (1 <= familyClass && familyClass <= 7) {
flags |= 1 << 1;
}
flags |= 1 << 2; // assume the font uses non-latin characters
if (familyClass === 10) {
flags |= 1 << 3;
}
if (this.font.head.macStyle.italic) {
flags |= 1 << 6;
}
// generate a random tag (6 uppercase letters. 65 is the char code for 'A')
const tag = [0, 1, 2, 3, 4, 5]
.map(() => String.fromCharCode(Math.random() * 26 + 65))
.join('');
const name = tag + '+' + this.font.postscriptName;
const { bbox } = this.font;
const descriptor = this.document.ref({
Type: 'FontDescriptor',
FontName: name,
Flags: flags,
FontBBox: [
bbox.minX * this.scale,
bbox.minY * this.scale,
bbox.maxX * this.scale,
bbox.maxY * this.scale
],
ItalicAngle: this.font.italicAngle,
Ascent: this.ascender,
Descent: this.descender,
CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,
XHeight: (this.font.xHeight || 0) * this.scale,
StemV: 0
}); // not sure how to calculate this
if (isCFF) {
descriptor.data.FontFile3 = fontFile;
} else {
descriptor.data.FontFile2 = fontFile;
}
descriptor.end();
const descendantFontData = {
Type: 'Font',
Subtype: 'CIDFontType0',
BaseFont: name,
CIDSystemInfo: {
Registry: new String('Adobe'),
Ordering: new String('Identity'),
Supplement: 0
},
FontDescriptor: descriptor,
W: [0, this.widths]
};
if (!isCFF) {
descendantFontData.Subtype = 'CIDFontType2';
descendantFontData.CIDToGIDMap = 'Identity';
}
const descendantFont = this.document.ref(descendantFontData);
descendantFont.end();
this.dictionary.data = {
Type: 'Font',
Subtype: 'Type0',
BaseFont: name,
Encoding: 'Identity-H',
DescendantFonts: [descendantFont],
ToUnicode: this.toUnicodeCmap()
};
return this.dictionary.end();
}
// Maps the glyph ids encoded in the PDF back to unicode strings
// Because of ligature substitutions and the like, there may be one or more
// unicode characters represented by each glyph.
toUnicodeCmap() {
const cmap = this.document.ref();
let entries = [];
let unicodeMap =
'/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo <<\n /Registry (Adobe)\n /Ordering (UCS)\n /Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000>\nendcodespacerange';
for (let [index, codePoints] of this.unicode.entries()) {
const encoded = [];
if (entries.length >= 100) {
unicodeMap +=
'\n' +
entries.length +
' beginbfchar\n' +
entries.join('\n') +
'\nendbfchar';
entries = [];
}
// encode codePoints to utf16
for (let value of codePoints) {
if (value > 0xffff) {
value -= 0x10000;
encoded.push(toHex(((value >>> 10) & 0x3ff) | 0xd800));
value = 0xdc00 | (value & 0x3ff);
}
encoded.push(toHex(value));
}
entries.push('<' + toHex(index) + '>' + '<' + encoded.join(' ') + '>');
}
if (entries.length) {
unicodeMap +=
'\n' +
entries.length +
' beginbfchar\n' +
entries.join('\n') +
'\nendbfchar\n';
}
unicodeMap +=
'endcmap\nCMapName currentdict /CMap defineresource pop\nend\nend';
cmap.end(unicodeMap);
return cmap;
}
};
export default createEmbeddedFont;
================================================
FILE: packages/pdfkit/src/font/standard.js
================================================
import AFMFont from './afm';
import data from './data/index.json';
import expandData from './data/expandData';
const STANDARD_FONTS = expandData(data);
const createStandardFont = (PDFFont) =>
class StandardFont extends PDFFont {
constructor(document, name, id) {
super();
this.document = document;
this.name = name;
this.id = id;
this.font = AFMFont.fromJson(STANDARD_FONTS[this.name]);
this.ascender = this.font.ascender;
this.descender = this.font.descender;
this.bbox = this.font.bbox;
this.lineGap = this.font.lineGap;
}
embed() {
this.dictionary.data = {
Type: 'Font',
BaseFont: this.name,
Subtype: 'Type1',
Encoding: 'WinAnsiEncoding'
};
return this.dictionary.end();
}
encode(text) {
const encoded = this.font.encodeText(text);
const glyphs = this.font.glyphsForString(`${text}`);
const advances = this.font.advancesForGlyphs(glyphs);
const positions = [];
for (let i = 0; i < glyphs.length; i++) {
const glyph = glyphs[i];
positions.push({
xAdvance: advances[i],
yAdvance: 0,
xOffset: 0,
yOffset: 0,
advanceWidth: this.font.widthOfGlyph(glyph)
});
}
return [encoded, positions];
}
encodeGlyphs(glyphs) {
const res = [];
for (let glyph of Array.from(glyphs)) {
res.push(`00${glyph.id.toString(16)}`.slice(-2));
}
return res;
}
widthOfString(string, size) {
const glyphs = this.font.glyphsForString(`${string}`);
const advances = this.font.advancesForGlyphs(glyphs);
let width = 0;
for (let advance of Array.from(advances)) {
width += advance;
}
const scale = size / 1000;
return width * scale;
}
static isStandardFont(name) {
return name in STANDARD_FONTS;
}
};
export default createStandardFont;
================================================
FILE: packages/pdfkit/src/font.js
================================================
import * as fontkit from 'fontkit';
import createStandardFont from './font/standard';
import createEmbeddedFont from './font/embedded';
export class PDFFont {
static open(document, src, family, id) {
let font;
if (typeof src === 'string') {
if (StandardFont.isStandardFont(src)) {
return new StandardFont(document, src, id);
}
if (!BROWSER) {
font = fontkit.openSync(src, family);
} else {
throw new Error(`Can't open ${src} in browser build`);
}
} else if (src instanceof Uint8Array) {
font = fontkit.create(src, family);
} else if (src instanceof ArrayBuffer) {
font = fontkit.create(new Uint8Array(src), family);
} else if (typeof src === 'object') {
font = src;
}
if (font == null) {
throw new Error('Not a supported font format or standard PDF font.');
}
return new EmbeddedFont(document, font, id);
}
encode() {
throw new Error('Must be implemented by subclasses');
}
widthOfString() {
throw new Error('Must be implemented by subclasses');
}
ref() {
return this.dictionary != null
? this.dictionary
: (this.dictionary = this.document.ref());
}
finalize() {
if (this.embedded || this.dictionary == null) {
return;
}
this.embed();
return (this.embedded = true);
}
embed() {
throw new Error('Must be implemented by subclasses');
}
lineHeight(size, includeGap) {
if (includeGap == null) {
includeGap = false;
}
const gap = includeGap ? this.lineGap : 0;
return ((this.ascender + gap - this.descender) / 1000) * size;
}
}
export const StandardFont = createStandardFont(PDFFont);
export const EmbeddedFont = createEmbeddedFont(PDFFont);
export default PDFFont;
================================================
FILE: packages/pdfkit/src/font_factory.js
================================================
import fs from 'fs';
import * as fontkit from 'fontkit';
import StandardFont from './font/standard';
import EmbeddedFont from './font/embedded';
class PDFFontFactory {
static open(document, src, family, id) {
let font;
if (typeof src === 'string') {
if (StandardFont.isStandardFont(src)) {
return new StandardFont(document, src, id);
}
src = fs.readFileSync(src);
}
if (src instanceof Uint8Array) {
font = fontkit.create(src, family);
} else if (src instanceof ArrayBuffer) {
font = fontkit.create(new Uint8Array(src), family);
}
if (font == null) {
throw new Error('Not a supported font format or standard PDF font.');
}
return new EmbeddedFont(document, font, id);
}
}
export default PDFFontFactory;
================================================
FILE: packages/pdfkit/src/gradient.js
================================================
import PDFObject from './object';
const { number } = PDFObject;
class PDFGradient {
constructor(doc) {
this.doc = doc;
this.stops = [];
this.embedded = false;
this.transform = [1, 0, 0, 1, 0, 0];
}
stop(pos, color, opacity) {
if (opacity == null) {
opacity = 1;
}
color = this.doc._normalizeColor(color);
if (this.stops.length === 0) {
if (color.length === 3) {
this._colorSpace = 'DeviceRGB';
} else if (color.length === 4) {
this._colorSpace = 'DeviceCMYK';
} else if (color.length === 1) {
this._colorSpace = 'DeviceGray';
} else {
throw new Error('Unknown color space');
}
} else if (
(this._colorSpace === 'DeviceRGB' && color.length !== 3) ||
(this._colorSpace === 'DeviceCMYK' && color.length !== 4) ||
(this._colorSpace === 'DeviceGray' && color.length !== 1)
) {
throw new Error('All gradient stops must use the same color space');
}
opacity = Math.max(0, Math.min(1, opacity));
this.stops.push([pos, color, opacity]);
return this;
}
setTransform(m11, m12, m21, m22, dx, dy) {
this.transform = [m11, m12, m21, m22, dx, dy];
return this;
}
embed(m) {
let fn;
const stopsLength = this.stops.length;
if (stopsLength === 0) {
return;
}
this.embedded = true;
this.matrix = m;
// if the last stop comes before 100%, add a copy at 100%
const last = this.stops[stopsLength - 1];
if (last[0] < 1) {
this.stops.push([1, last[1], last[2]]);
}
const bounds = [];
const encode = [];
const stops = [];
for (let i = 0; i < stopsLength - 1; i++) {
encode.push(0, 1);
if (i + 2 !== stopsLength) {
bounds.push(this.stops[i + 1][0]);
}
fn = this.doc.ref({
FunctionType: 2,
Domain: [0, 1],
C0: this.stops[i + 0][1],
C1: this.stops[i + 1][1],
N: 1
});
stops.push(fn);
fn.end();
}
// if there are only two stops, we don't need a stitching function
if (stopsLength === 1) {
fn = stops[0];
} else {
fn = this.doc.ref({
FunctionType: 3, // stitching function
Domain: [0, 1],
Functions: stops,
Bounds: bounds,
Encode: encode
});
fn.end();
}
this.id = `Sh${++this.doc._gradCount}`;
const shader = this.shader(fn);
shader.end();
const pattern = this.doc.ref({
Type: 'Pattern',
PatternType: 2,
Shading: shader,
Matrix: this.matrix.map(number)
});
pattern.end();
if (this.stops.some((stop) => stop[2] < 1)) {
let grad = this.opacityGradient();
grad._colorSpace = 'DeviceGray';
for (let stop of this.stops) {
grad.stop(stop[0], [stop[2]]);
}
grad = grad.embed(this.matrix);
const pageBBox = [0, 0, this.doc.page.width, this.doc.page.height];
const form = this.doc.ref({
Type: 'XObject',
Subtype: 'Form',
FormType: 1,
BBox: pageBBox,
Group: {
Type: 'Group',
S: 'Transparency',
CS: 'DeviceGray'
},
Resources: {
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
Pattern: {
Sh1: grad
}
}
});
form.write('/Pattern cs /Sh1 scn');
form.end(`${pageBBox.join(' ')} re f`);
const gstate = this.doc.ref({
Type: 'ExtGState',
SMask: {
Type: 'Mask',
S: 'Luminosity',
G: form
}
});
gstate.end();
const opacityPattern = this.doc.ref({
Type: 'Pattern',
PatternType: 1,
PaintType: 1,
TilingType: 2,
BBox: pageBBox,
XStep: pageBBox[2],
YStep: pageBBox[3],
Resources: {
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
Pattern: {
Sh1: pattern
},
ExtGState: {
Gs1: gstate
}
}
});
opacityPattern.write('/Gs1 gs /Pattern cs /Sh1 scn');
opacityPattern.end(`${pageBBox.join(' ')} re f`);
this.doc.page.patterns[this.id] = opacityPattern;
} else {
this.doc.page.patterns[this.id] = pattern;
}
return pattern;
}
apply(stroke) {
// apply gradient transform to existing document ctm
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
const [m11, m12, m21, m22, dx, dy] = this.transform;
const m = [
m0 * m11 + m2 * m12,
m1 * m11 + m3 * m12,
m0 * m21 + m2 * m22,
m1 * m21 + m3 * m22,
m0 * dx + m2 * dy + m4,
m1 * dx + m3 * dy + m5
];
if (!this.embedded || m.join(' ') !== this.matrix.join(' ')) {
this.embed(m);
}
this.doc._setColorSpace('Pattern', stroke);
const op = stroke ? 'SCN' : 'scn';
return this.doc.addContent(`/${this.id} ${op}`);
}
}
class PDFLinearGradient extends PDFGradient {
constructor(doc, x1, y1, x2, y2) {
super(doc);
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
shader(fn) {
return this.doc.ref({
ShadingType: 2,
ColorSpace: this._colorSpace,
Coords: [this.x1, this.y1, this.x2, this.y2],
Function: fn,
Extend: [true, true]
});
}
opacityGradient() {
return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);
}
}
class PDFRadialGradient extends PDFGradient {
constructor(doc, x1, y1, r1, x2, y2, r2) {
super(doc);
this.doc = doc;
this.x1 = x1;
this.y1 = y1;
this.r1 = r1;
this.x2 = x2;
this.y2 = y2;
this.r2 = r2;
}
shader(fn) {
return this.doc.ref({
ShadingType: 3,
ColorSpace: this._colorSpace,
Coords: [this.x1, this.y1, this.r1, this.x2, this.y2, this.r2],
Function: fn,
Extend: [true, true]
});
}
opacityGradient() {
return new PDFRadialGradient(
this.doc,
this.x1,
this.y1,
this.r1,
this.x2,
this.y2,
this.r2
);
}
}
export default { PDFGradient, PDFLinearGradient, PDFRadialGradient };
================================================
FILE: packages/pdfkit/src/image/jpeg.js
================================================
import _JPEG from 'jay-peg';
const COLOR_SPACE_MAP = {
1: 'DeviceGray',
3: 'DeviceRGB',
4: 'DeviceCMYK'
};
class JPEG {
constructor(data, label) {
this.data = data;
this.label = label;
this.orientation = 1;
if (this.data.readUInt16BE(0) !== 0xffd8) {
throw 'SOI not found in JPEG';
}
const markers = _JPEG.decode(this.data);
for (let i = 0; i < markers.length; i += 1) {
const marker = markers[i];
if (marker.name === 'EXIF' && marker.entries.orientation) {
this.orientation = marker.entries.orientation;
}
if (marker.name === 'SOF') {
this.bits ||= marker.precision;
this.width ||= marker.width;
this.height ||= marker.height;
this.colorSpace ||= COLOR_SPACE_MAP[marker.numberOfComponents];
}
}
this.obj = null;
}
embed(document) {
if (this.obj) {
return;
}
this.obj = document.ref({
Type: 'XObject',
Subtype: 'Image',
BitsPerComponent: this.bits,
Width: this.width,
Height: this.height,
ColorSpace: this.colorSpace,
Filter: 'DCTDecode'
});
// add extra decode params for CMYK images. By swapping the
// min and max values from the default, we invert the colors. See
// section 4.8.4 of the spec.
if (this.colorSpace === 'DeviceCMYK') {
this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
}
this.obj.end(this.data);
// free memory
return (this.data = null);
}
}
export default JPEG;
================================================
FILE: packages/pdfkit/src/image/png.js
================================================
import zlib from 'zlib';
import PNG from '@react-pdf/png-js';
class PNGImage {
constructor(data, label) {
this.label = label;
this.image = new PNG(data);
this.width = this.image.width;
this.height = this.image.height;
this.imgData = this.image.imgData;
this.obj = null;
}
embed(document) {
let dataDecoded = false;
this.document = document;
if (this.obj) {
return;
}
const hasAlphaChannel = this.image.hasAlphaChannel;
const isInterlaced = this.image.interlaceMethod === 1;
this.obj = this.document.ref({
Type: 'XObject',
Subtype: 'Image',
BitsPerComponent: hasAlphaChannel ? 8 : this.image.bits,
Width: this.width,
Height: this.height,
Filter: 'FlateDecode'
});
if (!hasAlphaChannel) {
const params = this.document.ref({
Predictor: isInterlaced ? 1 : 15,
Colors: this.image.colors,
BitsPerComponent: this.image.bits,
Columns: this.width
});
this.obj.data.DecodeParms = params;
params.end();
}
if (this.image.palette.length === 0) {
this.obj.data.ColorSpace = this.image.colorSpace;
} else {
// embed the color palette in the PDF as an object stream
const palette = this.document.ref();
palette.end(Buffer.from(this.image.palette));
// build the color space array for the image
this.obj.data.ColorSpace = [
'Indexed',
'DeviceRGB',
this.image.palette.length / 3 - 1,
palette
];
}
// For PNG color types 0, 2 and 3, the transparency data is stored in
// a dedicated PNG chunk.
if (this.image.transparency.grayscale != null) {
// Use Color Key Masking (spec section 4.8.5)
// An array with N elements, where N is two times the number of color components.
const val = this.image.transparency.grayscale;
this.obj.data.Mask = [val, val];
} else if (this.image.transparency.rgb) {
// Use Color Key Masking (spec section 4.8.5)
// An array with N elements, where N is two times the number of color components.
const { rgb } = this.image.transparency;
const mask = [];
for (let x of rgb) {
mask.push(x, x);
}
this.obj.data.Mask = mask;
} else if (this.image.transparency.indexed) {
// Create a transparency SMask for the image based on the data
// in the PLTE and tRNS sections. See below for details on SMasks.
dataDecoded = true;
return this.loadIndexedAlphaChannel();
} else if (hasAlphaChannel) {
// For PNG color types 4 and 6, the transparency data is stored as a alpha
// channel mixed in with the main image data. Separate this data out into an
// SMask object and store it separately in the PDF.
dataDecoded = true;
return this.splitAlphaChannel();
}
if (isInterlaced && !dataDecoded) {
return this.decodeData();
}
this.finalize();
}
finalize() {
if (this.alphaChannel) {
const sMask = this.document.ref({
Type: 'XObject',
Subtype: 'Image',
Height: this.height,
Width: this.width,
BitsPerComponent: 8,
Filter: 'FlateDecode',
ColorSpace: 'DeviceGray',
Decode: [0, 1]
});
sMask.end(this.alphaChannel);
this.obj.data.SMask = sMask;
}
// add the actual image data
this.obj.end(this.imgData);
// free memory
this.image = null;
return (this.imgData = null);
}
splitAlphaChannel() {
return this.image.decodePixels((pixels) => {
let a;
let p;
const colorCount = this.image.colors;
const pixelCount = this.width * this.height;
const imgData = Buffer.alloc(pixelCount * colorCount);
const alphaChannel = Buffer.alloc(pixelCount);
let i = (p = a = 0);
const len = pixels.length;
// For 16bit images copy only most significant byte (MSB) - PNG data is always stored in network byte order (MSB first)
const skipByteCount = this.image.bits === 16 ? 1 : 0;
while (i < len) {
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
imgData[p++] = pixels[i++];
i += skipByteCount;
}
alphaChannel[a++] = pixels[i++];
i += skipByteCount;
}
this.imgData = zlib.deflateSync(imgData);
this.alphaChannel = zlib.deflateSync(alphaChannel);
return this.finalize();
});
}
loadIndexedAlphaChannel() {
const transparency = this.image.transparency.indexed;
return this.image.decodePixels((pixels) => {
const alphaChannel = Buffer.alloc(this.width * this.height);
let i = 0;
for (let j = 0, end = pixels.length; j < end; j++) {
alphaChannel[i++] = transparency[pixels[j]];
}
this.alphaChannel = zlib.deflateSync(alphaChannel);
return this.finalize();
});
}
decodeData() {
this.image.decodePixels((pixels) => {
this.imgData = zlib.deflateSync(pixels);
this.finalize();
});
}
}
export default PNGImage;
================================================
FILE: packages/pdfkit/src/image.js
================================================
/*
PDFImage - embeds images in PDF documents
By Devon Govett
*/
import fs from 'fs';
import JPEG from './image/jpeg';
import PNG from './image/png';
class PDFImage {
static open(src, label) {
let data;
if (Buffer.isBuffer(src)) {
data = src;
} else if (src instanceof ArrayBuffer) {
data = Buffer.from(new Uint8Array(src));
} else {
let match;
if ((match = /^data:.+?;base64,(.*)$/.exec(src))) {
data = Buffer.from(match[1], 'base64');
} else {
data = fs.readFileSync(src);
if (!data) {
return;
}
}
}
if (data[0] === 0xff && data[1] === 0xd8) {
return new JPEG(data, label);
} else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') {
return new PNG(data, label);
} else {
throw new Error('Unknown image format.');
}
}
}
export default PDFImage;
================================================
FILE: packages/pdfkit/src/index.js
================================================
import PDFDocument from './document';
export * from './font';
export default PDFDocument;
================================================
FILE: packages/pdfkit/src/line_wrapper.js
================================================
import { EventEmitter } from 'events';
import LineBreaker from 'linebreak';
import { PDFNumber } from './utils';
const SOFT_HYPHEN = '\u00AD';
const HYPHEN = '-';
class LineWrapper extends EventEmitter {
constructor(document, options) {
super();
this.document = document;
this.horizontalScaling = options.horizontalScaling || 100;
this.indent = ((options.indent || 0) * this.horizontalScaling) / 100;
this.characterSpacing =
((options.characterSpacing || 0) * this.horizontalScaling) / 100;
this.wordSpacing =
((options.wordSpacing === 0) * this.horizontalScaling) / 100;
this.columns = options.columns || 1;
this.columnGap =
((options.columnGap != null ? options.columnGap : 18) *
this.horizontalScaling) /
100; // 1/4 inch
this.lineWidth =
((options.width * this.horizontalScaling) / 100 -
this.columnGap * (this.columns - 1)) /
this.columns;
this.spaceLeft = this.lineWidth;
this.startX = this.document.x;
this.startY = this.document.y;
this.column = 1;
this.ellipsis = options.ellipsis;
this.continuedX = 0;
this.features = options.features;
// calculate the maximum Y position the text can appear at
if (options.height != null) {
this.height = options.height;
this.maxY = PDFNumber(this.startY + options.height);
} else {
this.maxY = PDFNumber(this.document.page.maxY());
}
// handle paragraph indents
this.on('firstLine', (options) => {
// if this is the first line of the text segment, and
// we're continuing where we left off, indent that much
// otherwise use the user specified indent option
const indent = this.continuedX || this.indent;
this.document.x += indent;
this.lineWidth -= indent;
// if indentAllLines is set to true
// we're not resetting the indentation for this paragraph after the first line
if (options.indentAllLines) {
return;
}
// otherwise we start the next line without indent
return this.once('line', () => {
this.document.x -= indent;
this.lineWidth += indent;
if (options.continued && !this.continuedX) {
this.continuedX = this.indent;
}
if (!options.continued) {
return (this.continuedX = 0);
}
});
});
// handle left aligning last lines of paragraphs
this.on('lastLine', (options) => {
const { align } = options;
if (align === 'justify') {
options.align = 'left';
}
this.lastLine = true;
return this.once('line', () => {
this.document.y += options.paragraphGap || 0;
options.align = align;
return (this.lastLine = false);
});
});
}
wordWidth(word) {
return (
this.document.widthOfString(word, this) +
this.characterSpacing +
this.wordSpacing
);
}
canFit(word, w) {
if (word[word.length - 1] != SOFT_HYPHEN) {
return w <= this.spaceLeft;
}
return w + this.wordWidth(HYPHEN) <= this.spaceLeft;
}
eachWord(text, fn) {
// setup a unicode line breaker
let bk;
const breaker = new LineBreaker(text);
let last = null;
const wordWidths = Object.create(null);
while ((bk = breaker.nextBreak())) {
var shouldContinue;
let word = text.slice(
(last != null ? last.position : undefined) || 0,
bk.position
);
let w =
wordWidths[word] != null
? wordWidths[word]
: (wordWidths[word] = this.wordWidth(word));
// if the word is longer than the whole line, chop it up
// TODO: break by grapheme clusters, not JS string characters
if (w > this.lineWidth + this.continuedX) {
// make some fake break objects
let lbk = last;
const fbk = {};
while (word.length) {
// fit as much of the word as possible into the space we have
var l, mightGrow;
if (w > this.spaceLeft) {
// start our check at the end of our available space - this method is faster than a loop of each character and it resolves
// an issue with long loops when processing massive words, such as a huge number of spaces
l = Math.ceil(this.spaceLeft / (w / word.length));
w = this.wordWidth(word.slice(0, l));
mightGrow = w <= this.spaceLeft && l < word.length;
} else {
l = word.length;
}
let mustShrink = w > this.spaceLeft && l > 0;
// shrink or grow word as necessary after our near-guess above
while (mustShrink || mightGrow) {
if (mustShrink) {
w = this.wordWidth(word.slice(0, --l));
mustShrink = w > this.spaceLeft && l > 0;
} else {
w = this.wordWidth(word.slice(0, ++l));
mustShrink = w > this.spaceLeft && l > 0;
mightGrow = w <= this.spaceLeft && l < word.length;
}
}
// check for the edge case where a single character cannot fit into a line.
if (l === 0 && this.spaceLeft === this.lineWidth) {
l = 1;
}
// send a required break unless this is the last piece and a linebreak is not specified
fbk.required = bk.required || l < word.length;
shouldContinue = fn(word.slice(0, l), w, fbk, lbk);
lbk = { required: false };
// get the remaining piece of the word
word = word.slice(l);
w = this.wordWidth(word);
if (shouldContinue === false) {
break;
}
}
} else {
// otherwise just emit the break as it was given to us
shouldContinue = fn(word, w, bk, last);
}
if (shouldContinue === false) {
break;
}
last = bk;
}
}
wrap(text, options) {
// override options from previous continued fragments
this.horizontalScaling = options.horizontalScaling || 100;
if (options.indent != null) {
this.indent = (options.indent * this.horizontalScaling) / 100;
}
if (options.characterSpacing != null) {
this.characterSpacing =
(options.characterSpacing * this.horizontalScaling) / 100;
}
if (options.wordSpacing != null) {
this.wordSpacing = (options.wordSpacing * this.horizontalScaling) / 100;
}
if (options.ellipsis != null) {
this.ellipsis = options.ellipsis;
}
// make sure we're actually on the page
// and that the first line of is never by
// itself at the bottom of a page (orphans)
const nextY = this.document.y + this.document.currentLineHeight(true);
if (this.document.y > this.maxY || nextY > this.maxY) {
this.nextSection();
}
let buffer = '';
let textWidth = 0;
let wc = 0;
let lc = 0;
let { y } = this.document; // used to reset Y pos if options.continued (below)
const emitLine = () => {
options.textWidth = textWidth + this.wordSpacing * (wc - 1);
options.wordCount = wc;
options.lineWidth = this.lineWidth;
({ y } = this.document);
this.emit('line', buffer, options, this);
return lc++;
};
this.emit('sectionStart', options, this);
this.eachWord(text, (word, w, bk, last) => {
if (last == null || last.required) {
this.emit('firstLine', options, this);
this.spaceLeft = this.lineWidth;
}
if (this.canFit(word, w)) {
buffer += word;
textWidth += w;
wc++;
}
if (bk.required || !this.canFit(word, w)) {
// if the user specified a max height and an ellipsis, and is about to pass the
// max height and max columns after the next line, append the ellipsis
const lh = this.document.currentLineHeight(true);
if (
this.height != null &&
this.ellipsis &&
PDFNumber(this.document.y + lh * 2) > this.maxY &&
this.column >= this.columns
) {
if (this.ellipsis === true) {
this.ellipsis = '…';
} // map default ellipsis character
buffer = buffer.replace(/\s+$/, '');
textWidth = this.wordWidth(buffer + this.ellipsis);
// remove characters from the buffer until the ellipsis fits
// to avoid infinite loop need to stop while-loop if buffer is empty string
while (buffer && textWidth > this.lineWidth) {
buffer = buffer.slice(0, -1).replace(/\s+$/, '');
textWidth = this.wordWidth(buffer + this.ellipsis);
}
// need to add ellipsis only if there is enough space for it
if (textWidth <= this.lineWidth) {
buffer = buffer + this.ellipsis;
}
textWidth = this.wordWidth(buffer);
}
if (bk.required) {
if (w > this.spaceLeft) {
emitLine();
buffer = word;
textWidth = w;
wc = 1;
}
this.emit('lastLine', options, this);
}
// Previous entry is a soft hyphen - add visible hyphen.
if (buffer[buffer.length - 1] == SOFT_HYPHEN) {
buffer = buffer.slice(0, -1) + HYPHEN;
this.spaceLeft -= this.wordWidth(HYPHEN);
}
emitLine();
// if we've reached the edge of the page,
// continue on a new page or column
if (PDFNumber(this.document.y + lh) > this.maxY) {
const shouldContinue = this.nextSection();
// stop if we reached the maximum height
if (!shouldContinue) {
wc = 0;
buffer = '';
return false;
}
}
// reset the space left and buffer
if (bk.required) {
this.spaceLeft = this.lineWidth;
buffer = '';
textWidth = 0;
return (wc = 0);
} else {
// reset the space left and buffer
this.spaceLeft = this.lineWidth - w;
buffer = word;
textWidth = w;
return (wc = 1);
}
} else {
return (this.spaceLeft -= w);
}
});
if (wc > 0) {
this.emit('lastLine', options, this);
emitLine();
}
this.emit('sectionEnd', options, this);
// if the wrap is set to be continued, save the X position
// to start the first line of the next segment at, and reset
// the y position
if (options.continued === true) {
if (lc > 1) {
this.continuedX = 0;
}
this.continuedX += options.textWidth || 0;
return (this.document.y = y);
} else {
return (this.document.x = this.startX);
}
}
nextSection(options) {
this.emit('sectionEnd', options, this);
if (++this.column > this.columns) {
// if a max height was specified by the user, we're done.
// otherwise, the default is to make a new page at the bottom.
if (this.height != null) {
return false;
}
this.document.continueOnNewPage();
this.column = 1;
this.startY = this.document.page.margins.top;
this.maxY = this.document.page.maxY();
this.document.x = this.startX;
if (this.document._fillColor) {
this.document.fillColor(...this.document._fillColor);
}
this.emit('pageBreak', options, this);
} else {
this.document.x += this.lineWidth + this.columnGap;
this.document.y = this.startY;
this.emit('columnBreak', options, this);
}
this.emit('sectionStart', options, this);
return true;
}
}
export default LineWrapper;
================================================
FILE: packages/pdfkit/src/metadata.js
================================================
class PDFMetadata {
constructor() {
this._metadata = `
`;
}
_closeTags() {
this._metadata = this._metadata.concat(`
`);
}
append(xml, newline = true) {
this._metadata = this._metadata.concat(xml);
if (newline) this._metadata = this._metadata.concat('\n');
}
getXML() {
return this._metadata;
}
getLength() {
return this._metadata.length;
}
end() {
this._closeTags();
this._metadata = this._metadata.trim();
}
}
export default PDFMetadata;
================================================
FILE: packages/pdfkit/src/mixins/acroform.js
================================================
const FIELD_FLAGS = {
readOnly: 1,
required: 2,
noExport: 4,
multiline: 0x1000,
password: 0x2000,
toggleToOffButton: 0x4000,
radioButton: 0x8000,
pushButton: 0x10000,
combo: 0x20000,
edit: 0x40000,
sort: 0x80000,
multiSelect: 0x200000,
noSpell: 0x400000
};
const FIELD_JUSTIFY = {
left: 0,
center: 1,
right: 2
};
const VALUE_MAP = { value: 'V', defaultValue: 'DV' };
const FORMAT_SPECIAL = {
zip: '0',
zipPlus4: '1',
zip4: '1',
phone: '2',
ssn: '3'
};
const FORMAT_DEFAULT = {
number: {
nDec: 0,
sepComma: false,
negStyle: 'MinusBlack',
currency: '',
currencyPrepend: true
},
percent: {
nDec: 0,
sepComma: false
}
};
export default {
/**
* Must call if adding AcroForms to a document. Must also call font() before
* this method to set the default font.
*/
initForm() {
if (!this._font) {
throw new Error('Must set a font before calling initForm method');
}
this._acroform = {
fonts: {},
defaultFont: this._font.name
};
this._acroform.fonts[this._font.id] = this._font.ref();
let data = {
Fields: [],
NeedAppearances: true,
DA: new String(`/${this._font.id} 0 Tf 0 g`),
DR: {
Font: {}
}
};
data.DR.Font[this._font.id] = this._font.ref();
const AcroForm = this.ref(data);
this._root.data.AcroForm = AcroForm;
return this;
},
/**
* Called automatically by document.js
*/
endAcroForm() {
if (this._root.data.AcroForm) {
if (
!Object.keys(this._acroform.fonts).length &&
!this._acroform.defaultFont
) {
throw new Error('No fonts specified for PDF form');
}
let fontDict = this._root.data.AcroForm.data.DR.Font;
Object.keys(this._acroform.fonts).forEach((name) => {
fontDict[name] = this._acroform.fonts[name];
});
this._root.data.AcroForm.data.Fields.forEach((fieldRef) => {
this._endChild(fieldRef);
});
this._root.data.AcroForm.end();
}
return this;
},
_endChild(ref) {
if (Array.isArray(ref.data.Kids)) {
ref.data.Kids.forEach((childRef) => {
this._endChild(childRef);
});
ref.end();
}
return this;
},
/**
* Creates and adds a form field to the document. Form fields are intermediate
* nodes in a PDF form that are used to specify form name heirarchy and form
* value defaults.
* @param {string} name - field name (T attribute in field dictionary)
* @param {object} options - other attributes to include in field dictionary
*/
formField(name, options = {}) {
let fieldDict = this._fieldDict(name, null, options);
let fieldRef = this.ref(fieldDict);
this._addToParent(fieldRef);
return fieldRef;
},
/**
* Creates and adds a Form Annotation to the document. Form annotations are
* called Widget annotations internally within a PDF file.
* @param {string} name - form field name (T attribute of widget annotation
* dictionary)
* @param {number} x
* @param {number} y
* @param {number} w
* @param {number} h
* @param {object} options
*/
formAnnotation(name, type, x, y, w, h, options = {}) {
let fieldDict = this._fieldDict(name, type, options);
fieldDict.Subtype = 'Widget';
if (fieldDict.F === undefined) {
fieldDict.F = 4; // print the annotation
}
// Add Field annot to page, and get it's ref
this.annotate(x, y, w, h, fieldDict);
let annotRef = this.page.annotations[this.page.annotations.length - 1];
return this._addToParent(annotRef);
},
formText(name, x, y, w, h, options = {}) {
return this.formAnnotation(name, 'text', x, y, w, h, options);
},
formPushButton(name, x, y, w, h, options = {}) {
return this.formAnnotation(name, 'pushButton', x, y, w, h, options);
},
formCombo(name, x, y, w, h, options = {}) {
return this.formAnnotation(name, 'combo', x, y, w, h, options);
},
formList(name, x, y, w, h, options = {}) {
return this.formAnnotation(name, 'list', x, y, w, h, options);
},
formRadioButton(name, x, y, w, h, options = {}) {
return this.formAnnotation(name, 'radioButton', x, y, w, h, options);
},
formCheckbox(name, x, y, w, h, options = {}) {
return this.formAnnotation(name, 'checkbox', x, y, w, h, options);
},
_addToParent(fieldRef) {
let parent = fieldRef.data.Parent;
if (parent) {
if (!parent.data.Kids) {
parent.data.Kids = [];
}
parent.data.Kids.push(fieldRef);
} else {
this._root.data.AcroForm.data.Fields.push(fieldRef);
}
return this;
},
_fieldDict(name, type, options = {}) {
if (!this._acroform) {
throw new Error(
'Call document.initForm() method before adding form elements to document'
);
}
let opts = Object.assign({}, options);
if (type !== null) {
opts = this._resolveType(type, options);
}
opts = this._resolveFlags(opts);
opts = this._resolveJustify(opts);
opts = this._resolveFont(opts);
opts = this._resolveStrings(opts);
opts = this._resolveColors(opts);
opts = this._resolveFormat(opts);
opts.T = new String(name);
if (opts.parent) {
opts.Parent = opts.parent;
delete opts.parent;
}
return opts;
},
_resolveType(type, opts) {
if (type === 'text') {
opts.FT = 'Tx';
} else if (type === 'pushButton') {
opts.FT = 'Btn';
opts.pushButton = true;
} else if (type === 'radioButton') {
opts.FT = 'Btn';
opts.radioButton = true;
} else if (type === 'checkbox') {
opts.FT = 'Btn';
} else if (type === 'combo') {
opts.FT = 'Ch';
opts.combo = true;
} else if (type === 'list') {
opts.FT = 'Ch';
} else {
throw new Error(`Invalid form annotation type '${type}'`);
}
return opts;
},
_resolveFormat(opts) {
const f = opts.format;
if (f && f.type) {
let fnKeystroke;
let fnFormat;
let params = '';
if (FORMAT_SPECIAL[f.type] !== undefined) {
fnKeystroke = `AFSpecial_Keystroke`;
fnFormat = `AFSpecial_Format`;
params = FORMAT_SPECIAL[f.type];
} else {
let format = f.type.charAt(0).toUpperCase() + f.type.slice(1);
fnKeystroke = `AF${format}_Keystroke`;
fnFormat = `AF${format}_Format`;
if (f.type === 'date') {
fnKeystroke += 'Ex';
params = String(f.param);
} else if (f.type === 'time') {
params = String(f.param);
} else if (f.type === 'number') {
let p = Object.assign({}, FORMAT_DEFAULT.number, f);
params = String(
[
String(p.nDec),
p.sepComma ? '0' : '1',
'"' + p.negStyle + '"',
'null',
'"' + p.currency + '"',
String(p.currencyPrepend)
].join(',')
);
} else if (f.type === 'percent') {
let p = Object.assign({}, FORMAT_DEFAULT.percent, f);
params = String([String(p.nDec), p.sepComma ? '0' : '1'].join(','));
}
}
opts.AA = opts.AA ? opts.AA : {};
opts.AA.K = {
S: 'JavaScript',
JS: new String(`${fnKeystroke}(${params});`)
};
opts.AA.F = {
S: 'JavaScript',
JS: new String(`${fnFormat}(${params});`)
};
}
delete opts.format;
return opts;
},
_resolveColors(opts) {
let color = this._normalizeColor(opts.backgroundColor);
if (color) {
if (!opts.MK) {
opts.MK = {};
}
opts.MK.BG = color;
}
color = this._normalizeColor(opts.borderColor);
if (color) {
if (!opts.MK) {
opts.MK = {};
}
opts.MK.BC = color;
}
delete opts.backgroundColor;
delete opts.borderColor;
return opts;
},
_resolveFlags(options) {
let result = 0;
Object.keys(options).forEach((key) => {
if (FIELD_FLAGS[key]) {
if (options[key]) {
result |= FIELD_FLAGS[key];
}
delete options[key];
}
});
if (result !== 0) {
options.Ff = options.Ff ? options.Ff : 0;
options.Ff |= result;
}
return options;
},
_resolveJustify(options) {
let result = 0;
if (options.align !== undefined) {
if (typeof FIELD_JUSTIFY[options.align] === 'number') {
result = FIELD_JUSTIFY[options.align];
}
delete options.align;
}
if (result !== 0) {
options.Q = result; // default
}
return options;
},
_resolveFont(options) {
// add current font to document-level AcroForm dict if necessary
if (this._acroform.fonts[this._font.id] == null) {
this._acroform.fonts[this._font.id] = this._font.ref();
}
// add current font to field's resource dict (RD) if not the default acroform font
if (this._acroform.defaultFont !== this._font.name) {
options.DR = { Font: {} };
// Get the fontSize option. If not set use auto sizing
const fontSize = options.fontSize || 0;
options.DR.Font[this._font.id] = this._font.ref();
options.DA = new String(`/${this._font.id} ${fontSize} Tf 0 g`);
}
return options;
},
_resolveStrings(options) {
let select = [];
function appendChoices(a) {
if (Array.isArray(a)) {
for (let idx = 0; idx < a.length; idx++) {
if (typeof a[idx] === 'string') {
select.push(new String(a[idx]));
} else {
select.push(a[idx]);
}
}
}
}
appendChoices(options.Opt);
if (options.select) {
appendChoices(options.select);
delete options.select;
}
if (select.length) {
options.Opt = select;
}
Object.keys(VALUE_MAP).forEach((key) => {
if (options[key] !== undefined) {
options[VALUE_MAP[key]] = options[key];
delete options[key];
}
});
['V', 'DV'].forEach((key) => {
if (typeof options[key] === 'string') {
options[key] = new String(options[key]);
}
});
if (options.MK && options.MK.CA) {
options.MK.CA = new String(options.MK.CA);
}
if (options.label) {
options.MK = options.MK ? options.MK : {};
options.MK.CA = new String(options.label);
delete options.label;
}
return options;
}
};
================================================
FILE: packages/pdfkit/src/mixins/annotations.js
================================================
export default {
annotate(x, y, w, h, options) {
options.Type = 'Annot';
options.Rect = this._convertRect(x, y, w, h);
options.Border = [0, 0, 0];
if (options.Subtype === 'Link' && typeof options.F === 'undefined') {
options.F = 1 << 2; // Print Annotation Flag
}
if (options.Subtype !== 'Link') {
if (options.C == null) {
options.C = this._normalizeColor(options.color || [0, 0, 0]);
}
} // convert colors
delete options.color;
if (typeof options.Dest === 'string') {
options.Dest = new String(options.Dest);
}
// Capitalize keys
for (let key in options) {
const val = options[key];
options[key[0].toUpperCase() + key.slice(1)] = val;
}
const ref = this.ref(options);
this.page.annotations.push(ref);
ref.end();
return this;
},
note(x, y, w, h, contents, options = {}) {
options.Subtype = 'Text';
options.Contents = new String(contents);
if (options.Name == null) {
options.Name = 'Comment';
}
if (options.color == null) {
options.color = [243, 223, 92];
}
return this.annotate(x, y, w, h, options);
},
goTo(x, y, w, h, name, options = {}) {
options.Subtype = 'Link';
options.A = this.ref({
S: 'GoTo',
D: new String(name)
});
options.A.end();
return this.annotate(x, y, w, h, options);
},
link(x, y, w, h, url, options = {}) {
options.Subtype = 'Link';
if (typeof url === 'number') {
// Link to a page in the document (the page must already exist)
const pages = this._root.data.Pages.data;
if (url >= 0 && url < pages.Kids.length) {
options.A = this.ref({
S: 'GoTo',
D: [pages.Kids[url], 'XYZ', null, null, null]
});
options.A.end();
} else {
throw new Error(`The document has no page ${url}`);
}
} else {
// Link to an external url
options.A = this.ref({
S: 'URI',
URI: new String(url)
});
options.A.end();
}
return this.annotate(x, y, w, h, options);
},
_markup(x, y, w, h, options = {}) {
const [x1, y1, x2, y2] = this._convertRect(x, y, w, h);
options.QuadPoints = [x1, y2, x2, y2, x1, y1, x2, y1];
options.Contents = new String();
return this.annotate(x, y, w, h, options);
},
highlight(x, y, w, h, options = {}) {
options.Subtype = 'Highlight';
if (options.color == null) {
options.color = [241, 238, 148];
}
return this._markup(x, y, w, h, options);
},
underline(x, y, w, h, options = {}) {
options.Subtype = 'Underline';
return this._markup(x, y, w, h, options);
},
strike(x, y, w, h, options = {}) {
options.Subtype = 'StrikeOut';
return this._markup(x, y, w, h, options);
},
lineAnnotation(x1, y1, x2, y2, options = {}) {
options.Subtype = 'Line';
options.Contents = new String();
options.L = [x1, this.page.height - y1, x2, this.page.height - y2];
return this.annotate(x1, y1, x2, y2, options);
},
rectAnnotation(x, y, w, h, options = {}) {
options.Subtype = 'Square';
options.Contents = new String();
return this.annotate(x, y, w, h, options);
},
ellipseAnnotation(x, y, w, h, options = {}) {
options.Subtype = 'Circle';
options.Contents = new String();
return this.annotate(x, y, w, h, options);
},
textAnnotation(x, y, w, h, text, options = {}) {
options.Subtype = 'FreeText';
options.Contents = new String(text);
options.DA = new String();
return this.annotate(x, y, w, h, options);
},
fileAnnotation(x, y, w, h, file = {}, options = {}) {
// create hidden file
const filespec = this.file(file.src, Object.assign({ hidden: true }, file));
options.Subtype = 'FileAttachment';
options.FS = filespec;
// add description from filespec unless description (Contents) has already been set
if (options.Contents) {
options.Contents = new String(options.Contents);
} else if (filespec.data.Desc) {
options.Contents = filespec.data.Desc;
}
return this.annotate(x, y, w, h, options);
},
_convertRect(x1, y1, w, h) {
// flip y1 and y2
let y2 = y1;
y1 += h;
// make x2
let x2 = x1 + w;
// apply current transformation matrix to points
const [m0, m1, m2, m3, m4, m5] = this._ctm;
x1 = m0 * x1 + m2 * y1 + m4;
y1 = m1 * x1 + m3 * y1 + m5;
x2 = m0 * x2 + m2 * y2 + m4;
y2 = m1 * x2 + m3 * y2 + m5;
return [x1, y1, x2, y2];
}
};
================================================
FILE: packages/pdfkit/src/mixins/attachments.js
================================================
import fs from 'fs';
import CryptoJS from 'crypto-js';
export default {
/**
* Embed contents of `src` in PDF
* @param {Buffer | ArrayBuffer | string} src input Buffer, ArrayBuffer, base64 encoded string or path to file
* @param {object} options
* * options.name: filename to be shown in PDF, will use `src` if none set
* * options.type: filetype to be shown in PDF
* * options.description: description to be shown in PDF
* * options.hidden: if true, do not add attachment to EmbeddedFiles dictionary. Useful for file attachment annotations
* * options.creationDate: override creation date
* * options.modifiedDate: override modified date
* * options.relationship: Relationship between the PDF document and its attached file. Can be 'Alternative', 'Data', 'Source', 'Supplement' or 'Unspecified'.
* @returns filespec reference
*/
file(src, options = {}) {
options.name = options.name || src;
options.relationship = options.relationship || 'Unspecified';
const refBody = {
Type: 'EmbeddedFile',
Params: {}
};
let data;
if (!src) {
throw new Error('No src specified');
}
if (Buffer.isBuffer(src)) {
data = src;
} else if (src instanceof ArrayBuffer) {
data = Buffer.from(new Uint8Array(src));
} else {
let match;
if ((match = /^data:(.*?);base64,(.*)$/.exec(src))) {
if (match[1]) {
refBody.Subtype = match[1].replace('/', '#2F');
}
data = Buffer.from(match[2], 'base64');
} else {
data = fs.readFileSync(src);
if (!data) {
throw new Error(`Could not read contents of file at filepath ${src}`);
}
// update CreationDate and ModDate
const { birthtime, ctime } = fs.statSync(src);
refBody.Params.CreationDate = birthtime;
refBody.Params.ModDate = ctime;
}
}
// override creation date and modified date
if (options.creationDate instanceof Date) {
refBody.Params.CreationDate = options.creationDate;
}
if (options.modifiedDate instanceof Date) {
refBody.Params.ModDate = options.modifiedDate;
}
// add optional subtype
if (options.type) {
refBody.Subtype = options.type.replace('/', '#2F');
}
// add checksum and size information
const checksum = CryptoJS.MD5(
CryptoJS.lib.WordArray.create(new Uint8Array(data))
);
refBody.Params.CheckSum = new String(checksum);
refBody.Params.Size = data.byteLength;
// save some space when embedding the same file again
// if a file with the same name and metadata exists, reuse its reference
let ref;
if (!this._fileRegistry) this._fileRegistry = {};
let file = this._fileRegistry[options.name];
if (file && isEqual(refBody, file)) {
ref = file.ref;
} else {
ref = this.ref(refBody);
ref.end(data);
this._fileRegistry[options.name] = { ...refBody, ref };
}
// add filespec for embedded file
const fileSpecBody = {
Type: 'Filespec',
AFRelationship: options.relationship,
F: new String(options.name),
EF: { F: ref },
UF: new String(options.name)
};
if (options.description) {
fileSpecBody.Desc = new String(options.description);
}
const filespec = this.ref(fileSpecBody);
filespec.end();
if (!options.hidden) {
this.addNamedEmbeddedFile(options.name, filespec);
}
// Add file to the catalogue to be PDF/A3 compliant
if (this._root.data.AF) {
this._root.data.AF.push(filespec);
} else {
this._root.data.AF = [filespec];
}
return filespec;
}
};
/** check two embedded file metadata objects for equality */
function isEqual(a, b) {
return (
a.Subtype === b.Subtype &&
a.Params.CheckSum.toString() === b.Params.CheckSum.toString() &&
a.Params.Size === b.Params.Size &&
a.Params.CreationDate.getTime() === b.Params.CreationDate.getTime() &&
((a.Params.ModDate === undefined && b.Params.ModDate === undefined) ||
a.Params.ModDate.getTime() === b.Params.ModDate.getTime())
);
}
================================================
FILE: packages/pdfkit/src/mixins/color.js
================================================
import Gradient from '../gradient';
import pattern from '../pattern';
import SpotColor from '../spotcolor';
const { PDFGradient, PDFLinearGradient, PDFRadialGradient } = Gradient;
const { PDFTilingPattern } = pattern;
export default {
initColor() {
this.spotColors = {};
// The opacity dictionaries
this._opacityRegistry = {};
this._opacityCount = 0;
this._patternCount = 0;
return (this._gradCount = 0);
},
_normalizeColor(color) {
if (typeof color === 'string') {
if (color.charAt(0) === '#') {
if (color.length === 4) {
color = color.replace(
/#([0-9A-F])([0-9A-F])([0-9A-F])/i,
'#$1$1$2$2$3$3'
);
}
const hex = parseInt(color.slice(1), 16);
color = [hex >> 16, (hex >> 8) & 0xff, hex & 0xff];
} else if (namedColors[color]) {
color = namedColors[color];
} else if (this.spotColors[color]) {
return this.spotColors[color];
}
}
if (Array.isArray(color)) {
// RGB
if (color.length === 3) {
color = color.map((part) => part / 255);
// CMYK
} else if (color.length === 4) {
color = color.map((part) => part / 100);
}
return color;
}
return null;
},
_setColor(color, stroke) {
if (color instanceof PDFGradient) {
color.apply(stroke);
return true;
// see if tiling pattern, decode & apply it it
} else if (Array.isArray(color) && color[0] instanceof PDFTilingPattern) {
color[0].apply(stroke, color[1]);
return true;
}
// any other case should be a normal color and not a pattern
return this._setColorCore(color, stroke);
},
_setColorCore(color, stroke) {
color = this._normalizeColor(color);
if (!color) {
return false;
}
const op = stroke ? 'SCN' : 'scn';
const space = this._getColorSpace(color);
this._setColorSpace(space, stroke);
if (color instanceof SpotColor) {
this.page.colorSpaces[color.id] = color.ref;
this.addContent(`1 ${op}`);
} else {
this.addContent(`${color.join(' ')} ${op}`);
}
return true;
},
_setColorSpace(space, stroke) {
const op = stroke ? 'CS' : 'cs';
return this.addContent(`/${space} ${op}`);
},
_getColorSpace(color) {
if (color instanceof SpotColor) {
return color.id;
}
return color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';
},
fillColor(color, opacity) {
const set = this._setColor(color, false);
if (set) {
this.fillOpacity(opacity);
}
// save this for text wrapper, which needs to reset
// the fill color on new pages
this._fillColor = [color, opacity];
return this;
},
strokeColor(color, opacity) {
const set = this._setColor(color, true);
if (set) {
this.strokeOpacity(opacity);
}
return this;
},
opacity(opacity) {
this._doOpacity(opacity, opacity);
return this;
},
fillOpacity(opacity) {
this._doOpacity(opacity, null);
return this;
},
strokeOpacity(opacity) {
this._doOpacity(null, opacity);
return this;
},
_doOpacity(fillOpacity, strokeOpacity) {
let dictionary, name;
if (fillOpacity == null && strokeOpacity == null) {
return;
}
if (fillOpacity != null) {
fillOpacity = Math.max(0, Math.min(1, fillOpacity));
}
if (strokeOpacity != null) {
strokeOpacity = Math.max(0, Math.min(1, strokeOpacity));
}
const key = `${fillOpacity}_${strokeOpacity}`;
if (this._opacityRegistry[key]) {
[dictionary, name] = this._opacityRegistry[key];
} else {
dictionary = { Type: 'ExtGState' };
if (fillOpacity != null) {
dictionary.ca = fillOpacity;
}
if (strokeOpacity != null) {
dictionary.CA = strokeOpacity;
}
dictionary = this.ref(dictionary);
dictionary.end();
const id = ++this._opacityCount;
name = `Gs${id}`;
this._opacityRegistry[key] = [dictionary, name];
}
this.page.ext_gstates[name] = dictionary;
return this.addContent(`/${name} gs`);
},
linearGradient(x1, y1, x2, y2) {
return new PDFLinearGradient(this, x1, y1, x2, y2);
},
radialGradient(x1, y1, r1, x2, y2, r2) {
return new PDFRadialGradient(this, x1, y1, r1, x2, y2, r2);
},
pattern(bbox, xStep, yStep, stream) {
return new PDFTilingPattern(this, bbox, xStep, yStep, stream);
},
addSpotColor(name, C, M, Y, K) {
const color = new SpotColor(this, name, C, M, Y, K);
this.spotColors[name] = color;
return this;
}
};
var namedColors = {
aliceblue: [240, 248, 255],
antiquewhite: [250, 235, 215],
aqua: [0, 255, 255],
aquamarine: [127, 255, 212],
azure: [240, 255, 255],
beige: [245, 245, 220],
bisque: [255, 228, 196],
black: [0, 0, 0],
blanchedalmond: [255, 235, 205],
blue: [0, 0, 255],
blueviolet: [138, 43, 226],
brown: [165, 42, 42],
burlywood: [222, 184, 135],
cadetblue: [95, 158, 160],
chartreuse: [127, 255, 0],
chocolate: [210, 105, 30],
coral: [255, 127, 80],
cornflowerblue: [100, 149, 237],
cornsilk: [255, 248, 220],
crimson: [220, 20, 60],
cyan: [0, 255, 255],
darkblue: [0, 0, 139],
darkcyan: [0, 139, 139],
darkgoldenrod: [184, 134, 11],
darkgray: [169, 169, 169],
darkgreen: [0, 100, 0],
darkgrey: [169, 169, 169],
darkkhaki: [189, 183, 107],
darkmagenta: [139, 0, 139],
darkolivegreen: [85, 107, 47],
darkorange: [255, 140, 0],
darkorchid: [153, 50, 204],
darkred: [139, 0, 0],
darksalmon: [233, 150, 122],
darkseagreen: [143, 188, 143],
darkslateblue: [72, 61, 139],
darkslategray: [47, 79, 79],
darkslategrey: [47, 79, 79],
darkturquoise: [0, 206, 209],
darkviolet: [148, 0, 211],
deeppink: [255, 20, 147],
deepskyblue: [0, 191, 255],
dimgray: [105, 105, 105],
dimgrey: [105, 105, 105],
dodgerblue: [30, 144, 255],
firebrick: [178, 34, 34],
floralwhite: [255, 250, 240],
forestgreen: [34, 139, 34],
fuchsia: [255, 0, 255],
gainsboro: [220, 220, 220],
ghostwhite: [248, 248, 255],
gold: [255, 215, 0],
goldenrod: [218, 165, 32],
gray: [128, 128, 128],
grey: [128, 128, 128],
green: [0, 128, 0],
greenyellow: [173, 255, 47],
honeydew: [240, 255, 240],
hotpink: [255, 105, 180],
indianred: [205, 92, 92],
indigo: [75, 0, 130],
ivory: [255, 255, 240],
khaki: [240, 230, 140],
lavender: [230, 230, 250],
lavenderblush: [255, 240, 245],
lawngreen: [124, 252, 0],
lemonchiffon: [255, 250, 205],
lightblue: [173, 216, 230],
lightcoral: [240, 128, 128],
lightcyan: [224, 255, 255],
lightgoldenrodyellow: [250, 250, 210],
lightgray: [211, 211, 211],
lightgreen: [144, 238, 144],
lightgrey: [211, 211, 211],
lightpink: [255, 182, 193],
lightsalmon: [255, 160, 122],
lightseagreen: [32, 178, 170],
lightskyblue: [135, 206, 250],
lightslategray: [119, 136, 153],
lightslategrey: [119, 136, 153],
lightsteelblue: [176, 196, 222],
lightyellow: [255, 255, 224],
lime: [0, 255, 0],
limegreen: [50, 205, 50],
linen: [250, 240, 230],
magenta: [255, 0, 255],
maroon: [128, 0, 0],
mediumaquamarine: [102, 205, 170],
mediumblue: [0, 0, 205],
mediumorchid: [186, 85, 211],
mediumpurple: [147, 112, 219],
mediumseagreen: [60, 179, 113],
mediumslateblue: [123, 104, 238],
mediumspringgreen: [0, 250, 154],
mediumturquoise: [72, 209, 204],
mediumvioletred: [199, 21, 133],
midnightblue: [25, 25, 112],
mintcream: [245, 255, 250],
mistyrose: [255, 228, 225],
moccasin: [255, 228, 181],
navajowhite: [255, 222, 173],
navy: [0, 0, 128],
oldlace: [253, 245, 230],
olive: [128, 128, 0],
olivedrab: [107, 142, 35],
orange: [255, 165, 0],
orangered: [255, 69, 0],
orchid: [218, 112, 214],
palegoldenrod: [238, 232, 170],
palegreen: [152, 251, 152],
paleturquoise: [175, 238, 238],
palevioletred: [219, 112, 147],
papayawhip: [255, 239, 213],
peachpuff: [255, 218, 185],
peru: [205, 133, 63],
pink: [255, 192, 203],
plum: [221, 160, 221],
powderblue: [176, 224, 230],
purple: [128, 0, 128],
red: [255, 0, 0],
rosybrown: [188, 143, 143],
royalblue: [65, 105, 225],
saddlebrown: [139, 69, 19],
salmon: [250, 128, 114],
sandybrown: [244, 164, 96],
seagreen: [46, 139, 87],
seashell: [255, 245, 238],
sienna: [160, 82, 45],
silver: [192, 192, 192],
skyblue: [135, 206, 235],
slateblue: [106, 90, 205],
slategray: [112, 128, 144],
slategrey: [112, 128, 144],
snow: [255, 250, 250],
springgreen: [0, 255, 127],
steelblue: [70, 130, 180],
tan: [210, 180, 140],
teal: [0, 128, 128],
thistle: [216, 191, 216],
tomato: [255, 99, 71],
turquoise: [64, 224, 208],
violet: [238, 130, 238],
wheat: [245, 222, 179],
white: [255, 255, 255],
whitesmoke: [245, 245, 245],
yellow: [255, 255, 0],
yellowgreen: [154, 205, 50]
};
================================================
FILE: packages/pdfkit/src/mixins/fonts.js
================================================
import PDFFont from '../font';
export default {
initFonts() {
// Lookup table for embedded fonts
this._fontFamilies = {};
this._fontCount = 0;
// Font state
this._fontSize = 12;
this._font = null;
this._registeredFonts = {};
// Set the default font
return this.font('Helvetica');
},
font(src, family, size) {
let cacheKey;
let font;
if (typeof family === 'number') {
size = family;
family = null;
}
// check registered fonts if src is a string
if (typeof src === 'string' && this._registeredFonts[src]) {
cacheKey = src;
({ src, family } = this._registeredFonts[src]);
} else {
cacheKey = family || src;
if (typeof cacheKey !== 'string') {
cacheKey = null;
}
}
if (size != null) {
this.fontSize(size);
}
// fast path: check if the font is already in the PDF
if ((font = this._fontFamilies[cacheKey])) {
this._font = font;
return this;
}
// load the font
const id = `F${++this._fontCount}`;
this._font = PDFFont.open(this, src, family, id);
// check for existing font familes with the same name already in the PDF
// useful if the font was passed as a buffer
if ((font = this._fontFamilies[this._font.name])) {
this._font = font;
return this;
}
// save the font for reuse later
if (cacheKey) {
this._fontFamilies[cacheKey] = this._font;
}
if (this._font.name) {
this._fontFamilies[this._font.name] = this._font;
}
return this;
},
fontSize(_fontSize) {
this._fontSize = _fontSize;
return this;
},
currentLineHeight(includeGap) {
if (includeGap == null) {
includeGap = false;
}
return this._font.lineHeight(this._fontSize, includeGap);
},
registerFont(name, src, family) {
this._registeredFonts[name] = {
src,
family
};
return this;
}
};
================================================
FILE: packages/pdfkit/src/mixins/images.js
================================================
import PDFImage from '../image';
export default {
initImages() {
this._imageRegistry = {};
return (this._imageCount = 0);
},
image(src, x, y, options = {}) {
let bh, bp, bw, image, ip, left, left1, rotateAngle, originX, originY;
if (typeof x === 'object') {
options = x;
x = null;
}
// Ignore orientation based on document options or image options
const ignoreOrientation =
options.ignoreOrientation ||
(options.ignoreOrientation !== false && this.options.ignoreOrientation);
x = (left = x != null ? x : options.x) != null ? left : this.x;
y = (left1 = y != null ? y : options.y) != null ? left1 : this.y;
if (typeof src === 'string') {
image = this._imageRegistry[src];
}
if (!image) {
if (src.width && src.height) {
image = src;
} else {
image = this.openImage(src);
}
}
if (!image.obj) {
image.embed(this);
}
if (this.page.xobjects[image.label] == null) {
this.page.xobjects[image.label] = image.obj;
}
let { width, height } = image;
// If EXIF orientation calls for it, swap width and height
if (!ignoreOrientation && image.orientation > 4) {
[width, height] = [height, width];
}
let w = options.width || width;
let h = options.height || height;
if (options.width && !options.height) {
const wp = w / width;
w = width * wp;
h = height * wp;
} else if (options.height && !options.width) {
const hp = h / height;
w = width * hp;
h = height * hp;
} else if (options.scale) {
w = width * options.scale;
h = height * options.scale;
} else if (options.fit) {
[bw, bh] = options.fit;
bp = bw / bh;
ip = width / height;
if (ip > bp) {
w = bw;
h = bw / ip;
} else {
h = bh;
w = bh * ip;
}
} else if (options.cover) {
[bw, bh] = options.cover;
bp = bw / bh;
ip = width / height;
if (ip > bp) {
h = bh;
w = bh * ip;
} else {
w = bw;
h = bw / ip;
}
}
if (options.fit || options.cover) {
if (options.align === 'center') {
x = x + bw / 2 - w / 2;
} else if (options.align === 'right') {
x = x + bw - w;
}
if (options.valign === 'center') {
y = y + bh / 2 - h / 2;
} else if (options.valign === 'bottom') {
y = y + bh - h;
}
}
if (!ignoreOrientation) {
switch (image.orientation) {
// No orientation (need to flip image, though, because of the default transform matrix on the document)
default:
case 1:
h = -h;
y -= h;
rotateAngle = 0;
break;
// Flip Horizontal
case 2:
w = -w;
h = -h;
x -= w;
y -= h;
rotateAngle = 0;
break;
// Rotate 180 degrees
case 3:
originX = x;
originY = y;
h = -h;
x -= w;
rotateAngle = 180;
break;
// Flip vertical
case 4:
// Do nothing, image will be flipped
break;
// Flip horizontally and rotate 270 degrees CW
case 5:
originX = x;
originY = y;
[w, h] = [h, w];
y -= h;
rotateAngle = 90;
break;
// Rotate 90 degrees CW
case 6:
originX = x;
originY = y;
[w, h] = [h, w];
h = -h;
rotateAngle = 90;
break;
// Flip horizontally and rotate 90 degrees CW
case 7:
originX = x;
originY = y;
[w, h] = [h, w];
h = -h;
w = -w;
x -= w;
rotateAngle = 90;
break;
// Rotate 270 degrees CW
case 8:
originX = x;
originY = y;
[w, h] = [h, w];
h = -h;
x -= w;
y -= h;
rotateAngle = -90;
break;
}
} else {
h = -h;
y -= h;
rotateAngle = 0;
}
// create link annotations if the link option is given
if (options.link != null) {
this.link(x, y, w, h, options.link);
}
if (options.goTo != null) {
this.goTo(x, y, w, h, options.goTo);
}
if (options.destination != null) {
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
}
// Set the current y position to below the image if it is in the document flow
if (this.y === y) {
this.y += h;
}
this.save();
if (rotateAngle) {
this.rotate(rotateAngle, {
origin: [originX, originY]
});
}
this.transform(w, 0, 0, h, x, y);
this.addContent(`/${image.label} Do`);
this.restore();
return this;
},
openImage(src) {
let image;
if (typeof src === 'string') {
image = this._imageRegistry[src];
}
if (!image) {
image = PDFImage.open(src, `I${++this._imageCount}`);
if (typeof src === 'string') {
this._imageRegistry[src] = image;
}
}
return image;
}
};
================================================
FILE: packages/pdfkit/src/mixins/markings.js
================================================
/*
Markings mixin - support marked content sequences in content streams
By Ben Schmidt
*/
import PDFStructureElement from '../structure_element';
import PDFStructureContent from '../structure_content';
import PDFNumberTree from '../number_tree';
import PDFObject from '../object';
export default {
initMarkings(options) {
this.structChildren = [];
if (options.tagged) {
this.getMarkInfoDictionary().data.Marked = true;
this.getStructTreeRoot();
}
},
markContent(tag, options = null) {
if (tag === 'Artifact' || (options && options.mcid)) {
let toClose = 0;
this.page.markings.forEach((marking) => {
if (toClose || marking.structContent || marking.tag === 'Artifact') {
toClose++;
}
});
while (toClose--) {
this.endMarkedContent();
}
}
if (!options) {
this.page.markings.push({ tag });
this.addContent(`/${tag} BMC`);
return this;
}
this.page.markings.push({ tag, options });
const dictionary = {};
if (typeof options.mcid !== 'undefined') {
dictionary.MCID = options.mcid;
}
if (tag === 'Artifact') {
if (typeof options.type === 'string') {
dictionary.Type = options.type;
}
if (Array.isArray(options.bbox)) {
dictionary.BBox = [
options.bbox[0],
this.page.height - options.bbox[3],
options.bbox[2],
this.page.height - options.bbox[1]
];
}
if (
Array.isArray(options.attached) &&
options.attached.every((val) => typeof val === 'string')
) {
dictionary.Attached = options.attached;
}
}
if (tag === 'Span') {
if (options.lang) {
dictionary.Lang = new String(options.lang);
}
if (options.alt) {
dictionary.Alt = new String(options.alt);
}
if (options.expanded) {
dictionary.E = new String(options.expanded);
}
if (options.actual) {
dictionary.ActualText = new String(options.actual);
}
}
this.addContent(`/${tag} ${PDFObject.convert(dictionary)} BDC`);
return this;
},
markStructureContent(tag, options = {}) {
const pageStructParents = this.getStructParentTree().get(
this.page.structParentTreeKey
);
const mcid = pageStructParents.length;
pageStructParents.push(null);
this.markContent(tag, { ...options, mcid });
const structContent = new PDFStructureContent(this.page.dictionary, mcid);
this.page.markings.slice(-1)[0].structContent = structContent;
return structContent;
},
endMarkedContent() {
this.page.markings.pop();
this.addContent('EMC');
return this;
},
struct(type, options = {}, children = null) {
return new PDFStructureElement(this, type, options, children);
},
addStructure(structElem) {
const structTreeRoot = this.getStructTreeRoot();
structElem.setParent(structTreeRoot);
structElem.setAttached();
this.structChildren.push(structElem);
if (!structTreeRoot.data.K) {
structTreeRoot.data.K = [];
}
structTreeRoot.data.K.push(structElem.dictionary);
return this;
},
initPageMarkings(pageMarkings) {
pageMarkings.forEach((marking) => {
if (marking.structContent) {
const structContent = marking.structContent;
const newStructContent = this.markStructureContent(
marking.tag,
marking.options
);
structContent.push(newStructContent);
this.page.markings.slice(-1)[0].structContent = structContent;
} else {
this.markContent(marking.tag, marking.options);
}
});
},
endPageMarkings(page) {
const pageMarkings = page.markings;
pageMarkings.forEach(() => page.write('EMC'));
page.markings = [];
return pageMarkings;
},
getMarkInfoDictionary() {
if (!this._root.data.MarkInfo) {
this._root.data.MarkInfo = this.ref({});
}
return this._root.data.MarkInfo;
},
hasMarkInfoDictionary() {
return !!this._root.data.MarkInfo;
},
getStructTreeRoot() {
if (!this._root.data.StructTreeRoot) {
this._root.data.StructTreeRoot = this.ref({
Type: 'StructTreeRoot',
ParentTree: new PDFNumberTree(),
ParentTreeNextKey: 0
});
}
return this._root.data.StructTreeRoot;
},
getStructParentTree() {
return this.getStructTreeRoot().data.ParentTree;
},
createStructParentTreeNextKey() {
// initialise the MarkInfo dictionary
this.getMarkInfoDictionary();
const structTreeRoot = this.getStructTreeRoot();
const key = structTreeRoot.data.ParentTreeNextKey++;
structTreeRoot.data.ParentTree.add(key, []);
return key;
},
endMarkings() {
const structTreeRoot = this._root.data.StructTreeRoot;
if (structTreeRoot) {
structTreeRoot.end();
this.structChildren.forEach((structElem) => structElem.end());
}
if (this._root.data.MarkInfo) {
this._root.data.MarkInfo.end();
}
}
};
================================================
FILE: packages/pdfkit/src/mixins/metadata.js
================================================
import PDFMetadata from '../metadata';
export default {
initMetadata() {
this.metadata = new PDFMetadata();
},
appendXML(xml, newline = true) {
this.metadata.append(xml, newline);
},
_addInfo() {
this.appendXML(`
${this.info.CreationDate.toISOString().split('.')[0] + 'Z'}
${this.info.Creator}
`);
if (this.info.Title || this.info.Author || this.info.Subject) {
this.appendXML(`
`);
if (this.info.Title) {
this.appendXML(`
${this.info.Title}
`);
}
if (this.info.Author) {
this.appendXML(`
${this.info.Author}
`);
}
if (this.info.Subject) {
this.appendXML(`
${this.info.Subject}
`);
}
this.appendXML(`
`);
}
this.appendXML(
`
${this.info.Creator} `,
false
);
if (this.info.Keywords) {
this.appendXML(
`
${this.info.Keywords} `,
false
);
}
this.appendXML(`
`);
},
endMetadata() {
this._addInfo();
this.metadata.end();
/*
Metadata was introduced in PDF 1.4, so adding it to 1.3
will likely only take up more space.
*/
if (this.version != 1.3) {
this.metadataRef = this.ref({
length: this.metadata.getLength(),
Type: 'Metadata',
Subtype: 'XML'
});
this.metadataRef.compress = false;
this.metadataRef.write(Buffer.from(this.metadata.getXML(), 'utf-8'));
this.metadataRef.end();
this._root.data.Metadata = this.metadataRef;
}
}
};
================================================
FILE: packages/pdfkit/src/mixins/outline.js
================================================
import PDFOutline from '../outline';
export default {
initOutline() {
return (this.outline = new PDFOutline(this, null, null, null));
},
endOutline() {
this.outline.endOutline();
if (this.outline.children.length > 0) {
this._root.data.Outlines = this.outline.dictionary;
/* Custom fork start */
return (this._root.data.PageMode = this._root.data.PageMode || 'UseOutlines');
/* Custom fork end */
}
}
};
================================================
FILE: packages/pdfkit/src/mixins/pdfa.js
================================================
import fs from 'fs';
export default {
initPDFA(pSubset) {
if (pSubset.charAt(pSubset.length - 3) === '-') {
this.subset_conformance = pSubset
.charAt(pSubset.length - 1)
.toUpperCase();
this.subset = parseInt(pSubset.charAt(pSubset.length - 2));
} else {
// Default to Basic conformance when user doesn't specify
this.subset_conformance = 'B';
this.subset = parseInt(pSubset.charAt(pSubset.length - 1));
}
},
endSubset() {
this._addPdfaMetadata();
this._addColorOutputIntent();
},
_addColorOutputIntent() {
const iccProfile = fs.readFileSync(
`${__dirname}/data/sRGB_IEC61966_2_1.icc`
);
const colorProfileRef = this.ref({
Length: iccProfile.length,
N: 3
});
colorProfileRef.write(iccProfile);
colorProfileRef.end();
const intentRef = this.ref({
Type: 'OutputIntent',
S: 'GTS_PDFA1',
Info: new String('sRGB IEC61966-2.1'),
OutputConditionIdentifier: new String('sRGB IEC61966-2.1'),
DestOutputProfile: colorProfileRef
});
intentRef.end();
this._root.data.OutputIntents = [intentRef];
},
_getPdfaid() {
return `
${this.subset}
${this.subset_conformance}
`;
},
_addPdfaMetadata() {
this.appendXML(this._getPdfaid());
}
};
================================================
FILE: packages/pdfkit/src/mixins/pdfua.js
================================================
export default {
initPDFUA() {
this.subset = 1;
},
endSubset() {
this._addPdfuaMetadata();
},
_addPdfuaMetadata() {
this.appendXML(this._getPdfuaid());
},
_getPdfuaid() {
return `
${this.subset}
`;
}
};
================================================
FILE: packages/pdfkit/src/mixins/subsets.js
================================================
import PDFA from './pdfa';
import PDFUA from './pdfua';
export default {
_importSubset(subset) {
Object.assign(this, subset);
},
initSubset(options) {
switch (options.subset) {
case 'PDF/A-1':
case 'PDF/A-1a':
case 'PDF/A-1b':
case 'PDF/A-2':
case 'PDF/A-2a':
case 'PDF/A-2b':
case 'PDF/A-3':
case 'PDF/A-3a':
case 'PDF/A-3b':
this._importSubset(PDFA);
this.initPDFA(options.subset);
break;
case 'PDF/UA':
this._importSubset(PDFUA);
this.initPDFUA();
break;
}
}
};
================================================
FILE: packages/pdfkit/src/mixins/text.js
================================================
import LineWrapper from '../line_wrapper';
import PDFObject from '../object';
import { cosine, sine } from '../utils';
const { number } = PDFObject;
export default {
initText() {
this._line = this._line.bind(this);
// Current coordinates
this.x = 0;
this.y = 0;
return (this._lineGap = 0);
},
lineGap(_lineGap) {
this._lineGap = _lineGap;
return this;
},
moveDown(lines) {
if (lines == null) {
lines = 1;
}
this.y += this.currentLineHeight(true) * lines + this._lineGap;
return this;
},
moveUp(lines) {
if (lines == null) {
lines = 1;
}
this.y -= this.currentLineHeight(true) * lines + this._lineGap;
return this;
},
_text(text, x, y, options, lineCallback) {
options = this._initOptions(x, y, options);
// Convert text to a string
text = text == null ? '' : `${text}`;
// if the wordSpacing option is specified, remove multiple consecutive spaces
if (options.wordSpacing) {
text = text.replace(/\s{2,}/g, ' ');
}
const addStructure = () => {
if (options.structParent) {
options.structParent.add(
this.struct(options.structType || 'P', [
this.markStructureContent(options.structType || 'P')
])
);
}
};
// We can save some bytes if there is no rotation
if (options.rotation !== 0) {
this.save();
this.rotate(-options.rotation, { origin: [this.x, this.y] });
}
// word wrapping
if (options.width) {
let wrapper = this._wrapper;
if (!wrapper) {
wrapper = new LineWrapper(this, options);
wrapper.on('line', lineCallback);
wrapper.on('firstLine', addStructure);
}
this._wrapper = options.continued ? wrapper : null;
this._textOptions = options.continued ? options : null;
wrapper.wrap(text, options);
// render paragraphs as single lines
} else {
for (let line of text.split('\n')) {
addStructure();
lineCallback(line, options);
}
}
// Cleanup if there was a rotation
if (options.rotation !== 0) this.restore();
return this;
},
text(text, x, y, options) {
return this._text(text, x, y, options, this._line);
},
widthOfString(string, options = {}) {
const horizontalScaling = options.horizontalScaling || 100;
return (
((this._font.widthOfString(string, this._fontSize, options.features) +
(options.characterSpacing || 0) * (string.length - 1)) *
horizontalScaling) /
100
);
},
/**
* Compute the bounding box of a string
* based on what will actually be rendered by `doc.text()`
*
* @param string - The string
* @param x - X position of text (defaults to this.x)
* @param y - Y position of text (defaults to this.y)
* @param options - Any text options (The same you would apply to `doc.text()`)
* @returns {{x: number, y: number, width: number, height: number}}
*/
boundsOfString(string, x, y, options) {},
heightOfString(text, options) {
const { x, y } = this;
options = this._initOptions(options);
options.height = Infinity; // don't break pages
const lineGap = options.lineGap || this._lineGap || 0;
this._text(text, this.x, this.y, options, () => {
return (this.y += this.currentLineHeight(true) + lineGap);
});
const height = this.y - y;
this.x = x;
this.y = y;
return height;
},
list(list, x, y, options, wrapper) {
options = this._initOptions(x, y, options);
const listType = options.listType || 'bullet';
const unit = Math.round((this._font.ascender / 1000) * this._fontSize);
const midLine = unit / 2;
const r = options.bulletRadius || unit / 3;
const indent =
options.textIndent || (listType === 'bullet' ? r * 5 : unit * 2);
const itemIndent =
options.bulletIndent || (listType === 'bullet' ? r * 8 : unit * 2);
let level = 1;
const items = [];
const levels = [];
const numbers = [];
var flatten = function (list) {
let n = 1;
for (let i = 0; i < list.length; i++) {
const item = list[i];
if (Array.isArray(item)) {
level++;
flatten(item);
level--;
} else {
items.push(item);
levels.push(level);
if (listType !== 'bullet') {
numbers.push(n++);
}
}
}
};
flatten(list);
const label = function (n) {
switch (listType) {
case 'numbered':
return `${n}.`;
case 'lettered':
var letter = String.fromCharCode(((n - 1) % 26) + 65);
var times = Math.floor((n - 1) / 26 + 1);
var text = Array(times + 1).join(letter);
return `${text}.`;
}
};
const drawListItem = function (listItem, i) {
wrapper = new LineWrapper(this, options);
wrapper.on('line', this._line);
level = 1;
wrapper.once('firstLine', () => {
let item, itemType, labelType, bodyType;
if (options.structParent) {
if (options.structTypes) {
[itemType, labelType, bodyType] = options.structTypes;
} else {
[itemType, labelType, bodyType] = ['LI', 'Lbl', 'LBody'];
}
}
if (itemType) {
item = this.struct(itemType);
options.structParent.add(item);
} else if (options.structParent) {
item = options.structParent;
}
let l;
if ((l = levels[i++]) !== level) {
const diff = itemIndent * (l - level);
this.x += diff;
wrapper.lineWidth -= diff;
level = l;
}
if (item && (labelType || bodyType)) {
item.add(
this.struct(labelType || bodyType, [
this.markStructureContent(labelType || bodyType)
])
);
}
switch (listType) {
case 'bullet':
this.circle(this.x - indent + r, this.y + midLine, r);
this.fill();
break;
case 'numbered':
case 'lettered':
var text = label(numbers[i - 1]);
this._fragment(text, this.x - indent, this.y, options);
break;
}
if (item && labelType && bodyType) {
item.add(
this.struct(bodyType, [this.markStructureContent(bodyType)])
);
}
if (item && item !== options.structParent) {
item.end();
}
});
wrapper.on('sectionStart', () => {
const pos = indent + itemIndent * (level - 1);
this.x += pos;
return (wrapper.lineWidth -= pos);
});
wrapper.on('sectionEnd', () => {
const pos = indent + itemIndent * (level - 1);
this.x -= pos;
return (wrapper.lineWidth += pos);
});
wrapper.wrap(listItem, options);
};
for (let i = 0; i < items.length; i++) {
drawListItem.call(this, items[i], i);
}
return this;
},
_initOptions(x = {}, y, options = {}) {
if (typeof x === 'object') {
options = x;
x = null;
}
// clone options object
const result = Object.assign({}, options);
// extend options with previous values for continued text
if (this._textOptions) {
for (let key in this._textOptions) {
const val = this._textOptions[key];
if (key !== 'continued') {
if (result[key] === undefined) {
result[key] = val;
}
}
}
}
// Update the current position
if (x != null) {
this.x = x;
}
if (y != null) {
this.y = y;
}
// wrap to margins if no x or y position passed
if (result.lineBreak !== false) {
if (result.width == null) {
result.width = this.page.width - this.x - this.page.margins.right;
}
result.width = Math.max(result.width, 0);
}
if (!result.columns) {
result.columns = 0;
}
if (result.columnGap == null) {
result.columnGap = 18;
} // 1/4 inch
// Normalize rotation to between 0 - 360
result.rotation = Number(options.rotation ?? 0) % 360;
if (result.rotation < 0) result.rotation += 360;
return result;
},
_line(text, options = {}, wrapper) {
this._fragment(text, this.x, this.y, options);
const lineGap = options.lineGap || this._lineGap || 0;
if (!wrapper) {
return (this.x += this.widthOfString(text, options));
} else {
return (this.y += this.currentLineHeight(true) + lineGap);
}
},
_fragment(text, x, y, options) {
let dy, encoded, i, positions, textWidth, words;
text = `${text}`.replace(/\n/g, '');
if (text.length === 0) {
return;
}
// handle options
const align = options.align || 'left';
let wordSpacing = options.wordSpacing || 0;
const characterSpacing = options.characterSpacing || 0;
const horizontalScaling = options.horizontalScaling || 100;
// text alignments
if (options.width) {
switch (align) {
case 'right':
textWidth = this.widthOfString(text.replace(/\s+$/, ''), options);
x += options.lineWidth - textWidth;
break;
case 'center':
x += options.lineWidth / 2 - options.textWidth / 2;
break;
case 'justify':
// calculate the word spacing value
words = text.trim().split(/\s+/);
textWidth = this.widthOfString(text.replace(/\s+/g, ''), options);
var spaceWidth = this.widthOfString(' ') + characterSpacing;
wordSpacing = Math.max(
0,
(options.lineWidth - textWidth) / Math.max(1, words.length - 1) -
spaceWidth
);
break;
}
}
// text baseline alignments based on http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
if (typeof options.baseline === 'number') {
dy = -options.baseline;
} else {
switch (options.baseline) {
case 'svg-middle':
dy = 0.5 * this._font.xHeight;
break;
case 'middle':
case 'svg-central':
dy = 0.5 * (this._font.descender + this._font.ascender);
break;
case 'bottom':
case 'ideographic':
dy = this._font.descender;
break;
case 'alphabetic':
dy = 0;
break;
case 'mathematical':
dy = 0.5 * this._font.ascender;
break;
case 'hanging':
dy = 0.8 * this._font.ascender;
break;
case 'top':
dy = this._font.ascender;
break;
default:
dy = this._font.ascender;
}
dy = (dy / 1000) * this._fontSize;
}
// calculate the actual rendered width of the string after word and character spacing
const renderedWidth =
options.textWidth +
wordSpacing * (options.wordCount - 1) +
characterSpacing * (text.length - 1);
// create link annotations if the link option is given
if (options.link != null) {
this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);
}
if (options.goTo != null) {
this.goTo(x, y, renderedWidth, this.currentLineHeight(), options.goTo);
}
if (options.destination != null) {
this.addNamedDestination(options.destination, 'XYZ', x, y, null);
}
// create underline
if (options.underline) {
this.save();
if (!options.stroke) {
this.strokeColor(...(this._fillColor || []));
}
const lineWidth =
this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10);
this.lineWidth(lineWidth);
let lineY = y + this.currentLineHeight() - lineWidth;
this.moveTo(x, lineY);
this.lineTo(x + renderedWidth, lineY);
this.stroke();
this.restore();
}
// create strikethrough line
if (options.strike) {
this.save();
if (!options.stroke) {
this.strokeColor(...(this._fillColor || []));
}
const lineWidth =
this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10);
this.lineWidth(lineWidth);
let lineY = y + this.currentLineHeight() / 2;
this.moveTo(x, lineY);
this.lineTo(x + renderedWidth, lineY);
this.stroke();
this.restore();
}
this.save();
// oblique (angle in degrees or boolean)
if (options.oblique) {
let skew;
if (typeof options.oblique === 'number') {
skew = -Math.tan((options.oblique * Math.PI) / 180);
} else {
skew = -0.25;
}
this.transform(1, 0, 0, 1, x, y);
this.transform(1, 0, skew, 1, -skew * dy, 0);
this.transform(1, 0, 0, 1, -x, -y);
}
// flip coordinate system
this.transform(1, 0, 0, -1, 0, this.page.height);
y = this.page.height - y - dy;
// add current font to page if necessary
if (this.page.fonts[this._font.id] == null) {
this.page.fonts[this._font.id] = this._font.ref();
}
// begin the text object
this.addContent('BT');
// text position
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
// font and font size
this.addContent(`/${this._font.id} ${number(this._fontSize)} Tf`);
// rendering mode
const mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;
if (mode) {
this.addContent(`${mode} Tr`);
}
// Character spacing
if (characterSpacing) {
this.addContent(`${number(characterSpacing)} Tc`);
}
// Horizontal scaling
if (horizontalScaling !== 100) {
this.addContent(`${horizontalScaling} Tz`);
}
// Add the actual text
// If we have a word spacing value, we need to encode each word separately
// since the normal Tw operator only works on character code 32, which isn't
// used for embedded fonts.
if (wordSpacing) {
words = text.trim().split(/\s+/);
wordSpacing += this.widthOfString(' ') + characterSpacing;
wordSpacing *= 1000 / this._fontSize;
encoded = [];
positions = [];
for (let word of words) {
const [encodedWord, positionsWord] = this._font.encode(
word,
options.features
);
encoded = encoded.concat(encodedWord);
positions = positions.concat(positionsWord);
// add the word spacing to the end of the word
// clone object because of cache
const space = {};
const object = positions[positions.length - 1];
for (let key in object) {
const val = object[key];
space[key] = val;
}
space.xAdvance += wordSpacing;
positions[positions.length - 1] = space;
}
} else {
[encoded, positions] = this._font.encode(text, options.features);
}
const scale = this._fontSize / 1000;
const commands = [];
let last = 0;
let hadOffset = false;
// Adds a segment of text to the TJ command buffer
const addSegment = (cur) => {
if (last < cur) {
const hex = encoded.slice(last, cur).join('');
const advance =
positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;
commands.push(`<${hex}> ${number(-advance)}`);
}
return (last = cur);
};
// Flushes the current TJ commands to the output stream
const flush = (i) => {
addSegment(i);
if (commands.length > 0) {
this.addContent(`[${commands.join(' ')}] TJ`);
return (commands.length = 0);
}
};
for (i = 0; i < positions.length; i++) {
// If we have an x or y offset, we have to break out of the current TJ command
// so we can move the text position.
const pos = positions[i];
if (pos.xOffset || pos.yOffset) {
// Flush the current buffer
flush(i);
// Move the text position and flush just the current character
this.addContent(
`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(
y + pos.yOffset * scale
)} Tm`
);
flush(i + 1);
hadOffset = true;
} else {
// If the last character had an offset, reset the text position
if (hadOffset) {
this.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
hadOffset = false;
}
// Group segments that don't have any advance adjustments
if (pos.xAdvance - pos.advanceWidth !== 0) {
addSegment(i + 1);
}
}
x += pos.xAdvance * scale;
}
// Flush any remaining commands
flush(i);
// end the text object
this.addContent('ET');
// restore flipped coordinate system
return this.restore();
}
};
================================================
FILE: packages/pdfkit/src/mixins/vector.js
================================================
import SVGPath from '../path';
import PDFObject from '../object';
const { number } = PDFObject;
// This constant is used to approximate a symmetrical arc using a cubic
// Bezier curve.
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
export default {
initVector() {
this._ctm = [1, 0, 0, 1, 0, 0]; // current transformation matrix
return (this._ctmStack = []);
},
save() {
this._ctmStack.push(this._ctm.slice());
// TODO: save/restore colorspace and styles so not setting it unnessesarily all the time?
return this.addContent('q');
},
restore() {
this._ctm = this._ctmStack.pop() || [1, 0, 0, 1, 0, 0];
return this.addContent('Q');
},
closePath() {
return this.addContent('h');
},
lineWidth(w) {
return this.addContent(`${number(w)} w`);
},
_CAP_STYLES: {
BUTT: 0,
ROUND: 1,
SQUARE: 2
},
lineCap(c) {
if (typeof c === 'string') {
c = this._CAP_STYLES[c.toUpperCase()];
}
return this.addContent(`${c} J`);
},
_JOIN_STYLES: {
MITER: 0,
ROUND: 1,
BEVEL: 2
},
lineJoin(j) {
if (typeof j === 'string') {
j = this._JOIN_STYLES[j.toUpperCase()];
}
return this.addContent(`${j} j`);
},
miterLimit(m) {
return this.addContent(`${number(m)} M`);
},
dash(length, options = {}) {
const originalLength = length;
if (!Array.isArray(length)) {
length = [length, options.space || length];
}
const valid = length.every((x) => Number.isFinite(x) && x > 0);
if (!valid) {
throw new Error(
`dash(${JSON.stringify(originalLength)}, ${JSON.stringify(
options
)}) invalid, lengths must be numeric and greater than zero`
);
}
length = length.map(number).join(' ');
return this.addContent(`[${length}] ${number(options.phase || 0)} d`);
},
undash() {
return this.addContent('[] 0 d');
},
moveTo(x, y) {
return this.addContent(`${number(x)} ${number(y)} m`);
},
lineTo(x, y) {
return this.addContent(`${number(x)} ${number(y)} l`);
},
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
return this.addContent(
`${number(cp1x)} ${number(cp1y)} ${number(cp2x)} ${number(cp2y)} ${number(
x
)} ${number(y)} c`
);
},
quadraticCurveTo(cpx, cpy, x, y) {
return this.addContent(
`${number(cpx)} ${number(cpy)} ${number(x)} ${number(y)} v`
);
},
rect(x, y, w, h) {
return this.addContent(
`${number(x)} ${number(y)} ${number(w)} ${number(h)} re`
);
},
roundedRect(x, y, w, h, r) {
if (r == null) {
r = 0;
}
r = Math.min(r, 0.5 * w, 0.5 * h);
// amount to inset control points from corners (see `ellipse`)
const c = r * (1.0 - KAPPA);
this.moveTo(x + r, y);
this.lineTo(x + w - r, y);
this.bezierCurveTo(x + w - c, y, x + w, y + c, x + w, y + r);
this.lineTo(x + w, y + h - r);
this.bezierCurveTo(x + w, y + h - c, x + w - c, y + h, x + w - r, y + h);
this.lineTo(x + r, y + h);
this.bezierCurveTo(x + c, y + h, x, y + h - c, x, y + h - r);
this.lineTo(x, y + r);
this.bezierCurveTo(x, y + c, x + c, y, x + r, y);
return this.closePath();
},
ellipse(x, y, r1, r2) {
// based on http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas/2173084#2173084
if (r2 == null) {
r2 = r1;
}
x -= r1;
y -= r2;
const ox = r1 * KAPPA;
const oy = r2 * KAPPA;
const xe = x + r1 * 2;
const ye = y + r2 * 2;
const xm = x + r1;
const ym = y + r2;
this.moveTo(x, ym);
this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
return this.closePath();
},
circle(x, y, radius) {
return this.ellipse(x, y, radius);
},
arc(x, y, radius, startAngle, endAngle, anticlockwise) {
if (anticlockwise == null) {
anticlockwise = false;
}
const TWO_PI = 2.0 * Math.PI;
const HALF_PI = 0.5 * Math.PI;
let deltaAng = endAngle - startAngle;
if (Math.abs(deltaAng) > TWO_PI) {
// draw only full circle if more than that is specified
deltaAng = TWO_PI;
} else if (deltaAng !== 0 && anticlockwise !== deltaAng < 0) {
// necessary to flip direction of rendering
const dir = anticlockwise ? -1 : 1;
deltaAng = dir * TWO_PI + deltaAng;
}
const numSegs = Math.ceil(Math.abs(deltaAng) / HALF_PI);
const segAng = deltaAng / numSegs;
const handleLen = (segAng / HALF_PI) * KAPPA * radius;
let curAng = startAngle;
// component distances between anchor point and control point
let deltaCx = -Math.sin(curAng) * handleLen;
let deltaCy = Math.cos(curAng) * handleLen;
// anchor point
let ax = x + Math.cos(curAng) * radius;
let ay = y + Math.sin(curAng) * radius;
// calculate and render segments
this.moveTo(ax, ay);
for (let segIdx = 0; segIdx < numSegs; segIdx++) {
// starting control point
const cp1x = ax + deltaCx;
const cp1y = ay + deltaCy;
// step angle
curAng += segAng;
// next anchor point
ax = x + Math.cos(curAng) * radius;
ay = y + Math.sin(curAng) * radius;
// next control point delta
deltaCx = -Math.sin(curAng) * handleLen;
deltaCy = Math.cos(curAng) * handleLen;
// ending control point
const cp2x = ax - deltaCx;
const cp2y = ay - deltaCy;
// render segment
this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);
}
return this;
},
polygon(...points) {
this.moveTo(...(points.shift() || []));
for (let point of points) {
this.lineTo(...(point || []));
}
return this.closePath();
},
path(path) {
SVGPath.apply(this, path);
return this;
},
_windingRule(rule) {
if (/even-?odd/.test(rule)) {
return '*';
}
return '';
},
fill(color, rule) {
if (/(even-?odd)|(non-?zero)/.test(color)) {
rule = color;
color = null;
}
if (color) {
this.fillColor(color);
}
return this.addContent(`f${this._windingRule(rule)}`);
},
stroke(color) {
if (color) {
this.strokeColor(color);
}
return this.addContent('S');
},
fillAndStroke(fillColor, strokeColor, rule) {
if (strokeColor == null) {
strokeColor = fillColor;
}
const isFillRule = /(even-?odd)|(non-?zero)/;
if (isFillRule.test(fillColor)) {
rule = fillColor;
fillColor = null;
}
if (isFillRule.test(strokeColor)) {
rule = strokeColor;
strokeColor = fillColor;
}
if (fillColor) {
this.fillColor(fillColor);
this.strokeColor(strokeColor);
}
return this.addContent(`B${this._windingRule(rule)}`);
},
clip(rule) {
return this.addContent(`W${this._windingRule(rule)} n`);
},
transform(m11, m12, m21, m22, dx, dy) {
// keep track of the current transformation matrix
if (
m11 === 1 &&
m12 === 0 &&
m21 === 0 &&
m22 === 1 &&
dx === 0 &&
dy === 0
) {
// Ignore identity transforms
return this;
}
const m = this._ctm;
const [m0, m1, m2, m3, m4, m5] = m;
m[0] = m0 * m11 + m2 * m12;
m[1] = m1 * m11 + m3 * m12;
m[2] = m0 * m21 + m2 * m22;
m[3] = m1 * m21 + m3 * m22;
m[4] = m0 * dx + m2 * dy + m4;
m[5] = m1 * dx + m3 * dy + m5;
const values = [m11, m12, m21, m22, dx, dy].map((v) => number(v)).join(' ');
return this.addContent(`${values} cm`);
},
translate(x, y) {
return this.transform(1, 0, 0, 1, x, y);
},
rotate(angle, options = {}) {
let y;
const rad = (angle * Math.PI) / 180;
const cos = Math.cos(rad);
const sin = Math.sin(rad);
let x = (y = 0);
if (options.origin != null) {
[x, y] = options.origin;
const x1 = x * cos - y * sin;
const y1 = x * sin + y * cos;
x -= x1;
y -= y1;
}
return this.transform(cos, sin, -sin, cos, x, y);
},
scale(xFactor, yFactor, options = {}) {
let y;
if (yFactor == null) {
yFactor = xFactor;
}
if (typeof yFactor === 'object') {
options = yFactor;
yFactor = xFactor;
}
let x = (y = 0);
if (options.origin != null) {
[x, y] = options.origin;
x -= xFactor * x;
y -= yFactor * y;
}
return this.transform(xFactor, 0, 0, yFactor, x, y);
}
};
================================================
FILE: packages/pdfkit/src/name_tree.js
================================================
/*
PDFNameTree - represents a name tree object
*/
import PDFTree from './tree';
class PDFNameTree extends PDFTree {
_compareKeys(a, b) {
return a.localeCompare(b);
}
_keysName() {
return 'Names';
}
_dataForKey(k) {
return new String(k);
}
}
export default PDFNameTree;
================================================
FILE: packages/pdfkit/src/number_tree.js
================================================
/*
PDFNumberTree - represents a number tree object
*/
import PDFTree from './tree';
class PDFNumberTree extends PDFTree {
_compareKeys(a, b) {
return parseInt(a) - parseInt(b);
}
_keysName() {
return 'Nums';
}
_dataForKey(k) {
return parseInt(k);
}
}
export default PDFNumberTree;
================================================
FILE: packages/pdfkit/src/object.js
================================================
/*
PDFObject - converts JavaScript types into their corresponding PDF types.
By Devon Govett
*/
import PDFReference from './reference';
import PDFNameTree from './name_tree';
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
const escapableRe = /[\n\r\t\b\f()\\]/g;
const escapable = {
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\b': '\\b',
'\f': '\\f',
'\\': '\\\\',
'(': '\\(',
')': '\\)'
};
// Convert little endian UTF-16 to big endian
const swapBytes = function (buff) {
const l = buff.length;
if (l & 0x01) {
throw new Error('Buffer length must be even');
} else {
for (let i = 0, end = l - 1; i < end; i += 2) {
const a = buff[i];
buff[i] = buff[i + 1];
buff[i + 1] = a;
}
}
return buff;
};
class PDFObject {
static convert(object) {
// String literals are converted to the PDF name type
if (typeof object === 'string') {
return `/${object}`;
}
// String objects are converted to PDF strings (UTF-16)
if (object instanceof String) {
let string = object;
// Detect if this is a unicode string
let isUnicode = false;
for (let i = 0, end = string.length; i < end; i++) {
if (string.charCodeAt(i) > 0x7f) {
isUnicode = true;
break;
}
}
// If so, encode it as big endian UTF-16
if (isUnicode) {
string = swapBytes(Buffer.from(`\ufeff${string}`, 'utf16le')).toString(
'binary'
);
}
// Escape characters as required by the spec
string = string.replace(escapableRe, (c) => escapable[c]);
return `(${string})`;
// Buffers are converted to PDF hex strings
}
if (Buffer.isBuffer(object)) {
return `<${object.toString('hex')}>`;
}
if (object instanceof PDFReference || object instanceof PDFNameTree) {
return object.toString();
}
if (object instanceof Date) {
return (
`(D:${pad(object.getUTCFullYear(), 4)}` +
pad(object.getUTCMonth() + 1, 2) +
pad(object.getUTCDate(), 2) +
pad(object.getUTCHours(), 2) +
pad(object.getUTCMinutes(), 2) +
pad(object.getUTCSeconds(), 2) +
'Z)'
);
}
if (Array.isArray(object)) {
const items = Array.from(object)
.map((e) => PDFObject.convert(e))
.join(' ');
return `[${items}]`;
}
if ({}.toString.call(object) === '[object Object]') {
const out = ['<<'];
for (let key in object) {
const val = object[key];
out.push(`/${key} ${PDFObject.convert(val)}`);
}
out.push('>>');
return out.join('\n');
}
if (typeof object === 'number') {
return PDFObject.number(object);
}
return `${object}`;
}
static number(n) {
if (n > -1e21 && n < 1e21) {
return Math.round(n * 1e6) / 1e6;
}
throw new Error(`unsupported number: ${n}`);
}
}
export default PDFObject;
================================================
FILE: packages/pdfkit/src/outline.js
================================================
/* Custom fork start */
const DEFAULT_OPTIONS = {
top: 0,
left: 0,
zoom: 0,
fit: false,
pageNumber: null,
expanded: false
};
/* Custom fork end */
class PDFOutline {
constructor(document, parent, title, dest, options = DEFAULT_OPTIONS) {
this.document = document;
this.options = options;
this.outlineData = {};
if (dest !== null) {
/* Custom fork start */
const destWidth = dest.data.MediaBox[2];
const destHeight = dest.data.MediaBox[3];
const top = destHeight - (options.top || 0);
const left = destWidth - (options.left || 0);
const zoom = options.zoom || 0;
this.outlineData['Dest'] = options.fit
? [dest, 'Fit']
: [dest, 'XYZ', left, top, zoom];
/* Custom fork end */
}
if (parent !== null) {
this.outlineData['Parent'] = parent;
}
if (title !== null) {
this.outlineData['Title'] = new String(title);
}
this.dictionary = this.document.ref(this.outlineData);
this.children = [];
}
addItem(title, options = DEFAULT_OPTIONS) {
/* Custom fork start */
const pages = this.document._root.data.Pages.data.Kids;
const dest =
options.pageNumber !== null
? pages[options.pageNumber]
: this.document.page.dictionary;
/* Custom fork end */
const result = new PDFOutline(
this.document,
this.dictionary,
title,
dest,
options
);
this.children.push(result);
return result;
}
endOutline() {
if (this.children.length > 0) {
if (this.options.expanded) {
this.outlineData.Count = this.children.length;
}
const first = this.children[0],
last = this.children[this.children.length - 1];
this.outlineData.First = first.dictionary;
this.outlineData.Last = last.dictionary;
for (let i = 0, len = this.children.length; i < len; i++) {
const child = this.children[i];
if (i > 0) {
child.outlineData.Prev = this.children[i - 1].dictionary;
}
if (i < this.children.length - 1) {
child.outlineData.Next = this.children[i + 1].dictionary;
}
child.endOutline();
}
}
return this.dictionary.end();
}
}
export default PDFOutline;
================================================
FILE: packages/pdfkit/src/page.js
================================================
/*
PDFPage - represents a single page in the PDF document
By Devon Govett
*/
/**
* @type {SideDefinition}
*/
const DEFAULT_MARGINS = {
top: 72,
left: 72,
bottom: 72,
right: 72
};
const SIZES = {
'4A0': [4767.87, 6740.79],
'2A0': [3370.39, 4767.87],
A0: [2383.94, 3370.39],
A1: [1683.78, 2383.94],
A2: [1190.55, 1683.78],
A3: [841.89, 1190.55],
A4: [595.28, 841.89],
A5: [419.53, 595.28],
A6: [297.64, 419.53],
A7: [209.76, 297.64],
A8: [147.4, 209.76],
A9: [104.88, 147.4],
A10: [73.7, 104.88],
B0: [2834.65, 4008.19],
B1: [2004.09, 2834.65],
B2: [1417.32, 2004.09],
B3: [1000.63, 1417.32],
B4: [708.66, 1000.63],
B5: [498.9, 708.66],
B6: [354.33, 498.9],
B7: [249.45, 354.33],
B8: [175.75, 249.45],
B9: [124.72, 175.75],
B10: [87.87, 124.72],
C0: [2599.37, 3676.54],
C1: [1836.85, 2599.37],
C2: [1298.27, 1836.85],
C3: [918.43, 1298.27],
C4: [649.13, 918.43],
C5: [459.21, 649.13],
C6: [323.15, 459.21],
C7: [229.61, 323.15],
C8: [161.57, 229.61],
C9: [113.39, 161.57],
C10: [79.37, 113.39],
RA0: [2437.8, 3458.27],
RA1: [1729.13, 2437.8],
RA2: [1218.9, 1729.13],
RA3: [864.57, 1218.9],
RA4: [609.45, 864.57],
SRA0: [2551.18, 3628.35],
SRA1: [1814.17, 2551.18],
SRA2: [1275.59, 1814.17],
SRA3: [907.09, 1275.59],
SRA4: [637.8, 907.09],
EXECUTIVE: [521.86, 756.0],
FOLIO: [612.0, 936.0],
LEGAL: [612.0, 1008.0],
LETTER: [612.0, 792.0],
TABLOID: [792.0, 1224.0]
};
class PDFPage {
constructor(document, options = {}) {
this.document = document;
this._options = options;
this.size = options.size || 'letter';
this.layout = options.layout || 'portrait';
this.userUnit = options.userUnit || 1.0;
// process margins
if (typeof options.margin === 'number') {
this.margins = {
top: options.margin,
left: options.margin,
bottom: options.margin,
right: options.margin
};
// default to 1 inch margins
} else {
this.margins = options.margins || DEFAULT_MARGINS;
}
// calculate page dimensions
const dimensions = Array.isArray(this.size)
? this.size
: SIZES[this.size.toUpperCase()];
this.width = dimensions[this.layout === 'portrait' ? 0 : 1];
this.height = dimensions[this.layout === 'portrait' ? 1 : 0];
this.content = this.document.ref();
if (options.font) document.font(options.font, options.fontFamily);
if (options.fontSize) document.fontSize(options.fontSize);
// Initialize the Font, XObject, and ExtGState dictionaries
this.resources = this.document.ref({
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']
});
// The page dictionary
this.dictionary = this.document.ref({
Type: 'Page',
Parent: this.document._root.data.Pages,
MediaBox: [0, 0, this.width, this.height],
Contents: this.content,
Resources: this.resources,
UserUnit: this.userUnit
});
this.markings = [];
}
// Lazily create these objects
get fonts() {
const data = this.resources.data;
return data.Font != null ? data.Font : (data.Font = {});
}
get xobjects() {
const data = this.resources.data;
return data.XObject != null ? data.XObject : (data.XObject = {});
}
get ext_gstates() {
const data = this.resources.data;
return data.ExtGState != null ? data.ExtGState : (data.ExtGState = {});
}
get patterns() {
const data = this.resources.data;
return data.Pattern != null ? data.Pattern : (data.Pattern = {});
}
get colorSpaces() {
const data = this.resources.data;
return data.ColorSpace || (data.ColorSpace = {});
}
get annotations() {
const data = this.dictionary.data;
return data.Annots != null ? data.Annots : (data.Annots = []);
}
get structParentTreeKey() {
const data = this.dictionary.data;
return data.StructParents != null
? data.StructParents
: (data.StructParents = this.document.createStructParentTreeNextKey());
}
maxY() {
return this.height - this.margins.bottom;
}
write(chunk) {
return this.content.write(chunk);
}
// Set tab order if document is tagged for accessibility.
_setTabOrder() {
if (!this.dictionary.Tabs && this.document.hasMarkInfoDictionary()) {
this.dictionary.data.Tabs = 'S';
}
}
end() {
this._setTabOrder();
this.dictionary.end();
this.resources.data.ColorSpace = this.resources.data.ColorSpace || {};
for (let color of Object.values(this.document.spotColors)) {
this.resources.data.ColorSpace[color.id] = color;
}
this.resources.end();
return this.content.end();
}
}
export default PDFPage;
================================================
FILE: packages/pdfkit/src/path.js
================================================
let cx;
let cy;
let px;
let py;
let sx;
let sy;
cx = cy = px = py = sx = sy = 0;
// parseDataPath copy pasted from svgo
// https://github.com/svg/svgo/blob/e4918ccdd1a2b5831defe0f00c1286744b479448/lib/path.js
/**
* @typedef {'M' | 'm' | 'Z' | 'z' | 'L' | 'l' | 'H' | 'h' | 'V' | 'v' | 'C' | 'c' | 'S' | 's' | 'Q' | 'q' | 'T' | 't' | 'A' | 'a'} PathDataCommand
*/
/**
* @typedef {Object} PathDataItem
* @property {PathDataCommand} command
* @property {number[]} args
*/
const argsCountPerCommand = {
M: 2,
m: 2,
Z: 0,
z: 0,
L: 2,
l: 2,
H: 1,
h: 1,
V: 1,
v: 1,
C: 6,
c: 6,
S: 4,
s: 4,
Q: 4,
q: 4,
T: 2,
t: 2,
A: 7,
a: 7
};
/**
* @type {(c: string) => c is PathDataCommand}
*/
const isCommand = (c) => {
return c in argsCountPerCommand;
};
/**
* @type {(c: string) => boolean}
*/
const isWsp = (c) => {
const codePoint = c.codePointAt(0);
return (
codePoint === 0x20 ||
codePoint === 0x9 ||
codePoint === 0xd ||
codePoint === 0xa
);
};
/**
* @type {(c: string) => boolean}
*/
const isDigit = (c) => {
const codePoint = c.codePointAt(0);
if (codePoint == null) {
return false;
}
return 48 <= codePoint && codePoint <= 57;
};
/**
* @typedef {'none' | 'sign' | 'whole' | 'decimal_point' | 'decimal' | 'e' | 'exponent_sign' | 'exponent'} ReadNumberState
*/
/**
* @type {(string: string, cursor: number) => [number, number | null]}
*/
const readNumber = (string, cursor) => {
let i = cursor;
let value = '';
let state = /** @type {ReadNumberState} */ ('none');
for (; i < string.length; i += 1) {
const c = string[i];
if (c === '+' || c === '-') {
if (state === 'none') {
state = 'sign';
value += c;
continue;
}
if (state === 'e') {
state = 'exponent_sign';
value += c;
continue;
}
}
if (isDigit(c)) {
if (state === 'none' || state === 'sign' || state === 'whole') {
state = 'whole';
value += c;
continue;
}
if (state === 'decimal_point' || state === 'decimal') {
state = 'decimal';
value += c;
continue;
}
if (state === 'e' || state === 'exponent_sign' || state === 'exponent') {
state = 'exponent';
value += c;
continue;
}
}
if (c === '.') {
if (state === 'none' || state === 'sign' || state === 'whole') {
state = 'decimal_point';
value += c;
continue;
}
}
if (c === 'E' || c === 'e') {
if (
state === 'whole' ||
state === 'decimal_point' ||
state === 'decimal'
) {
state = 'e';
value += c;
continue;
}
}
break;
}
const number = Number.parseFloat(value);
if (Number.isNaN(number)) {
return [cursor, null];
}
// step back to delegate iteration to parent loop
return [i - 1, number];
};
/**
* @type {(string: string) => Array}
*/
const parsePathData = (string) => {
/**
* @type {Array}
*/
const pathData = [];
/**
* @type {null | PathDataCommand}
*/
let command = null;
let args = /** @type {number[]} */ ([]);
let argsCount = 0;
let canHaveComma = false;
let hadComma = false;
for (let i = 0; i < string.length; i += 1) {
const c = string.charAt(i);
if (isWsp(c)) {
continue;
}
// allow comma only between arguments
if (canHaveComma && c === ',') {
if (hadComma) {
break;
}
hadComma = true;
continue;
}
if (isCommand(c)) {
if (hadComma) {
return pathData;
}
if (command == null) {
// moveto should be leading command
if (c !== 'M' && c !== 'm') {
return pathData;
}
} else {
// stop if previous command arguments are not flushed
if (args.length !== 0) {
return pathData;
}
}
command = c;
args = [];
argsCount = argsCountPerCommand[command];
canHaveComma = false;
// flush command without arguments
if (argsCount === 0) {
pathData.push({ command, args });
}
continue;
}
// avoid parsing arguments if no command detected
if (command == null) {
return pathData;
}
// read next argument
let newCursor = i;
let number = null;
if (command === 'A' || command === 'a') {
const position = args.length;
if (position === 0 || position === 1) {
// allow only positive number without sign as first two arguments
if (c !== '+' && c !== '-') {
[newCursor, number] = readNumber(string, i);
}
}
if (position === 2 || position === 5 || position === 6) {
[newCursor, number] = readNumber(string, i);
}
if (position === 3 || position === 4) {
// read flags
if (c === '0') {
number = 0;
}
if (c === '1') {
number = 1;
}
}
} else {
[newCursor, number] = readNumber(string, i);
}
if (number == null) {
return pathData;
}
args.push(number);
canHaveComma = true;
hadComma = false;
i = newCursor;
// flush arguments when necessary count is reached
if (args.length === argsCount) {
pathData.push({ command, args });
// subsequent moveto coordinates are threated as implicit lineto commands
if (command === 'M') {
command = 'L';
}
if (command === 'm') {
command = 'l';
}
args = [];
}
}
return pathData;
};
const apply = function (commands, doc) {
// current point, control point, and subpath starting point
cx = cy = px = py = sx = sy = 0;
// run the commands
for (let i = 0; i < commands.length; i++) {
const { command, args } = commands[i];
if (typeof runners[command] === 'function') {
runners[command](doc, args);
}
}
};
const runners = {
M(doc, a) {
cx = a[0];
cy = a[1];
px = py = null;
sx = cx;
sy = cy;
return doc.moveTo(cx, cy);
},
m(doc, a) {
cx += a[0];
cy += a[1];
px = py = null;
sx = cx;
sy = cy;
return doc.moveTo(cx, cy);
},
C(doc, a) {
cx = a[4];
cy = a[5];
px = a[2];
py = a[3];
return doc.bezierCurveTo(...a);
},
c(doc, a) {
doc.bezierCurveTo(
a[0] + cx,
a[1] + cy,
a[2] + cx,
a[3] + cy,
a[4] + cx,
a[5] + cy
);
px = cx + a[2];
py = cy + a[3];
cx += a[4];
return (cy += a[5]);
},
S(doc, a) {
if (px === null) {
px = cx;
py = cy;
}
doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), a[0], a[1], a[2], a[3]);
px = a[0];
py = a[1];
cx = a[2];
return (cy = a[3]);
},
s(doc, a) {
if (px === null) {
px = cx;
py = cy;
}
doc.bezierCurveTo(
cx - (px - cx),
cy - (py - cy),
cx + a[0],
cy + a[1],
cx + a[2],
cy + a[3]
);
px = cx + a[0];
py = cy + a[1];
cx += a[2];
return (cy += a[3]);
},
Q(doc, a) {
px = a[0];
py = a[1];
cx = a[2];
cy = a[3];
return doc.quadraticCurveTo(a[0], a[1], cx, cy);
},
q(doc, a) {
doc.quadraticCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy);
px = cx + a[0];
py = cy + a[1];
cx += a[2];
return (cy += a[3]);
},
T(doc, a) {
if (px === null) {
px = cx;
py = cy;
} else {
px = cx - (px - cx);
py = cy - (py - cy);
}
doc.quadraticCurveTo(px, py, a[0], a[1]);
px = cx - (px - cx);
py = cy - (py - cy);
cx = a[0];
return (cy = a[1]);
},
t(doc, a) {
if (px === null) {
px = cx;
py = cy;
} else {
px = cx - (px - cx);
py = cy - (py - cy);
}
doc.quadraticCurveTo(px, py, cx + a[0], cy + a[1]);
cx += a[0];
return (cy += a[1]);
},
A(doc, a) {
solveArc(doc, cx, cy, a);
cx = a[5];
return (cy = a[6]);
},
a(doc, a) {
a[5] += cx;
a[6] += cy;
solveArc(doc, cx, cy, a);
cx = a[5];
return (cy = a[6]);
},
L(doc, a) {
cx = a[0];
cy = a[1];
px = py = null;
return doc.lineTo(cx, cy);
},
l(doc, a) {
cx += a[0];
cy += a[1];
px = py = null;
return doc.lineTo(cx, cy);
},
H(doc, a) {
cx = a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
h(doc, a) {
cx += a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
V(doc, a) {
cy = a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
v(doc, a) {
cy += a[0];
px = py = null;
return doc.lineTo(cx, cy);
},
Z(doc) {
doc.closePath();
cx = sx;
return (cy = sy);
},
z(doc) {
doc.closePath();
cx = sx;
return (cy = sy);
}
};
const solveArc = function (doc, x, y, coords) {
const [rx, ry, rot, large, sweep, ex, ey] = coords;
const segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
for (let seg of segs) {
const bez = segmentToBezier(...seg);
doc.bezierCurveTo(...bez);
}
};
// from Inkscape svgtopdf, thanks!
const arcToSegments = function (x, y, rx, ry, large, sweep, rotateX, ox, oy) {
const th = rotateX * (Math.PI / 180);
const sin_th = Math.sin(th);
const cos_th = Math.cos(th);
rx = Math.abs(rx);
ry = Math.abs(ry);
px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
let pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
if (pl > 1) {
pl = Math.sqrt(pl);
rx *= pl;
ry *= pl;
}
const a00 = cos_th / rx;
const a01 = sin_th / rx;
const a10 = -sin_th / ry;
const a11 = cos_th / ry;
const x0 = a00 * ox + a01 * oy;
const y0 = a10 * ox + a11 * oy;
const x1 = a00 * x + a01 * y;
const y1 = a10 * x + a11 * y;
const d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
let sfactor_sq = 1 / d - 0.25;
if (sfactor_sq < 0) {
sfactor_sq = 0;
}
let sfactor = Math.sqrt(sfactor_sq);
if (sweep === large) {
sfactor = -sfactor;
}
const xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
const yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
const th0 = Math.atan2(y0 - yc, x0 - xc);
const th1 = Math.atan2(y1 - yc, x1 - xc);
let th_arc = th1 - th0;
if (th_arc < 0 && sweep === 1) {
th_arc += 2 * Math.PI;
} else if (th_arc > 0 && sweep === 0) {
th_arc -= 2 * Math.PI;
}
const segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
const result = [];
for (let i = 0; i < segments; i++) {
const th2 = th0 + (i * th_arc) / segments;
const th3 = th0 + ((i + 1) * th_arc) / segments;
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
}
return result;
};
const segmentToBezier = function (cx, cy, th0, th1, rx, ry, sin_th, cos_th) {
const a00 = cos_th * rx;
const a01 = -sin_th * ry;
const a10 = sin_th * rx;
const a11 = cos_th * ry;
const th_half = 0.5 * (th1 - th0);
const t =
((8 / 3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5)) /
Math.sin(th_half);
const x1 = cx + Math.cos(th0) - t * Math.sin(th0);
const y1 = cy + Math.sin(th0) + t * Math.cos(th0);
const x3 = cx + Math.cos(th1);
const y3 = cy + Math.sin(th1);
const x2 = x3 + t * Math.sin(th1);
const y2 = y3 - t * Math.cos(th1);
return [
a00 * x1 + a01 * y1,
a10 * x1 + a11 * y1,
a00 * x2 + a01 * y2,
a10 * x2 + a11 * y2,
a00 * x3 + a01 * y3,
a10 * x3 + a11 * y3
];
};
class SVGPath {
static apply(doc, path) {
const commands = parsePathData(path);
apply(commands, doc);
}
}
export default SVGPath;
================================================
FILE: packages/pdfkit/src/pattern.js
================================================
/*
PDF tiling pattern support. Uncolored only.
*/
const underlyingColorSpaces = ['DeviceCMYK', 'DeviceRGB'];
class PDFTilingPattern {
constructor(doc, bBox, xStep, yStep, stream) {
this.doc = doc;
this.bBox = bBox;
this.xStep = xStep;
this.yStep = yStep;
this.stream = stream;
}
createPattern() {
// no resources needed for our current usage
// required entry
const resources = this.doc.ref();
resources.end();
// apply default transform matrix (flipped in the default doc._ctm)
// see document.js & gradient.js
const [m0, m1, m2, m3, m4, m5] = this.doc._ctm;
const [m11, m12, m21, m22, dx, dy] = [1, 0, 0, 1, 0, 0];
const m = [
m0 * m11 + m2 * m12,
m1 * m11 + m3 * m12,
m0 * m21 + m2 * m22,
m1 * m21 + m3 * m22,
m0 * dx + m2 * dy + m4,
m1 * dx + m3 * dy + m5
];
const pattern = this.doc.ref({
Type: 'Pattern',
PatternType: 1, // tiling
PaintType: 2, // 1-colored, 2-uncolored
TilingType: 2, // 2-no distortion
BBox: this.bBox,
XStep: this.xStep,
YStep: this.yStep,
Matrix: m.map((v) => +v.toFixed(5)),
Resources: resources
});
pattern.end(this.stream);
return pattern;
}
embedPatternColorSpaces() {
// map each pattern to an underlying color space
// and embed on each page
underlyingColorSpaces.forEach((csName) => {
const csId = this.getPatternColorSpaceId(csName);
if (this.doc.page.colorSpaces[csId]) return;
const cs = this.doc.ref(['Pattern', csName]);
cs.end();
this.doc.page.colorSpaces[csId] = cs;
});
}
getPatternColorSpaceId(underlyingColorspace) {
return `CsP${underlyingColorspace}`;
}
embed() {
if (!this.id) {
this.doc._patternCount = this.doc._patternCount + 1;
this.id = 'P' + this.doc._patternCount;
this.pattern = this.createPattern();
}
// patterns are embedded in each page
if (!this.doc.page.patterns[this.id]) {
this.doc.page.patterns[this.id] = this.pattern;
}
}
apply(stroke, patternColor) {
// do any embedding/creating that might be needed
this.embedPatternColorSpaces();
this.embed();
const normalizedColor = this.doc._normalizeColor(patternColor);
if (!normalizedColor)
throw Error(`invalid pattern color. (value: ${patternColor})`);
// select one of the pattern color spaces
const csId = this.getPatternColorSpaceId(
this.doc._getColorSpace(normalizedColor)
);
this.doc._setColorSpace(csId, stroke);
// stroke/fill using the pattern and color (in the above underlying color space)
const op = stroke ? 'SCN' : 'scn';
return this.doc.addContent(
`${normalizedColor.join(' ')} /${this.id} ${op}`
);
}
}
export default { PDFTilingPattern };
================================================
FILE: packages/pdfkit/src/reference.js
================================================
/*
PDFReference - represents a reference to another object in the PDF object heirarchy
By Devon Govett
*/
import zlib from 'zlib';
import stream from 'stream';
import PDFObject from './object';
class PDFReference extends stream.Writable {
constructor(document, id, data) {
super({ decodeStrings: false });
this.finalize = this.finalize.bind(this);
this.document = document;
this.id = id;
if (data == null) {
data = {};
}
this.data = data;
this.gen = 0;
this.deflate = null;
this.compress = this.document.compress && !this.data.Filter;
this.uncompressedLength = 0;
this.chunks = [];
}
initDeflate() {
this.data.Filter = 'FlateDecode';
this.deflate = zlib.createDeflate();
this.deflate.on('data', (chunk) => {
this.chunks.push(chunk);
return (this.data.Length += chunk.length);
});
return this.deflate.on('end', this.finalize);
}
_write(chunk, encoding, callback) {
if (!(chunk instanceof Uint8Array)) {
chunk = Buffer.from(chunk + '\n', 'binary');
}
this.uncompressedLength += chunk.length;
if (this.data.Length == null) {
this.data.Length = 0;
}
if (this.compress) {
if (!this.deflate) {
this.initDeflate();
}
this.deflate.write(chunk);
} else {
this.chunks.push(chunk);
this.data.Length += chunk.length;
}
return callback();
}
end() {
super.end(...arguments);
if (this.deflate) {
return this.deflate.end();
}
return this.finalize();
}
finalize() {
this.offset = this.document._offset;
this.document._write(`${this.id} ${this.gen} obj`);
this.document._write(PDFObject.convert(this.data));
if (this.chunks.length) {
this.document._write('stream');
for (let chunk of Array.from(this.chunks)) {
this.document._write(chunk);
}
this.chunks.length = 0; // free up memory
this.document._write('\nendstream');
}
this.document._write('endobj');
return this.document._refEnd(this);
}
toString() {
return `${this.id} ${this.gen} R`;
}
}
export default PDFReference;
================================================
FILE: packages/pdfkit/src/security.js
================================================
/*
PDFSecurity - represents PDF security settings
By Yang Liu
*/
// This file is ran directly with Node - needs to have .js extension
import MD5 from 'crypto-js/md5.js';
const wordArrayToBuffer = (wordArray) => {
const byteArray = [];
for (let i = 0; i < wordArray.sigBytes; i++) {
byteArray.push(
(wordArray.words[Math.floor(i / 4)] >> (8 * (3 - (i % 4)))) & 0xff
);
}
return Buffer.from(byteArray);
};
class PDFSecurity {
static generateFileID(info = {}) {
let infoStr = `${info.CreationDate.getTime()}\n`;
for (let key in info) {
if (!info.hasOwnProperty(key)) continue;
infoStr += `${key}: ${info[key].valueOf()}\n`;
}
return wordArrayToBuffer(MD5(infoStr));
}
}
export default PDFSecurity;
================================================
FILE: packages/pdfkit/src/spotcolor.js
================================================
export default class SpotColor {
constructor(doc, name, C, M, Y, K) {
this.id = 'CS' + Object.keys(doc.spotColors).length;
this.name = name;
this.values = [C, M, Y, K];
this.ref = doc.ref([
'Separation',
this.name,
'DeviceCMYK',
{
Range: [0, 1, 0, 1, 0, 1, 0, 1],
C0: [0, 0, 0, 0],
C1: this.values.map((value) => value / 100),
FunctionType: 2,
Domain: [0, 1],
N: 1
}
]);
this.ref.end();
}
toString() {
return `${this.ref.id} 0 R`;
}
}
================================================
FILE: packages/pdfkit/src/structure_content.js
================================================
/*
PDFStructureContent - a reference to a marked structure content
By Ben Schmidt
*/
class PDFStructureContent {
constructor(pageRef, mcid) {
this.refs = [{ pageRef, mcid }];
}
push(structContent) {
structContent.refs.forEach((ref) => this.refs.push(ref));
}
}
export default PDFStructureContent;
================================================
FILE: packages/pdfkit/src/structure_element.js
================================================
/*
PDFStructureElement - represents an element in the PDF logical structure tree
By Ben Schmidt
*/
import PDFStructureContent from './structure_content';
class PDFStructureElement {
constructor(document, type, options = {}, children = null) {
this.document = document;
this._attached = false;
this._ended = false;
this._flushed = false;
this.dictionary = document.ref({
// Type: "StructElem",
S: type
});
const data = this.dictionary.data;
if (Array.isArray(options) || this._isValidChild(options)) {
children = options;
options = {};
}
if (typeof options.title !== 'undefined') {
data.T = new String(options.title);
}
if (typeof options.lang !== 'undefined') {
data.Lang = new String(options.lang);
}
if (typeof options.alt !== 'undefined') {
data.Alt = new String(options.alt);
}
if (typeof options.expanded !== 'undefined') {
data.E = new String(options.expanded);
}
if (typeof options.actual !== 'undefined') {
data.ActualText = new String(options.actual);
}
this._children = [];
if (children) {
if (!Array.isArray(children)) {
children = [children];
}
children.forEach((child) => this.add(child));
this.end();
}
}
add(child) {
if (this._ended) {
throw new Error(`Cannot add child to already-ended structure element`);
}
if (!this._isValidChild(child)) {
throw new Error(`Invalid structure element child`);
}
if (child instanceof PDFStructureElement) {
child.setParent(this.dictionary);
if (this._attached) {
child.setAttached();
}
}
if (child instanceof PDFStructureContent) {
this._addContentToParentTree(child);
}
if (typeof child === 'function' && this._attached) {
// _contentForClosure() adds the content to the parent tree
child = this._contentForClosure(child);
}
this._children.push(child);
return this;
}
_addContentToParentTree(content) {
content.refs.forEach(({ pageRef, mcid }) => {
const pageStructParents = this.document
.getStructParentTree()
.get(pageRef.data.StructParents);
pageStructParents[mcid] = this.dictionary;
});
}
setParent(parentRef) {
if (this.dictionary.data.P) {
throw new Error(`Structure element added to more than one parent`);
}
this.dictionary.data.P = parentRef;
this._flush();
}
setAttached() {
if (this._attached) {
return;
}
this._children.forEach((child, index) => {
if (child instanceof PDFStructureElement) {
child.setAttached();
}
if (typeof child === 'function') {
this._children[index] = this._contentForClosure(child);
}
});
this._attached = true;
this._flush();
}
end() {
if (this._ended) {
return;
}
this._children
.filter((child) => child instanceof PDFStructureElement)
.forEach((child) => child.end());
this._ended = true;
this._flush();
}
_isValidChild(child) {
return (
child instanceof PDFStructureElement ||
child instanceof PDFStructureContent ||
typeof child === 'function'
);
}
_contentForClosure(closure) {
const content = this.document.markStructureContent(this.dictionary.data.S);
closure();
this.document.endMarkedContent();
this._addContentToParentTree(content);
return content;
}
_isFlushable() {
if (!this.dictionary.data.P || !this._ended) {
return false;
}
return this._children.every((child) => {
if (typeof child === 'function') {
return false;
}
if (child instanceof PDFStructureElement) {
return child._isFlushable();
}
return true;
});
}
_flush() {
if (this._flushed || !this._isFlushable()) {
return;
}
this.dictionary.data.K = [];
this._children.forEach((child) => this._flushChild(child));
this.dictionary.end();
// free memory used by children; the dictionary itself may still be
// referenced by a parent structure element or root, but we can
// at least trim the tree here
this._children = [];
this.dictionary.data.K = null;
this._flushed = true;
}
_flushChild(child) {
if (child instanceof PDFStructureElement) {
this.dictionary.data.K.push(child.dictionary);
}
if (child instanceof PDFStructureContent) {
child.refs.forEach(({ pageRef, mcid }) => {
if (!this.dictionary.data.Pg) {
this.dictionary.data.Pg = pageRef;
}
if (this.dictionary.data.Pg === pageRef) {
this.dictionary.data.K.push(mcid);
} else {
this.dictionary.data.K.push({
Type: 'MCR',
Pg: pageRef,
MCID: mcid
});
}
});
}
}
}
export default PDFStructureElement;
================================================
FILE: packages/pdfkit/src/tree.js
================================================
/*
PDFTree - abstract base class for name and number tree objects
*/
import PDFObject from './object';
class PDFTree {
constructor(options = {}) {
this._items = {};
// disable /Limits output for this tree
this.limits = typeof options.limits === 'boolean' ? options.limits : true;
}
add(key, val) {
return (this._items[key] = val);
}
get(key) {
return this._items[key];
}
toString() {
// Needs to be sorted by key
const sortedKeys = Object.keys(this._items).sort((a, b) =>
this._compareKeys(a, b)
);
const out = ['<<'];
if (this.limits && sortedKeys.length > 1) {
const first = sortedKeys[0],
last = sortedKeys[sortedKeys.length - 1];
out.push(
` /Limits ${PDFObject.convert([this._dataForKey(first), this._dataForKey(last)])}`
);
}
out.push(` /${this._keysName()} [`);
for (let key of sortedKeys) {
out.push(
` ${PDFObject.convert(this._dataForKey(key))} ${PDFObject.convert(
this._items[key]
)}`
);
}
out.push(']');
out.push('>>');
return out.join('\n');
}
_compareKeys(/*a, b*/) {
throw new Error('Must be implemented by subclasses');
}
_keysName() {
throw new Error('Must be implemented by subclasses');
}
_dataForKey(/*k*/) {
throw new Error('Must be implemented by subclasses');
}
}
export default PDFTree;
================================================
FILE: packages/pdfkit/src/utils/range.js
================================================
const range = (left, right, inclusive) => {
let range = [];
let ascending = left < right;
let end = !inclusive ? right : ascending ? right + 1 : right - 1;
for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) {
range.push(i);
}
return range;
};
export default range;
================================================
FILE: packages/pdfkit/src/utils.js
================================================
export function PDFNumber(n) {
// PDF numbers are strictly 32bit
// so convert this number to the nearest 32bit number
// @see ISO 32000-1 Annex C.2 (real numbers)
return Math.fround(n);
}
/**
* Measurement of size
*
* @typedef {number | `${number}` | `${number}${'em' | 'in' | 'px' | 'cm' | 'mm' | 'pc' | 'ex' | 'ch' | 'rem' | 'vw' | 'vmin' | 'vmax' | '%' | 'pt'}`} Size
*/
/**
* Measurement of how wide something is, false means 0 and true means 1
*
* @typedef {Size | boolean} Wideness
*/
/**
* Side definitions
* - To define all sides, use a single value
* - To define up-down left-right, use a `[Y, X]` array
* - To define each side, use `[top, right, bottom, left]` array
* - Or `{vertical: SideValue, horizontal: SideValue}`
* - Or `{top: SideValue, right: SideValue, bottom: SideValue, left: SideValue}`
*
* @template T
* @typedef {T | [T, T] | [T, T, T, T] | { vertical: T; horizontal: T } | ExpandedSideDefinition} SideDefinition
**/
/**
* @template T
* @typedef {{ top: T; right: T; bottom: T; left: T }} ExpandedSideDefinition
*/
/**
* Convert any side definition into a static structure
*
* @template S
* @template D
* @template O
* @template {S | D} T
* @param {SideDefinition} sides - The sides to convert
* @param {SideDefinition} defaultDefinition - The value to use when no definition is provided
* @param {function(T): O} transformer - The transformation to apply to the sides once normalized
* @returns {ExpandedSideDefinition}
*/
export function normalizeSides(
sides,
defaultDefinition = undefined,
transformer = (v) => v
) {
if (
sides === undefined ||
sides === null ||
(typeof sides === 'object' && Object.keys(sides).length === 0)
) {
sides = defaultDefinition;
}
if (typeof sides !== 'object' || sides === null) {
sides = [sides, sides, sides, sides];
}
if (Array.isArray(sides)) {
if (sides.length === 2) {
sides = { vertical: sides[0], horizontal: sides[1] };
} else {
sides = {
top: sides[0],
right: sides[1],
bottom: sides[2],
left: sides[3]
};
}
}
if ('vertical' in sides || 'horizontal' in sides) {
sides = {
top: sides.vertical,
right: sides.horizontal,
bottom: sides.vertical,
left: sides.horizontal
};
}
return {
top: transformer(sides.top),
right: transformer(sides.right),
bottom: transformer(sides.bottom),
left: transformer(sides.left)
};
}
export const MM_TO_CM = 1 / 10; // 1MM = 1CM
export const CM_TO_IN = 1 / 2.54; // 1CM = 1/2.54 IN
export const PX_TO_IN = 1 / 96; // 1 PX = 1/96 IN
export const IN_TO_PT = 72; // 1 IN = 72 PT
export const PC_TO_PT = 12; // 1 PC = 12 PT
/**
* Get cosine in degrees of a
*
* Rounding errors are handled
* @param a
* @returns {number}
*/
export function cosine(a) {
if (a === 0) return 1;
if (a === 90) return 0;
if (a === 180) return -1;
if (a === 270) return 0;
return Math.cos((a * Math.PI) / 180);
}
/**
* Get sine in degrees of a
*
* Rounding errors are handled
* @param a
* @returns {number}
*/
export function sine(a) {
if (a === 0) return 0;
if (a === 90) return 1;
if (a === 180) return 0;
if (a === 270) return -1;
return Math.sin((a * Math.PI) / 180);
}
================================================
FILE: packages/pdfkit/src/virtual-fs.js
================================================
class VirtualFileSystem {
constructor() {
this.fileData = {};
}
readFileSync(fileName, options = {}) {
const encoding = typeof options === 'string' ? options : options.encoding;
const virtualFileName = normalizeFilename(fileName);
const data = this.fileData[virtualFileName];
if (data == null) {
throw new Error(
`File '${virtualFileName}' not found in virtual file system`
);
}
if (encoding) {
// return a string
return typeof data === 'string' ? data : data.toString(encoding);
}
return Buffer.from(data, typeof data === 'string' ? 'base64' : undefined);
}
writeFileSync(fileName, content) {
this.fileData[normalizeFilename(fileName)] = content;
}
bindFileData(data = {}, options = {}) {
if (options.reset) {
this.fileData = data;
} else {
Object.assign(this.fileData, data);
}
}
}
function normalizeFilename(fileName) {
if (fileName.indexOf(__dirname) === 0) {
fileName = fileName.substring(__dirname.length);
}
if (fileName.indexOf('/') === 0) {
fileName = fileName.substring(1);
}
return fileName;
}
export default new VirtualFileSystem();
================================================
FILE: packages/pdfkit/tests/font/standard.test.ts
================================================
import { describe, expect, it } from 'vitest';
import StandardFont from '../../src/font.js';
describe('standard fonts', () => {
it('should resolve advanceWidth of soft hyphen to be zero', () => {
const SOFT_HYPHEN = '\u00AD';
const font = StandardFont.open({}, 'Helvetica', 'Helvetica', 'foobar');
expect(font.encode(SOFT_HYPHEN)[1][0].advanceWidth).toBe(0);
});
});
================================================
FILE: packages/png-js/.gitignore
================================================
lib
================================================
FILE: packages/png-js/CHANGELOG.md
================================================
# @react-pdf/png-js
## 3.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
## 2.3.1
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
## 2.3.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
## 2.2.0
### Minor Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- [#1941](https://github.com/diegomura/react-pdf/pull/1941) [`001a208`](https://github.com/diegomura/react-pdf/commit/001a20812fa039d09931b22eb97a8869e3b31cc5) Thanks [@PhilippMeissner](https://github.com/PhilippMeissner)! - chore: adds missing licenses to package.json
## 2.1.0
### Minor Changes
- [#1610](https://github.com/diegomura/react-pdf/pull/1610) [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e) Thanks [@jeetiss](https://github.com/jeetiss)! - updated rollup rollup-plugins and babel
### Patch Changes
- [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
================================================
FILE: packages/png-js/LICENSE
================================================
MIT License
Copyright (c) 2017 Devon Govett
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: packages/png-js/README.md
================================================
# @react-pdf/png-js
A PNG decoder in JS for the canvas element or Node.js.
## Acknowledges
This project is a fork of [png.js](https://github.com/foliojs/png.js) by @devongovett and continued under the scope of this project since it has react-pdf specific features. Any recongnition should go to him and the original project mantainers.
## About this fork
> Updated to 977b857a11676c1e720e79ed8d9178a005a9abd6
- Build node and browser specific bundles
- Uses rollup for build
## Browser Usage
Simply include png.js and zlib.js on your HTML page, create a canvas element, and call PNG.load to load an image.
The source code for the browser version resides in `png.js` and also supports loading and displaying animated PNGs.
## Node.js Usage
Install the module using npm
sudo npm install png-js
Require the module and decode a PNG
import PNG from 'png-js';
PNG.decode('some.png', function(pixels) {
// pixels is a 1d array (in rgba order) of decoded pixel data
});
You can also call `PNG.load` if you want to load the PNG (but not decode the pixels) synchronously. If you already
have the PNG data in a buffer, simply use `new PNG(buffer)`. In both of these cases, you need to call `png.decode`
yourself which passes your callback the decoded pixels as a buffer. If you already have a buffer you want the pixels
copied to, call `copyToImageData` with your buffer and the decoded pixels as returned from `decodePixels`.
================================================
FILE: packages/png-js/babel.config.js
================================================
export default { extends: '../../babel.config.js' };
================================================
FILE: packages/png-js/package.json
================================================
{
"name": "@react-pdf/png-js",
"description": "A PNG decoder in JS",
"version": "3.0.0",
"license": "MIT",
"type": "module",
"main": "./lib/png-js.js",
"browser": {
"./lib/png-js.js": "./lib/png-js.browser.js"
},
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/png-js"
},
"author": {
"name": "Devon Govett",
"email": "devongovett@gmail.com",
"url": "http://badassjs.com/"
},
"scripts": {
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w"
},
"files": [
"lib"
],
"dependencies": {
"browserify-zlib": "^0.2.0"
}
}
================================================
FILE: packages/png-js/rollup.config.js
================================================
import babel from '@rollup/plugin-babel';
import replace from '@rollup/plugin-replace';
import ignore from 'rollup-plugin-ignore';
import alias from '@rollup/plugin-alias';
import nodePolyfills from 'rollup-plugin-polyfill-node';
import nodeResolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import pkg from './package.json' with { type: 'json' };
const input = 'src/index.js';
const babelConfig = () => ({
babelrc: true,
babelHelpers: 'runtime',
exclude: 'node_modules/**',
});
const getExternal = ({ browser }) =>
browser
? [
...Object.keys(pkg.dependencies).filter(
(dep) => dep !== 'browserify-zlib',
),
]
: ['fs', ...Object.keys(pkg.dependencies)];
const getPlugins = ({ browser }) => [
...(browser
? [
ignore(['fs']),
alias({
entries: [{ find: 'zlib', replacement: 'browserify-zlib' }],
}),
commonjs(),
nodeResolve({ browser, preferBuiltins: !browser }),
nodePolyfills({
include: [/node_modules\/.+\.js/, /\/png-js\/src\/.*\.js/],
}),
]
: []),
babel(babelConfig()),
replace({
preventAssignment: true,
values: {
BROWSER: JSON.stringify(browser),
},
}),
];
const serverConfig = {
input,
output: { format: 'es', file: 'lib/png-js.js' },
external: getExternal({ browser: false }),
plugins: getPlugins({ browser: false }),
};
const browserConfig = {
input,
output: { format: 'es', file: 'lib/png-js.browser.js' },
external: getExternal({ browser: true }),
plugins: getPlugins({ browser: true }),
};
export default [serverConfig, browserConfig];
================================================
FILE: packages/png-js/src/index.js
================================================
import fs from 'fs';
import zlib from 'zlib';
class PNG {
static decode(path, fn) {
if (BROWSER) {
throw new Error('PNG.decode not available in browser build');
} else {
return fs.readFile(path, (err, file) => {
const png = new PNG(file);
return png.decode((pixels) => fn(pixels));
});
}
}
static load(path) {
if (BROWSER) {
throw new Error('PNG.load not available in browser build');
} else {
const file = fs.readFileSync(path);
return new PNG(file);
}
}
constructor(data) {
let i;
this.data = data;
this.pos = 8; // Skip the default header
this.palette = [];
this.imgData = [];
this.transparency = {};
this.text = {};
while (true) {
const chunkSize = this.readUInt32();
let section = '';
for (i = 0; i < 4; i++) {
section += String.fromCharCode(this.data[this.pos++]);
}
switch (section) {
case 'IHDR':
// we can grab interesting values from here (like width, height, etc)
this.width = this.readUInt32();
this.height = this.readUInt32();
this.bits = this.data[this.pos++];
this.colorType = this.data[this.pos++];
this.compressionMethod = this.data[this.pos++];
this.filterMethod = this.data[this.pos++];
this.interlaceMethod = this.data[this.pos++];
break;
case 'PLTE':
this.palette = this.read(chunkSize);
break;
case 'IDAT':
for (i = 0; i < chunkSize; i++) {
this.imgData.push(this.data[this.pos++]);
}
break;
case 'tRNS':
// This chunk can only occur once and it must occur after the
// PLTE chunk and before the IDAT chunk.
this.transparency = {};
switch (this.colorType) {
case 3:
// Indexed color, RGB. Each byte in this chunk is an alpha for
// the palette index in the PLTE ("palette") chunk up until the
// last non-opaque entry. Set up an array, stretching over all
// palette entries which will be 0 (opaque) or 1 (transparent).
this.transparency.indexed = this.read(chunkSize);
var short = 255 - this.transparency.indexed.length;
if (short > 0) {
for (i = 0; i < short; i++) {
this.transparency.indexed.push(255);
}
}
break;
case 0:
// Greyscale. Corresponding to entries in the PLTE chunk.
// Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
this.transparency.grayscale = this.read(chunkSize)[0];
break;
case 2:
// True color with proper alpha channel.
this.transparency.rgb = this.read(chunkSize);
break;
}
break;
case 'tEXt':
var text = this.read(chunkSize);
var index = text.indexOf(0);
var key = String.fromCharCode.apply(String, text.slice(0, index));
this.text[key] = String.fromCharCode.apply(
String,
text.slice(index + 1),
);
break;
case 'IEND':
// we've got everything we need!
switch (this.colorType) {
case 0:
case 3:
case 4:
this.colors = 1;
break;
case 2:
case 6:
this.colors = 3;
break;
}
this.hasAlphaChannel = [4, 6].includes(this.colorType);
var colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
this.pixelBitlength = this.bits * colors;
switch (this.colors) {
case 1:
this.colorSpace = 'DeviceGray';
break;
case 3:
this.colorSpace = 'DeviceRGB';
break;
}
this.imgData = Buffer.from(this.imgData);
return;
default:
// unknown (or unimportant) section, skip it
this.pos += chunkSize;
}
this.pos += 4; // Skip the CRC
if (this.pos > this.data.length) {
throw new Error('Incomplete or corrupt PNG file');
}
}
}
read(bytes) {
const result = new Array(bytes);
for (let i = 0; i < bytes; i++) {
result[i] = this.data[this.pos++];
}
return result;
}
readUInt32() {
const b1 = this.data[this.pos++] << 24;
const b2 = this.data[this.pos++] << 16;
const b3 = this.data[this.pos++] << 8;
const b4 = this.data[this.pos++];
return b1 | b2 | b3 | b4;
}
readUInt16() {
const b1 = this.data[this.pos++] << 8;
const b2 = this.data[this.pos++];
return b1 | b2;
}
decodePixels(fn) {
return zlib.inflate(this.imgData, (err, data) => {
if (err) throw err;
var pos = 0;
const { width, height } = this;
var pixelBytes = this.pixelBitlength / 8;
const pixels = Buffer.alloc(width * height * pixelBytes);
function pass(x0, y0, dx, dy, singlePass = false) {
const w = Math.ceil((width - x0) / dx);
const h = Math.ceil((height - y0) / dy);
const scanlineLength = pixelBytes * w;
const buffer = singlePass ? pixels : Buffer.alloc(scanlineLength * h);
let row = 0;
let c = 0;
while (row < h && pos < data.length) {
var byte;
var col;
var i;
var left;
var upper;
switch (data[pos++]) {
case 0: // None
for (i = 0; i < scanlineLength; i++) {
buffer[c++] = data[pos++];
}
break;
case 1: // Sub
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
left = i < pixelBytes ? 0 : buffer[c - pixelBytes];
buffer[c++] = (byte + left) % 256;
}
break;
case 2: // Up
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
upper =
row &&
buffer[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
buffer[c++] = (upper + byte) % 256;
}
break;
case 3: // Average
for (i = 0; i < scanlineLength; i++) {
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
left = i < pixelBytes ? 0 : buffer[c - pixelBytes];
upper =
row &&
buffer[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
buffer[c++] = (byte + Math.floor((left + upper) / 2)) % 256;
}
break;
case 4: // Paeth
for (i = 0; i < scanlineLength; i++) {
var paeth;
var upperLeft;
byte = data[pos++];
col = (i - (i % pixelBytes)) / pixelBytes;
left = i < pixelBytes ? 0 : buffer[c - pixelBytes];
if (row === 0) {
upper = upperLeft = 0;
} else {
upper =
buffer[
(row - 1) * scanlineLength +
col * pixelBytes +
(i % pixelBytes)
];
upperLeft =
col &&
buffer[
(row - 1) * scanlineLength +
(col - 1) * pixelBytes +
(i % pixelBytes)
];
}
const p = left + upper - upperLeft;
const pa = Math.abs(p - left);
const pb = Math.abs(p - upper);
const pc = Math.abs(p - upperLeft);
if (pa <= pb && pa <= pc) {
paeth = left;
} else if (pb <= pc) {
paeth = upper;
} else {
paeth = upperLeft;
}
buffer[c++] = (byte + paeth) % 256;
}
break;
default:
throw new Error(`Invalid filter algorithm: ${data[pos - 1]}`);
}
if (!singlePass) {
let pixelsPos = ((y0 + row * dy) * width + x0) * pixelBytes;
let bufferPos = row * scanlineLength;
for (i = 0; i < w; i++) {
for (let j = 0; j < pixelBytes; j++)
pixels[pixelsPos++] = buffer[bufferPos++];
pixelsPos += (dx - 1) * pixelBytes;
}
}
row++;
}
}
if (this.interlaceMethod === 1) {
/*
1 6 4 6 2 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
3 6 4 6 3 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
*/
pass(0, 0, 8, 8); // 1
pass(4, 0, 8, 8); // 2
pass(0, 4, 4, 8); // 3
pass(2, 0, 4, 4); // 4
pass(0, 2, 2, 4); // 5
pass(1, 0, 2, 2); // 6
pass(0, 1, 1, 2); // 7
} else {
pass(0, 0, 1, 1, true);
}
return fn(pixels);
});
}
decodePalette() {
const { palette } = this;
const { length } = palette;
const transparency = this.transparency.indexed || [];
const ret = Buffer.alloc(transparency.length + length);
let pos = 0;
let c = 0;
for (let i = 0; i < length; i += 3) {
var left;
ret[pos++] = palette[i];
ret[pos++] = palette[i + 1];
ret[pos++] = palette[i + 2];
ret[pos++] = (left = transparency[c++]) != null ? left : 255;
}
return ret;
}
copyToImageData(imageData, pixels) {
let j;
var k;
let { colors } = this;
let palette = null;
let alpha = this.hasAlphaChannel;
if (this.palette.length) {
palette =
this._decodedPalette || (this._decodedPalette = this.decodePalette());
colors = 4;
alpha = true;
}
const data = imageData.data || imageData;
const { length } = data;
const input = palette || pixels;
let i = (j = 0);
if (colors === 1) {
while (i < length) {
k = palette ? pixels[i / 4] * 4 : j;
const v = input[k++];
data[i++] = v;
data[i++] = v;
data[i++] = v;
data[i++] = alpha ? input[k++] : 255;
j = k;
}
} else {
while (i < length) {
k = palette ? pixels[i / 4] * 4 : j;
data[i++] = input[k++];
data[i++] = input[k++];
data[i++] = input[k++];
data[i++] = alpha ? input[k++] : 255;
j = k;
}
}
}
decode(fn) {
const ret = Buffer.alloc(this.width * this.height * 4);
return this.decodePixels((pixels) => {
this.copyToImageData(ret, pixels);
return fn(ret);
});
}
}
export default PNG;
================================================
FILE: packages/primitives/.gitignore
================================================
lib
================================================
FILE: packages/primitives/CHANGELOG.md
================================================
# @react-pdf/primitives
## 4.1.1
### Patch Changes
- [#3067](https://github.com/diegomura/react-pdf/pull/3067) [`96c2464d`](https://github.com/diegomura/react-pdf/commit/96c2464dfaa7294e0d79b7ed64743bfd7b1a8c72) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert primitives package to TS
## 4.1.0
### Minor Changes
- [`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2) Thanks [@diegomura](https://github.com/diegomura)! - feat: added Form Annotation support
## 4.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
## 3.1.1
### Patch Changes
- [#2510](https://github.com/diegomura/react-pdf/pull/2510) [`42bbbda`](https://github.com/diegomura/react-pdf/commit/42bbbda48058acd2d36d7a92c812d133608c459e) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fix require @react-pdf/primitives from CJS
## 3.1.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
## 3.0.1
### Patch Changes
- [#1845](https://github.com/diegomura/react-pdf/pull/1845) [`c6d5a8f`](https://github.com/diegomura/react-pdf/commit/c6d5a8fa9d26d3aca5593773844a5a1e9fad06ae) Thanks [@jeetiss](https://github.com/jeetiss)! - publish commonjs files to npm
## 3.0.0
### Major Changes
- [#1658](https://github.com/diegomura/react-pdf/pull/1658) [`e938df0`](https://github.com/diegomura/react-pdf/commit/e938df0857642707b10b7f65f17ed22dc394ac1b) Thanks [@jeetiss](https://github.com/jeetiss)! - convert code to esm
## 2.0.2
### Patch Changes
- [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
================================================
FILE: packages/primitives/README.md
================================================
# @react-pdf/primitives
Internal element type constants for react-pdf. This package defines the primitive node types used throughout the react-pdf rendering pipeline.
## Installation
```bash
yarn add @react-pdf/primitives
```
## Usage
```js
import { View, Text, Page, Document } from '@react-pdf/primitives';
console.log(View); // 'VIEW'
console.log(Text); // 'TEXT'
console.log(Page); // 'PAGE'
console.log(Document); // 'DOCUMENT'
```
These constants are primarily used internally by react-pdf packages to identify element types during the rendering process.
## Available Primitives
### Document Structure
| Export | Value | Description |
| ---------- | ------------ | --------------------------------- |
| `Document` | `'DOCUMENT'` | Root document container |
| `Page` | `'PAGE'` | Individual page within a document |
| `View` | `'VIEW'` | Generic container element |
| `Text` | `'TEXT'` | Text content container |
| `Link` | `'LINK'` | Hyperlink element |
| `Note` | `'NOTE'` | Annotation/note element |
| `Image` | `'IMAGE'` | Image element |
| `Canvas` | `'CANVAS'` | Custom drawing canvas |
### Form Elements
| Export | Value | Description |
| ----------- | -------------- | ----------------------------- |
| `FieldSet` | `'FIELD_SET'` | Form field grouping container |
| `TextInput` | `'TEXT_INPUT'` | Text input field |
| `Select` | `'SELECT'` | Dropdown select field |
| `Checkbox` | `'CHECKBOX'` | Checkbox input field |
| `List` | `'LIST'` | List element for forms |
### SVG Elements
| Export | Value | Description |
| ---------------- | ------------------- | -------------------------- |
| `Svg` | `'SVG'` | SVG root container |
| `G` | `'G'` | SVG group element |
| `Path` | `'PATH'` | SVG path element |
| `Rect` | `'RECT'` | SVG rectangle element |
| `Line` | `'LINE'` | SVG line element |
| `Circle` | `'CIRCLE'` | SVG circle element |
| `Ellipse` | `'ELLIPSE'` | SVG ellipse element |
| `Polygon` | `'POLYGON'` | SVG polygon element |
| `Polyline` | `'POLYLINE'` | SVG polyline element |
| `Tspan` | `'TSPAN'` | SVG text span element |
| `ClipPath` | `'CLIP_PATH'` | SVG clipping path |
| `Defs` | `'DEFS'` | SVG definitions container |
| `Stop` | `'STOP'` | Gradient stop element |
| `LinearGradient` | `'LINEAR_GRADIENT'` | Linear gradient definition |
| `RadialGradient` | `'RADIAL_GRADIENT'` | Radial gradient definition |
### Internal Types
| Export | Value | Description |
| -------------- | ----------------- | --------------------------------------- |
| `TextInstance` | `'TEXT_INSTANCE'` | Internal representation of text content |
## License
MIT
================================================
FILE: packages/primitives/babel.config.js
================================================
export default { extends: '../../babel.config.js' };
================================================
FILE: packages/primitives/jest.config.js
================================================
export default {
testRegex: 'tests/.*?(test)\\.js$',
};
================================================
FILE: packages/primitives/package.json
================================================
{
"name": "@react-pdf/primitives",
"version": "4.1.1",
"license": "MIT",
"description": "Define uninitialized elements",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/primitives"
},
"scripts": {
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"test": "vitest",
"typecheck": "tsc --noEmit"
},
"files": [
"lib"
]
}
================================================
FILE: packages/primitives/rollup.config.js
================================================
import typescript from '@rollup/plugin-typescript';
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
const config = {
input: 'src/index.ts',
output: {
dir: 'lib',
format: 'es',
},
plugins: [typescript()],
};
const dtsConfig = {
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
};
export default [config, dtsConfig];
================================================
FILE: packages/primitives/src/index.ts
================================================
export const G = 'G';
export const Svg = 'SVG';
export const View = 'VIEW';
export const Text = 'TEXT';
export const Link = 'LINK';
export const Page = 'PAGE';
export const Note = 'NOTE';
export const Path = 'PATH';
export const Rect = 'RECT';
export const Line = 'LINE';
export const FieldSet = 'FIELD_SET';
export const TextInput = 'TEXT_INPUT';
export const Select = 'SELECT';
export const Checkbox = 'CHECKBOX';
export const List = 'LIST';
export const Stop = 'STOP';
export const Defs = 'DEFS';
export const Image = 'IMAGE';
export const Tspan = 'TSPAN';
export const Canvas = 'CANVAS';
export const Circle = 'CIRCLE';
export const Ellipse = 'ELLIPSE';
export const Polygon = 'POLYGON';
export const Document = 'DOCUMENT';
export const Polyline = 'POLYLINE';
export const ClipPath = 'CLIP_PATH';
export const TextInstance = 'TEXT_INSTANCE';
export const LinearGradient = 'LINEAR_GRADIENT';
export const RadialGradient = 'RADIAL_GRADIENT';
================================================
FILE: packages/primitives/tests/index.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as primitives from '../src/index';
describe('primitives', () => {
test('should export group', () => {
expect(primitives.G).toBeTruthy();
});
test('should export svg', () => {
expect(primitives.Svg).toBeTruthy();
});
test('should export view', () => {
expect(primitives.View).toBeTruthy();
});
test('should export link', () => {
expect(primitives.Link).toBeTruthy();
});
test('should export page', () => {
expect(primitives.Page).toBeTruthy();
});
test('should export note', () => {
expect(primitives.Note).toBeTruthy();
});
test('should export path', () => {
expect(primitives.Path).toBeTruthy();
});
test('should export rect', () => {
expect(primitives.Rect).toBeTruthy();
});
test('should export line', () => {
expect(primitives.Line).toBeTruthy();
});
test('should export field set', () => {
expect(primitives.FieldSet).toBeTruthy();
});
test('should export text input', () => {
expect(primitives.TextInput).toBeTruthy();
});
test('should export form list', () => {
expect(primitives.List).toBeTruthy();
});
test('should export select', () => {
expect(primitives.Select).toBeTruthy();
});
test('should export stop', () => {
expect(primitives.Stop).toBeTruthy();
});
test('should export defs', () => {
expect(primitives.Defs).toBeTruthy();
});
test('should export image', () => {
expect(primitives.Image).toBeTruthy();
});
test('should export tspan', () => {
expect(primitives.Tspan).toBeTruthy();
});
test('should export canvas', () => {
expect(primitives.Canvas).toBeTruthy();
});
test('should export circle', () => {
expect(primitives.Circle).toBeTruthy();
});
test('should export ellipse', () => {
expect(primitives.Ellipse).toBeTruthy();
});
test('should export polygon', () => {
expect(primitives.Polygon).toBeTruthy();
});
test('should export document', () => {
expect(primitives.Document).toBeTruthy();
});
test('should export polyline', () => {
expect(primitives.Polyline).toBeTruthy();
});
test('should export clippath', () => {
expect(primitives.ClipPath).toBeTruthy();
});
test('should export text intance', () => {
expect(primitives.TextInstance).toBeTruthy();
});
test('should export text linear gradient', () => {
expect(primitives.LinearGradient).toBeTruthy();
});
test('should export text radial gradient', () => {
expect(primitives.RadialGradient).toBeTruthy();
});
});
================================================
FILE: packages/primitives/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src", "globals.d.ts"],
}
================================================
FILE: packages/reconciler/.gitignore
================================================
lib
================================================
FILE: packages/reconciler/CHANGELOG.md
================================================
# @react-pdf/reconciler
## 2.0.0
### Major Changes
- [#3224](https://github.com/diegomura/react-pdf/pull/3224) [`fafbcb12`](https://github.com/diegomura/react-pdf/commit/fafbcb12a0ecf3231165bb2944de7ad3b7761dec) Thanks [@ZandercraftGames](https://github.com/ZandercraftGames)! - feat: add React 19.2.X support
### Patch Changes
- [#3261](https://github.com/diegomura/react-pdf/pull/3261) [`2eba70bd`](https://github.com/diegomura/react-pdf/commit/2eba70bd9cbb942a675ac686a2b335164279035a) Thanks [@Nukem154](https://github.com/Nukem154)! - fix(reconciler): prevent crash when removing elements
## 1.1.4
### Patch Changes
- [`b95a6dc4`](https://github.com/diegomura/react-pdf/commit/b95a6dc4350b0580ee8c1c8320871cc7145676f2) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert reconciler package to TS
## 1.1.3
### Patch Changes
- [#2983](https://github.com/diegomura/react-pdf/pull/2983) [`1916e840`](https://github.com/diegomura/react-pdf/commit/1916e8405ce2b566110f2a1d66cfd8b4c4fa34d4) Thanks [@diegomura](https://github.com/diegomura)! - fix: conditional rendering
- [#2980](https://github.com/diegomura/react-pdf/pull/2980) [`165c70fb`](https://github.com/diegomura/react-pdf/commit/165c70fbd31a7a4520af83b218a03f2f78f486e9) Thanks [@diegomura](https://github.com/diegomura)! - fix(reconciler): missing dependencies
## 1.1.2
### Patch Changes
- [#2958](https://github.com/diegomura/react-pdf/pull/2958) [`f6e9e113`](https://github.com/diegomura/react-pdf/commit/f6e9e1136f47fe05f86158c76561729b2cc425c4) Thanks [@diegomura](https://github.com/diegomura)! - fix: add scheduler dependency
## 1.1.1
### Patch Changes
- [#2943](https://github.com/diegomura/react-pdf/pull/2943) [`82192b3a`](https://github.com/diegomura/react-pdf/commit/82192b3a53cf5db62230287e7456dc5bdeee6244) Thanks [@diegomura](https://github.com/diegomura)! - fix: reconciler build
## 1.1.0
### Minor Changes
- [`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd) Thanks [@diegomura](https://github.com/diegomura)! - feat: add React 19 support
## 1.0.1
### Patch Changes
- [#2936](https://github.com/diegomura/react-pdf/pull/2936) [`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b) Thanks [@diegomura](https://github.com/diegomura)! - feat: pre-bundle + bump react-reconciler
================================================
FILE: packages/reconciler/README.md
================================================
# @react-pdf/reconciler
================================================
FILE: packages/reconciler/build/trim-reconciler.js
================================================
import * as recast from 'recast';
import { visit } from 'ast-types';
const trueLiteral = recast.types.builders.literal(true);
const falseLiteral = recast.types.builders.literal(false);
const nullLiteral = recast.types.builders.literal(null);
const KEEP_OPTIONS = {
commitUpdate: true,
commitTextUpdate: true,
removeChildFromContainer: true,
removeChild: true,
insertBefore: true,
appendChildToContainer: true,
appendChild: true,
shouldSetTextContent: true,
getChildHostContext: true,
getRootHostContext: true,
resetTextContent: true,
resetAfterCommit: true,
prepareUpdate: true,
clearContainer: true,
prepareForCommit: true,
getPublicInstance: true,
finalizeInitialChildren: true,
createTextInstance: true,
createInstance: true,
appendInitialChild: true,
noTimeout: true,
getCurrentUpdatePriority: true,
setCurrentUpdatePriority: true,
resolveUpdatePriority: true,
shouldAttemptEagerTransition: true,
requestPostPaintCallback: true,
maySuspendCommit: true,
detachDeletedInstance: true,
resolveEventTimeStamp: true,
resolveEventType: true,
trackSchedulerEvent: true,
};
const STATIC_OPTIONS = {
useSyncScheduling: { value: true },
supportsMutation: { value: true },
isPrimaryRenderer: { value: false },
warnsIfNotActing: { value: false },
};
const METHOD_KEYS = {
updateContainer: true,
updateContainerSync: true,
createContainer: true,
flushSyncWork: true,
};
function clearReconcilerOptions(path) {
const { node } = path;
const objectName = node.object?.name;
const optionName = node.property?.name;
// If we are not visiting config object, skip.
if (objectName !== '$$$hostConfig' && objectName !== '$$$config') return;
// If it's an option we want to keep, skip.
if (KEEP_OPTIONS[optionName]) return;
// If it's an option we want to replace, replace it.
if (STATIC_OPTIONS[optionName]) {
const newValue = STATIC_OPTIONS[optionName].value;
path.replace(newValue ? trueLiteral : falseLiteral);
return;
}
// Remove option.
path.replace(nullLiteral);
}
function clearReconcilerMethods(path) {
const { node } = path;
const objectName = node.object?.name;
const optionName = node.property?.name;
// If we are not visiting an exported method, skip.
if (objectName !== 'exports') return;
// If it's a method we want to keep, skip.
if (METHOD_KEYS[optionName]) return;
// Remove method.
path.parent.replace(nullLiteral);
}
const trimReconciler = () => {
return {
name: 'trim-reconciler',
transform(code) {
const ast = recast.parse(code);
visit(ast, {
visitMemberExpression(path) {
clearReconcilerOptions(path);
clearReconcilerMethods(path);
this.traverse(path);
},
});
return { code: recast.print(ast).code };
},
};
};
export default trimReconciler;
================================================
FILE: packages/reconciler/package.json
================================================
{
"name": "@react-pdf/reconciler",
"version": "2.0.0",
"license": "MIT",
"description": "Define uninitialized elements",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/reconciler"
},
"scripts": {
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"size": "size-limit",
"lint": "eslint src",
"test": "vitest"
},
"files": [
"lib"
],
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"dependencies": {
"object-assign": "^4.1.1",
"scheduler": "0.25.0-rc-603e6108-20241029"
},
"devDependencies": {
"ast-types": "^0.14.2",
"react-reconciler-23": "npm:react-reconciler@0.23.0",
"react-reconciler-31": "npm:react-reconciler@0.31.0-rc-603e6108-20241029",
"react-reconciler-33": "npm:react-reconciler@0.33.0",
"recast": "^0.23.9"
}
}
================================================
FILE: packages/reconciler/rollup.config.js
================================================
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
import typescript from '@rollup/plugin-typescript';
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
import trimReconciler from './build/trim-reconciler.js';
export default [
{
input: 'src/index.ts',
output: { format: 'es', file: 'lib/index.js' },
external: [
'./reconciler-23.js',
'./reconciler-31.js',
'./reconciler-33.js',
],
plugins: [typescript()],
},
{
input: 'src/reconciler-23.ts',
output: { format: 'es', file: 'lib/reconciler-23.js' },
plugins: [
typescript(),
resolve({ resolveOnly: ['react-reconciler-23'] }),
commonjs({ esmExternals: (id) => id === 'scheduler' }),
trimReconciler(),
terser({ compress: { dead_code: true } }),
],
},
{
input: 'src/reconciler-31.ts',
output: { format: 'es', file: 'lib/reconciler-31.js' },
plugins: [
typescript(),
resolve({ resolveOnly: ['react-reconciler-31'] }),
commonjs({ esmExternals: (id) => id === 'scheduler' }),
trimReconciler(),
terser({ compress: { dead_code: true } }),
],
},
{
input: 'src/reconciler-33.ts',
output: { format: 'es', file: 'lib/reconciler-33.js' },
plugins: [
typescript(),
resolve({ resolveOnly: ['react-reconciler-33'] }),
commonjs({ esmExternals: (id) => id === 'scheduler' }),
trimReconciler(),
terser({ compress: { dead_code: true } }),
],
},
{
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
},
];
================================================
FILE: packages/reconciler/src/index.ts
================================================
import React from 'react';
import createRendererForReact19 from './reconciler-31.js';
import createRendererForReact19_2 from './reconciler-33.js';
import createRendererForReact18AndLess from './reconciler-23.js';
const [major, minor] = React.version.split('.').map((v) => parseInt(v, 10));
let renderer;
if (major >= 20 || (major === 19 && minor >= 2)) {
// Use the reconciler built for 19.2, assuming it's compatible with later versions.
renderer = createRendererForReact19_2;
} else if (major === 19) {
// Use the older 19.x reconciler (for 19.0.x and 19.1.x)
renderer = createRendererForReact19;
} else {
// Fallback for React 18.x and previous versions.
renderer = createRendererForReact18AndLess;
}
export default renderer;
================================================
FILE: packages/reconciler/src/propsEqual.ts
================================================
/**
* Checks if two sets of props are equal (recursively)
*
* @param {Object} a props A
* @param {Object} b props B
* @returns {boolean} props equals?
*
*/
const propsEqual = (a, b) => {
const oldPropsKeys = Object.keys(a);
const newPropsKeys = Object.keys(b);
if (oldPropsKeys.length !== newPropsKeys.length) {
return false;
}
for (let i = 0; i < oldPropsKeys.length; i += 1) {
const propName = oldPropsKeys[i];
if (propName === 'render' && !a[propName] !== !b[propName]) {
return false;
}
if (propName !== 'children' && a[propName] !== b[propName]) {
if (
typeof a[propName] === 'object' &&
typeof b[propName] === 'object' &&
propsEqual(a[propName], b[propName])
) {
continue;
}
return false;
}
if (
propName === 'children' &&
(typeof a[propName] === 'string' || typeof b[propName] === 'string')
) {
return a[propName] === b[propName];
}
}
return true;
};
export default propsEqual;
================================================
FILE: packages/reconciler/src/reconciler-23.ts
================================================
import Reconciler from 'react-reconciler-23/cjs/react-reconciler.production.min.js';
import propsEqual from './propsEqual';
import { ReconcilerFactory } from './types';
const emptyObject = {};
const createRenderer: ReconcilerFactory = ({
appendChild,
appendChildToContainer,
commitTextUpdate,
commitUpdate,
createInstance,
createTextInstance,
insertBefore,
removeChild,
removeChildFromContainer,
resetAfterCommit,
}) => {
return Reconciler({
appendChild,
appendChildToContainer,
appendInitialChild: appendChild,
createInstance,
createTextInstance,
insertBefore,
commitUpdate,
commitTextUpdate,
removeChild,
removeChildFromContainer,
resetAfterCommit,
shouldSetTextContent: () => false,
finalizeInitialChildren: () => false,
getPublicInstance: (instance) => instance,
getRootHostContext: () => emptyObject,
getChildHostContext: () => emptyObject,
prepareForCommit() {},
clearContainer() {},
resetTextContent() {},
prepareUpdate: (element, type, oldProps, newProps) =>
!propsEqual(oldProps, newProps),
});
};
export default createRenderer;
================================================
FILE: packages/reconciler/src/reconciler-31.ts
================================================
import Reconciler from 'react-reconciler-31';
import {
ConcurrentRoot,
DefaultEventPriority,
} from 'react-reconciler-31/constants';
import propsEqual from './propsEqual';
import { ReconcilerFactory } from './types';
const emptyObject = {};
const logRecoverableError = console.error;
const createRenderer: ReconcilerFactory = ({
appendChild,
appendChildToContainer,
commitTextUpdate,
commitUpdate,
createInstance,
createTextInstance,
insertBefore,
removeChild,
removeChildFromContainer,
resetAfterCommit,
}) => {
const _commitUpdate = (instance, type, oldProps, newProps) => {
if (propsEqual(oldProps, newProps)) return;
commitUpdate(instance, null, type, oldProps, newProps);
};
const reconciler = Reconciler({
appendChild,
appendChildToContainer,
appendInitialChild: appendChild,
createInstance,
createTextInstance,
insertBefore,
commitUpdate: _commitUpdate,
commitTextUpdate,
removeChild,
removeChildFromContainer,
resetAfterCommit,
noTimeout: -1,
shouldSetTextContent: () => false,
finalizeInitialChildren: () => false,
getPublicInstance: (instance) => instance,
getRootHostContext: () => emptyObject,
getChildHostContext: () => emptyObject,
prepareForCommit() {},
clearContainer() {},
resetTextContent() {},
getCurrentUpdatePriority: () => DefaultEventPriority,
maySuspendCommit: () => false,
requestPostPaintCallback: () => {},
resolveUpdatePriority: () => DefaultEventPriority,
setCurrentUpdatePriority: () => {},
shouldAttemptEagerTransition: () => false,
detachDeletedInstance: () => {},
});
const createContainer = (container) => {
return reconciler.createContainer(
container,
ConcurrentRoot, // tag
null, // hydration callbacks
false, // isStrictMode
null, // concurrentUpdatesByDefaultOverride
'', // identifierPrefix
logRecoverableError, // onUncaughtError
logRecoverableError, // onCaughtError
logRecoverableError, // onRecoverableError
null, // transitionCallbacks
);
};
const updateContainer = (doc, mountNode, parentComponent, callback) => {
reconciler.updateContainerSync(doc, mountNode, parentComponent, callback);
reconciler.flushSyncWork();
};
return {
createContainer,
updateContainer,
};
};
export default createRenderer;
================================================
FILE: packages/reconciler/src/reconciler-33.ts
================================================
import Reconciler from 'react-reconciler-33';
import {
ConcurrentRoot,
DefaultEventPriority,
} from 'react-reconciler-33/constants';
import propsEqual from './propsEqual';
import { ReconcilerFactory } from './types';
const emptyObject = {};
const logRecoverableError = console.error;
const createRenderer: ReconcilerFactory = ({
appendChild,
appendChildToContainer,
commitTextUpdate,
commitUpdate,
createInstance,
createTextInstance,
insertBefore,
removeChild,
removeChildFromContainer,
resetAfterCommit,
}) => {
const _commitUpdate = (instance, type, oldProps, newProps) => {
if (propsEqual(oldProps, newProps)) return;
commitUpdate(instance, null, type, oldProps, newProps);
};
const reconciler = Reconciler({
appendChild,
appendChildToContainer,
appendInitialChild: appendChild,
createInstance,
createTextInstance,
insertBefore,
commitUpdate: _commitUpdate,
commitTextUpdate,
removeChild,
removeChildFromContainer,
resetAfterCommit,
noTimeout: -1,
shouldSetTextContent: () => false,
finalizeInitialChildren: () => false,
getPublicInstance: (instance) => instance,
getRootHostContext: () => emptyObject,
getChildHostContext: () => emptyObject,
prepareForCommit() {},
clearContainer() {},
resetTextContent() {},
getCurrentUpdatePriority: () => DefaultEventPriority,
maySuspendCommit: () => false,
requestPostPaintCallback: () => {},
resolveUpdatePriority: () => DefaultEventPriority,
setCurrentUpdatePriority: () => {},
shouldAttemptEagerTransition: () => false,
detachDeletedInstance: () => {},
resolveEventTimeStamp: () => {},
resolveEventType: () => {},
trackSchedulerEvent: () => {},
});
const createContainer = (container) => {
return reconciler.createContainer(
container, // containerInfo: Container
ConcurrentRoot, // tag: RootTag
null, // hydration callbacks: null | SuspenseHydrationCallbacks
false, // isStrictMode: boolean
null, // concurrentUpdatesByDefaultOverride: null | boolean
'', // identifierPrefix: string
logRecoverableError, // onUncaughtError: (error: mixed, errorInfo: {+componentStack?: ?string}) => void
logRecoverableError, // onCaughtError: (error: mixed, errorInfo: { ... }) => void
logRecoverableError, // onRecoverableError: (error: mixed, errorInfo: {+componentStack?: ?string}) => void
() => {}, // NEW IN REACT 19.2.0: onDefaultTransitionIndicator: () => void | (() => void)
null, // transitionCallbacks: null | TransitionTracingCallbacks
);
};
const updateContainer = (doc, mountNode, parentComponent, callback) => {
reconciler.updateContainerSync(doc, mountNode, parentComponent, callback);
reconciler.flushSyncWork();
};
return {
createContainer,
updateContainer,
};
};
export default createRenderer;
================================================
FILE: packages/reconciler/src/types.ts
================================================
export interface Reconciler {
createContainer: (container: any) => T;
updateContainer: (
element: T,
container: T,
parentComponent: T,
callback?: () => void,
) => void;
}
export type ReconcilerFactory = (config: {
appendChild: (parent: I, child: I | T) => void;
appendChildToContainer: (parent: I, child: I | T) => void;
commitTextUpdate: (textInstance: T, oldText: string, newText: string) => void;
commitUpdate: (
instance: I,
updatePayload: any,
type: string,
oldProps: any,
newProps: any,
) => void;
createInstance: (type: string, props: any) => I;
createTextInstance: (text: string) => T;
insertBefore: (parent: I, child: I | T, beforeChild: I | T) => void;
removeChild: (parent: I, child: I | T) => void;
removeChildFromContainer: (parent: I, child: I | T) => void;
resetAfterCommit: () => void;
}) => Reconciler;
================================================
FILE: packages/reconciler/tests/propsEqual.test.ts
================================================
import { describe, expect, test } from 'vitest';
import propsEqual from '../src/propsEqual';
describe('propsEqual', () => {
test('should be true for two empty objects', () => {
expect(propsEqual({}, {})).toBeTruthy();
});
test('should be true for equal objects', () => {
const a = { foo: 'bar', bar: 'foo' };
const b = { bar: 'foo', foo: 'bar' };
expect(propsEqual(a, b)).toBeTruthy();
});
test('should be false for diffent length objects', () => {
const a = { foo: 'bar', bar: 'foo' };
const b = { baz: 'foo' };
expect(propsEqual(a, b)).toBeFalsy();
});
test('should be false if string children attributes differ', () => {
const a = { foo: 'bar', children: 'test' };
const b = { foo: 'bar', children: 'else' };
expect(propsEqual(a, b)).toBeFalsy();
});
test('should be false if nested values differ', () => {
const a = { foo: 'bar', something: { hey: 'there' } };
const b = { foo: 'bar', something: { hey: 'back' } };
expect(propsEqual(a, b)).toBeFalsy();
});
});
================================================
FILE: packages/reconciler/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src", "globals.d.ts"],
}
================================================
FILE: packages/render/.gitignore
================================================
lib
================================================
FILE: packages/render/CHANGELOG.md
================================================
# @react-pdf/render
## 4.3.2
### Patch Changes
- Updated dependencies [[`f034491b`](https://github.com/diegomura/react-pdf/commit/f034491b1f77ce6f18a5db88e70b10b9c502ca35)]:
- @react-pdf/textkit@6.1.0
- @react-pdf/types@2.9.2
## 4.3.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/types@2.9.1
## 4.3.0
### Minor Changes
- [#3112](https://github.com/diegomura/react-pdf/pull/3112) [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a) Thanks [@diegomura](https://github.com/diegomura)! - feat: add xLinkHref, gradientTransform and gradientUnits support
### Patch Changes
- [`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982) Thanks [@diegomura](https://github.com/diegomura)! - fix: debug prop
- Updated dependencies [[`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/types@2.9.0
## 4.2.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/types@2.8.2
## 4.2.0
### Minor Changes
- [#3098](https://github.com/diegomura/react-pdf/pull/3098) [`bfb51ec0`](https://github.com/diegomura/react-pdf/commit/bfb51ec09b851c52659ce16fed1286173e9516a9) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert render package to TS
- [#3102](https://github.com/diegomura/react-pdf/pull/3102) [`24690f52`](https://github.com/diegomura/react-pdf/commit/24690f5238e4eacf28351cf9996856a7d196d29e) Thanks [@diegomura](https://github.com/diegomura)! - feat: handle standard fonts in fonts package
### Patch Changes
- [#3104](https://github.com/diegomura/react-pdf/pull/3104) [`ddfa3675`](https://github.com/diegomura/react-pdf/commit/ddfa367587618b313b4b0b3b57a9a7631e8e7604) Thanks [@diegomura](https://github.com/diegomura)! - feat(textkit): expect font array
- Updated dependencies [[`7cd66e4f`](https://github.com/diegomura/react-pdf/commit/7cd66e4fc37cd1393adc6250a919fe2629812082), [`ddfa3675`](https://github.com/diegomura/react-pdf/commit/ddfa367587618b313b4b0b3b57a9a7631e8e7604), [`c7b74963`](https://github.com/diegomura/react-pdf/commit/c7b749632f07db7808d58d99357dc830d4895da8), [`bfb51ec0`](https://github.com/diegomura/react-pdf/commit/bfb51ec09b851c52659ce16fed1286173e9516a9), [`24690f52`](https://github.com/diegomura/react-pdf/commit/24690f5238e4eacf28351cf9996856a7d196d29e), [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8), [`b06d3a0f`](https://github.com/diegomura/react-pdf/commit/b06d3a0f64593ac18097efd061334f1e5bd70095)]:
- @react-pdf/types@2.8.1
- @react-pdf/textkit@6.0.0
- @react-pdf/fns@3.1.2
## 4.1.2
### Patch Changes
- [#3065](https://github.com/diegomura/react-pdf/pull/3065) [`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6) Thanks [@diegomura](https://github.com/diegomura)! - refactor: partially unify pdfkit
- Updated dependencies [[`96c2464d`](https://github.com/diegomura/react-pdf/commit/96c2464dfaa7294e0d79b7ed64743bfd7b1a8c72), [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45), [`700535c5`](https://github.com/diegomura/react-pdf/commit/700535c57ff1b105d923be70f4fc4bfdf4479f91), [`442ce355`](https://github.com/diegomura/react-pdf/commit/442ce35534f916b9146a35fd03870387ed488d92), [`3007d34a`](https://github.com/diegomura/react-pdf/commit/3007d34ad3e10bf32ada3631938f5bb08e1c549f)]:
- @react-pdf/primitives@4.1.1
- @react-pdf/types@2.8.0
- @react-pdf/fns@3.1.1
- @react-pdf/textkit@5.0.3
## 4.1.1
### Patch Changes
- Updated dependencies [[`d36ace66`](https://github.com/diegomura/react-pdf/commit/d36ace66c77d57d845894e89772be7ae0cdd25ee)]:
- @react-pdf/fns@3.1.0
- @react-pdf/textkit@5.0.2
## 4.1.0
### Minor Changes
- [`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2) Thanks [@diegomura](https://github.com/diegomura)! - feat: added Form Annotation support
### Patch Changes
- [#3062](https://github.com/diegomura/react-pdf/pull/3062) [`5cc47319`](https://github.com/diegomura/react-pdf/commit/5cc47319bb428f6d4bcad21cd6dba9afca5cdc17) Thanks [@diegomura](https://github.com/diegomura)! - refactor: unify pdfkit image mixin
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`01944231`](https://github.com/diegomura/react-pdf/commit/01944231a342d502b832aeecb4c313020b8360c8)]:
- @react-pdf/primitives@4.1.0
- @react-pdf/types@2.7.1
## 4.0.2
### Patch Changes
- Updated dependencies [[`00bfdc1e`](https://github.com/diegomura/react-pdf/commit/00bfdc1e5a6c673d2de7b3ab09d5020e932562fb)]:
- @react-pdf/textkit@5.0.1
## 4.0.1
### Patch Changes
- [#2948](https://github.com/diegomura/react-pdf/pull/2948) [`03322a75`](https://github.com/diegomura/react-pdf/commit/03322a756f44863543673ff597582444c180989b) Thanks [@diegomura](https://github.com/diegomura)! - fix: stroke dash array computation
- [#2945](https://github.com/diegomura/react-pdf/pull/2945) [`b5c0fe64`](https://github.com/diegomura/react-pdf/commit/b5c0fe646108a960a528290b175511842020d600) Thanks [@diegomura](https://github.com/diegomura)! - fix: skew transformation
## 4.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Patch Changes
- Updated dependencies [[`46c3047d`](https://github.com/diegomura/react-pdf/commit/46c3047de56ae82f062b72c4910a4e6096eee99f), [`55973278`](https://github.com/diegomura/react-pdf/commit/55973278ac8bc8f703b63844f57d6f155ae8d86f), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/types@2.7.0
- @react-pdf/primitives@4.0.0
- @react-pdf/textkit@5.0.0
- @react-pdf/fns@3.0.0
## 3.5.0
### Minor Changes
- [#2771](https://github.com/diegomura/react-pdf/pull/2771) [`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2) Thanks [@nikischin](https://github.com/nikischin)! - fix: fix dpi
### Patch Changes
- [#2836](https://github.com/diegomura/react-pdf/pull/2836) [`53bf803`](https://github.com/diegomura/react-pdf/commit/53bf803465f4fecf13531d1a10697c3d4067cf8f) Thanks [@obi-awyss](https://github.com/obi-awyss)! - [fix] "TypeError: renderFn is not a function"
It may also address issue #2644
- Updated dependencies [[`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2), [`4bafab8`](https://github.com/diegomura/react-pdf/commit/4bafab8455c9003759f48bad20a720baf4ed189b)]:
- @react-pdf/types@2.6.0
## 3.4.4
### Patch Changes
- Updated dependencies [[`22a34a9`](https://github.com/diegomura/react-pdf/commit/22a34a91b16a201cd8288e0dbea9368b12ca73f5)]:
- @react-pdf/types@2.5.0
## 3.4.3
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/textkit@4.4.1
- @react-pdf/fns@2.2.1
## 3.4.2
### Patch Changes
- Updated dependencies [[`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235), [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7)]:
- @react-pdf/types@2.4.1
- @react-pdf/textkit@4.4.0
- @react-pdf/fns@2.2.0
## 3.4.1
### Patch Changes
- [#2544](https://github.com/diegomura/react-pdf/pull/2544) [`b5380a1`](https://github.com/diegomura/react-pdf/commit/b5380a1a0a7397b4111d68ce97b4acb702d34d51) Thanks [@satelllte](https://github.com/satelllte)! - fix: creationDate and modificationDate types
## 3.4.0
### Minor Changes
- [#2539](https://github.com/diegomura/react-pdf/pull/2539) [`fb5273d`](https://github.com/diegomura/react-pdf/commit/fb5273d8d80d919f7b9c214e02d67b79ce23fa19) Thanks [@diegomura](https://github.com/diegomura)! - feat: add creation and modification dates
### Patch Changes
- [#2538](https://github.com/diegomura/react-pdf/pull/2538) [`cfd050c`](https://github.com/diegomura/react-pdf/commit/cfd050c3ae0980f78c4a466565852d81c8254e19) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fix strokeDasharray crash
- Updated dependencies [[`fb5273d`](https://github.com/diegomura/react-pdf/commit/fb5273d8d80d919f7b9c214e02d67b79ce23fa19)]:
- @react-pdf/types@2.4.0
## 3.3.2
### Patch Changes
- Updated dependencies [[`9e5842b`](https://github.com/diegomura/react-pdf/commit/9e5842bbecca6e249af2c5fc50078bb7ddd5420f)]:
- @react-pdf/types@2.3.6
## 3.3.1
### Patch Changes
- Updated dependencies [[`42bbbda`](https://github.com/diegomura/react-pdf/commit/42bbbda48058acd2d36d7a92c812d133608c459e)]:
- @react-pdf/primitives@3.1.1
## 3.3.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
### Patch Changes
- [#2498](https://github.com/diegomura/react-pdf/pull/2498) [`6bfe7e8`](https://github.com/diegomura/react-pdf/commit/6bfe7e8a30d96c04a1552800159992705f3605b1) Thanks [@diegomura](https://github.com/diegomura)! - fix: color parse error
- Updated dependencies [[`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37)]:
- @react-pdf/primitives@3.1.0
- @react-pdf/textkit@4.3.0
- @react-pdf/fns@2.1.0
## 3.2.8
### Patch Changes
- [#2363](https://github.com/diegomura/react-pdf/pull/2363) [`8654d00`](https://github.com/diegomura/react-pdf/commit/8654d003023dd0899cddfc2ea2f5a552e01cf570) Thanks [@azmy60](https://github.com/azmy60)! - fix: SVGPresentationAttributes types
- Updated dependencies [[`e5c8fde`](https://github.com/diegomura/react-pdf/commit/e5c8fde9379a9a85ecac7e3d6273953e39d65f8d), [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4), [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2), [`4c40b14`](https://github.com/diegomura/react-pdf/commit/4c40b149cfed42f2513e1dd330a92ccc3363c04f)]:
- @react-pdf/types@2.3.5
- @react-pdf/textkit@4.2.1
## 3.2.7
### Patch Changes
- Updated dependencies [[`4a55c1b`](https://github.com/diegomura/react-pdf/commit/4a55c1b2ed19e460ccae6e749ed94c16729a23c4)]:
- @react-pdf/types@2.3.4
## 3.2.6
### Patch Changes
- [#2320](https://github.com/diegomura/react-pdf/pull/2320) [`5385a43`](https://github.com/diegomura/react-pdf/commit/5385a438cb4876d1dc00d49d5fdd2e07c0d16167) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fixed empty strings replaced with defaults in `creator` and `producer` props
- Updated dependencies [[`1e1fbdc`](https://github.com/diegomura/react-pdf/commit/1e1fbdc3c33ced46d8c7ebba7a196733cb789d59), [`8636812`](https://github.com/diegomura/react-pdf/commit/86368122ed87621d19ae3bc248080e17703d9fcb)]:
- @react-pdf/types@2.3.3
## 3.2.5
### Patch Changes
- [#2311](https://github.com/diegomura/react-pdf/pull/2311) [`2e724df`](https://github.com/diegomura/react-pdf/commit/2e724dfaff3c9b39e9862d24b0d0e037c8a9e8c2) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fixed crash on `transform="translate(1)"`
* [#2314](https://github.com/diegomura/react-pdf/pull/2314) [`d6018d5`](https://github.com/diegomura/react-pdf/commit/d6018d5a80492270ff5f5b4c00e694f7dc1cd93f) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Make `cx` and `cy` optional in `Circle` and `Ellipse`
* Updated dependencies [[`a25dbcb`](https://github.com/diegomura/react-pdf/commit/a25dbcb32b65c300f5b088e8b210bb0c1abca5c2)]:
- @react-pdf/types@2.3.2
## 3.2.4
### Patch Changes
- Updated dependencies [[`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59)]:
- @react-pdf/types@2.3.1
## 3.2.3
### Patch Changes
- Updated dependencies [[`2db67a3`](https://github.com/diegomura/react-pdf/commit/2db67a38b9be98b7816a2b5aa4733446b95e3724), [`eff1ff0`](https://github.com/diegomura/react-pdf/commit/eff1ff0fefcd710994e4654904ef55843af76a17)]:
- @react-pdf/textkit@4.2.0
- @react-pdf/types@2.3.0
- @react-pdf/fns@2.0.1
## 3.2.2
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
- Updated dependencies [[`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905)]:
- @react-pdf/textkit@4.1.1
## 3.2.1
### Patch Changes
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81), [`4bb97c3`](https://github.com/diegomura/react-pdf/commit/4bb97c3b92e82d7d7be2698c770f42560c6fcab6)]:
- @react-pdf/fns@2.0.0
- @react-pdf/textkit@4.1.0
## 3.2.0
### Minor Changes
- [#1892](https://github.com/diegomura/react-pdf/pull/1892) [`035d3f8`](https://github.com/diegomura/react-pdf/commit/035d3f8d24fa4f4af9f350950d81b51547858367) Thanks [@diegomura](https://github.com/diegomura)! - feat: add skew transformation support
### Patch Changes
- [#1906](https://github.com/diegomura/react-pdf/pull/1906) [`884695b`](https://github.com/diegomura/react-pdf/commit/884695b44feb974f155c83e0714e8e939b4f641b) Thanks [@diegomura](https://github.com/diegomura)! - feat: build textkit with rollup & define public api
- Updated dependencies [[`0fcc594`](https://github.com/diegomura/react-pdf/commit/0fcc594310d5af30ca1e752b3efc7a047e813dcb), [`37a9a74`](https://github.com/diegomura/react-pdf/commit/37a9a747f7677fa05e3ddf5669c0379aa65c1e39), [`884695b`](https://github.com/diegomura/react-pdf/commit/884695b44feb974f155c83e0714e8e939b4f641b)]:
- @react-pdf/textkit@4.0.0
## 3.1.0
### Minor Changes
- [#1862](https://github.com/diegomura/react-pdf/pull/1862) [`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb) Thanks [@diegomura](https://github.com/diegomura)! - feat: bookmarks support
* [#1869](https://github.com/diegomura/react-pdf/pull/1869) [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57) Thanks [@diegomura](https://github.com/diegomura)! - feat: variable dpi
### Patch Changes
- [#1863](https://github.com/diegomura/react-pdf/pull/1863) [`eecddbd`](https://github.com/diegomura/react-pdf/commit/eecddbda083561273eda21ee9b8d6107ad21800b) Thanks [@diegomura](https://github.com/diegomura)! - fix: dont use global image cache
* [#1864](https://github.com/diegomura/react-pdf/pull/1864) [`205aa03`](https://github.com/diegomura/react-pdf/commit/205aa0334c67e7436d0a35b95b919ecee189a192) Thanks [@diegomura](https://github.com/diegomura)! - fix: props undefiend access
- [#1857](https://github.com/diegomura/react-pdf/pull/1857) [`d958b0a`](https://github.com/diegomura/react-pdf/commit/d958b0ae06a61c157b2581488a9121a0464222f4) Thanks [@diegomura](https://github.com/diegomura)! - feat: embed same image once in final document
* [#1865](https://github.com/diegomura/react-pdf/pull/1865) [`24f5c77`](https://github.com/diegomura/react-pdf/commit/24f5c77706e12dbab45053cb704a2fe7cf60eb53) Thanks [@diegomura](https://github.com/diegomura)! - feat: add background color and border with Note support
- [#1855](https://github.com/diegomura/react-pdf/pull/1855) [`9347466`](https://github.com/diegomura/react-pdf/commit/9347466e8cd33d149678903cf4cf53850a8fc64a) Thanks [@diegomura](https://github.com/diegomura)! - fix: image dimension warning for JSON sources
* [#1861](https://github.com/diegomura/react-pdf/pull/1861) [`6730bc2`](https://github.com/diegomura/react-pdf/commit/6730bc210712e6fc67b94f89f23a3d86f6a203f9) Thanks [@diegomura](https://github.com/diegomura)! - fix: image opacity 0 rendering
- [#1859](https://github.com/diegomura/react-pdf/pull/1859) [`810f459`](https://github.com/diegomura/react-pdf/commit/810f45904e9abeaff5583ed4ceb6d77e123bbaea) Thanks [@diegomura](https://github.com/diegomura)! - feat: build render package as ES module
- Updated dependencies [[`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb), [`4fadb48`](https://github.com/diegomura/react-pdf/commit/4fadb48983d7269452f89f80c7e341ece859aaee), [`ce8762f`](https://github.com/diegomura/react-pdf/commit/ce8762f6de5c796e69ec5a225c7f3ff9c619a960), [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57)]:
- @react-pdf/types@2.1.0
## 3.0.0
### Major Changes
- [#1834](https://github.com/diegomura/react-pdf/pull/1834) [`7e97bb5`](https://github.com/diegomura/react-pdf/commit/7e97bb579aaa847e5a2de650b5b327ac90a465c7) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from render package
### Patch Changes
- [#1827](https://github.com/diegomura/react-pdf/pull/1827) [`7c1d373`](https://github.com/diegomura/react-pdf/commit/7c1d373a06b04369e762069be4b96d4e40371ecc) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from layout package
* [#1838](https://github.com/diegomura/react-pdf/pull/1838) [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de) Thanks [@diegomura](https://github.com/diegomura)! - feat: create fns package
* Updated dependencies [[`e938df0`](https://github.com/diegomura/react-pdf/commit/e938df0857642707b10b7f65f17ed22dc394ac1b), [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de), [`fe0f214`](https://github.com/diegomura/react-pdf/commit/fe0f214dbbf2f632b852ebfe65f886ecc4dd6953), [`9a2b935`](https://github.com/diegomura/react-pdf/commit/9a2b935cfe173f80425ed87d9f474da271c050d2)]:
- @react-pdf/primitives@3.0.0
- @react-pdf/fns@1.0.0
- @react-pdf/textkit@3.0.0
- @react-pdf/types@2.0.9
## 2.1.0
### Minor Changes
- [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1648](https://github.com/diegomura/react-pdf/pull/1648) [`46a4b0c`](https://github.com/diegomura/react-pdf/commit/46a4b0c88836e0653db0c8bae6f71f969882277c) Thanks [@jeetiss](https://github.com/jeetiss)! - fixed render crush when a node has `debug` prop and `margin: auto`
* [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
* Updated dependencies [[`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca), [`5d2d688`](https://github.com/diegomura/react-pdf/commit/5d2d688e18c830bb96c6e08446437d29f9f9c65f), [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b)]:
- @react-pdf/primitives@2.0.2
- @react-pdf/textkit@2.1.0
- @react-pdf/types@2.0.8
================================================
FILE: packages/render/README.md
================================================
# @react-pdf/render
> React-pdf render engine
## How to install
```sh
yarn add @react-pdf/render
```
## How it works
```js
import render from '@react-pdf/render';
import primitives from '@react-pdf/primitives';
const view = {
type: primitives.View,
style: {
backgroundColor: 'red',
borderTopLeftRadius: 5,
borderTopRightRadius: 10,
borderBottomLeftRadius: 0,
borderBottomRightRadius: 15,
borderTopColor: 'yellow',
borderLeftColor: 'green',
borderBottomColor: 'black',
borderRightColor: 'purple',
},
box: {
left: 20,
top: 20,
width: 100,
height: 80,
borderTopWidth: 3,
borderLeftWidth: 2,
borderBottomWidth: 1,
borderRightWidth: 4,
},
};
const doc = {
type: primitives.Document,
children: [
{
type: primitives.Page,
box: { width: 400, height: 600 },
children: [view],
},
],
};
// Provide your own context
const ctx = createContext();
render.default(ctx, doc);
```
This library exports a `render` function that takes two arguments:
- _ctx_: This is the target context where the document is going to be rendered. React-pdf currently uses a [pdfkit](https://github.com/react-pdf/pdfkit) document as context, but it can target any other type of structure as long as it signature matches pdfkit API. In the future this will enable rendering documents into muliple formats in addition to PDF.
- _node_: Document root node. A node is a nested structure that defines a single element in a document. They are defined by it's `type` and arguments.
## Node structure
A node represents a single element inside a document. It's mainly defined by it's `type` (mandatory) field in addition to other values to define where that element is positioned inside the document (`box`), how it looks (`style`), how it should behave (`params`) and what sub-nodes it contains (`children`).
The root node must always be of type `DOCUMENT`, containing as many `PAGE` nodes as desired inside it's children field.
Bare in mind this package does not handle any type of node positioning, inheritance, style transformations or any other layout related logic. It's role is limited to render exactly the node it get's into the provided context. Take this into account when definig styles as `paddingTop`, `paddingLeft` and so on instead of the shortcut `padding`. For layout or styles transformation this project provides separate packages.
### node.type
Mandatory field specifiying the type of the particular node. The full list of types can be found and imported from `@react-pdf/primitives`
### node.box
Defines bounding box where a particular node is located inside a document
- left
- top
- width
- height
- paddingTop
- paddingLeft
- paddingBottom
- paddingRight
- marginTop
- marginLeft
- marginBottom
- marginRight
- borderTopWidth
- borderLeftWidth
- borderBottomWidth
- borderRightWidth
### node.style
Defines how the node looks like. There are some types of nodes that expect special style values, but generally all support:
- color
- opacity
- overflow
- backgroundColor
- borderTopLeftRadius
- borderTopRightRadius
- borderBottomLeftRadius
- borderBottomRightRadius
- borderTopColor
- borderLeftColor
- borderBottomColor
- borderRightColor
- _others..._
### node.props
Specific node params needed to render correctly ot behave like certain way. Specially needed for SVG nodes
## PDF example
```js
import fs from 'fs';
import render from '@react-pdf/render';
import pdfkit from '@react-pdf/pdfkit';
const PDFDocument = pdfkit.default;
const ctx = new PDFDocument({ autoFirstPage: false });
const doc = {}; // See above
render.default(ctx, doc);
const stream = fs.createWriteStream('./test.pdf');
ctx.pipe(stream);
```
## License
MIT © [Diego Muracciole](http://github.com/diegomura)
================================================
FILE: packages/render/globals.d.ts
================================================
declare module 'abs-svg-path';
declare module 'color-string' {
function get(hex: string): { model: string; value: number[] } | null;
function toHex(color: number[]): string;
export default {
get,
to: { hex: toHex },
};
}
declare module 'normalize-svg-path' {
export default function normalizePath(path: any[]): any[];
}
declare module 'parse-svg-path' {
export default function parsePath(path: string): any[];
}
================================================
FILE: packages/render/jest.config.js
================================================
export default {
testRegex: 'tests/.*?(test)\\.js$',
};
================================================
FILE: packages/render/package.json
================================================
{
"name": "@react-pdf/render",
"version": "4.3.2",
"license": "MIT",
"description": "A render engine for Node and the browser",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/render"
},
"scripts": {
"test": "vitest",
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@react-pdf/fns": "3.1.2",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/textkit": "^6.1.0",
"@react-pdf/types": "^2.9.2",
"abs-svg-path": "^0.1.1",
"color-string": "^1.9.1",
"normalize-svg-path": "^1.1.0",
"parse-svg-path": "^0.1.2",
"svg-arc-to-cubic-bezier": "^3.2.0"
},
"devDependencies": {
"@react-pdf/layout": "^4.4.2",
"@types/abs-svg-path": "^0.1.3",
"@types/color-string": "^1.5.5",
"@types/pdfkit": "^0.13.9"
},
"files": [
"lib"
]
}
================================================
FILE: packages/render/rollup.config.js
================================================
import json from '@rollup/plugin-json';
import typescript from '@rollup/plugin-typescript';
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
import pkg from './package.json' with { type: 'json' };
const config = [
{
input: 'src/index.ts',
output: { format: 'es', file: 'lib/index.js' },
external: Object.keys(pkg.dependencies).concat(/@react-pdf/),
plugins: [json(), typescript()],
},
{
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
},
];
export default config;
================================================
FILE: packages/render/src/index.ts
================================================
import type { SafeDocumentNode } from '@react-pdf/layout';
import renderNode from './primitives/renderNode';
import addBookmarks from './operations/addBookmarks';
import { Context } from './types';
const render = (ctx: Context, doc: SafeDocumentNode) => {
const pages = doc.children || [];
const options = { imageCache: new Map(), fieldSets: [] };
pages.forEach((page) => renderNode(ctx, page, options));
addBookmarks(ctx, doc);
ctx.end();
return ctx;
};
export default render;
================================================
FILE: packages/render/src/operations/addBookmarks.ts
================================================
import { SafeDocumentNode, SafeNode } from '@react-pdf/layout';
import { Context } from '../types';
type Registry = Record;
const addNodeBookmark = (
ctx: Context,
node: SafeNode,
pageNumber: number,
registry: Registry,
) => {
if (!node.box) return;
if (!node.props) return;
if ('bookmark' in node.props && node.props.bookmark) {
const bookmark = node.props.bookmark;
const { title, parent, expanded, zoom, fit } = bookmark;
const outline = registry[parent!] || ctx.outline;
const top = bookmark.top || node.box.top;
const left = bookmark.left || node.box.left;
const instance = outline.addItem(title, {
pageNumber,
expanded,
top,
left,
zoom,
fit,
});
registry[bookmark.ref!] = instance;
}
if (!node.children) return;
node.children.forEach((child) =>
addNodeBookmark(ctx, child, pageNumber, registry),
);
};
const addBookmarks = (ctx: Context, root: SafeDocumentNode) => {
const registry = {};
const pages = root.children || [];
pages.forEach((page, i) => {
addNodeBookmark(ctx, page, i, registry);
});
};
export default addBookmarks;
================================================
FILE: packages/render/src/operations/clipNode.ts
================================================
// This constant is used to approximate a symmetrical arc using a cubic
import { SafeNode } from '@react-pdf/layout';
import { Context } from '../types';
// Bezier curve.
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
const clipNode = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
if (!node.style) return;
const { top, left, width, height } = node.box;
const {
borderTopLeftRadius = 0,
borderTopRightRadius = 0,
borderBottomRightRadius = 0,
borderBottomLeftRadius = 0,
} = node.style;
// Border top
// @ts-expect-error this is always a number due to resolve border radius step
const rtr = Math.min(borderTopRightRadius, 0.5 * width, 0.5 * height);
const ctr = rtr * (1.0 - KAPPA);
ctx.moveTo(left + rtr, top);
ctx.lineTo(left + width - rtr, top);
ctx.bezierCurveTo(
left + width - ctr,
top,
left + width,
top + ctr,
left + width,
top + rtr,
);
// Border right
// @ts-expect-error this is always a number due to resolve border radius step
const rbr = Math.min(borderBottomRightRadius, 0.5 * width, 0.5 * height);
const cbr = rbr * (1.0 - KAPPA);
ctx.lineTo(left + width, top + height - rbr);
ctx.bezierCurveTo(
left + width,
top + height - cbr,
left + width - cbr,
top + height,
left + width - rbr,
top + height,
);
// Border bottom
// @ts-expect-error this is always a number due to resolve border radius step
const rbl = Math.min(borderBottomLeftRadius, 0.5 * width, 0.5 * height);
const cbl = rbl * (1.0 - KAPPA);
ctx.lineTo(left + rbl, top + height);
ctx.bezierCurveTo(
left + cbl,
top + height,
left,
top + height - cbl,
left,
top + height - rbl,
);
// Border left
// @ts-expect-error this is always a number due to resolve border radius step
const rtl = Math.min(borderTopLeftRadius, 0.5 * width, 0.5 * height);
const ctl = rtl * (1.0 - KAPPA);
ctx.lineTo(left, top + rtl);
ctx.bezierCurveTo(left, top + ctl, left + ctl, top, left + rtl, top);
ctx.closePath();
ctx.clip();
};
export default clipNode;
================================================
FILE: packages/render/src/operations/embedImage.ts
================================================
import { SafeImageNode } from '@react-pdf/layout';
import { Context } from '../types';
const embedImage = (ctx: Context, node: SafeImageNode) => {
const src = node.image!.data;
let image;
if (typeof src === 'string') {
image = ctx._imageRegistry[src];
}
if (!image) {
image = ctx.openImage(src);
}
if (!image.obj) {
image.embed(ctx);
}
return image;
};
export default embedImage;
================================================
FILE: packages/render/src/operations/setDestination.ts
================================================
import { SafeNode } from '@react-pdf/layout';
import { Context } from '../types';
const setDestination = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
if (!node.props) return;
if ('id' in node.props) {
ctx.addNamedDestination(node.props.id!, 'XYZ', null, node.box.top, null);
}
};
export default setDestination;
================================================
FILE: packages/render/src/operations/setLink.ts
================================================
import { SafeNode } from '@react-pdf/layout';
import { Context } from '../types';
const isString = (value: any): value is string => typeof value === 'string';
const isSrcId = (value: string) => /^#.+/.test(value);
const renderLink = (ctx: Context, node: SafeNode, src: string) => {
if (!src || !node.box) return;
const isId = isSrcId(src);
const method = isId ? 'goTo' : 'link';
const value = isId ? src.slice(1) : src;
const { top, left, width, height } = node.box;
ctx[method](left, top, width, height, value);
};
const setLink = (ctx: Context, node: SafeNode) => {
const props = node.props || {};
if ('src' in props && isString(props.src))
return renderLink(ctx, node, props.src);
if ('href' in props && isString(props.href))
return renderLink(ctx, node, props.href);
};
export default setLink;
================================================
FILE: packages/render/src/operations/transform.ts
================================================
import { SafeNode } from '@react-pdf/layout';
import { Transform } from '@react-pdf/stylesheet';
import { Context } from '../types';
const applySingleTransformation = (
ctx: Context,
transform: Transform,
origin: number[],
) => {
const { operation, value } = transform;
switch (operation) {
case 'scale': {
const [scaleX, scaleY] = value;
ctx.scale(scaleX, scaleY, { origin });
break;
}
case 'rotate': {
const [angle] = value;
ctx.rotate(angle, { origin });
break;
}
case 'translate': {
const [x, y = 0] = value;
ctx.translate(x, y, { origin });
break;
}
case 'skew': {
const [xAngle = 0, yAngle = 0] = value;
const radx = (xAngle * Math.PI) / 180;
const rady = (yAngle * Math.PI) / 180;
const tanx = Math.tan(radx);
const tany = Math.tan(rady);
let x = 0;
let y = 0;
if (origin != null) {
[x, y] = Array.from(origin);
const x1 = x + tanx * y;
const y1 = y + tany * x;
x -= x1;
y -= y1;
}
ctx.transform(1, tany, tanx, 1, x, y);
break;
}
case 'matrix': {
ctx.transform(...value);
break;
}
default: {
console.error(`Transform operation: '${operation}' doesn't supported`);
}
}
};
const applyTransformations = (ctx: Context, node: SafeNode) => {
if (!node.origin) return;
const { props, style } = node;
const origin = [node.origin.left, node.origin.top];
const propsTransform = 'transform' in props ? props.transform : undefined;
const operations = style?.transform || propsTransform || [];
operations.forEach((operation) => {
applySingleTransformation(ctx, operation, origin);
});
};
export default applyTransformations;
================================================
FILE: packages/render/src/primitives/renderBackground.ts
================================================
import { isNil } from '@react-pdf/fns';
import clipNode from '../operations/clipNode';
import parseColor from '../utils/parseColor';
import { Context } from '../types';
import { SafeNode } from '@react-pdf/layout';
const drawBackground = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
const { top, left, width, height } = node.box;
const color = parseColor(node.style.backgroundColor);
const nodeOpacity = isNil(node.style?.opacity) ? 1 : node.style.opacity;
const opacity = Math.min(color.opacity, nodeOpacity);
ctx
.fillOpacity(opacity)
.fillColor(color.value)
.rect(left, top, width, height)
.fill();
};
const renderBackground = (ctx: Context, node: SafeNode) => {
const hasBackground = !!node.box && !!node.style?.backgroundColor;
if (hasBackground) {
ctx.save();
clipNode(ctx, node);
drawBackground(ctx, node);
ctx.restore();
}
};
export default renderBackground;
================================================
FILE: packages/render/src/primitives/renderBorders.ts
================================================
// Ref: https://www.w3.org/TR/css-backgrounds-3/#borders
import { Box, SafeNode } from '@react-pdf/layout';
import { Context } from '../types';
type SafeBorderStyle = {
borderTopColor: string;
borderTopWidth: number;
borderTopStyle: string;
borderLeftColor: string;
borderLeftWidth: number;
borderLeftStyle: string;
borderRightColor: string;
borderRightWidth: number;
borderRightStyle: string;
borderBottomColor: string;
borderBottomWidth: number;
borderBottomStyle: string;
borderTopLeftRadius: number;
borderTopRightRadius: number;
borderBottomLeftRadius: number;
borderBottomRightRadius: number;
};
// This constant is used to approximate a symmetrical arc using a cubic Bezier curve.
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
const clipBorderTop = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rtr: number,
rtl: number,
) => {
const { top, left, width, height } = layout;
const { borderTopWidth, borderRightWidth, borderLeftWidth } = style;
// Clip outer top border edge
ctx.moveTo(left + rtl, top);
ctx.lineTo(left + width - rtr, top);
// Ellipse coefficients outer top right cap
const c0 = rtr * (1.0 - KAPPA);
// Clip outer top right cap
ctx.bezierCurveTo(
left + width - c0,
top,
left + width,
top + c0,
left + width,
top + rtr,
);
// Move down in case the margin exceedes the radius
const topRightYCoord = top + Math.max(borderTopWidth, rtr);
ctx.lineTo(left + width, topRightYCoord);
// Clip inner top right cap
ctx.lineTo(left + width - borderRightWidth, topRightYCoord);
// Ellipse coefficients inner top right cap
const innerTopRightRadiusX = Math.max(rtr - borderRightWidth, 0);
const innerTopRightRadiusY = Math.max(rtr - borderTopWidth, 0);
const c1 = innerTopRightRadiusX * (1.0 - KAPPA);
const c2 = innerTopRightRadiusY * (1.0 - KAPPA);
// Clip inner top right cap
ctx.bezierCurveTo(
left + width - borderRightWidth,
top + borderTopWidth + c2,
left + width - borderRightWidth - c1,
top + borderTopWidth,
left + width - borderRightWidth - innerTopRightRadiusX,
top + borderTopWidth,
);
// Clip inner top border edge
ctx.lineTo(left + Math.max(rtl, borderLeftWidth), top + borderTopWidth);
// Ellipse coefficients inner top left cap
const innerTopLeftRadiusX = Math.max(rtl - borderLeftWidth, 0);
const innerTopLeftRadiusY = Math.max(rtl - borderTopWidth, 0);
const c3 = innerTopLeftRadiusX * (1.0 - KAPPA);
const c4 = innerTopLeftRadiusY * (1.0 - KAPPA);
const topLeftYCoord = top + Math.max(borderTopWidth, rtl);
// Clip inner top left cap
ctx.bezierCurveTo(
left + borderLeftWidth + c3,
top + borderTopWidth,
left + borderLeftWidth,
top + borderTopWidth + c4,
left + borderLeftWidth,
topLeftYCoord,
);
ctx.lineTo(left, topLeftYCoord);
// Move down in case the margin exceedes the radius
ctx.lineTo(left, top + rtl);
// Ellipse coefficients outer top left cap
const c5 = rtl * (1.0 - KAPPA);
// Clip outer top left cap
ctx.bezierCurveTo(left, top + c5, left + c5, top, left + rtl, top);
ctx.closePath();
ctx.clip();
// Clip border top cap joins
if (borderRightWidth) {
const trSlope = -borderTopWidth / borderRightWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left + width, top);
ctx.lineTo(left, top);
ctx.lineTo(left, top + height);
ctx.closePath();
ctx.clip();
}
if (borderLeftWidth) {
const trSlope = -borderTopWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left, top);
ctx.lineTo(left + width, top);
ctx.lineTo(left + width, top + height);
ctx.closePath();
ctx.clip();
}
};
const fillBorderTop = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rtr: number,
rtl: number,
) => {
const { top, left, width } = layout;
const {
borderTopColor,
borderTopWidth,
borderTopStyle,
borderRightWidth,
borderLeftWidth,
} = style;
const c0 = rtl * (1.0 - KAPPA);
const c1 = rtr * (1.0 - KAPPA);
ctx.moveTo(left, top + Math.max(rtl, borderTopWidth));
ctx.bezierCurveTo(left, top + c0, left + c0, top, left + rtl, top);
ctx.lineTo(left + width - rtr, top);
ctx.bezierCurveTo(
left + width - c1,
top,
left + width,
top + c1,
left + width,
top + rtr,
);
ctx.strokeColor(borderTopColor);
ctx.lineWidth(
Math.max(borderRightWidth, borderTopWidth, borderLeftWidth) * 2,
);
if (borderTopStyle === 'dashed') {
ctx.dash(borderTopWidth * 2, { space: borderTopWidth * 1.2 });
} else if (borderTopStyle === 'dotted') {
ctx.dash(borderTopWidth, { space: borderTopWidth * 1.2 });
}
ctx.stroke();
ctx.undash();
};
const clipBorderRight = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rtr: number,
rbr: number,
) => {
const { top, left, width, height } = layout;
const { borderTopWidth, borderRightWidth, borderBottomWidth } = style;
// Clip outer right border edge
ctx.moveTo(left + width, top + rtr);
ctx.lineTo(left + width, top + height - rbr);
// Ellipse coefficients outer bottom right cap
const c0 = rbr * (1.0 - KAPPA);
// Clip outer top right cap
ctx.bezierCurveTo(
left + width,
top + height - c0,
left + width - c0,
top + height,
left + width - rbr,
top + height,
);
// Move left in case the margin exceedes the radius
const topBottomXCoord = left + width - Math.max(borderRightWidth, rbr);
ctx.lineTo(topBottomXCoord, top + height);
// Clip inner bottom right cap
ctx.lineTo(topBottomXCoord, top + height - borderBottomWidth);
// Ellipse coefficients inner bottom right cap
const innerBottomRightRadiusX = Math.max(rbr - borderRightWidth, 0);
const innerBottomRightRadiusY = Math.max(rbr - borderBottomWidth, 0);
const c1 = innerBottomRightRadiusX * (1.0 - KAPPA);
const c2 = innerBottomRightRadiusY * (1.0 - KAPPA);
// Clip inner top right cap
ctx.bezierCurveTo(
left + width - borderRightWidth - c1,
top + height - borderBottomWidth,
left + width - borderRightWidth,
top + height - borderBottomWidth - c2,
left + width - borderRightWidth,
top + height - Math.max(rbr, borderBottomWidth),
);
// Clip inner right border edge
ctx.lineTo(
left + width - borderRightWidth,
top + Math.max(rtr, borderTopWidth),
);
// Ellipse coefficients inner top right cap
const innerTopRightRadiusX = Math.max(rtr - borderRightWidth, 0);
const innerTopRightRadiusY = Math.max(rtr - borderTopWidth, 0);
const c3 = innerTopRightRadiusX * (1.0 - KAPPA);
const c4 = innerTopRightRadiusY * (1.0 - KAPPA);
const topRightXCoord = left + width - Math.max(rtr, borderRightWidth);
// Clip inner top left cap
ctx.bezierCurveTo(
left + width - borderRightWidth,
top + borderTopWidth + c4,
left + width - borderRightWidth - c3,
top + borderTopWidth,
topRightXCoord,
top + borderTopWidth,
);
ctx.lineTo(topRightXCoord, top);
// Move right in case the margin exceedes the radius
ctx.lineTo(left + width - rtr, top);
// Ellipse coefficients outer top right cap
const c5 = rtr * (1.0 - KAPPA);
// Clip outer top right cap
ctx.bezierCurveTo(
left + width - c5,
top,
left + width,
top + c5,
left + width,
top + rtr,
);
ctx.closePath();
ctx.clip();
// Clip border right cap joins
if (borderTopWidth) {
const trSlope = -borderTopWidth / borderRightWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left + width, top);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left, top + height);
ctx.closePath();
ctx.clip();
}
if (borderBottomWidth) {
const brSlope = borderBottomWidth / borderRightWidth;
ctx.moveTo(left + width / 2, brSlope * (-width / 2) + top + height);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left + width, top);
ctx.lineTo(left, top);
ctx.closePath();
ctx.clip();
}
};
const fillBorderRight = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rtr: number,
rbr: number,
) => {
const { top, left, width, height } = layout;
const {
borderRightColor,
borderRightStyle,
borderRightWidth,
borderTopWidth,
borderBottomWidth,
} = style;
const c0 = rbr * (1.0 - KAPPA);
const c1 = rtr * (1.0 - KAPPA);
ctx.moveTo(left + width - rtr, top);
ctx.bezierCurveTo(
left + width - c1,
top,
left + width,
top + c1,
left + width,
top + rtr,
);
ctx.lineTo(left + width, top + height - rbr);
ctx.bezierCurveTo(
left + width,
top + height - c0,
left + width - c0,
top + height,
left + width - rbr,
top + height,
);
ctx.strokeColor(borderRightColor);
ctx.lineWidth(
Math.max(borderRightWidth, borderTopWidth, borderBottomWidth) * 2,
);
if (borderRightStyle === 'dashed') {
ctx.dash(borderRightWidth * 2, { space: borderRightWidth * 1.2 });
} else if (borderRightStyle === 'dotted') {
ctx.dash(borderRightWidth, { space: borderRightWidth * 1.2 });
}
ctx.stroke();
ctx.undash();
};
const clipBorderBottom = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rbl: number,
rbr: number,
) => {
const { top, left, width, height } = layout;
const { borderBottomWidth, borderRightWidth, borderLeftWidth } = style;
// Clip outer top border edge
ctx.moveTo(left + width - rbr, top + height);
ctx.lineTo(left + rbl, top + height);
// Ellipse coefficients outer top right cap
const c0 = rbl * (1.0 - KAPPA);
// Clip outer top right cap
ctx.bezierCurveTo(
left + c0,
top + height,
left,
top + height - c0,
left,
top + height - rbl,
);
// Move up in case the margin exceedes the radius
const bottomLeftYCoord = top + height - Math.max(borderBottomWidth, rbl);
ctx.lineTo(left, bottomLeftYCoord);
// Clip inner bottom left cap
ctx.lineTo(left + borderLeftWidth, bottomLeftYCoord);
// Ellipse coefficients inner top right cap
const innerBottomLeftRadiusX = Math.max(rbl - borderLeftWidth, 0);
const innerBottomLeftRadiusY = Math.max(rbl - borderBottomWidth, 0);
const c1 = innerBottomLeftRadiusX * (1.0 - KAPPA);
const c2 = innerBottomLeftRadiusY * (1.0 - KAPPA);
// Clip inner bottom left cap
ctx.bezierCurveTo(
left + borderLeftWidth,
top + height - borderBottomWidth - c2,
left + borderLeftWidth + c1,
top + height - borderBottomWidth,
left + borderLeftWidth + innerBottomLeftRadiusX,
top + height - borderBottomWidth,
);
// Clip inner bottom border edge
ctx.lineTo(
left + width - Math.max(rbr, borderRightWidth),
top + height - borderBottomWidth,
);
// Ellipse coefficients inner top left cap
const innerBottomRightRadiusX = Math.max(rbr - borderRightWidth, 0);
const innerBottomRightRadiusY = Math.max(rbr - borderBottomWidth, 0);
const c3 = innerBottomRightRadiusX * (1.0 - KAPPA);
const c4 = innerBottomRightRadiusY * (1.0 - KAPPA);
const bottomRightYCoord = top + height - Math.max(borderBottomWidth, rbr);
// Clip inner top left cap
ctx.bezierCurveTo(
left + width - borderRightWidth - c3,
top + height - borderBottomWidth,
left + width - borderRightWidth,
top + height - borderBottomWidth - c4,
left + width - borderRightWidth,
bottomRightYCoord,
);
ctx.lineTo(left + width, bottomRightYCoord);
// Move down in case the margin exceedes the radius
ctx.lineTo(left + width, top + height - rbr);
// Ellipse coefficients outer top left cap
const c5 = rbr * (1.0 - KAPPA);
// Clip outer top left cap
ctx.bezierCurveTo(
left + width,
top + height - c5,
left + width - c5,
top + height,
left + width - rbr,
top + height,
);
ctx.closePath();
ctx.clip();
// Clip border bottom cap joins
if (borderRightWidth) {
const brSlope = borderBottomWidth / borderRightWidth;
ctx.moveTo(left + width / 2, brSlope * (-width / 2) + top + height);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left, top + height);
ctx.lineTo(left, top);
ctx.closePath();
ctx.clip();
}
if (borderLeftWidth) {
const trSlope = -borderBottomWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (width / 2) + top + height);
ctx.lineTo(left, top + height);
ctx.lineTo(left + width, top + height);
ctx.lineTo(left + width, top);
ctx.closePath();
ctx.clip();
}
};
const fillBorderBottom = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rbl: number,
rbr: number,
) => {
const { top, left, width, height } = layout;
const {
borderBottomColor,
borderBottomStyle,
borderBottomWidth,
borderRightWidth,
borderLeftWidth,
} = style;
const c0 = rbl * (1.0 - KAPPA);
const c1 = rbr * (1.0 - KAPPA);
ctx.moveTo(left + width, top + height - rbr);
ctx.bezierCurveTo(
left + width,
top + height - c1,
left + width - c1,
top + height,
left + width - rbr,
top + height,
);
ctx.lineTo(left + rbl, top + height);
ctx.bezierCurveTo(
left + c0,
top + height,
left,
top + height - c0,
left,
top + height - rbl,
);
ctx.strokeColor(borderBottomColor);
ctx.lineWidth(
Math.max(borderBottomWidth, borderRightWidth, borderLeftWidth) * 2,
);
if (borderBottomStyle === 'dashed') {
ctx.dash(borderBottomWidth * 2, { space: borderBottomWidth * 1.2 });
} else if (borderBottomStyle === 'dotted') {
ctx.dash(borderBottomWidth, { space: borderBottomWidth * 1.2 });
}
ctx.stroke();
ctx.undash();
};
const clipBorderLeft = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rbl: number,
rtl: number,
) => {
const { top, left, width, height } = layout;
const { borderTopWidth, borderLeftWidth, borderBottomWidth } = style;
// Clip outer left border edge
ctx.moveTo(left, top + height - rbl);
ctx.lineTo(left, top + rtl);
// Ellipse coefficients outer top left cap
const c0 = rtl * (1.0 - KAPPA);
// Clip outer top left cap
ctx.bezierCurveTo(left, top + c0, left + c0, top, left + rtl, top);
// Move right in case the margin exceedes the radius
const topLeftCoordX = left + Math.max(borderLeftWidth, rtl);
ctx.lineTo(topLeftCoordX, top);
// Clip inner top left cap
ctx.lineTo(topLeftCoordX, top + borderTopWidth);
// Ellipse coefficients inner top left cap
const innerTopLeftRadiusX = Math.max(rtl - borderLeftWidth, 0);
const innerTopLeftRadiusY = Math.max(rtl - borderTopWidth, 0);
const c1 = innerTopLeftRadiusX * (1.0 - KAPPA);
const c2 = innerTopLeftRadiusY * (1.0 - KAPPA);
// Clip inner top right cap
ctx.bezierCurveTo(
left + borderLeftWidth + c1,
top + borderTopWidth,
left + borderLeftWidth,
top + borderTopWidth + c2,
left + borderLeftWidth,
top + Math.max(rtl, borderTopWidth),
);
// Clip inner left border edge
ctx.lineTo(
left + borderLeftWidth,
top + height - Math.max(rbl, borderBottomWidth),
);
// Ellipse coefficients inner bottom left cap
const innerBottomLeftRadiusX = Math.max(rbl - borderLeftWidth, 0);
const innerBottomLeftRadiusY = Math.max(rbl - borderBottomWidth, 0);
const c3 = innerBottomLeftRadiusX * (1.0 - KAPPA);
const c4 = innerBottomLeftRadiusY * (1.0 - KAPPA);
const bottomLeftXCoord = left + Math.max(rbl, borderLeftWidth);
// Clip inner top left cap
ctx.bezierCurveTo(
left + borderLeftWidth,
top + height - borderBottomWidth - c4,
left + borderLeftWidth + c3,
top + height - borderBottomWidth,
bottomLeftXCoord,
top + height - borderBottomWidth,
);
ctx.lineTo(bottomLeftXCoord, top + height);
// Move left in case the margin exceedes the radius
ctx.lineTo(left + rbl, top + height);
// Ellipse coefficients outer top right cap
const c5 = rbl * (1.0 - KAPPA);
// Clip outer top right cap
ctx.bezierCurveTo(
left + c5,
top + height,
left,
top + height - c5,
left,
top + height - rbl,
);
ctx.closePath();
ctx.clip();
// Clip border right cap joins
if (borderBottomWidth) {
const trSlope = -borderBottomWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (width / 2) + top + height);
ctx.lineTo(left, top + height);
ctx.lineTo(left, top);
ctx.lineTo(left + width, top);
ctx.closePath();
ctx.clip();
}
if (borderBottomWidth) {
const trSlope = -borderTopWidth / borderLeftWidth;
ctx.moveTo(left + width / 2, trSlope * (-width / 2) + top);
ctx.lineTo(left, top);
ctx.lineTo(left, top + height);
ctx.lineTo(left + width, top + height);
ctx.closePath();
ctx.clip();
}
};
const fillBorderLeft = (
ctx: Context,
layout: Box,
style: SafeBorderStyle,
rbl: number,
rtl: number,
) => {
const { top, left, height } = layout;
const {
borderLeftColor,
borderLeftStyle,
borderLeftWidth,
borderTopWidth,
borderBottomWidth,
} = style;
const c0 = rbl * (1.0 - KAPPA);
const c1 = rtl * (1.0 - KAPPA);
ctx.moveTo(left + rbl, top + height);
ctx.bezierCurveTo(
left + c0,
top + height,
left,
top + height - c0,
left,
top + height - rbl,
);
ctx.lineTo(left, top + rtl);
ctx.bezierCurveTo(left, top + c1, left + c1, top, left + rtl, top);
ctx.strokeColor(borderLeftColor);
ctx.lineWidth(
Math.max(borderLeftWidth, borderTopWidth, borderBottomWidth) * 2,
);
if (borderLeftStyle === 'dashed') {
ctx.dash(borderLeftWidth * 2, { space: borderLeftWidth * 1.2 });
} else if (borderLeftStyle === 'dotted') {
ctx.dash(borderLeftWidth, { space: borderLeftWidth * 1.2 });
}
ctx.stroke();
ctx.undash();
};
const shouldRenderBorders = (node: SafeNode) =>
node.box &&
(node.box.borderTopWidth ||
node.box.borderRightWidth ||
node.box.borderBottomWidth ||
node.box.borderLeftWidth);
const renderBorders = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
if (!shouldRenderBorders(node)) return;
const {
width,
height,
borderTopWidth = 0,
borderLeftWidth = 0,
borderRightWidth = 0,
borderBottomWidth = 0,
} = node.box;
const {
opacity = 1,
borderTopColor = 'black',
borderTopStyle = 'solid',
borderLeftColor = 'black',
borderLeftStyle = 'solid',
borderRightColor = 'black',
borderRightStyle = 'solid',
borderBottomColor = 'black',
borderBottomStyle = 'solid',
} = node.style;
// @ts-expect-error this is always a number due to resolve border radius step
const borderTopLeftRadius: number = node.style.borderTopLeftRadius || 0;
// @ts-expect-error this is always a number due to resolve border radius step
const borderTopRightRadius: number = node.style.borderTopRightRadius || 0;
// @ts-expect-error this is always a number due to resolve border radius step
const borderBottomLeftRadius: number = node.style.borderBottomLeftRadius || 0;
// @ts-expect-error this is always a number due to resolve border radius step
const borderBottomRightRadius: number =
node.style.borderBottomRightRadius || 0;
const style: SafeBorderStyle = {
borderTopColor,
borderTopWidth,
borderTopStyle,
borderLeftColor,
borderLeftWidth,
borderLeftStyle,
borderRightColor,
borderRightWidth,
borderRightStyle,
borderBottomColor,
borderBottomWidth,
borderBottomStyle,
borderTopLeftRadius,
borderTopRightRadius,
borderBottomLeftRadius,
borderBottomRightRadius,
};
const rtr = Math.min(borderTopRightRadius, 0.5 * width, 0.5 * height);
const rtl = Math.min(borderTopLeftRadius, 0.5 * width, 0.5 * height);
const rbr = Math.min(borderBottomRightRadius, 0.5 * width, 0.5 * height);
const rbl = Math.min(borderBottomLeftRadius, 0.5 * width, 0.5 * height);
ctx.save();
ctx.strokeOpacity(opacity);
if (borderTopWidth) {
ctx.save();
clipBorderTop(ctx, node.box, style, rtr, rtl);
fillBorderTop(ctx, node.box, style, rtr, rtl);
ctx.restore();
}
if (borderRightWidth) {
ctx.save();
clipBorderRight(ctx, node.box, style, rtr, rbr);
fillBorderRight(ctx, node.box, style, rtr, rbr);
ctx.restore();
}
if (borderBottomWidth) {
ctx.save();
clipBorderBottom(ctx, node.box, style, rbl, rbr);
fillBorderBottom(ctx, node.box, style, rbl, rbr);
ctx.restore();
}
if (borderLeftWidth) {
ctx.save();
clipBorderLeft(ctx, node.box, style, rbl, rtl);
fillBorderLeft(ctx, node.box, style, rbl, rtl);
ctx.restore();
}
ctx.restore();
};
export default renderBorders;
================================================
FILE: packages/render/src/primitives/renderCanvas.ts
================================================
import { SafeCanvasNode } from '@react-pdf/layout';
import { Context } from '../types';
const availableMethods = [
'dash',
'clip',
'save',
'path',
'fill',
'font',
'text',
'rect',
'scale',
'moveTo',
'lineTo',
'stroke',
'rotate',
'circle',
'lineCap',
'opacity',
'ellipse',
'polygon',
'restore',
'lineJoin',
'fontSize',
'fillColor',
'lineWidth',
'translate',
'miterLimit',
'strokeColor',
'fillOpacity',
'roundedRect',
'fillAndStroke',
'strokeOpacity',
'bezierCurveTo',
'quadraticCurveTo',
'linearGradient',
'radialGradient',
];
const painter = (ctx: Context) => {
const p = availableMethods.reduce(
(acc, prop) => ({
...acc,
[prop]: (...args: any) => {
// @ts-expect-error ctx[prop] is a function
ctx[prop](...args);
return p;
},
}),
{},
);
return p;
};
const renderCanvas = (ctx: Context, node: SafeCanvasNode) => {
if (!node.box) return;
const { top, left, width, height } = node.box;
const paddingTop = node.box.paddingTop || 0;
const paddingLeft = node.box.paddingLeft || 0;
const paddingRight = node.box.paddingRight || 0;
const paddingBottom = node.box.paddingBottom || 0;
const availableWidth = width - paddingLeft - paddingRight;
const availableHeight = height - paddingTop - paddingBottom;
if (!availableWidth || !availableHeight) {
console.warn(
'Canvas element has null width or height. Please provide valid values via the `style` prop in order to correctly render it.',
);
}
ctx.save().translate(left + paddingLeft, top + paddingTop);
if (node.props.paint) {
node.props.paint(painter(ctx), availableWidth, availableHeight);
}
ctx.restore();
};
export default renderCanvas;
================================================
FILE: packages/render/src/primitives/renderCheckbox.ts
================================================
import { SafeCheckboxNode } from '@react-pdf/layout';
import { Context, RenderOptions } from '../types';
import { parseCheckboxOptions } from '../utils/parseFormOptions';
const renderCheckbox = (
ctx: Context,
node: SafeCheckboxNode,
options: RenderOptions,
) => {
if (!node.box) return;
const { top, left, width, height } = node.box;
// Element's name
const name = node.props?.name || '';
const fieldSetOptions = options.fieldSets?.at(0);
if (!ctx._root.data.AcroForm) {
ctx.initForm();
}
ctx.formCheckbox(
name,
left,
top,
width,
height,
parseCheckboxOptions(ctx, node, fieldSetOptions),
);
};
export default renderCheckbox;
================================================
FILE: packages/render/src/primitives/renderCircle.ts
================================================
import { SafeCircleNode } from '@react-pdf/layout';
import { Context } from '../types';
import { drawEllipse } from './renderEllipse';
const renderCircle = (ctx: Context, node: SafeCircleNode) => {
const cx = node.props?.cx;
const cy = node.props?.cy;
const r = node.props?.r;
drawEllipse(ctx, r, r, cx, cy);
};
export default renderCircle;
================================================
FILE: packages/render/src/primitives/renderDebug.ts
================================================
import { SafeNode } from '@react-pdf/layout';
import { Context } from '../types';
const CONTENT_COLOR = '#a1c6e7';
const PADDING_COLOR = '#c4deb9';
const MARGIN_COLOR = '#f8cca1';
// TODO: Draw debug boxes using clipping to enhance quality
const debugContent = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
const {
left,
top,
width,
height,
paddingLeft = 0,
paddingTop = 0,
paddingRight = 0,
paddingBottom = 0,
borderLeftWidth = 0,
borderTopWidth = 0,
borderRightWidth = 0,
borderBottomWidth = 0,
} = node.box;
ctx
.fillColor(CONTENT_COLOR)
.opacity(0.5)
.rect(
left + paddingLeft + borderLeftWidth,
top + paddingTop + borderTopWidth,
width - paddingLeft - paddingRight - borderRightWidth - borderLeftWidth,
height - paddingTop - paddingBottom - borderTopWidth - borderBottomWidth,
)
.fill();
};
const debugPadding = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
const {
left,
top,
width,
height,
paddingLeft = 0,
paddingTop = 0,
paddingRight = 0,
paddingBottom = 0,
borderLeftWidth = 0,
borderTopWidth = 0,
borderRightWidth = 0,
borderBottomWidth = 0,
} = node.box;
ctx.fillColor(PADDING_COLOR).opacity(0.5);
// Padding top
ctx
.rect(
left + paddingLeft + borderLeftWidth,
top + borderTopWidth,
width - paddingRight - paddingLeft - borderLeftWidth - borderRightWidth,
paddingTop,
)
.fill();
// Padding left
ctx
.rect(
left + borderLeftWidth,
top + borderTopWidth,
paddingLeft,
height - borderTopWidth - borderBottomWidth,
)
.fill();
// Padding right
ctx
.rect(
left + width - paddingRight - borderRightWidth,
top + borderTopWidth,
paddingRight,
height - borderTopWidth - borderBottomWidth,
)
.fill();
// Padding bottom
ctx
.rect(
left + paddingLeft + borderLeftWidth,
top + height - paddingBottom - borderBottomWidth,
width - paddingRight - paddingLeft - borderLeftWidth - borderRightWidth,
paddingBottom,
)
.fill();
};
const debugMargin = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
const { left, top, width, height } = node.box;
const {
marginLeft = 0,
marginTop = 0,
marginRight = 0,
marginBottom = 0,
} = node.box;
ctx.fillColor(MARGIN_COLOR).opacity(0.5);
// Margin top
ctx.rect(left, top - marginTop, width, marginTop).fill();
// Margin left
ctx
.rect(
left - marginLeft,
top - marginTop,
marginLeft,
height + marginTop + marginBottom,
)
.fill();
// Margin right
ctx
.rect(
left + width,
top - marginTop,
marginRight,
height + marginTop + marginBottom,
)
.fill();
// Margin bottom
ctx.rect(left, top + height, width, marginBottom).fill();
};
const debugText = (ctx: Context, node: SafeNode) => {
if (!node.box) return;
const { left, top, width, height } = node.box;
const {
marginLeft = 0,
marginTop = 0,
marginRight = 0,
marginBottom = 0,
} = node.box;
const roundedWidth = Math.round(width + marginLeft + marginRight);
const roundedHeight = Math.round(height + marginTop + marginBottom);
ctx
.fontSize(6)
.opacity(1)
.fillColor('black')
.text(
`${roundedWidth} x ${roundedHeight}`,
left - marginLeft,
Math.max(top - marginTop - 4, 1),
{ width: Infinity },
);
};
const debugOrigin = (ctx: Context, node: SafeNode) => {
if (node.origin) {
ctx
.circle(node.origin.left, node.origin.top, 3)
.fill('red')
.circle(node.origin.left, node.origin.top, 5)
.stroke('red');
}
};
const renderDebug = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('debug' in node.props) || !node.props.debug) return;
ctx.save();
debugContent(ctx, node);
debugPadding(ctx, node);
debugMargin(ctx, node);
debugText(ctx, node);
debugOrigin(ctx, node);
ctx.restore();
};
export default renderDebug;
================================================
FILE: packages/render/src/primitives/renderEllipse.ts
================================================
import { SafeEllipseNode } from '@react-pdf/layout';
import { Context } from '../types';
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
export const drawEllipse = (
ctx: Context,
rx: number,
ry: number,
cx: number = 0,
cy: number = 0,
) => {
const x = cx - rx;
const y = cy - ry;
const ox = rx * KAPPA;
const oy = ry * KAPPA;
const xe = x + rx * 2;
const ye = y + ry * 2;
const xm = x + rx;
const ym = y + ry;
ctx.moveTo(x, ym);
ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
ctx.closePath();
};
const renderEllipse = (ctx: Context, node: SafeEllipseNode) => {
const { cx, cy, rx, ry } = node.props || {};
drawEllipse(ctx, rx, ry, cx, cy);
};
export default renderEllipse;
================================================
FILE: packages/render/src/primitives/renderFieldSet.ts
================================================
import { SafeFieldSetNode } from '@react-pdf/layout';
import { Context, RenderOptions } from '../types';
const renderFieldSet = (
ctx: Context,
node: SafeFieldSetNode,
options: Pick,
) => {
const name = node.props?.name || '';
if (!ctx._root.data.AcroForm) {
ctx.initForm();
}
const formField = ctx.formField(name);
const option = options;
if (!option.fieldSets) {
option.fieldSets = [formField];
} else {
option.fieldSets.push(formField);
}
};
export const cleanUpFieldSet = (
_ctx: Context,
_node: SafeFieldSetNode,
options: RenderOptions,
) => {
options.fieldSets.pop();
};
export default renderFieldSet;
================================================
FILE: packages/render/src/primitives/renderGlyphs.ts
================================================
/* eslint-disable no-return-assign */
import { Glyph, Position } from '@react-pdf/textkit';
import { Context } from '../types';
const number = (n: number) => {
if (n > -1e21 && n < 1e21) {
return Math.round(n * 1e6) / 1e6;
}
throw new Error(`unsupported number: ${n}`);
};
const _renderGlyphs = (
ctx: Context,
encoded: Glyph[],
positions: Position[],
x: number,
y: number,
) => {
const commands: string[] = [];
const scale = ctx._fontSize / 1000;
let i;
let last = 0;
let hadOffset = false;
ctx.save();
// flip coordinate system
ctx.transform(1, 0, 0, -1, 0, ctx.page.height);
y = ctx.page.height - y;
// add current font to page if necessary
if (ctx.page.fonts[ctx._font.id] == null) {
ctx.page.fonts[ctx._font.id] = ctx._font.ref();
}
// begin the text object
ctx.addContent('BT');
// text position
ctx.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
// font and font size
ctx.addContent(`/${ctx._font.id} ${number(ctx._fontSize)} Tf`);
// Adds a segment of text to the TJ command buffer
const addSegment = (cur: number) => {
if (last < cur) {
const hex = encoded.slice(last, cur).join('');
const advance =
positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth!;
commands.push(`<${hex}> ${number(-advance)}`);
}
return (last = cur);
};
// Flushes the current TJ commands to the output stream
const flush = (s: number) => {
addSegment(s);
if (commands.length > 0) {
ctx.addContent(`[${commands.join(' ')}] TJ`);
return (commands.length = 0);
}
};
for (i = 0; i < positions.length; i += 1) {
// If we have an x or y offset, we have to break out of the current TJ command
// so we can move the text position.
const pos = positions[i];
if (pos.xOffset || pos.yOffset) {
// Flush the current buffer
flush(i);
// Move the text position and flush just the current character
ctx.addContent(
`1 0 0 1 ${number(x + pos.xOffset * scale)} ${number(
y + pos.yOffset * scale,
)} Tm`,
);
flush(i + 1);
hadOffset = true;
} else {
// If the last character had an offset, reset the text position
if (hadOffset) {
ctx.addContent(`1 0 0 1 ${number(x)} ${number(y)} Tm`);
hadOffset = false;
}
// Group segments that don't have any advance adjustments
if (pos.xAdvance - pos.advanceWidth! !== 0) {
addSegment(i + 1);
}
}
x += pos.xAdvance * scale;
}
// Flush any remaining commands
flush(i);
// end the text object
ctx.addContent('ET');
// restore flipped coordinate system
return ctx.restore();
};
const renderGlyphs = (
ctx: Context,
glyphs: Glyph[],
positions: Position[],
x: number,
y: number,
) => {
const scale = 1000 / ctx._fontSize;
const unitsPerEm = ctx._font.font.unitsPerEm || 1000;
const advanceWidthScale = 1000 / unitsPerEm;
// Glyph encoding and positioning
const encodedGlyphs = ctx._font.encodeGlyphs(glyphs);
const encodedPositions = positions.map((pos, i) => ({
xAdvance: pos.xAdvance * scale,
yAdvance: pos.yAdvance * scale,
xOffset: pos.xOffset,
yOffset: pos.yOffset,
advanceWidth: glyphs[i].advanceWidth * advanceWidthScale,
}));
return _renderGlyphs(ctx, encodedGlyphs, encodedPositions, x, y);
};
export default renderGlyphs;
================================================
FILE: packages/render/src/primitives/renderGroup.ts
================================================
const renderGroup = () => {
// noop
};
export default renderGroup;
================================================
FILE: packages/render/src/primitives/renderImage.ts
================================================
import { isNil } from '@react-pdf/fns';
import { SafeImageNode } from '@react-pdf/layout';
import clipNode from '../operations/clipNode';
import embedImage from '../operations/embedImage';
import resolveObjectFit from '../utils/resolveObjectFit';
import { Context, RenderOptions } from '../types';
const drawImage = (
ctx: Context,
node: SafeImageNode,
options: RenderOptions,
) => {
if (!node.box) return;
if (!node.image) return;
const { left, top } = node.box;
const opacity = node.style?.opacity;
const objectFit = node.style?.objectFit;
const objectPositionX = node.style?.objectPositionX;
const objectPositionY = node.style?.objectPositionY;
const paddingTop = node.box.paddingTop || 0;
const paddingRight = node.box.paddingRight || 0;
const paddingBottom = node.box.paddingBottom || 0;
const paddingLeft = node.box.paddingLeft || 0;
const imageCache = options.imageCache || new Map();
const { width, height, xOffset, yOffset } = resolveObjectFit(
objectFit,
node.box.width - paddingLeft - paddingRight,
node.box.height - paddingTop - paddingBottom,
node.image.width,
node.image.height,
objectPositionX,
objectPositionY,
);
if (node.image.data) {
if (width !== 0 && height !== 0) {
const cacheKey = node.image.key;
const image = imageCache.get(cacheKey) || embedImage(ctx, node);
if (cacheKey) imageCache.set(cacheKey, image);
const imageOpacity = isNil(opacity) ? 1 : opacity;
ctx
.fillOpacity(imageOpacity)
.image(
image,
left + paddingLeft + xOffset,
top + paddingTop + yOffset,
{
width,
height,
},
);
} else {
console.warn(
`Image with src '${JSON.stringify(
node.props.src || node.props.source,
)}' skipped due to invalid dimensions`,
);
}
}
};
const renderImage = (
ctx: Context,
node: SafeImageNode,
options: RenderOptions,
) => {
ctx.save();
clipNode(ctx, node);
drawImage(ctx, node, options);
ctx.restore();
};
export default renderImage;
================================================
FILE: packages/render/src/primitives/renderLine.ts
================================================
import { SafeLineNode } from '@react-pdf/layout';
import { Context } from '../types';
const renderLine = (ctx: Context, node: SafeLineNode) => {
const { x1, x2, y1, y2 } = node.props || {};
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
};
export default renderLine;
================================================
FILE: packages/render/src/primitives/renderList.ts
================================================
import { SafeListNode } from '@react-pdf/layout';
import { Context } from '../types';
import { parseSelectAndListFieldOptions } from '../utils/parseFormOptions';
const renderList = (ctx: Context, node: SafeListNode) => {
if (!node.box) return;
const { top, left, width, height } = node.box || {};
// Element's name
const name = ('name' in node.props ? node.props.name || '' : '') as string;
if (!ctx._root.data.AcroForm) {
ctx.initForm();
}
ctx.formList(
name,
left,
top,
width,
height,
parseSelectAndListFieldOptions(node),
);
};
export default renderList;
================================================
FILE: packages/render/src/primitives/renderNode.ts
================================================
import * as P from '@react-pdf/primitives';
import { SafeNode } from '@react-pdf/layout';
import renderSvg from './renderSvg';
import renderText from './renderText';
import renderPage from './renderPage';
import renderNote from './renderNote';
import renderImage from './renderImage';
import renderDebug from './renderDebug';
import renderCanvas from './renderCanvas';
import renderBorders from './renderBorders';
import renderBackground from './renderBackground';
import setLink from '../operations/setLink';
import clipNode from '../operations/clipNode';
import transform from '../operations/transform';
import setDestination from '../operations/setDestination';
import renderTextInput from './renderTextInput';
import renderSelect from './renderSelect';
import renderFieldSet, { cleanUpFieldSet } from './renderFieldSet';
import renderList from './renderList';
import renderCheckbox from './renderCheckbox';
import { Context, RenderOptions } from '../types';
type Primitives = (typeof P)[keyof typeof P];
const isRecursiveNode = (node: SafeNode) =>
node.type !== P.Text && node.type !== P.Svg;
const renderChildren = (
ctx: Context,
node: SafeNode,
options: RenderOptions,
) => {
ctx.save();
if (node.box) {
ctx.translate(node.box.left, node.box.top);
}
const children = node.children || [];
const renderChild = (child: SafeNode) => renderNode(ctx, child, options);
children.forEach(renderChild);
ctx.restore();
};
const renderFns: Partial> = {
[P.Text]: renderText,
[P.Note]: renderNote,
[P.Image]: renderImage,
[P.FieldSet]: renderFieldSet,
[P.TextInput]: renderTextInput,
[P.Select]: renderSelect,
[P.Checkbox]: renderCheckbox,
[P.List]: renderList,
[P.Canvas]: renderCanvas,
[P.Svg]: renderSvg,
[P.Link]: setLink,
};
const cleanUpFns: Partial> = {
[P.FieldSet]: cleanUpFieldSet,
};
const renderNode = (ctx: Context, node: SafeNode, options: RenderOptions) => {
const overflowHidden = node.style?.overflow === 'hidden';
const shouldRenderChildren = isRecursiveNode(node);
if (node.type === P.Page) renderPage(ctx, node);
ctx.save();
if (overflowHidden) clipNode(ctx, node);
transform(ctx, node);
renderBackground(ctx, node);
renderBorders(ctx, node);
const renderFn = renderFns[node.type];
if (renderFn) renderFn(ctx, node, options);
if (shouldRenderChildren) renderChildren(ctx, node, options);
const cleanUpFn = cleanUpFns[node.type];
if (cleanUpFn) cleanUpFn(ctx, node, options);
setDestination(ctx, node);
renderDebug(ctx, node);
ctx.restore();
};
export default renderNode;
================================================
FILE: packages/render/src/primitives/renderNote.ts
================================================
import { SafeNoteNode } from '@react-pdf/layout';
import { Context } from '../types';
const renderNote = (ctx: Context, node: SafeNoteNode) => {
if (!node.box) return;
const { top, left } = node.box;
const value = node?.children?.[0].value || '';
const color = node.style?.backgroundColor;
ctx.note(left, top, 0, 0, value, { color });
};
export default renderNote;
================================================
FILE: packages/render/src/primitives/renderPage.ts
================================================
import { SafePageNode } from '@react-pdf/layout';
import { Context } from '../types';
const renderPage = (ctx: Context, node: SafePageNode) => {
if (!node.box) return;
const { width, height } = node.box;
const dpi = node.props?.dpi || 72;
const userUnit = dpi / 72;
ctx.addPage({ size: [width, height], margin: 0, userUnit });
};
export default renderPage;
================================================
FILE: packages/render/src/primitives/renderPath.ts
================================================
import { SafePathNode } from '@react-pdf/layout';
import { Context } from '../types';
const renderPath = (ctx: Context, node: SafePathNode) => {
const d = node.props?.d;
if (d) ctx.path(node.props.d);
};
export default renderPath;
================================================
FILE: packages/render/src/primitives/renderPolygon.ts
================================================
import { SafePolygonNode } from '@react-pdf/layout';
import { Context } from '../types';
import parsePoints from '../svg/parsePoints';
import { drawPolyline } from './renderPolyline';
const renderPolygon = (ctx: Context, node: SafePolygonNode) => {
const points = parsePoints(node.props.points || '');
drawPolyline(ctx, points);
ctx.closePath();
};
export default renderPolygon;
================================================
FILE: packages/render/src/primitives/renderPolyline.ts
================================================
import { SafePolylineNode } from '@react-pdf/layout';
import parsePoints from '../svg/parsePoints';
import { Context } from '../types';
export const drawPolyline = (ctx: Context, points: number[][]) => {
if (points.length > 0) {
ctx.moveTo(points[0][0], points[0][1]);
points.slice(1).forEach((p) => ctx.lineTo(p[0], p[1]));
}
};
const renderPolyline = (ctx: Context, node: SafePolylineNode) => {
const points = parsePoints(node.props.points || '');
drawPolyline(ctx, points);
};
export default renderPolyline;
================================================
FILE: packages/render/src/primitives/renderRect.ts
================================================
import { SafeRectNode } from '@react-pdf/layout';
import { Context } from '../types';
const KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);
const renderRect = (ctx: Context, node: SafeRectNode) => {
const x = node.props?.x || 0;
const y = node.props?.y || 0;
const rx = node.props?.rx || 0;
const ry = node.props?.ry || 0;
const width = node.props?.width || 0;
const height = node.props?.height || 0;
if (!width || !height) return;
if (rx && ry) {
const krx = rx * KAPPA;
const kry = ry * KAPPA;
ctx.moveTo(x + rx, y);
ctx.lineTo(x - rx + width, y);
ctx.bezierCurveTo(
x - rx + width + krx,
y,
x + width,
y + ry - kry,
x + width,
y + ry,
);
ctx.lineTo(x + width, y + height - ry);
ctx.bezierCurveTo(
x + width,
y + height - ry + kry,
x - rx + width + krx,
y + height,
x - rx + width,
y + height,
);
ctx.lineTo(x + rx, y + height);
ctx.bezierCurveTo(
x + rx - krx,
y + height,
x,
y + height - ry + kry,
x,
y + height - ry,
);
ctx.lineTo(x, y + ry);
ctx.bezierCurveTo(x, y + ry - kry, x + rx - krx, y, x + rx, y);
} else {
ctx.moveTo(x, y);
ctx.lineTo(x + width, y);
ctx.lineTo(x + width, y + height);
ctx.lineTo(x, y + height);
}
ctx.closePath();
};
export default renderRect;
================================================
FILE: packages/render/src/primitives/renderSelect.ts
================================================
import { SafeSelectNode } from '@react-pdf/layout';
import { Context } from '../types';
import { parseSelectAndListFieldOptions } from '../utils/parseFormOptions';
const renderSelect = (ctx: Context, node: SafeSelectNode) => {
if (!node.box) return;
const { top, left, width, height } = node.box;
// Element's name
const name = node.props?.name || '';
if (!ctx._root.data.AcroForm) {
ctx.initForm();
}
ctx.formCombo(
name,
left,
top,
width,
height,
parseSelectAndListFieldOptions(node),
);
};
export default renderSelect;
================================================
FILE: packages/render/src/primitives/renderSvg.ts
================================================
import * as P from '@react-pdf/primitives';
import { isNil } from '@react-pdf/fns';
import { Transform } from '@react-pdf/stylesheet';
import {
SafeLinearGradientNode,
SafeNode,
SafeRadialGradientNode,
SafeSvgNode,
} from '@react-pdf/layout';
import renderPath from './renderPath';
import renderRect from './renderRect';
import renderLine from './renderLine';
import renderGroup from './renderGroup';
import renderCircle from './renderCircle';
import renderSvgText from './renderSvgText';
import renderEllipse from './renderEllipse';
import renderPolygon from './renderPolygon';
import renderPolyline from './renderPolyline';
import renderSvgImage from './renderSvgImage';
import clipNode from '../operations/clipNode';
import transform from '../operations/transform';
import getBoundingBox from '../svg/getBoundingBox';
import { Context } from '../types';
type Primitives = (typeof P)[keyof typeof P];
const setStrokeWidth = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('strokeWidth' in node.props)) return;
const lineWidth = node.props.strokeWidth;
if (lineWidth) ctx.lineWidth(lineWidth);
};
const setStrokeColor = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('stroke' in node.props)) return;
const strokeColor = node.props.stroke;
if (strokeColor) ctx.strokeColor(strokeColor);
};
const setOpacity = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('opacity' in node.props)) return;
const opacity = node.props.opacity;
if (!isNil(opacity)) ctx.opacity(opacity);
};
const setFillOpacity = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('fillOpacity' in node.props)) return;
const fillOpacity = node.props.fillOpacity || null;
if (!isNil(fillOpacity)) ctx.fillOpacity(fillOpacity);
};
const setStrokeOpacity = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('strokeOpacity' in node.props)) return;
const strokeOpacity = node.props?.strokeOpacity;
if (!isNil(strokeOpacity)) ctx.strokeOpacity(strokeOpacity);
};
const setLineJoin = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('strokeLinejoin' in node.props)) return;
const lineJoin = node.props.strokeLinejoin;
if (lineJoin) ctx.lineJoin(lineJoin);
};
const setLineCap = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('strokeLinecap' in node.props)) return;
const lineCap = node.props?.strokeLinecap;
if (lineCap) ctx.lineCap(lineCap);
};
const setLineDash = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('strokeDasharray' in node.props)) return;
const value = node.props?.strokeDasharray || null;
// @ts-expect-error check this works as expected
if (value) ctx.dash(value.split(/[\s,]+/).map(Number));
};
const hasLinearGradientFill = (node: SafeNode) => {
if (!node.props) return false;
if (!('fill' in node.props)) return false;
if (typeof node.props.fill === 'string') return false;
return node.props.fill?.type === P.LinearGradient;
};
const hasRadialGradientFill = (node: SafeNode) => {
if (!node.props) return false;
if (!('fill' in node.props)) return false;
if (typeof node.props.fill === 'string') return false;
return node.props.fill?.type === P.RadialGradient;
};
function multiplyMatrices(m1: number[], m2: number[]) {
const a = m1[0] * m2[0] + m1[2] * m2[1];
const b = m1[1] * m2[0] + m1[3] * m2[1];
const c = m1[0] * m2[2] + m1[2] * m2[3];
const d = m1[1] * m2[2] + m1[3] * m2[3];
const e = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
const f = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
return [a, b, c, d, e, f];
}
const transformGradient = (
grad: any,
transforms: Transform[],
bbox: number[],
units: string,
) => {
const matrices = transforms.map((transform) => {
switch (transform.operation) {
case 'scale': {
const value = transform.value;
return [value[0], 0, 0, value[1], 0, 0];
}
case 'translate': {
const value = transform.value;
let x = value[0] || 0;
let y = value[1] || 0;
if (units === 'objectBoundingBox') {
x = (bbox[2] - bbox[0]) * x;
y = (bbox[3] - bbox[1]) * y;
}
return [1, 0, 0, 1, x, y];
}
case 'rotate': {
const value = transform.value;
const cos = Math.cos(value[0]);
const sin = Math.sin(value[0]);
return [cos, sin, -sin, cos, 0, 0];
}
case 'skew': {
const value = transform.value;
return [1, Math.tan(value[0]), Math.tan(value[1]), 1, 0, 0];
}
case 'matrix': {
const value = transform.value;
let x = value[4] || 0;
let y = value[5] || 0;
if (units === 'objectBoundingBox') {
x = (bbox[2] - bbox[0]) * x;
y = (bbox[3] - bbox[1]) * y;
}
return [value[0], value[1], value[2], value[3], x, y];
}
default:
return [1, 0, 0, 1, 0, 0];
}
});
const matrix = matrices.reduce(multiplyMatrices, [1, 0, 0, 1, 0, 0]);
grad.setTransform(...matrix);
};
// Math simplified from https://github.com/devongovett/svgkit/blob/master/src/elements/SVGGradient.js#L104
const setLinearGradientFill = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('fill' in node.props)) return;
const bbox = getBoundingBox(node);
const gradient = node.props?.fill as SafeLinearGradientNode;
if (!gradient) return;
const units = gradient.props.gradientUnits || 'objectBoundingBox';
const transforms = gradient.props.gradientTransform || [];
let x1 = gradient.props.x1 || 0;
let y1 = gradient.props.y1 || 0;
let x2 = gradient.props.x2 || 1;
let y2 = gradient.props.y2 || 0;
if (units === 'objectBoundingBox') {
const m0 = bbox[2] - bbox[0];
const m3 = bbox[3] - bbox[1];
const m4 = bbox[0];
const m5 = bbox[1];
x1 = m0 * x1 + m4;
y1 = m3 * y1 + m5;
x2 = m0 * x2 + m4;
y2 = m3 * y2 + m5;
}
const grad = ctx.linearGradient(x1, y1, x2, y2);
transformGradient(grad, transforms, bbox, units);
gradient.children?.forEach((stop) => {
grad.stop(stop.props.offset, stop.props.stopColor, stop.props.stopOpacity);
});
ctx.fill(grad);
};
// Math simplified from https://github.com/devongovett/svgkit/blob/master/src/elements/SVGGradient.js#L155
const setRadialGradientFill = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('fill' in node.props)) return;
const bbox = getBoundingBox(node);
const gradient = node.props?.fill as SafeRadialGradientNode;
if (!gradient) return;
const units = gradient.props.gradientUnits || 'objectBoundingBox';
const transforms = gradient.props.gradientTransform || [];
let r = gradient.props.r || 0.5;
let cx = gradient.props.cx || 0.5;
let cy = gradient.props.cy || 0.5;
let fx = gradient.props.fx || cx;
let fy = gradient.props.fy || cy;
if (units === 'objectBoundingBox') {
const m0 = bbox[2] - bbox[0];
const m3 = bbox[3] - bbox[1];
const m4 = bbox[0];
const m5 = bbox[1];
r = r * m0;
cx = m0 * cx + m4;
cy = m3 * cy + m5;
fx = m0 * fx + m4;
fy = m3 * fy + m5;
}
const grad = ctx.radialGradient(cx, cy, 0, fx, fy, r);
transformGradient(grad, transforms, bbox, units);
gradient.children?.forEach((stop) => {
grad.stop(stop.props.offset, stop.props.stopColor, stop.props.stopOpacity);
});
ctx.fill(grad);
};
const setFillColor = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('fill' in node.props)) return;
const fillColor = node.props?.fill as string;
if (fillColor) ctx.fillColor(fillColor);
};
const setFill = (ctx: Context, node: SafeNode) => {
if (hasLinearGradientFill(node)) return setLinearGradientFill(ctx, node);
if (hasRadialGradientFill(node)) return setRadialGradientFill(ctx, node);
return setFillColor(ctx, node);
};
const draw = (ctx: Context, node: SafeNode) => {
const props = node.props || {};
if ('fill' in props && 'stroke' in props && props.fill && props.stroke) {
ctx.fillAndStroke(props.fillRule);
} else if ('fill' in props && props.fill) {
ctx.fill(props.fillRule);
} else if ('stroke' in props && props.stroke) {
ctx.stroke();
} else {
ctx.save();
ctx.opacity(0);
ctx.fill(null!);
ctx.restore();
}
};
const noop = () => {};
const renderFns: Partial> = {
[P.Tspan]: noop,
[P.TextInstance]: noop,
[P.Path]: renderPath,
[P.Rect]: renderRect,
[P.Line]: renderLine,
[P.G]: renderGroup,
[P.Text]: renderSvgText,
[P.Circle]: renderCircle,
[P.Image]: renderSvgImage,
[P.Ellipse]: renderEllipse,
[P.Polygon]: renderPolygon,
[P.Polyline]: renderPolyline,
};
const renderNode = (ctx: Context, node: SafeNode) => {
const renderFn = renderFns[node.type];
if (renderFn) {
renderFn(ctx, node);
} else {
console.warn(`SVG node of type ${node.type} is not currently supported`);
}
};
const drawNode = (ctx: Context, node: SafeNode) => {
setLineCap(ctx, node);
setLineDash(ctx, node);
setLineJoin(ctx, node);
setStrokeWidth(ctx, node);
setStrokeColor(ctx, node);
setFill(ctx, node);
setStrokeOpacity(ctx, node);
setFillOpacity(ctx, node);
setOpacity(ctx, node);
transform(ctx, node);
renderNode(ctx, node);
draw(ctx, node);
};
const clipPath = (ctx: Context, node: SafeNode) => {
if (!node.props) return;
if (!('clipPath' in node.props)) return;
const value = node.props.clipPath;
if (value) {
const children = value.children || [];
children.forEach((child) => renderNode(ctx, child));
ctx.clip();
}
};
const drawChildren = (ctx: Context, node: SafeNode) => {
const children = node.children || [];
children.forEach((child) => {
ctx.save();
clipPath(ctx, child);
drawNode(ctx, child);
drawChildren(ctx, child);
ctx.restore();
});
};
const resolveAspectRatio = (ctx: Context, node: SafeSvgNode) => {
if (!node.box) return;
const { width, height } = node.box;
const { viewBox, preserveAspectRatio } = node.props;
const { meetOrSlice = 'meet', align = 'xMidYMid' } =
preserveAspectRatio || {};
if (viewBox == null || width == null || height == null) return;
const x = viewBox?.minX || 0;
const y = viewBox?.minY || 0;
const logicalWidth = viewBox?.maxX || width;
const logicalHeight = viewBox?.maxY || height;
const logicalRatio = logicalWidth / logicalHeight;
const physicalRatio = width / height;
const scaleX = width / logicalWidth;
const scaleY = height / logicalHeight;
if (align === 'none') {
ctx.scale(scaleX, scaleY);
ctx.translate(-x, -y);
return;
}
if (
(logicalRatio < physicalRatio && meetOrSlice === 'meet') ||
(logicalRatio >= physicalRatio && meetOrSlice === 'slice')
) {
ctx.scale(scaleY, scaleY);
switch (align) {
case 'xMinYMin':
case 'xMinYMid':
case 'xMinYMax':
ctx.translate(-x, -y);
break;
case 'xMidYMin':
case 'xMidYMid':
case 'xMidYMax':
ctx.translate(
-x - (logicalWidth - (width * logicalHeight) / height) / 2,
-y,
);
break;
default:
ctx.translate(
-x - (logicalWidth - (width * logicalHeight) / height),
-y,
);
}
} else {
ctx.scale(scaleX, scaleX);
switch (align) {
case 'xMinYMin':
case 'xMidYMin':
case 'xMaxYMin':
ctx.translate(-x, -y);
break;
case 'xMinYMid':
case 'xMidYMid':
case 'xMaxYMid':
ctx.translate(
-x,
-y - (logicalHeight - (height * logicalWidth) / width) / 2,
);
break;
default:
ctx.translate(
-x,
-y - (logicalHeight - (height * logicalWidth) / width),
);
}
}
};
const moveToOrigin = (ctx: Context, node: SafeSvgNode) => {
if (!node.box) return;
const { top, left } = node.box;
const paddingLeft = node.box.paddingLeft || 0;
const paddingTop = node.box.paddingTop || 0;
ctx.translate(left + paddingLeft, top + paddingTop);
};
const renderSvg = (ctx: Context, node: SafeSvgNode) => {
ctx.save();
clipNode(ctx, node);
moveToOrigin(ctx, node);
resolveAspectRatio(ctx, node);
drawChildren(ctx, node);
ctx.restore();
};
export default renderSvg;
================================================
FILE: packages/render/src/primitives/renderSvgImage.ts
================================================
import { SafeImageNode } from '@react-pdf/layout';
import { Context } from '../types';
const renderImage = (ctx: Context, node: SafeImageNode) => {
if (!node.box) return;
if (!node.image?.data) return;
const { x = 0, y = 0 } = node.props;
const { width, height, opacity } = node.style;
const paddingTop = node.box.paddingLeft || 0;
const paddingLeft = node.box.paddingLeft || 0;
if (width === 0 || height === 0) {
console.warn(
`Image with src '${
(node.props as any).href
}' skipped due to invalid dimensions`,
);
return;
}
if (typeof width === 'string' || typeof height === 'string') {
console.warn(
`Image with src '${
(node.props as any).href
}' skipped due to percentage width or height`,
);
return;
}
ctx.save();
ctx
.fillOpacity(opacity || 1)
.image(node.image.data, x + paddingLeft, y + paddingTop, {
width,
height,
});
ctx.restore();
};
export default renderImage;
================================================
FILE: packages/render/src/primitives/renderSvgText.ts
================================================
import {
DominantBaseline,
SafeTextNode,
SafeTspanNode,
TextAnchor,
} from '@react-pdf/layout';
import { AttributedString, Run } from '@react-pdf/textkit';
import { Context } from '../types';
import renderGlyphs from './renderGlyphs';
const renderRun = (ctx: Context, run: Run) => {
if (!run.glyphs) return;
if (!run.positions) return;
const runAdvanceWidth = run.xAdvance;
const font = run.attributes.font?.[0];
const { fontSize, color, opacity } = run.attributes;
if (color) ctx.fillColor(color);
ctx.fillOpacity(opacity!);
if (font) {
ctx.font(font.type === 'STANDARD' ? font.fullName : font, fontSize);
}
try {
renderGlyphs(ctx, run.glyphs!, run.positions!, 0, 0);
} catch (error) {
console.log(error);
}
ctx.translate(runAdvanceWidth!, 0);
};
const renderSpan = (
ctx: Context,
line: AttributedString,
textAnchor?: TextAnchor,
dominantBaseline?: DominantBaseline,
) => {
ctx.save();
const x = line.box?.x || 0;
const y = line.box?.y || 0;
const font = line.runs[0]?.attributes.font?.[0];
const scale = line.runs[0]?.attributes?.scale || 1;
const width = line.xAdvance!;
if (!font) return;
const ascent = font.ascent * scale;
const xHeight = font.xHeight * scale;
const descent = font.descent * scale;
const capHeight = font.capHeight * scale;
let xTranslate = x;
let yTranslate = y;
switch (textAnchor) {
case 'middle':
xTranslate = x - width / 2;
break;
case 'end':
xTranslate = x - width;
break;
default:
xTranslate = x;
break;
}
switch (dominantBaseline) {
case 'middle':
case 'central':
yTranslate = y + capHeight / 2;
break;
case 'hanging':
yTranslate = y + capHeight;
break;
case 'mathematical':
yTranslate = y + xHeight;
break;
case 'text-after-edge':
yTranslate = y + descent;
break;
case 'text-before-edge':
yTranslate = y + ascent;
break;
default:
yTranslate = y;
break;
}
ctx.translate(xTranslate, yTranslate);
line.runs.forEach((run) => renderRun(ctx, run));
ctx.restore();
};
const renderSvgText = (ctx: Context, node: SafeTextNode) => {
const children = node.children as SafeTspanNode[];
children.forEach((span) =>
renderSpan(
ctx,
span.lines![0],
span.props.textAnchor,
span.props.dominantBaseline,
),
);
};
export default renderSvgText;
================================================
FILE: packages/render/src/primitives/renderText.ts
================================================
import { isNil } from '@react-pdf/fns';
import renderGlyphs from './renderGlyphs';
import parseColor from '../utils/parseColor';
import { Context } from '../types';
import { SafeTextNode } from '@react-pdf/layout';
import {
Attachment,
AttributedString,
DecorationLine,
Paragraph,
Rect,
Run,
} from '@react-pdf/textkit';
const DEST_REGEXP = /^#.+/;
const isSrcId = (src: string) => src.match(DEST_REGEXP);
const renderAttachment = (ctx: Context, attachment: Attachment) => {
const { xOffset = 0, yOffset = 0, width, height, image } = attachment;
ctx.translate(-width + xOffset, -height + yOffset);
ctx.image(image, 0, 0, {
fit: [width, height],
align: 'center',
valign: 'bottom',
});
};
const renderAttachments = (ctx: Context, run: Run, glyphs: Run['glyphs']) => {
if (!glyphs) return;
if (!run.positions) return;
const font = run.attributes.font?.[0];
if (!font) return;
ctx.save();
const space = font.glyphForCodePoint(0x20);
const objectReplacement = font.glyphForCodePoint(0xfffc);
let attachmentAdvance = 0;
for (let i = 0; i < glyphs.length; i += 1) {
const position = run.positions[i];
const glyph = glyphs[i];
attachmentAdvance += position.xAdvance || 0;
if (glyph.id === objectReplacement.id && run.attributes.attachment) {
ctx.translate(attachmentAdvance, position.yOffset || 0);
renderAttachment(ctx, run.attributes.attachment);
glyphs[i] = space;
attachmentAdvance = 0;
}
}
ctx.restore();
};
const renderRun = (ctx: Context, run: Run) => {
if (!run.glyphs) return;
if (!run.positions) return;
const font = run.attributes.font?.[0];
if (!font) return;
const { fontSize, link } = run.attributes;
const color = parseColor(run.attributes.color);
const opacity = isNil(run.attributes.opacity)
? color.opacity
: run.attributes.opacity;
const { height = 0, descent = 0, xAdvance = 0 } = run;
ctx.fillColor(color.value);
ctx.fillOpacity(opacity);
if (link) {
if (isSrcId(link)) {
ctx.goTo(0, -height - descent, xAdvance, height, link.slice(1));
} else {
ctx.link(0, -height - descent, xAdvance, height, link);
}
}
// Copy glyphs to avoid mutating the original array
const glyphs = [...run.glyphs];
renderAttachments(ctx, run, glyphs);
ctx.font(font.type === 'STANDARD' ? font.fullName : font, fontSize);
try {
renderGlyphs(ctx, glyphs, run.positions!, 0, 0);
} catch (error) {
console.log(error);
}
ctx.translate(xAdvance, 0);
};
const renderBackground = (
ctx: Context,
rect: Rect,
backgroundColor: string,
) => {
const color = parseColor(backgroundColor);
ctx.save();
ctx.fillOpacity(color.opacity);
ctx.rect(rect.x, rect.y, rect.width, rect.height);
ctx.fill(color.value);
ctx.restore();
};
const renderDecorationLine = (ctx: Context, decorationLine: DecorationLine) => {
ctx.save();
ctx.lineWidth(decorationLine.rect.height);
ctx.strokeOpacity(decorationLine.opacity);
if (/dashed/.test(decorationLine.style)) {
ctx.dash(3 * decorationLine.rect.height, {});
} else if (/dotted/.test(decorationLine.style)) {
ctx.dash(decorationLine.rect.height, {});
}
if (/wavy/.test(decorationLine.style)) {
const dist = Math.max(2, decorationLine.rect.height);
let step = 1.1 * dist;
const stepCount = Math.floor(decorationLine.rect.width / (2 * step));
// Adjust step to fill entire width
const remainingWidth = decorationLine.rect.width - stepCount * 2 * step;
const adjustment = remainingWidth / stepCount / 2;
step += adjustment;
const cp1y = decorationLine.rect.y + dist;
const cp2y = decorationLine.rect.y - dist;
let { x } = decorationLine.rect;
ctx.moveTo(decorationLine.rect.x, decorationLine.rect.y);
for (let i = 0; i < stepCount; i += 1) {
ctx.bezierCurveTo(
x + step,
cp1y,
x + step,
cp2y,
x + 2 * step,
decorationLine.rect.y,
);
x += 2 * step;
}
} else {
ctx.moveTo(decorationLine.rect.x, decorationLine.rect.y);
ctx.lineTo(
decorationLine.rect.x + decorationLine.rect.width,
decorationLine.rect.y,
);
if (/double/.test(decorationLine.style)) {
ctx.moveTo(
decorationLine.rect.x,
decorationLine.rect.y + decorationLine.rect.height * 2,
);
ctx.lineTo(
decorationLine.rect.x + decorationLine.rect.width,
decorationLine.rect.y + decorationLine.rect.height * 2,
);
}
}
ctx.stroke(decorationLine.color);
ctx.restore();
};
const renderLine = (ctx: Context, line: AttributedString) => {
if (!line.box) return;
const lineAscent = line.ascent || 0;
ctx.save();
ctx.translate(line.box.x, line.box.y + lineAscent);
for (let i = 0; i < line.runs.length; i += 1) {
const run = line.runs[i];
const isLastRun = i === line.runs.length - 1;
if (run.attributes.backgroundColor) {
const xAdvance = run.xAdvance ?? 0;
const overflowRight = isLastRun ? line.overflowRight ?? 0 : 0;
const backgroundRect = {
x: 0,
y: -lineAscent,
height: line.box.height,
width: xAdvance - overflowRight,
};
renderBackground(ctx, backgroundRect, run.attributes.backgroundColor);
}
renderRun(ctx, run);
}
ctx.restore();
ctx.save();
ctx.translate(line.box.x, line.box.y);
if (line.decorationLines) {
for (let i = 0; i < line.decorationLines.length; i += 1) {
const decorationLine = line.decorationLines[i];
renderDecorationLine(ctx, decorationLine);
}
}
ctx.restore();
};
const renderBlock = (ctx: Context, block: Paragraph) => {
block.forEach((line) => {
renderLine(ctx, line);
});
};
const renderText = (ctx: Context, node: SafeTextNode) => {
if (!node.box) return;
if (!node.lines) return;
const { top, left } = node.box;
const blocks = [node.lines];
const paddingTop = node.box?.paddingTop || 0;
const paddingLeft = node.box?.paddingLeft || 0;
const initialY = node.lines[0] ? node.lines[0].box!.y : 0;
const offsetX = node.alignOffset || 0;
ctx.save();
ctx.translate(left + paddingLeft - offsetX, top + paddingTop - initialY);
blocks.forEach((block) => {
renderBlock(ctx, block);
});
ctx.restore();
};
export default renderText;
================================================
FILE: packages/render/src/primitives/renderTextInput.ts
================================================
import { SafeTextInputNode } from '@react-pdf/layout';
import { Context, RenderOptions } from '../types';
import { parseTextInputOptions } from '../utils/parseFormOptions';
const renderTextInput = (
ctx: Context,
node: SafeTextInputNode,
options: RenderOptions,
) => {
if (!node.box) return;
const { top, left, width, height } = node.box;
// Element's name
const name = node.props?.name || '';
const fieldSetOptions = options.fieldSets?.at(0);
if (!ctx._root.data.AcroForm) {
ctx.initForm();
}
ctx.formText(
name,
left,
top,
width,
height,
parseTextInputOptions(node, fieldSetOptions),
);
};
export default renderTextInput;
================================================
FILE: packages/render/src/svg/getBoundingBox.ts
================================================
import * as P from '@react-pdf/primitives';
import absPath from 'abs-svg-path';
import parsePath from 'parse-svg-path';
import normalizePath from 'normalize-svg-path';
import parsePoints from './parsePoints';
import {
SafeCircleNode,
SafeEllipseNode,
SafeLineNode,
SafeNode,
SafePathNode,
SafePolylineNode,
SafeRectNode,
} from '@react-pdf/layout';
type Primitives = (typeof P)[keyof typeof P];
// From https://github.com/dy/svg-path-bounds/blob/master/index.js
const getPathBoundingBox = (node: SafePathNode) => {
const path = normalizePath(absPath(parsePath(node.props?.d || '')));
if (!path.length) return [0, 0, 0, 0];
const bounds = [Infinity, Infinity, -Infinity, -Infinity];
for (let i = 0, l = path.length; i < l; i += 1) {
const points = path[i].slice(1);
for (let j = 0; j < points.length; j += 2) {
if (points[j + 0] < bounds[0]) bounds[0] = points[j + 0];
if (points[j + 1] < bounds[1]) bounds[1] = points[j + 1];
if (points[j + 0] > bounds[2]) bounds[2] = points[j + 0];
if (points[j + 1] > bounds[3]) bounds[3] = points[j + 1];
}
}
return bounds;
};
const getCircleBoundingBox = (node: SafeCircleNode) => {
const r = node.props?.r || 0;
const cx = node.props?.cx || 0;
const cy = node.props?.cy || 0;
return [cx - r, cy - r, cx + r, cy + r];
};
const getEllipseBoundingBox = (node: SafeEllipseNode) => {
const cx = node.props?.cx || 0;
const cy = node.props?.cy || 0;
const rx = node.props?.rx || 0;
const ry = node.props?.ry || 0;
return [cx - rx, cy - ry, cx + rx, cy + ry];
};
const getLineBoundingBox = (node: SafeLineNode) => {
const x1 = node.props?.x1 || 0;
const y1 = node.props?.y1 || 0;
const x2 = node.props?.x2 || 0;
const y2 = node.props?.y2 || 0;
return [
Math.min(x1, x2),
Math.min(y1, y2),
Math.max(x1, x2),
Math.max(y1, y2),
];
};
const getRectBoundingBox = (node: SafeRectNode) => {
const x = node.props?.x || 0;
const y = node.props?.y || 0;
const width = node.props?.width || 0;
const height = node.props?.height || 0;
return [x, y, x + width, y + height];
};
const max = (values: number[]) => Math.max(-Infinity, ...values);
const min = (values: number[]) => Math.min(Infinity, ...values);
const getPolylineBoundingBox = (node: SafePolylineNode) => {
const points = parsePoints(node.props?.points);
const xValues = points.map((p) => p[0]);
const yValues = points.map((p) => p[1]);
return [min(xValues), min(yValues), max(xValues), max(yValues)];
};
const boundingBoxFns: Partial> = {
[P.Rect]: getRectBoundingBox,
[P.Line]: getLineBoundingBox,
[P.Path]: getPathBoundingBox,
[P.Circle]: getCircleBoundingBox,
[P.Ellipse]: getEllipseBoundingBox,
[P.Polygon]: getPolylineBoundingBox,
[P.Polyline]: getPolylineBoundingBox,
};
const getBoundingBox = (node: SafeNode): number[] => {
const boundingBoxFn = boundingBoxFns[node.type];
return boundingBoxFn ? boundingBoxFn(node) : [0, 0, 0, 0];
};
export default getBoundingBox;
================================================
FILE: packages/render/src/svg/parsePoints.ts
================================================
const pairs = (values: T[]): T[][] => {
const result = [];
for (let i = 0; i < values.length; i += 2) {
result.push([values[i], values[i + 1]]);
}
return result;
};
/**
* Parse svg-like points into number arrays
*
* @param points string ex. "20,30 50,60"
* @returns points array ex. [[20, 30], [50, 60]]
*/
const parsePoints = (points: string | null) => {
let values = (points || '')
.trim()
.replace(/,/g, ' ')
.replace(/(\d)-(\d)/g, '$1 -$2')
.split(/\s+/);
if (values.length % 2 !== 0) {
values = values.slice(0, -1);
}
const mappedValues = values.map(parseFloat);
return pairs(mappedValues);
};
export default parsePoints;
================================================
FILE: packages/render/src/types.ts
================================================
import { Font } from '@react-pdf/textkit';
import PDFKitDocument from 'pdfkit';
import PDFKitReference from 'pdfkit/js/reference';
type PDFFontSource = string | Buffer | Uint8Array | ArrayBuffer | Font;
export type Context = typeof PDFKitDocument & {
_root: any;
_font: any;
_imageRegistry: any;
_acroform: any;
_fontSize: number;
openImage: any;
addNamedDestination: any;
addPage(options?: any): Context;
translate(x: number, y: number, options: any): Context;
font(src: PDFFontSource, size?: number): Context;
font(src: PDFFontSource, family: string, size?: number): Context;
};
export interface RenderOptions {
imageCache: Map;
fieldSets: (typeof PDFKitReference)[];
}
================================================
FILE: packages/render/src/utils/parseColor.ts
================================================
import colorString from 'color-string';
const black = { value: '#000', opacity: 1 };
// TODO: parse to number[] in layout to avoid this step
const parseColor = (hex?: string) => {
if (!hex) return black;
const parsed = colorString.get(hex);
if (!parsed) return black;
const value = colorString.to.hex(parsed.value.slice(0, 3));
const opacity = parsed.value[3];
return { value, opacity };
};
export default parseColor;
================================================
FILE: packages/render/src/utils/parseFormOptions.ts
================================================
import {
SafeCheckboxNode,
SafeListNode,
SafeSelectNode,
SafeTextInputNode,
} from '@react-pdf/layout';
import { Context } from '../types';
const clean = (options: Record) => {
const opt = { ...options };
// We need to ensure the elements are no present if not true
Object.entries(opt).forEach((pair) => {
if (!pair[1]) {
delete opt[pair[0]];
}
});
return opt;
};
const parseCommonFormOptions = (node: any) => {
// Common Options
return {
required: node.props?.required || false,
noExport: node.props?.noExport || false,
readOnly: node.props?.readOnly || false,
value: node.props?.value || undefined,
defaultValue: node.props?.defaultValue || undefined,
};
};
const parseTextInputOptions = (node: SafeTextInputNode, fieldSet: any) => {
return clean({
...parseCommonFormOptions(node),
parent: fieldSet || undefined,
align: node.props?.align || 'left',
multiline: node.props?.multiline || undefined,
password: node.props?.password || false,
noSpell: node.props?.noSpell || false,
format: node.props?.format || undefined,
fontSize: node.props?.fontSize || undefined,
MaxLen: node.props?.maxLength || undefined,
});
};
const parseSelectAndListFieldOptions = (
node: SafeListNode | SafeSelectNode,
) => {
return clean({
...parseCommonFormOptions(node),
sort: node.props?.sort || false,
edit: node.props?.edit || false,
multiSelect: node.props?.multiSelect || false,
noSpell: node.props?.noSpell || false,
select: node.props?.select || [''],
});
};
const getAppearance = (
ctx: Context,
codepoint: '8' | '4' | ' ',
width: number,
height: number,
) => {
const appearance = ctx.ref({
Type: 'XObject',
Subtype: 'Form',
BBox: [0, 0, width, height],
Resources: {
ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
Font: {
ZaDi: ctx._acroform.fonts.ZaDi,
},
},
});
appearance.initDeflate();
appearance.write(
`/Tx BMC\nq\n/ZaDi ${height * 0.8} Tf\nBT\n${width * 0.45} ${
height / 4
} Td (${codepoint}) Tj\nET\nQ\nEMC`,
);
appearance.end(null);
return appearance;
};
const parseCheckboxOptions = (
ctx: Context,
node: SafeCheckboxNode,
fieldSet: any,
) => {
const { width, height } = node.box || {};
const onOption = node.props?.onState || 'Yes';
const offOption = node.props?.offState || 'Off';
const xMark = node.props?.xMark || false;
if (!Object.prototype.hasOwnProperty.call(ctx._acroform.fonts, 'ZaDi')) {
const ref = ctx.ref({
Type: 'Font',
Subtype: 'Type1',
BaseFont: 'ZapfDingbats',
});
ctx._acroform.fonts.ZaDi = ref;
ref.end(null);
}
const normalAppearance = {
[onOption]: getAppearance(ctx, xMark ? '8' : '4', width!, height!),
[offOption]: getAppearance(ctx, xMark ? ' ' : '8', width!, height!),
};
return clean({
...parseCommonFormOptions(node),
backgroundColor: node.props?.backgroundColor || undefined,
borderColor: node.props?.borderColor || undefined,
parent: fieldSet || undefined,
value: `/${node.props?.checked === true ? onOption : offOption}`,
defaultValue: `/${node.props?.checked === true ? onOption : offOption}`,
AS: node.props?.checked === true ? onOption : offOption,
AP: { N: normalAppearance, D: normalAppearance },
});
};
export {
parseTextInputOptions,
parseSelectAndListFieldOptions,
parseCheckboxOptions,
};
================================================
FILE: packages/render/src/utils/resolveObjectFit.ts
================================================
import { matchPercent } from '@react-pdf/fns';
const isNumeric = (n: any): n is number => {
return !Number.isNaN(parseFloat(n)) && Number.isFinite(n);
};
const applyContainObjectFit = (
cw: number,
ch: number,
iw: number,
ih: number,
px?: number | string,
py?: number | string,
) => {
const cr = cw / ch;
const ir = iw / ih;
const pxp = matchPercent(px ?? null);
const pyp = matchPercent(py ?? null);
const pxv = pxp ? pxp.percent : 0.5;
const pyv = pyp ? pyp.percent : 0.5;
if (cr > ir) {
const height = ch;
const width = height * ir;
const yOffset = isNumeric(py) ? py : 0;
const xOffset = isNumeric(px) ? px : (cw - width) * pxv;
return { width, height, xOffset, yOffset };
}
const width = cw;
const height = width / ir;
const xOffset = isNumeric(px) ? px : 0;
const yOffset = isNumeric(py) ? py : (ch - height) * pyv;
return { width, height, yOffset, xOffset };
};
const applyNoneObjectFit = (
cw: number,
ch: number,
iw: number,
ih: number,
px?: number | string,
py?: number | string,
) => {
const width = iw;
const height = ih;
const pxp = matchPercent(px ?? null);
const pyp = matchPercent(py ?? null);
const pxv = pxp ? pxp.percent : 0.5;
const pyv = pyp ? pyp.percent : 0.5;
const xOffset = isNumeric(px) ? px : (cw - width) * pxv;
const yOffset = isNumeric(py) ? py : (ch - height) * pyv;
return { width, height, xOffset, yOffset };
};
const applyCoverObjectFit = (
cw: number,
ch: number,
iw: number,
ih: number,
px?: number | string,
py?: number | string,
) => {
const ir = iw / ih;
const cr = cw / ch;
const pxp = matchPercent(px ?? null);
const pyp = matchPercent(py ?? null);
const pxv = pxp ? pxp.percent : 0.5;
const pyv = pyp ? pyp.percent : 0.5;
if (cr > ir) {
const width = cw;
const height = width / ir;
const xOffset = isNumeric(px) ? px : 0;
const yOffset = isNumeric(py) ? py : (ch - height) * pyv;
return { width, height, yOffset, xOffset };
}
const height = ch;
const width = height * ir;
const xOffset = isNumeric(px) ? px : (cw - width) * pxv;
const yOffset = isNumeric(py) ? py : 0;
return { width, height, xOffset, yOffset };
};
const applyScaleDownObjectFit = (
cw: number,
ch: number,
iw: number,
ih: number,
px?: number | string,
py?: number | string,
) => {
const containDimension = applyContainObjectFit(cw, ch, iw, ih, px, py);
const noneDimension = applyNoneObjectFit(cw, ch, iw, ih, px, py);
return containDimension.width < noneDimension.width
? containDimension
: noneDimension;
};
const applyFillObjectFit = (
cw: number,
ch: number,
px?: number | string,
py?: number | string,
) => {
return {
width: cw,
height: ch,
xOffset: matchPercent(px ?? null) ? 0 : (px as number) || 0,
yOffset: matchPercent(py ?? null) ? 0 : (py as number) || 0,
};
};
const resolveObjectFit = (
type = 'fill',
cw: number,
ch: number,
iw: number,
ih: number,
px?: number | string,
py?: number | string,
) => {
switch (type) {
case 'contain':
return applyContainObjectFit(cw, ch, iw, ih, px, py);
case 'cover':
return applyCoverObjectFit(cw, ch, iw, ih, px, py);
case 'none':
return applyNoneObjectFit(cw, ch, iw, ih, px, py);
case 'scale-down':
return applyScaleDownObjectFit(cw, ch, iw, ih, px, py);
default:
return applyFillObjectFit(cw, ch, px, py);
}
};
export default resolveObjectFit;
================================================
FILE: packages/render/tests/ctx.ts
================================================
import { vi } from 'vitest';
const createCTX = () => {
const instance: any = {};
instance.info = {};
instance.end = vi.fn().mockReturnValue(instance);
instance.rect = vi.fn().mockReturnValue(instance);
instance.save = vi.fn().mockReturnValue(instance);
instance.fill = vi.fn().mockReturnValue(instance);
instance.image = vi.fn().mockReturnValue(instance);
instance.restore = vi.fn().mockReturnValue(instance);
instance.addPage = vi.fn().mockReturnValue(instance);
instance.fillColor = vi.fn().mockReturnValue(instance);
instance.fillOpacity = vi.fn().mockReturnValue(instance);
instance.roundedRect = vi.fn().mockReturnValue(instance);
instance.registerFont = vi.fn().mockReturnValue(instance);
instance.lineWidth = vi.fn().mockReturnValue(instance);
instance.moveTo = vi.fn().mockReturnValue(instance);
instance.quadraticCurveTo = vi.fn().mockReturnValue(instance);
instance.lineTo = vi.fn().mockReturnValue(instance);
instance.strokeColor = vi.fn().mockReturnValue(instance);
instance.strokeOpacity = vi.fn().mockReturnValue(instance);
instance.stroke = vi.fn().mockReturnValue(instance);
instance.dash = vi.fn().mockReturnValue(instance);
instance.note = vi.fn().mockReturnValue(instance);
instance.rotate = vi.fn().mockReturnValue(instance);
instance.scale = vi.fn().mockReturnValue(instance);
instance.translate = vi.fn().mockReturnValue(instance);
instance.link = vi.fn().mockReturnValue(instance);
instance.goTo = vi.fn().mockReturnValue(instance);
instance.addNamedDestination = vi.fn().mockReturnValue(instance);
instance.clip = vi.fn().mockReturnValue(instance);
instance.bezierCurveTo = vi.fn().mockReturnValue(instance);
instance.closePath = vi.fn().mockReturnValue(instance);
instance.undash = vi.fn().mockReturnValue(instance);
instance.moveTo = vi.fn().mockReturnValue(instance);
instance.path = vi.fn().mockReturnValue(instance);
instance.radialGradient = vi.fn().mockReturnValue(instance);
instance.linearGradient = vi.fn().mockReturnValue(instance);
instance.miterLimit = vi.fn().mockReturnValue(instance);
instance.fontSize = vi.fn().mockReturnValue(instance);
instance.lineJoin = vi.fn().mockReturnValue(instance);
instance.polygon = vi.fn().mockReturnValue(instance);
instance.circle = vi.fn().mockReturnValue(instance);
instance.ellipse = vi.fn().mockReturnValue(instance);
instance.opacity = vi.fn().mockReturnValue(instance);
instance.lineCap = vi.fn().mockReturnValue(instance);
instance.text = vi.fn().mockReturnValue(instance);
instance.font = vi.fn().mockReturnValue(instance);
instance._root = { data: { AcroForm: {} } };
instance.textInput = vi.fn().mockReturnValue(instance);
instance.formField = vi.fn().mockReturnValue(instance);
instance.formCombo = vi.fn().mockReturnValue(instance);
instance.formList = vi.fn().mockReturnValue(instance);
instance.formText = vi.fn().mockReturnValue(instance);
instance.initForm = vi.fn().mockReturnValue(instance);
instance.outline = {
children: [],
document: vi.fn().mockReturnValue(instance),
addItem: vi.fn().mockReturnValue(instance),
endOutline: vi.fn().mockReturnValue(instance),
};
return instance;
};
export default createCTX;
================================================
FILE: packages/render/tests/operations/setDestination.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import { SafeNode } from '@react-pdf/layout';
import createCTX from '../ctx';
import setDestination from '../../src/operations/setDestination';
describe('operations setDestination', () => {
test('should call addNamedDestination method to passed context if id present', () => {
const ctx = createCTX();
const box = { top: 20 };
const props = { id: 'test' };
const doc = { type: P.View, style: {}, props, box } as SafeNode;
setDestination(ctx, doc);
expect(ctx.addNamedDestination.mock.calls).toHaveLength(1);
expect(ctx.addNamedDestination.mock.calls[0][0]).toBe('test');
expect(ctx.addNamedDestination.mock.calls[0][3]).toBe(20);
});
test('should not call addNamedDestination method to passed context if id missed', () => {
const ctx = createCTX();
const doc = { type: P.View, style: {}, props: {} } as SafeNode;
setDestination(ctx, doc);
expect(ctx.addNamedDestination.mock.calls).toHaveLength(0);
});
});
================================================
FILE: packages/render/tests/primitives/renderBackground.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import { Box, SafeNode } from '@react-pdf/layout';
import createCTX from '../ctx';
import renderBackground from '../../src/primitives/renderBackground';
describe('primitive renderBackground', () => {
test('should not render if node has no background', () => {
const ctx = createCTX();
const node: SafeNode = { type: P.View, props: {}, style: {} };
renderBackground(ctx, node);
expect(ctx.fill.mock.calls).toHaveLength(0);
});
test('should not render if has background but no dimensions', () => {
const ctx = createCTX();
const node: SafeNode = {
type: P.View,
props: {},
style: { backgroundColor: 'red' },
};
renderBackground(ctx, node);
expect(ctx.fill.mock.calls).toHaveLength(0);
});
test('should render background correctly', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const style = { backgroundColor: 'red' };
const node: SafeNode = { type: P.View, style, props: {}, box };
renderBackground(ctx, node);
expect(ctx.fillColor.mock.calls).toEqual([['#FF0000']]);
expect(ctx.rect.mock.calls).toEqual([[40, 20, 140, 200]]);
expect(ctx.fill.mock.calls).toEqual([[]]);
});
test('should be scoped operation', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const style = { backgroundColor: 'red' };
const node: SafeNode = { type: P.View, style, box, props: {} };
renderBackground(ctx, node);
expect(ctx.save.mock.calls).toHaveLength(1);
expect(ctx.restore.mock.calls).toHaveLength(1);
});
test('should render with opacity 1 by default', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const style = { backgroundColor: 'red' };
const node: SafeNode = { type: P.View, style, box, props: {} };
renderBackground(ctx, node);
expect(ctx.fillOpacity.mock.calls).toEqual([[1]]);
});
test('should render background opacity', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const style = { backgroundColor: 'red', opacity: 0.8 };
const node: SafeNode = { type: P.View, style, box, props: {} };
renderBackground(ctx, node);
expect(ctx.fillOpacity.mock.calls).toEqual([[0.8]]);
});
test('should render background opacity 0', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const style = { backgroundColor: 'red', opacity: 0 };
const node: SafeNode = { type: P.View, style, box, props: {} };
renderBackground(ctx, node);
expect(ctx.fillOpacity.mock.calls).toEqual([[0]]);
});
test('should render background color opacity 0', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const style = { backgroundColor: 'rgba(0, 0, 0, 0)', opacity: 1 };
const node: SafeNode = { type: P.View, style, box, props: {} };
renderBackground(ctx, node);
expect(ctx.fillOpacity.mock.calls).toEqual([[0]]);
});
});
================================================
FILE: packages/render/tests/primitives/renderCanvas.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import createCTX from '../ctx';
import renderCanvas from '../../src/primitives/renderCanvas';
import { Box, SafeCanvasNode } from '@react-pdf/layout';
describe('primitive renderCanvas', () => {
test('should be scoped operation', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 };
const node = { type: P.Canvas, box, props: {} } as SafeCanvasNode;
renderCanvas(ctx, node);
expect(ctx.save.mock.calls).toHaveLength(1);
expect(ctx.restore.mock.calls).toHaveLength(1);
});
test('should call paint method with ctx', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 } as Box;
const paint = (p) => expect(p).toBeTruthy();
const node: SafeCanvasNode = {
type: P.Canvas,
box,
props: { paint },
} as SafeCanvasNode;
renderCanvas(ctx, node);
});
test('should remove dangerous methods from passed ctx', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 };
const paint = (p) => expect(p.registerFont).toBeFalsy();
const node = { type: P.Canvas, box, props: { paint } } as SafeCanvasNode;
renderCanvas(ctx, node);
});
test('should get correct available width and height', () => {
const ctx = createCTX();
const box = { top: 20, left: 40, width: 140, height: 200 };
const paint = (_, width, height) => {
expect(width).toBe(140);
expect(height).toBe(200);
};
const node = { type: P.Canvas, box, props: { paint } } as SafeCanvasNode;
renderCanvas(ctx, node);
});
test('should get correct available width and height with paddings', () => {
const ctx = createCTX();
const box = {
top: 20,
left: 40,
width: 140,
height: 200,
paddingTop: 10,
paddingLeft: 20,
paddingBottom: 30,
paddingRight: 40,
};
const paint = (_, width, height) => {
expect(width).toBe(80);
expect(height).toBe(160);
};
const node = { type: P.Canvas, box, props: { paint } } as SafeCanvasNode;
renderCanvas(ctx, node);
});
});
================================================
FILE: packages/render/tests/primitives/renderCircle.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import createCTX from '../ctx';
import renderCircle from '../../src/primitives/renderCircle';
import { SafeCircleNode } from '@react-pdf/layout';
const round = (num: number) => Math.round(num * 100) / 100;
describe('primitive renderCircle', () => {
test('should render circle correctly', () => {
const ctx = createCTX();
const props = { cx: 50, cy: 80, r: 20 };
const node: SafeCircleNode = { type: P.Circle, props, style: {} };
renderCircle(ctx, node);
const bezierCalls = ctx.bezierCurveTo.mock.calls.map((c) => c.map(round));
expect(bezierCalls).toHaveLength(4);
expect(ctx.moveTo.mock.calls).toEqual([[30, 80]]);
expect(bezierCalls[0]).toEqual([30, 68.95, 38.95, 60, 50, 60]);
expect(bezierCalls[1]).toEqual([61.05, 60, 70, 68.95, 70, 80]);
expect(bezierCalls[2]).toEqual([70, 91.05, 61.05, 100, 50, 100]);
expect(bezierCalls[3]).toEqual([38.95, 100, 30, 91.05, 30, 80]);
expect(ctx.closePath.mock.calls).toHaveLength(1);
});
});
================================================
FILE: packages/render/tests/primitives/renderEllipse.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import createCTX from '../ctx';
import renderEllipse from '../../src/primitives/renderEllipse';
import { SafeEllipseNode } from '@react-pdf/layout';
const round = (num) => Math.round(num * 100) / 100;
describe('primitive renderEllipse', () => {
test('should render ellipse correctly', () => {
const ctx = createCTX();
const props = { cx: 50, cy: 80, rx: 20, ry: 10 };
const node: SafeEllipseNode = { type: P.Ellipse, props, style: {} };
renderEllipse(ctx, node);
const bezierCalls = ctx.bezierCurveTo.mock.calls.map((c) => c.map(round));
expect(bezierCalls).toHaveLength(4);
expect(ctx.moveTo.mock.calls).toEqual([[30, 80]]);
expect(bezierCalls[0]).toEqual([30, 74.48, 38.95, 70, 50, 70]);
expect(bezierCalls[1]).toEqual([61.05, 70, 70, 74.48, 70, 80]);
expect(bezierCalls[2]).toEqual([70, 85.52, 61.05, 90, 50, 90]);
expect(bezierCalls[3]).toEqual([38.95, 90, 30, 85.52, 30, 80]);
expect(ctx.closePath.mock.calls).toHaveLength(1);
});
});
================================================
FILE: packages/render/tests/primitives/renderForm.test.ts
================================================
import { describe, expect, test } from 'vitest';
import * as P from '@react-pdf/primitives';
import createCTX from '../ctx';
import renderFieldSet from '../../src/primitives/renderFieldSet';
import { SafeFieldSetNode } from '@react-pdf/layout';
describe('primitive renderFieldSet', () => {
test('should render FieldSet correctly', () => {
const ctx = createCTX();
const args = 'example';
const props = { name: args };
const node: SafeFieldSetNode = { type: P.FieldSet, props, style: {} };
renderFieldSet(ctx, node, { fieldSets: [] });
expect(ctx.formField.mock.calls).toHaveLength(1);
expect(ctx.formField.mock.calls[0]).toHaveLength(1);
expect(ctx.formField.mock.calls[0][0]).toBe(args);
});
test.todo('FieldSet with one textInput direct child', () => {
const ctx = createCTX();
const node: SafeFieldSetNode = {
type: P.FieldSet,
style: {},
props: { name: 'example' },
children: [{ type: P.TextInput, style: {}, props: {} }],
};
renderFieldSet(ctx, node, { fieldSets: [] });
expect(ctx.textInput.mock.calls).toHaveLength(1);
});
});
================================================
FILE: packages/render/tests/svg/getBoundingBox.test.ts
================================================
import { describe, expect, test } from 'vitest';
import getBoundingBox from '../../src/svg/getBoundingBox';
describe('path getBoundingBox', () => {
test('should return empty path bounding box', () => {
const bbox = getBoundingBox({
type: 'PATH',
props: { d: '' },
style: {},
});
expect(bbox).toEqual([0, 0, 0, 0]);
});
test('should return path bounding box', () => {
const bbox = getBoundingBox({
type: 'PATH',
style: {},
props: {
d: 'M150 0 L75 200 L225 200 Z',
},
});
expect(bbox).toEqual([75, 0, 225, 200]);
});
test('should return ellipse bounding box', () => {
const bbox = getBoundingBox({
type: 'ELLIPSE',
style: {},
props: {
cx: 200,
cy: 80,
rx: 100,
ry: 50,
},
});
expect(bbox).toEqual([100, 30, 300, 130]);
});
test('should return circle bounding box', () => {
const bbox = getBoundingBox({
type: 'CIRCLE',
style: {},
props: { cx: 50, cy: 50, r: 40 },
});
expect(bbox).toEqual([10, 10, 90, 90]);
});
test('should return line bounding box', () => {
const bbox = getBoundingBox({
type: 'LINE',
style: {},
props: { x1: 10, y1: 15, x2: 200, y2: 180 },
});
expect(bbox).toEqual([10, 15, 200, 180]);
});
test('should return inverted line bounding box', () => {
const bbox = getBoundingBox({
type: 'LINE',
style: {},
props: { x1: 200, y1: 180, x2: 10, y2: 15 },
});
expect(bbox).toEqual([10, 15, 200, 180]);
});
test('should return rect bounding box', () => {
const bbox = getBoundingBox({
type: 'RECT',
style: {},
props: { x: 50, y: 20, width: 150, height: 150 },
});
expect(bbox).toEqual([50, 20, 200, 170]);
});
test('should return polygon bounding box', () => {
const bbox = getBoundingBox({
type: 'POLYGON',
style: {},
props: { points: '200,10 250,190 160,210' },
});
expect(bbox).toEqual([160, 10, 250, 210]);
});
test('should return polyline bounding box', () => {
const bbox = getBoundingBox({
type: 'POLYGON',
style: {},
props: { points: '20,20 40,25 60,40 80,120 120,140 200,180' },
});
expect(bbox).toEqual([20, 20, 200, 180]);
});
});
================================================
FILE: packages/render/tests/svg/parsePoints.test.ts
================================================
import { describe, expect, test } from 'vitest';
import parsePoints from '../../src/svg/parsePoints';
describe('svg parsePoints', () => {
test('should return empty array for null argument', () => {
const points = parsePoints(null);
expect(points).toHaveLength(0);
});
test('should return empty array for empty string', () => {
const points = parsePoints('');
expect(points).toHaveLength(0);
});
test('should correctly parse svg points', () => {
const points = parsePoints('20,20 40,25 60,40 80,120 120,140 200,180');
expect(points[0]).toEqual([20, 20]);
expect(points[1]).toEqual([40, 25]);
expect(points[2]).toEqual([60, 40]);
expect(points[3]).toEqual([80, 120]);
expect(points[4]).toEqual([120, 140]);
expect(points[5]).toEqual([200, 180]);
});
test('should trim leading spaces', () => {
const points = parsePoints(' 20,20');
expect(points[0]).toEqual([20, 20]);
});
test('should trim trailing spaces', () => {
const points = parsePoints('20,20 ');
expect(points[0]).toEqual([20, 20]);
});
test('should parse float values', () => {
const points = parsePoints('20.5,20.5');
expect(points[0]).toEqual([20.5, 20.5]);
});
});
================================================
FILE: packages/render/tests/utils/objectFit.test.ts
================================================
import { describe, expect, test } from 'vitest';
import resolveObjectFit from '../../src/utils/resolveObjectFit';
describe('object-fit', () => {
test('should fill to content box for portrait images', () => {
const result = resolveObjectFit('fill', 200, 200, 40, 80);
expect(result.width).toBe(200);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should fill to content box for landscape images', () => {
const result = resolveObjectFit('fill', 200, 200, 80, 40);
expect(result.width).toBe(200);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should contain inside content box for portrait images', () => {
const result = resolveObjectFit('contain', 200, 200, 40, 80);
expect(result.width).toBe(100);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(50);
expect(result.yOffset).toBe(0);
});
test('should contain inside content box for landscape images', () => {
const result = resolveObjectFit('contain', 200, 200, 80, 40);
expect(result.width).toBe(200);
expect(result.height).toBe(100);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(50);
});
test('should cover inside content box for portrait images', () => {
const result = resolveObjectFit('cover', 200, 200, 40, 80);
expect(result.width).toBe(200);
expect(result.height).toBe(400);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(-100);
});
test('should cover inside content box for landscape images', () => {
const result = resolveObjectFit('cover', 200, 200, 80, 40);
expect(result.width).toBe(400);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(-100);
expect(result.yOffset).toBe(0);
});
test('should not fit inside content box for smaller portrait images', () => {
const result = resolveObjectFit('none', 200, 200, 40, 80);
expect(result.width).toBe(40);
expect(result.height).toBe(80);
expect(result.xOffset).toBe(80);
expect(result.yOffset).toBe(60);
});
test('should not fit inside content box for bigger portrait images', () => {
const result = resolveObjectFit('none', 200, 200, 400, 800);
expect(result.width).toBe(400);
expect(result.height).toBe(800);
expect(result.xOffset).toBe(-100);
expect(result.yOffset).toBe(-300);
});
test('should not fit inside content box for smaller landscape images', () => {
const result = resolveObjectFit('none', 200, 200, 80, 40);
expect(result.width).toBe(80);
expect(result.height).toBe(40);
expect(result.xOffset).toBe(60);
expect(result.yOffset).toBe(80);
});
test('should not fit inside content box for bigger landscape images', () => {
const result = resolveObjectFit('none', 200, 200, 800, 400);
expect(result.width).toBe(800);
expect(result.height).toBe(400);
expect(result.xOffset).toBe(-300);
expect(result.yOffset).toBe(-100);
});
test('should scale-down inside content box for smaller portrait images', () => {
const result = resolveObjectFit('scale-down', 200, 200, 40, 80);
expect(result.width).toBe(40);
expect(result.height).toBe(80);
expect(result.xOffset).toBe(80);
expect(result.yOffset).toBe(60);
});
test('should scale-down inside content box for bigger portrait images', () => {
const result = resolveObjectFit('scale-down', 200, 200, 400, 800);
expect(result.width).toBe(100);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(50);
expect(result.yOffset).toBe(0);
});
test('should scale-down inside content box for smaller landscape images', () => {
const result = resolveObjectFit('scale-down', 200, 200, 80, 40);
expect(result.width).toBe(80);
expect(result.height).toBe(40);
expect(result.xOffset).toBe(60);
expect(result.yOffset).toBe(80);
});
test('should scale-down inside content box for bigger landscape images', () => {
const result = resolveObjectFit('scale-down', 200, 200, 800, 400);
expect(result.width).toBe(200);
expect(result.height).toBe(100);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(50);
});
test('should fill to content box for portrait images with fixed positions', () => {
const result = resolveObjectFit('fill', 200, 200, 40, 80, 20, 40);
expect(result.width).toBe(200);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should fill to content box for landscape images with fixed positions', () => {
const result = resolveObjectFit('fill', 200, 200, 80, 40, 20, 40);
expect(result.width).toBe(200);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should contain inside content box for portrait images with fixed positions', () => {
const result = resolveObjectFit('contain', 200, 200, 40, 80, 20, 40);
expect(result.width).toBe(100);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should contain inside content box for landscape images with fixed positions', () => {
const result = resolveObjectFit('contain', 200, 200, 80, 40, 20, 40);
expect(result.width).toBe(200);
expect(result.height).toBe(100);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should contain inside content box for portrait images with zero fixed positions', () => {
const result = resolveObjectFit('contain', 200, 200, 40, 80, 0, 0);
expect(result.width).toBe(100);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should contain inside content box for landscape images with zero fixed positions', () => {
const result = resolveObjectFit('contain', 200, 200, 80, 40, 0, 0);
expect(result.width).toBe(200);
expect(result.height).toBe(100);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should cover inside content box for portrait images with fixed positions', () => {
const result = resolveObjectFit('cover', 200, 200, 40, 80, 20, 40);
expect(result.width).toBe(200);
expect(result.height).toBe(400);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should cover inside content box for landscape images with fixed positions', () => {
const result = resolveObjectFit('cover', 200, 200, 80, 40, 20, 40);
expect(result.width).toBe(400);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should cover inside content box for portrait images with zero fixed positions', () => {
const result = resolveObjectFit('cover', 200, 200, 40, 80, 0, 0);
expect(result.width).toBe(200);
expect(result.height).toBe(400);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should cover inside content box for landscape images with zero fixed positions', () => {
const result = resolveObjectFit('cover', 200, 200, 80, 40, 0, 0);
expect(result.width).toBe(400);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should not fit inside content box for smaller portrait images with fixed positions', () => {
const result = resolveObjectFit('none', 200, 200, 40, 80, 20, 40);
expect(result.width).toBe(40);
expect(result.height).toBe(80);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should not fit inside content box for bigger portrait images with fixed positions', () => {
const result = resolveObjectFit('none', 200, 200, 400, 800, 20, 40);
expect(result.width).toBe(400);
expect(result.height).toBe(800);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(40);
});
test('should not fit inside content box for portrait images with zero fixed positions', () => {
const result = resolveObjectFit('none', 200, 200, 40, 80, 0, 0);
expect(result.width).toBe(40);
expect(result.height).toBe(80);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should not fit inside content box for landscape images with zero fixed positions', () => {
const result = resolveObjectFit('none', 200, 200, 800, 400, 0, 0);
expect(result.width).toBe(800);
expect(result.height).toBe(400);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should fill to content box for portrait images with percentage positions', () => {
const result = resolveObjectFit('fill', 200, 200, 40, 80, '20%', '40%');
expect(result.width).toBe(200);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should fill to content box for landscape images with percentage positions', () => {
const result = resolveObjectFit('fill', 200, 200, 80, 40, '20%', '40%');
expect(result.width).toBe(200);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(0);
});
test('should contain inside content box for portrait images with percentage positions', () => {
const result = resolveObjectFit('contain', 200, 200, 40, 80, '20%', '40%');
expect(result.width).toBe(100);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(20);
expect(result.yOffset).toBe(0);
});
test('should contain inside content box for landscape images with percentage positions', () => {
const result = resolveObjectFit('contain', 200, 200, 80, 40, '20%', '40%');
expect(result.width).toBe(200);
expect(result.height).toBe(100);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(40);
});
test('should contain inside content box for portrait images with zero percentage positions', () => {
const result = resolveObjectFit('contain', 200, 200, 40, 80, '0%', '0%');
expect(result.width).toBe(100);
expect(result.height).toBe(200);
expect(Math.abs(result.xOffset)).toBe(0);
expect(Math.abs(result.yOffset)).toBe(0);
});
test('should contain inside content box for landscape images with zero percentage positions', () => {
const result = resolveObjectFit('contain', 200, 200, 80, 40, '0%', '0%');
expect(result.width).toBe(200);
expect(result.height).toBe(100);
expect(Math.abs(result.xOffset)).toBe(0);
expect(Math.abs(result.yOffset)).toBe(0);
});
test('should cover inside content box for portrait images with percentage positions', () => {
const result = resolveObjectFit('cover', 200, 200, 40, 80, '20%', '40%');
expect(result.width).toBe(200);
expect(result.height).toBe(400);
expect(result.xOffset).toBe(0);
expect(result.yOffset).toBe(-80);
});
test('should cover inside content box for landscape images with percentage positions', () => {
const result = resolveObjectFit('cover', 200, 200, 80, 40, '20%', '40%');
expect(result.width).toBe(400);
expect(result.height).toBe(200);
expect(result.xOffset).toBe(-40);
expect(result.yOffset).toBe(0);
});
test('should cover inside content box for portrait images with zero percentage positions', () => {
const result = resolveObjectFit('cover', 200, 200, 40, 80, '0%', '0%');
expect(result.width).toBe(200);
expect(result.height).toBe(400);
expect(Math.abs(result.xOffset)).toBe(0);
expect(Math.abs(result.yOffset)).toBe(0);
});
test('should cover inside content box for landscape images with zero percentage positions', () => {
const result = resolveObjectFit('cover', 200, 200, 80, 40, '0%', '0%');
expect(result.width).toBe(400);
expect(result.height).toBe(200);
expect(Math.abs(result.xOffset)).toBe(0);
expect(Math.abs(result.yOffset)).toBe(0);
});
test('should not fit inside content box for smaller portrait images with percentage positions', () => {
const result = resolveObjectFit('none', 200, 200, 40, 80, '20%', '40%');
expect(result.width).toBe(40);
expect(result.height).toBe(80);
expect(result.xOffset).toBe(32);
expect(result.yOffset).toBe(48);
});
test('should not fit inside content box for bigger portrait images with percentage positions', () => {
const result = resolveObjectFit('none', 200, 200, 400, 800, '20%', '40%');
expect(result.width).toBe(400);
expect(result.height).toBe(800);
expect(result.xOffset).toBe(-40);
expect(result.yOffset).toBe(-240);
});
test('should not fit inside content box for portrait images with zero percentage positions', () => {
const result = resolveObjectFit('none', 200, 200, 40, 80, '0%', '0%');
expect(result.width).toBe(40);
expect(result.height).toBe(80);
expect(Math.abs(result.xOffset)).toBe(0);
expect(Math.abs(result.yOffset)).toBe(0);
});
test('should not fit inside content box for landscape images with zero percentage positions', () => {
const result = resolveObjectFit('none', 200, 200, 800, 400, '0%', '0%');
expect(result.width).toBe(800);
expect(result.height).toBe(400);
expect(Math.abs(result.xOffset)).toBe(0);
expect(Math.abs(result.yOffset)).toBe(0);
});
});
================================================
FILE: packages/render/tests/utils/parseColor.test.ts
================================================
import { describe, expect, test } from 'vitest';
import parseColor from '../../src/utils/parseColor';
describe('parse color util', () => {
test(`should parse regular hex color`, () => {
const color = parseColor('#FF00FF');
expect(color.value).toBe('#FF00FF');
});
test(`should parse opacity as 1 if not provided`, () => {
const color = parseColor('#FF00FF');
expect(color.opacity).toBe(1);
});
test(`should parse opacity as 1 when provided`, () => {
const color = parseColor('#FF00FFFF');
expect(color.opacity).toBe(1);
});
test(`should parse opacity as 0 when provided`, () => {
const color = parseColor('#FF00FF00');
expect(color.opacity).toBe(0);
});
test(`should parse opacit provided`, () => {
const color = parseColor('#FF00FF54');
expect(color.opacity).toBe(0.32941176470588235);
});
});
================================================
FILE: packages/render/tsconfig.json
================================================
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "lib",
"declaration": true,
"declarationDir": "lib/types",
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"types": ["vitest/globals"],
},
"include": ["src", "globals.d.ts"],
}
================================================
FILE: packages/renderer/.gitignore
================================================
lib
================================================
FILE: packages/renderer/.size-limit.cjs
================================================
module.exports = [
{
path: 'lib/react-pdf.browser.js',
limit: '550 kB',
modifyWebpackConfig: (config) => {
config.resolve = {
fallback: {
fs: false,
},
alias: {
// TODO: ignore iconv-lite on default because it contains exotic encodings like `win1251`, that isn't used in pdf
'iconv-lite': false,
},
};
return config;
},
},
];
================================================
FILE: packages/renderer/CHANGELOG.md
================================================
# @react-pdf/renderer
## 4.3.2
### Patch Changes
- Updated dependencies [[`f034491b`](https://github.com/diegomura/react-pdf/commit/f034491b1f77ce6f18a5db88e70b10b9c502ca35), [`2eba70bd`](https://github.com/diegomura/react-pdf/commit/2eba70bd9cbb942a675ac686a2b335164279035a), [`fafbcb12`](https://github.com/diegomura/react-pdf/commit/fafbcb12a0ecf3231165bb2944de7ad3b7761dec), [`cc1aff24`](https://github.com/diegomura/react-pdf/commit/cc1aff2454263f64d1f79c9df051d21d74f8d7cf)]:
- @react-pdf/pdfkit@4.1.0
- @react-pdf/reconciler@2.0.0
- @react-pdf/layout@4.4.2
- @react-pdf/font@4.0.4
- @react-pdf/render@4.3.2
- @react-pdf/types@2.9.2
## 4.3.1
### Patch Changes
- [#3124](https://github.com/diegomura/react-pdf/pull/3124) [`dcc7b403`](https://github.com/diegomura/react-pdf/commit/dcc7b40313b5662b9bd16678fbc0b62eeaf65d71) Thanks [@pcorpet](https://github.com/pcorpet)! - feat(pdfdownloadlink): add a ref to the link component
- Updated dependencies [[`beaffd3d`](https://github.com/diegomura/react-pdf/commit/beaffd3d2bb5ac81033ef53421413662d6d71158), [`a99d10fb`](https://github.com/diegomura/react-pdf/commit/a99d10fb2fbb6bfeb233ccb9bf0b703ed092e8d5), [`5cbe2fb0`](https://github.com/diegomura/react-pdf/commit/5cbe2fb0bde45c44eb68dde01f20feea245908c6), [`ec063bec`](https://github.com/diegomura/react-pdf/commit/ec063bec8d6a56df42849a8e66521fad7719dc29)]:
- @react-pdf/layout@4.4.1
- @react-pdf/pdfkit@4.0.4
- @react-pdf/render@4.3.1
- @react-pdf/font@4.0.3
- @react-pdf/types@2.9.1
## 4.3.0
### Minor Changes
- [#3112](https://github.com/diegomura/react-pdf/pull/3112) [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a) Thanks [@diegomura](https://github.com/diegomura)! - feat: add xLinkHref, gradientTransform and gradientUnits support
### Patch Changes
- [`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982) Thanks [@diegomura](https://github.com/diegomura)! - fix: debug prop
- Updated dependencies [[`01b4ff5c`](https://github.com/diegomura/react-pdf/commit/01b4ff5cb00420dd37c2f28fb95822dd18cdd982), [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a), [`106699e8`](https://github.com/diegomura/react-pdf/commit/106699e850dad2285e6999d59975111f217e8a81)]:
- @react-pdf/render@4.3.0
- @react-pdf/layout@4.4.0
- @react-pdf/types@2.9.0
- @react-pdf/pdfkit@4.0.3
- @react-pdf/font@4.0.2
## 4.2.4
### Patch Changes
- Updated dependencies [[`b95a6dc4`](https://github.com/diegomura/react-pdf/commit/b95a6dc4350b0580ee8c1c8320871cc7145676f2), [`e257f7ee`](https://github.com/diegomura/react-pdf/commit/e257f7ee18ff09f4895cd16c0b21b824678384c8)]:
- @react-pdf/reconciler@1.1.4
- @react-pdf/layout@4.3.1
- @react-pdf/font@4.0.1
- @react-pdf/render@4.2.1
- @react-pdf/types@2.8.2
## 4.2.3
### Patch Changes
- Updated dependencies [[`a9ef6416`](https://github.com/diegomura/react-pdf/commit/a9ef6416473c86f6d8fe35c3d7231e642d6ae265), [`7cd66e4f`](https://github.com/diegomura/react-pdf/commit/7cd66e4fc37cd1393adc6250a919fe2629812082), [`ddfa3675`](https://github.com/diegomura/react-pdf/commit/ddfa367587618b313b4b0b3b57a9a7631e8e7604), [`bfb51ec0`](https://github.com/diegomura/react-pdf/commit/bfb51ec09b851c52659ce16fed1286173e9516a9), [`a2de2685`](https://github.com/diegomura/react-pdf/commit/a2de2685b25c797f266775c2e35a6535090393b7), [`24690f52`](https://github.com/diegomura/react-pdf/commit/24690f5238e4eacf28351cf9996856a7d196d29e), [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8), [`b06d3a0f`](https://github.com/diegomura/react-pdf/commit/b06d3a0f64593ac18097efd061334f1e5bd70095), [`fce45ea5`](https://github.com/diegomura/react-pdf/commit/fce45ea5860038e7f3b227cabf0dd6212f4404b8)]:
- @react-pdf/layout@4.3.0
- @react-pdf/types@2.8.1
- @react-pdf/font@4.0.0
- @react-pdf/render@4.2.0
- @react-pdf/fns@3.1.2
## 4.2.2
### Patch Changes
- [#3065](https://github.com/diegomura/react-pdf/pull/3065) [`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6) Thanks [@diegomura](https://github.com/diegomura)! - refactor: partially unify pdfkit
- Updated dependencies [[`226467e3`](https://github.com/diegomura/react-pdf/commit/226467e39443d3690b8f8c3298aa8278b43fbfa6), [`96c2464d`](https://github.com/diegomura/react-pdf/commit/96c2464dfaa7294e0d79b7ed64743bfd7b1a8c72), [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45), [`700535c5`](https://github.com/diegomura/react-pdf/commit/700535c57ff1b105d923be70f4fc4bfdf4479f91), [`442ce355`](https://github.com/diegomura/react-pdf/commit/442ce35534f916b9146a35fd03870387ed488d92), [`3007d34a`](https://github.com/diegomura/react-pdf/commit/3007d34ad3e10bf32ada3631938f5bb08e1c549f)]:
- @react-pdf/pdfkit@4.0.2
- @react-pdf/render@4.1.2
- @react-pdf/primitives@4.1.1
- @react-pdf/types@2.8.0
- @react-pdf/layout@4.2.3
- @react-pdf/fns@3.1.1
- @react-pdf/font@3.1.0
## 4.2.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/layout@4.2.2
- @react-pdf/render@4.1.1
## 4.2.0
### Minor Changes
- [`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2) Thanks [@diegomura](https://github.com/diegomura)! - feat: added Form Annotation support
### Patch Changes
- [#3014](https://github.com/diegomura/react-pdf/pull/3014) [`685890bd`](https://github.com/diegomura/react-pdf/commit/685890bd841b7d2480157117fcd3cbb1334f6324) Thanks [@islam-kamel](https://github.com/islam-kamel)! - fix: PDFDownloadLinkProps Type Error
- Updated dependencies [[`7cd71714`](https://github.com/diegomura/react-pdf/commit/7cd7171472b0f300db56b7805c5f966bf4ced6e2), [`fabecc56`](https://github.com/diegomura/react-pdf/commit/fabecc56727dfb6d590a3fa1e11f50250ecbbea1), [`01944231`](https://github.com/diegomura/react-pdf/commit/01944231a342d502b832aeecb4c313020b8360c8), [`6d875056`](https://github.com/diegomura/react-pdf/commit/6d875056a07e8479ef695416c1fed575491b6ff1), [`49daae8f`](https://github.com/diegomura/react-pdf/commit/49daae8fdfba672a3e828847232ee9b70bb51711), [`5cc47319`](https://github.com/diegomura/react-pdf/commit/5cc47319bb428f6d4bcad21cd6dba9afca5cdc17), [`aa0f6725`](https://github.com/diegomura/react-pdf/commit/aa0f672589683a66abc79f838291996ae9aaffb8)]:
- @react-pdf/primitives@4.1.0
- @react-pdf/render@4.1.0
- @react-pdf/layout@4.2.1
- @react-pdf/types@2.7.1
- @react-pdf/pdfkit@4.0.1
- @react-pdf/font@3.0.2
## 4.1.6
### Patch Changes
- Updated dependencies [[`18834efa`](https://github.com/diegomura/react-pdf/commit/18834efac2787a636c378718fee40cbe74f01ab8)]:
- @react-pdf/layout@4.2.0
## 4.1.5
### Patch Changes
- Updated dependencies [[`1916e840`](https://github.com/diegomura/react-pdf/commit/1916e8405ce2b566110f2a1d66cfd8b4c4fa34d4), [`165c70fb`](https://github.com/diegomura/react-pdf/commit/165c70fbd31a7a4520af83b218a03f2f78f486e9)]:
- @react-pdf/reconciler@1.1.3
- @react-pdf/layout@4.1.3
- @react-pdf/render@4.0.2
## 4.1.4
### Patch Changes
- Updated dependencies [[`f6e9e113`](https://github.com/diegomura/react-pdf/commit/f6e9e1136f47fe05f86158c76561729b2cc425c4)]:
- @react-pdf/reconciler@1.1.2
## 4.1.3
### Patch Changes
- Updated dependencies [[`425f1183`](https://github.com/diegomura/react-pdf/commit/425f1183bba9a83fd5712a1371abb6cea2ed8fca), [`2c3c887e`](https://github.com/diegomura/react-pdf/commit/2c3c887ea2d3aed2863f49bff375d08feaf975aa)]:
- @react-pdf/layout@4.1.2
## 4.1.2
### Patch Changes
- [#2951](https://github.com/diegomura/react-pdf/pull/2951) [`aab7d958`](https://github.com/diegomura/react-pdf/commit/aab7d95870d9073e4acb004aa0cce9cfa19b7f0e) Thanks [@diegomura](https://github.com/diegomura)! - fix: note rendering
- Updated dependencies [[`03322a75`](https://github.com/diegomura/react-pdf/commit/03322a756f44863543673ff597582444c180989b), [`ed562b9b`](https://github.com/diegomura/react-pdf/commit/ed562b9b7f14bc76a1cd83aaaf1dab966bd7540b), [`b5c0fe64`](https://github.com/diegomura/react-pdf/commit/b5c0fe646108a960a528290b175511842020d600)]:
- @react-pdf/render@4.0.1
- @react-pdf/font@3.0.1
- @react-pdf/layout@4.1.1
## 4.1.1
### Patch Changes
- Updated dependencies [[`82192b3a`](https://github.com/diegomura/react-pdf/commit/82192b3a53cf5db62230287e7456dc5bdeee6244)]:
- @react-pdf/reconciler@1.1.1
## 4.1.0
### Minor Changes
- [`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd) Thanks [@diegomura](https://github.com/diegomura)! - feat: add React 19 support
### Patch Changes
- Updated dependencies [[`52b2f253`](https://github.com/diegomura/react-pdf/commit/52b2f25349bee0c09399bc2e7e5e89db5e1433fd)]:
- @react-pdf/reconciler@1.1.0
## 4.0.2
### Patch Changes
- [#2936](https://github.com/diegomura/react-pdf/pull/2936) [`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b) Thanks [@diegomura](https://github.com/diegomura)! - feat: pre-bundle + bump react-reconciler
- Updated dependencies [[`b242e59a`](https://github.com/diegomura/react-pdf/commit/b242e59a14a856e280c9fcbad81f707248819721), [`7add014c`](https://github.com/diegomura/react-pdf/commit/7add014c6bc9cff649dd1a56fc47214888613b6b)]:
- @react-pdf/layout@4.1.0
- @react-pdf/reconciler@1.0.1
## 4.0.1
### Patch Changes
- Updated dependencies [[`58f9a047`](https://github.com/diegomura/react-pdf/commit/58f9a04740ed1331ef1dfa9999fb43c0ee10fa5b)]:
- @react-pdf/layout@4.0.1
## 4.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Minor Changes
- [#2876](https://github.com/diegomura/react-pdf/pull/2876) [`afe4bcfe`](https://github.com/diegomura/react-pdf/commit/afe4bcfe6f4b991cf22341242fc27d169b758d47) Thanks [@diegomura](https://github.com/diegomura)! - feat: add gap percentage support
### Patch Changes
- Updated dependencies [[`afe4bcfe`](https://github.com/diegomura/react-pdf/commit/afe4bcfe6f4b991cf22341242fc27d169b758d47), [`42570321`](https://github.com/diegomura/react-pdf/commit/42570321af54bf331ca81f09a102664cd9f7c46a), [`fdcef566`](https://github.com/diegomura/react-pdf/commit/fdcef5666e4eeed542b625d394cdfe60d6346600), [`46c3047d`](https://github.com/diegomura/react-pdf/commit/46c3047de56ae82f062b72c4910a4e6096eee99f), [`55973278`](https://github.com/diegomura/react-pdf/commit/55973278ac8bc8f703b63844f57d6f155ae8d86f), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/layout@4.0.0
- @react-pdf/pdfkit@4.0.0
- @react-pdf/types@2.7.0
- @react-pdf/primitives@4.0.0
- @react-pdf/render@4.0.0
- @react-pdf/font@3.0.0
## 3.4.5
### Patch Changes
- [#2669](https://github.com/diegomura/react-pdf/pull/2669) [`ed94775`](https://github.com/diegomura/react-pdf/commit/ed94775f4d44db0886ff08c71d09f446bace6392) Thanks [@Finanzasparahippies](https://github.com/Finanzasparahippies)! - fix: download IE checks
- Updated dependencies [[`e425ca4`](https://github.com/diegomura/react-pdf/commit/e425ca4add7eb353b6282a40fd1020aad0da36c4), [`e42a79a`](https://github.com/diegomura/react-pdf/commit/e42a79a3857932a4ebc89feb6e4d2c891280d633), [`5af35ec`](https://github.com/diegomura/react-pdf/commit/5af35ec9743cc0d7bf75f5ca789627517ff35816), [`53bf803`](https://github.com/diegomura/react-pdf/commit/53bf803465f4fecf13531d1a10697c3d4067cf8f), [`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2), [`4bafab8`](https://github.com/diegomura/react-pdf/commit/4bafab8455c9003759f48bad20a720baf4ed189b)]:
- @react-pdf/layout@3.13.0
- @react-pdf/render@3.5.0
- @react-pdf/pdfkit@3.2.0
- @react-pdf/types@2.6.0
- @react-pdf/font@2.5.2
## 3.4.4
### Patch Changes
- Updated dependencies [[`22a34a9`](https://github.com/diegomura/react-pdf/commit/22a34a91b16a201cd8288e0dbea9368b12ca73f5)]:
- @react-pdf/types@2.5.0
- @react-pdf/font@2.5.1
- @react-pdf/layout@3.12.1
- @react-pdf/render@3.4.4
## 3.4.3
### Patch Changes
- Updated dependencies [[`67c265a`](https://github.com/diegomura/react-pdf/commit/67c265a7e39cc0baa319f49137219677904695e6), [`713690c`](https://github.com/diegomura/react-pdf/commit/713690cca266116bb7e80d13cf84bc843f9dfd52)]:
- @react-pdf/layout@3.12.0
- @react-pdf/font@2.5.0
- @react-pdf/pdfkit@3.1.10
## 3.4.2
### Patch Changes
- Updated dependencies [[`e2d21a4`](https://github.com/diegomura/react-pdf/commit/e2d21a433b881bb96ea4d0b3a01a7297dd1f4a94)]:
- @react-pdf/pdfkit@3.1.9
- @react-pdf/layout@3.11.5
## 3.4.1
### Patch Changes
- Updated dependencies [[`68bfc57`](https://github.com/diegomura/react-pdf/commit/68bfc575adfb95302e320019715d1eec5398259f)]:
- @react-pdf/pdfkit@3.1.8
- @react-pdf/layout@3.11.4
## 3.4.0
### Minor Changes
- [#2582](https://github.com/diegomura/react-pdf/pull/2582) [`fab09cc`](https://github.com/diegomura/react-pdf/commit/fab09cc9814326fdb44d2bcb7097ba9960d441d1) Thanks [@SethThoburn](https://github.com/SethThoburn)! - Pass \_INTERNAL\_\_LAYOUT\_\_DATA\_ to onRenderCallback in toBuffer
### Patch Changes
- Updated dependencies [[`da10a9b`](https://github.com/diegomura/react-pdf/commit/da10a9bb43dc4c4765687850444a24cbc4eb402a), [`087ee22`](https://github.com/diegomura/react-pdf/commit/087ee22f63a922a2d3ee01bae3b0351f99cb9021)]:
- @react-pdf/pdfkit@3.1.7
- @react-pdf/layout@3.11.3
## 3.3.8
### Patch Changes
- Updated dependencies [[`dc54c13`](https://github.com/diegomura/react-pdf/commit/dc54c13625510482e93f80ed5cc07cf3a6a6d34c)]:
- @react-pdf/pdfkit@3.1.6
- @react-pdf/layout@3.11.2
## 3.3.7
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/layout@3.11.1
- @react-pdf/render@3.4.3
- @react-pdf/font@2.4.4
- @react-pdf/pdfkit@3.1.5
## 3.3.6
### Patch Changes
- Updated dependencies [[`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235), [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7)]:
- @react-pdf/layout@3.11.0
- @react-pdf/types@2.4.1
- @react-pdf/pdfkit@3.1.4
- @react-pdf/font@2.4.3
- @react-pdf/render@3.4.2
## 3.3.5
### Patch Changes
- Updated dependencies [[`0590324`](https://github.com/diegomura/react-pdf/commit/0590324d7a6d75c0a49520b3f99cfb6594239390)]:
- @react-pdf/pdfkit@3.1.3
- @react-pdf/layout@3.10.4
## 3.3.4
### Patch Changes
- Updated dependencies [[`44bd45b`](https://github.com/diegomura/react-pdf/commit/44bd45b1961ca8bae4a2f84cc77db945e5c43419)]:
- @react-pdf/pdfkit@3.1.2
- @react-pdf/layout@3.10.3
## 3.3.3
### Patch Changes
- [#2544](https://github.com/diegomura/react-pdf/pull/2544) [`b5380a1`](https://github.com/diegomura/react-pdf/commit/b5380a1a0a7397b4111d68ce97b4acb702d34d51) Thanks [@satelllte](https://github.com/satelllte)! - fix: creationDate and modificationDate types
- Updated dependencies [[`b5380a1`](https://github.com/diegomura/react-pdf/commit/b5380a1a0a7397b4111d68ce97b4acb702d34d51)]:
- @react-pdf/render@3.4.1
## 3.3.2
### Patch Changes
- Updated dependencies [[`fb5273d`](https://github.com/diegomura/react-pdf/commit/fb5273d8d80d919f7b9c214e02d67b79ce23fa19), [`cfd050c`](https://github.com/diegomura/react-pdf/commit/cfd050c3ae0980f78c4a466565852d81c8254e19)]:
- @react-pdf/render@3.4.0
- @react-pdf/types@2.4.0
- @react-pdf/font@2.4.2
- @react-pdf/layout@3.10.2
## 3.3.1
### Patch Changes
- [#2529](https://github.com/diegomura/react-pdf/pull/2529) [`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8) Thanks [@diegomura](https://github.com/diegomura)! - fix: jpeg exif orientation rendering
- Updated dependencies [[`36c6ba3`](https://github.com/diegomura/react-pdf/commit/36c6ba30ae73a512f19fe5bc47ac8c304887c0da), [`a35b1ba`](https://github.com/diegomura/react-pdf/commit/a35b1ba18d293df51293600d8d56015094d222d8)]:
- @react-pdf/pdfkit@3.1.1
- @react-pdf/layout@3.10.1
## 3.3.0
### Minor Changes
- [#2505](https://github.com/diegomura/react-pdf/pull/2505) [`0f5c43f`](https://github.com/diegomura/react-pdf/commit/0f5c43fa6f3c0b53c067200cc1ac21e651504760) Thanks [@diegomura](https://github.com/diegomura)! - feat: wasm yoga
### Patch Changes
- [#2515](https://github.com/diegomura/react-pdf/pull/2515) [`64f7bba`](https://github.com/diegomura/react-pdf/commit/64f7bba0d840d17188e50086169c84c415abd8d5) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Allow in TypeScript
* [#2522](https://github.com/diegomura/react-pdf/pull/2522) [`e817223`](https://github.com/diegomura/react-pdf/commit/e8172231d07d10ece4ca960641f9ee52c5d4660d) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Make options in usePDF optional in TypeScript
- [#2519](https://github.com/diegomura/react-pdf/pull/2519) [`cf73180`](https://github.com/diegomura/react-pdf/commit/cf7318069e63170e160a36602359fc8cbc3386c2) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Fix props unnecessarily required in LinearGradient and RadialGradient in TypeScript
* [#2516](https://github.com/diegomura/react-pdf/pull/2516) [`66a40b2`](https://github.com/diegomura/react-pdf/commit/66a40b2e41cefe11f1ef8d467ba449a8861adb69) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Allow in TypeScript
* Updated dependencies [[`9e5842b`](https://github.com/diegomura/react-pdf/commit/9e5842bbecca6e249af2c5fc50078bb7ddd5420f), [`0f5c43f`](https://github.com/diegomura/react-pdf/commit/0f5c43fa6f3c0b53c067200cc1ac21e651504760)]:
- @react-pdf/types@2.3.6
- @react-pdf/layout@3.10.0
- @react-pdf/font@2.4.1
- @react-pdf/render@3.3.2
## 3.2.1
### Patch Changes
- Updated dependencies [[`42bbbda`](https://github.com/diegomura/react-pdf/commit/42bbbda48058acd2d36d7a92c812d133608c459e)]:
- @react-pdf/primitives@3.1.1
- @react-pdf/layout@3.9.1
- @react-pdf/render@3.3.1
## 3.2.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
### Patch Changes
- Updated dependencies [[`e705d98`](https://github.com/diegomura/react-pdf/commit/e705d9862e3364fde00cbe6cdaf06d492bf58526), [`6bfe7e8`](https://github.com/diegomura/react-pdf/commit/6bfe7e8a30d96c04a1552800159992705f3605b1), [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37), [`c8fe2c8`](https://github.com/diegomura/react-pdf/commit/c8fe2c86639cb8e44f26f78e62fc67379a8e3ceb), [`96ea576`](https://github.com/diegomura/react-pdf/commit/96ea5764cbe4e6e3869cd0fe6620e5216f94ffc0)]:
- @react-pdf/layout@3.9.0
- @react-pdf/render@3.3.0
- @react-pdf/primitives@3.1.0
- @react-pdf/pdfkit@3.1.0
- @react-pdf/font@2.4.0
## 3.1.17
### Patch Changes
- Updated dependencies [[`0538bd9`](https://github.com/diegomura/react-pdf/commit/0538bd900e5490a5ef81bcdbd1676fc9f9ae6acb)]:
- @react-pdf/layout@3.8.0
## 3.1.16
### Patch Changes
- [#2363](https://github.com/diegomura/react-pdf/pull/2363) [`8654d00`](https://github.com/diegomura/react-pdf/commit/8654d003023dd0899cddfc2ea2f5a552e01cf570) Thanks [@azmy60](https://github.com/azmy60)! - fix: SVGPresentationAttributes types
- Updated dependencies [[`b227e0e`](https://github.com/diegomura/react-pdf/commit/b227e0e303da8bca754910f55f5d27dd18f3a874), [`e5c8fde`](https://github.com/diegomura/react-pdf/commit/e5c8fde9379a9a85ecac7e3d6273953e39d65f8d), [`45b2bd3`](https://github.com/diegomura/react-pdf/commit/45b2bd37037c605727ad5783f2f2a438dc19cac4), [`8654d00`](https://github.com/diegomura/react-pdf/commit/8654d003023dd0899cddfc2ea2f5a552e01cf570), [`b457a0c`](https://github.com/diegomura/react-pdf/commit/b457a0cc1c1352325e6c633af3000a3c9241f7f7), [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2), [`4c40b14`](https://github.com/diegomura/react-pdf/commit/4c40b149cfed42f2513e1dd330a92ccc3363c04f)]:
- @react-pdf/layout@3.7.0
- @react-pdf/types@2.3.5
- @react-pdf/pdfkit@3.0.4
- @react-pdf/render@3.2.8
- @react-pdf/font@2.3.8
## 3.1.15
### Patch Changes
- Updated dependencies [[`4cfb84d`](https://github.com/diegomura/react-pdf/commit/4cfb84d9f3d2301720b68b4c40a0257b9520c6e1)]:
- @react-pdf/pdfkit@3.0.3
- @react-pdf/layout@3.6.4
## 3.1.14
### Patch Changes
- Updated dependencies [[`4a55c1b`](https://github.com/diegomura/react-pdf/commit/4a55c1b2ed19e460ccae6e749ed94c16729a23c4)]:
- @react-pdf/types@2.3.4
- @react-pdf/layout@3.6.3
- @react-pdf/font@2.3.7
- @react-pdf/render@3.2.7
## 3.1.13
### Patch Changes
- [#2406](https://github.com/diegomura/react-pdf/pull/2406) [`3b5e1c7`](https://github.com/diegomura/react-pdf/commit/3b5e1c7c71a0f830ae2b70da8aac2b2bd5015ca3) Thanks [@JoachimKoenigslieb](https://github.com/JoachimKoenigslieb)! - Added an optional callback to the updateContainer method. This allows the user of the pdf instance to know when the update operation is finished in React. As this is an optional argument, no user code should be changed.
## 3.1.12
### Patch Changes
- [#2247](https://github.com/diegomura/react-pdf/pull/2247) [`6d408c8`](https://github.com/diegomura/react-pdf/commit/6d408c838b1aa9bea0db63bf36b2a6932a20404c) Thanks [@jeetiss](https://github.com/jeetiss)! - ### updates for `usePDF` hook
`update` function takes the new document and renders it:
```jsx
const PdfView = () => {
const [pdf, update] = usePdf();
useEffect(() => {
update( );
}, []);
if (pdf.loading) return null;
// use your PDF here
return <>{pdf.url}>;
};
```
## 3.1.11
### Patch Changes
- Updated dependencies [[`5385a43`](https://github.com/diegomura/react-pdf/commit/5385a438cb4876d1dc00d49d5fdd2e07c0d16167), [`1e1fbdc`](https://github.com/diegomura/react-pdf/commit/1e1fbdc3c33ced46d8c7ebba7a196733cb789d59), [`8636812`](https://github.com/diegomura/react-pdf/commit/86368122ed87621d19ae3bc248080e17703d9fcb)]:
- @react-pdf/render@3.2.6
- @react-pdf/types@2.3.3
- @react-pdf/font@2.3.6
- @react-pdf/layout@3.6.2
## 3.1.10
### Patch Changes
- [#2309](https://github.com/diegomura/react-pdf/pull/2309) [`113de53`](https://github.com/diegomura/react-pdf/commit/113de537b0fa9bae06a69e7c8daa988fe319fc6a) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Make `x` and `y` optional in `Rect`
* [#2314](https://github.com/diegomura/react-pdf/pull/2314) [`d6018d5`](https://github.com/diegomura/react-pdf/commit/d6018d5a80492270ff5f5b4c00e694f7dc1cd93f) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Make `cx` and `cy` optional in `Circle` and `Ellipse`
* Updated dependencies [[`a25dbcb`](https://github.com/diegomura/react-pdf/commit/a25dbcb32b65c300f5b088e8b210bb0c1abca5c2), [`2e724df`](https://github.com/diegomura/react-pdf/commit/2e724dfaff3c9b39e9862d24b0d0e037c8a9e8c2), [`d6018d5`](https://github.com/diegomura/react-pdf/commit/d6018d5a80492270ff5f5b4c00e694f7dc1cd93f)]:
- @react-pdf/types@2.3.2
- @react-pdf/render@3.2.5
- @react-pdf/font@2.3.5
- @react-pdf/layout@3.6.1
## 3.1.9
### Patch Changes
- Updated dependencies [[`d48039c`](https://github.com/diegomura/react-pdf/commit/d48039c9e224346fd22395f48eb03ceffa5e3dd6)]:
- @react-pdf/layout@3.6.0
## 3.1.8
### Patch Changes
- [#2232](https://github.com/diegomura/react-pdf/pull/2232) [`5832ff2`](https://github.com/diegomura/react-pdf/commit/5832ff20e1ce4a0e49cf5249dcdf4b304eab04c6) Thanks [@x-Wawa](https://github.com/x-Wawa)! - Add missing props types on `Document` component
* [#2236](https://github.com/diegomura/react-pdf/pull/2236) [`37bfa1b`](https://github.com/diegomura/react-pdf/commit/37bfa1ba26386d1725f42ba5e108d8c72aa71e85) Thanks [@jeetiss](https://github.com/jeetiss)! - remove loose-envify dependency
* Updated dependencies [[`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59)]:
- @react-pdf/layout@3.5.1
- @react-pdf/types@2.3.1
- @react-pdf/font@2.3.4
- @react-pdf/render@3.2.4
## 3.1.7
### Patch Changes
- [#2229](https://github.com/diegomura/react-pdf/pull/2229) [`b194b61`](https://github.com/diegomura/react-pdf/commit/b194b619b19a7683b64d47eaa2573635e6884e8d) Thanks [@jeetiss](https://github.com/jeetiss)! - deprecate `renderToString` use `renderToBuffer` instead
- Updated dependencies [[`2db67a3`](https://github.com/diegomura/react-pdf/commit/2db67a38b9be98b7816a2b5aa4733446b95e3724)]:
- @react-pdf/layout@3.5.0
- @react-pdf/types@2.3.0
- @react-pdf/render@3.2.3
- @react-pdf/font@2.3.3
## 3.1.6
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
* [#2211](https://github.com/diegomura/react-pdf/pull/2211) [`f6667e7`](https://github.com/diegomura/react-pdf/commit/f6667e75449c241d02f9f44fb717a71443c555c1) Thanks [@jeetiss](https://github.com/jeetiss)! - configure automatic runtime for react
* Updated dependencies [[`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905)]:
- @react-pdf/layout@3.4.1
- @react-pdf/pdfkit@3.0.2
- @react-pdf/render@3.2.2
- @react-pdf/font@2.3.2
## 3.1.5
### Patch Changes
- [#2202](https://github.com/diegomura/react-pdf/pull/2202) [`f4d2b68`](https://github.com/diegomura/react-pdf/commit/f4d2b68765d146e4718140f65eeceb7e69e2cfee) Thanks [@jeetiss](https://github.com/jeetiss)! - add `events` as dependency to fix build in vite
* [#2201](https://github.com/diegomura/react-pdf/pull/2201) [`75150ca`](https://github.com/diegomura/react-pdf/commit/75150ca137b709fcab6e7cefee9dfac6b48d5aaa) Thanks [@jeetiss](https://github.com/jeetiss)! - Reveal layout data in `onRender` callback
This is an experimental API, and it will change in the future. Use it at your own risk
## 3.1.4
### Patch Changes
- Updated dependencies [[`c981784`](https://github.com/diegomura/react-pdf/commit/c981784b172e9a7631edb7a1fe41ce77bc6ccdee)]:
- @react-pdf/layout@3.4.0
## 3.1.3
### Patch Changes
- [#2173](https://github.com/diegomura/react-pdf/pull/2173) [`18cb161`](https://github.com/diegomura/react-pdf/commit/18cb161e3a40581e79b4d3ee0410cb2c3472e987) Thanks [@jeetiss](https://github.com/jeetiss)! - export renderToBuffer type
* [#2172](https://github.com/diegomura/react-pdf/pull/2172) [`d0cc0bd`](https://github.com/diegomura/react-pdf/commit/d0cc0bd26f04731e1009fae15860892d04e5222f) Thanks [@rdennis](https://github.com/rdennis)! - Improved `children` prop types for react@18.
## 3.1.2
### Patch Changes
- [#2170](https://github.com/diegomura/react-pdf/pull/2170) [`b06f8f4`](https://github.com/diegomura/react-pdf/commit/b06f8f4e2ac8490b75093e05bfdc9a7be5594936) Thanks [@jeetiss](https://github.com/jeetiss)! - fix both esm and commonjs entries
## 3.1.1
### Patch Changes
- [#2161](https://github.com/diegomura/react-pdf/pull/2161) [`f648581`](https://github.com/diegomura/react-pdf/commit/f6485813c987f09a3aabca505fd0f6239ca5e58d) Thanks [@jeetiss](https://github.com/jeetiss)! - fix esm reexports
## 3.1.0
### Minor Changes
- [#2140](https://github.com/diegomura/react-pdf/pull/2140) [`327f071`](https://github.com/diegomura/react-pdf/commit/327f071ea72a7abb22423009666ddf06838a0654) Thanks [@jeetiss](https://github.com/jeetiss)! - fix react peer dependency problem
* [#2160](https://github.com/diegomura/react-pdf/pull/2160) [`a743c90`](https://github.com/diegomura/react-pdf/commit/a743c905fb5d201d2382bc9175fa36b83cc47284) Thanks [@jeetiss](https://github.com/jeetiss)! - implement flex gap
### Patch Changes
- [#2158](https://github.com/diegomura/react-pdf/pull/2158) [`2343a99`](https://github.com/diegomura/react-pdf/commit/2343a9982c647b0c6684df911d001120ed55596b) Thanks [@jeetiss](https://github.com/jeetiss)! - add type definition for renderToBuffer method
* [#2149](https://github.com/diegomura/react-pdf/pull/2149) [`54e9625`](https://github.com/diegomura/react-pdf/commit/54e962505a9917b20b2a3ffe8508a36a6bbc4f30) Thanks [@jeetiss](https://github.com/jeetiss)! - Fix "Invalid" error when a text label is a child of a Tspan element
- [#1798](https://github.com/diegomura/react-pdf/pull/1798) [`17a8006`](https://github.com/diegomura/react-pdf/commit/17a80066453454dce6141f7da2033d348b4d53c8) Thanks [@karlhorky](https://github.com/karlhorky)! - fix types for @types/react@18
- Updated dependencies [[`a743c90`](https://github.com/diegomura/react-pdf/commit/a743c905fb5d201d2382bc9175fa36b83cc47284)]:
- @react-pdf/layout@3.3.0
- @react-pdf/types@2.2.0
## 3.0.3
### Patch Changes
- [#2146](https://github.com/diegomura/react-pdf/pull/2146) [`2b05ef7`](https://github.com/diegomura/react-pdf/commit/2b05ef784b4ccf08dd06a91c4a6f054bddfaf5db) Thanks [@jeetiss](https://github.com/jeetiss)! - render text inside links
## 3.0.2
### Patch Changes
- [#2115](https://github.com/diegomura/react-pdf/pull/2115) [`a3f62c9`](https://github.com/diegomura/react-pdf/commit/a3f62c910c0128e0b4312480414dbf8b26dbca1c) Thanks [@jeetiss](https://github.com/jeetiss)! - fix `renderToString` method in node js
* [#2106](https://github.com/diegomura/react-pdf/pull/2106) [`24bb5de`](https://github.com/diegomura/react-pdf/commit/24bb5de969a854cc0226438985b34ef8ae2d7581) Thanks [@RDO34](https://github.com/RDO34)! - Add `dpi` and `bookmark` page prop types
* Updated dependencies [[`24bb5de`](https://github.com/diegomura/react-pdf/commit/24bb5de969a854cc0226438985b34ef8ae2d7581), [`8536f10`](https://github.com/diegomura/react-pdf/commit/8536f103830a9ed00211fc4c821b221377885a07)]:
- @react-pdf/types@2.1.1
- @react-pdf/pdfkit@3.0.1
## 3.0.1
### Patch Changes
- [#2056](https://github.com/diegomura/react-pdf/pull/2056) [`2ebba93`](https://github.com/diegomura/react-pdf/commit/2ebba93c43608a31655e99f226f1cf2d7006ac39) Thanks [@jasnross](https://github.com/jasnross)! - fix: TypeError when returning fragments or arrays from render prop
- Updated dependencies [[`ce1c43c`](https://github.com/diegomura/react-pdf/commit/ce1c43c1b450b3737a23a356c5143626ac2a43ad), [`2ebba93`](https://github.com/diegomura/react-pdf/commit/2ebba93c43608a31655e99f226f1cf2d7006ac39), [`992b91b`](https://github.com/diegomura/react-pdf/commit/992b91b3866e8e24efa014eef4d3eeec6a40f9a5)]:
- @react-pdf/font@2.3.1
- @react-pdf/layout@3.2.1
## 3.0.0
### Major Changes
- [#1908](https://github.com/diegomura/react-pdf/pull/1908) [`d1f3d5b`](https://github.com/diegomura/react-pdf/commit/d1f3d5b9b4103705e95e2160347ee253d842ed5d) Thanks [@diegomura](https://github.com/diegomura)! - chore: use fontkit mainline repo + drop node 12
### Minor Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- [#1604](https://github.com/diegomura/react-pdf/pull/1604) [`7eefc33`](https://github.com/diegomura/react-pdf/commit/7eefc3323390c59bf6d4f923749526831572ef1a) Thanks [@jeetiss](https://github.com/jeetiss)! - fix: skip empty text instance creation in jsx conditions
* [#1924](https://github.com/diegomura/react-pdf/pull/1924) [`3b054b7`](https://github.com/diegomura/react-pdf/commit/3b054b711f5dc0b1c4fd29feaf85b430baad2663) Thanks [@adamduncan](https://github.com/adamduncan)! - fix: bad type on onClick
- [#1929](https://github.com/diegomura/react-pdf/pull/1929) [`9996158`](https://github.com/diegomura/react-pdf/commit/9996158636edf2118c4a6dcce08a00408b982993) Thanks [@diegomura](https://github.com/diegomura)! - feat: remove blob stream dependency
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81), [`001a208`](https://github.com/diegomura/react-pdf/commit/001a20812fa039d09931b22eb97a8869e3b31cc5), [`5fe9754`](https://github.com/diegomura/react-pdf/commit/5fe9754f21f103e17d1b70498ee7961cde779b22), [`d1f3d5b`](https://github.com/diegomura/react-pdf/commit/d1f3d5b9b4103705e95e2160347ee253d842ed5d), [`27403f9`](https://github.com/diegomura/react-pdf/commit/27403f9a6ac1bbcfb144afc201c4a3e5aca25cbd), [`9996158`](https://github.com/diegomura/react-pdf/commit/9996158636edf2118c4a6dcce08a00408b982993), [`1a89506`](https://github.com/diegomura/react-pdf/commit/1a89506b4d325822d1a60a8f964434a6f6eb2d3f)]:
- @react-pdf/pdfkit@3.0.0
- @react-pdf/font@2.3.0
- @react-pdf/layout@3.2.0
- @react-pdf/render@3.2.1
## 2.3.0
### Minor Changes
- [#1902](https://github.com/diegomura/react-pdf/pull/1902) [`d011983`](https://github.com/diegomura/react-pdf/commit/d011983204cf45876594fa361f24b47e86c612c9) Thanks [@adamduncan](https://github.com/adamduncan)! - feat: add onClick event to PDFDownloadLink
### Patch Changes
- Updated dependencies [[`3acf53b`](https://github.com/diegomura/react-pdf/commit/3acf53b45200fa1415315f7dc22cc4b84a6b54c6), [`035d3f8`](https://github.com/diegomura/react-pdf/commit/035d3f8d24fa4f4af9f350950d81b51547858367), [`9527fe4`](https://github.com/diegomura/react-pdf/commit/9527fe4c9087818421eca4753172b06e3c0cb934), [`e94e50a`](https://github.com/diegomura/react-pdf/commit/e94e50a931df7347a8febc717ca76843502826c8), [`884695b`](https://github.com/diegomura/react-pdf/commit/884695b44feb974f155c83e0714e8e939b4f641b)]:
- @react-pdf/font@2.2.1
- @react-pdf/pdfkit@2.4.0
- @react-pdf/render@3.2.0
- @react-pdf/layout@3.1.2
## 2.2.0
### Minor Changes
- [#1867](https://github.com/diegomura/react-pdf/pull/1867) [`4fadb48`](https://github.com/diegomura/react-pdf/commit/4fadb48983d7269452f89f80c7e341ece859aaee) Thanks [@diegomura](https://github.com/diegomura)! - feat: add page layout support
* [#1868](https://github.com/diegomura/react-pdf/pull/1868) [`ce8762f`](https://github.com/diegomura/react-pdf/commit/ce8762f6de5c796e69ec5a225c7f3ff9c619a960) Thanks [@diegomura](https://github.com/diegomura)! - feat: add page mode support
### Patch Changes
- Updated dependencies [[`eecddbd`](https://github.com/diegomura/react-pdf/commit/eecddbda083561273eda21ee9b8d6107ad21800b), [`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb), [`205aa03`](https://github.com/diegomura/react-pdf/commit/205aa0334c67e7436d0a35b95b919ecee189a192), [`70c3c9f`](https://github.com/diegomura/react-pdf/commit/70c3c9f52517dc2820765e657dd2bff6b47d1ef2), [`22fb0f0`](https://github.com/diegomura/react-pdf/commit/22fb0f008ac2a2e251657e9cbd97ccedb4ff67db), [`4fadb48`](https://github.com/diegomura/react-pdf/commit/4fadb48983d7269452f89f80c7e341ece859aaee), [`d958b0a`](https://github.com/diegomura/react-pdf/commit/d958b0ae06a61c157b2581488a9121a0464222f4), [`24f5c77`](https://github.com/diegomura/react-pdf/commit/24f5c77706e12dbab45053cb704a2fe7cf60eb53), [`ce8762f`](https://github.com/diegomura/react-pdf/commit/ce8762f6de5c796e69ec5a225c7f3ff9c619a960), [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57), [`9347466`](https://github.com/diegomura/react-pdf/commit/9347466e8cd33d149678903cf4cf53850a8fc64a), [`6730bc2`](https://github.com/diegomura/react-pdf/commit/6730bc210712e6fc67b94f89f23a3d86f6a203f9), [`810f459`](https://github.com/diegomura/react-pdf/commit/810f45904e9abeaff5583ed4ceb6d77e123bbaea)]:
- @react-pdf/render@3.1.0
- @react-pdf/layout@3.1.0
- @react-pdf/pdfkit@2.3.0
- @react-pdf/types@2.1.0
## 2.1.2
### Patch Changes
- [#1836](https://github.com/diegomura/react-pdf/pull/1836) [`6c799ec`](https://github.com/diegomura/react-pdf/commit/6c799ec1bbe17106df6db109df4a62c70e39bd24) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove unused ramda dependency
- Updated dependencies [[`e938df0`](https://github.com/diegomura/react-pdf/commit/e938df0857642707b10b7f65f17ed22dc394ac1b), [`7c1d373`](https://github.com/diegomura/react-pdf/commit/7c1d373a06b04369e762069be4b96d4e40371ecc), [`5458a00`](https://github.com/diegomura/react-pdf/commit/5458a00979d883341c6df094243cae859344d2b9), [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de), [`fe0f214`](https://github.com/diegomura/react-pdf/commit/fe0f214dbbf2f632b852ebfe65f886ecc4dd6953), [`7e97bb5`](https://github.com/diegomura/react-pdf/commit/7e97bb579aaa847e5a2de650b5b327ac90a465c7), [`9a2b935`](https://github.com/diegomura/react-pdf/commit/9a2b935cfe173f80425ed87d9f474da271c050d2), [`25a80eb`](https://github.com/diegomura/react-pdf/commit/25a80ebd5f96ade7101883624010bad51474967c)]:
- @react-pdf/primitives@3.0.0
- @react-pdf/layout@3.0.0
- @react-pdf/render@3.0.0
- @react-pdf/types@2.0.9
- @react-pdf/font@2.2.0
- @react-pdf/pdfkit@2.2.0
## 2.1.1
### Patch Changes
- [#1681](https://github.com/diegomura/react-pdf/pull/1681) [`4eddbf5`](https://github.com/diegomura/react-pdf/commit/4eddbf5f21f5d58d4591d77e121faad5159424fc) Thanks [@dschu-lab](https://github.com/dschu-lab)! - defined renderToStream to return promise
- Updated dependencies [[`90ab2f8`](https://github.com/diegomura/react-pdf/commit/90ab2f8c040afc3d42961404bdf2ae09fac599eb)]:
- @react-pdf/font@2.1.1
- @react-pdf/layout@2.1.1
## 2.1.0
### Minor Changes
- [#1610](https://github.com/diegomura/react-pdf/pull/1610) [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e) Thanks [@jeetiss](https://github.com/jeetiss)! - updated rollup rollup-plugins and babel
* [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1605](https://github.com/diegomura/react-pdf/pull/1605) [`e7a93bc`](https://github.com/diegomura/react-pdf/commit/e7a93bcc18ef1dad74dcc80e84e5dcf6e4b04443) Thanks [@jeetiss](https://github.com/jeetiss)! - removed duplicate of `scheduler` package
* [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
* Updated dependencies [[`6f0e8d2`](https://github.com/diegomura/react-pdf/commit/6f0e8d2a130d39350cc4f61ff5c743b4b262c98a), [`4c5d527`](https://github.com/diegomura/react-pdf/commit/4c5d52721d29d843f1d09c3fd74370832429f70e), [`46a4b0c`](https://github.com/diegomura/react-pdf/commit/46a4b0c88836e0653db0c8bae6f71f969882277c), [`d341ae6`](https://github.com/diegomura/react-pdf/commit/d341ae66e91774e95e82deb8d9162bf458688768), [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca), [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b), [`a592e99`](https://github.com/diegomura/react-pdf/commit/a592e99f7df7481697582c2a12f31ce7f9559c66)]:
- @react-pdf/layout@2.1.0
- @react-pdf/font@2.1.0
- @react-pdf/pdfkit@2.1.0
- @react-pdf/render@2.1.0
- @react-pdf/primitives@2.0.2
- @react-pdf/types@2.0.8
================================================
FILE: packages/renderer/README.md
================================================
React renderer for creating PDF files on the browser and server
## How to install
```sh
yarn add @react-pdf/renderer
```
## How it works
```jsx
import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'row',
backgroundColor: '#E4E4E4',
},
section: {
margin: 10,
padding: 10,
flexGrow: 1,
},
});
// Create Document Component
const MyDocument = () => (
Section #1
Section #2
);
```
### `Web.` Render in DOM
```jsx
import ReactDOM from 'react-dom';
import { PDFViewer } from '@react-pdf/renderer';
const App = () => (
);
ReactDOM.render( , document.getElementById('root'));
```
### `Node.` Save in a file
```jsx
import ReactPDF from '@react-pdf/renderer';
ReactPDF.render( , `${__dirname}/example.pdf`);
```
## Examples
For each example, try opening `output.pdf` to see the result.
## Contributors
This project exists thanks to all the people who contribute. [[Contribute]](CONTRIBUTING.md).
## Sponsors
Thank you to all our sponsors! [[Become a sponsors](https://opencollective.com/react-pdf#sponsors)]
## Backers
Thank you to all our backers! [[Become a backer](https://opencollective.com/react-pdf#backer)]
## License
MIT © [Diego Muracciole](http://github.com/diegomura)
[](https://app.fossa.com/projects/git%2Bgithub.com%2Ftaylorudell%2Freact-pdf?ref=badge_large)
---

================================================
FILE: packages/renderer/babel.config.js
================================================
export default { extends: '../../babel.config.js' };
================================================
FILE: packages/renderer/index.d.ts
================================================
/* eslint-disable max-classes-per-file */
import * as React from 'react';
import {
Style,
PageSize,
FontStore,
PDFVersion,
Orientation,
SourceObject,
HyphenationCallback,
SVGPresentationAttributes,
Bookmark,
PageLayout,
PageMode,
} from '@react-pdf/types';
declare class ReactPDF {
static default: typeof ReactPDF;
}
export = ReactPDF;
declare namespace ReactPDF {
interface Styles {
[key: string]: Style;
}
interface OnRenderProps {
blob?: Blob;
}
interface DocumentProps {
style?: Style | Style[];
title?: string;
author?: string;
subject?: string;
creator?: string;
keywords?: string;
producer?: string;
language?: string;
creationDate?: Date;
modificationDate?: Date;
pdfVersion?: PDFVersion;
pageMode?: PageMode;
pageLayout?: PageLayout;
onRender?: (props: OnRenderProps) => any;
}
/**
* This component represent the PDF document itself. It must be the root
* of your tree element structure, and under no circumstances should it be
* used as children of another react-pdf component. In addition, it should
* only have childs of type .
*/
export class Document extends React.Component<
React.PropsWithChildren
> {}
interface NodeProps {
id?: string;
style?: Style | Style[];
/**
* Render component in all wrapped pages.
* @see https://react-pdf.org/advanced#fixed-components
*/
fixed?: boolean;
/**
* Force the wrapping algorithm to start a new page when rendering the
* element.
* @see https://react-pdf.org/advanced#page-breaks
*/
break?: boolean;
/**
* Hint that no page wrapping should occur between all sibling elements following the element within n points
* @see https://react-pdf.org/advanced#orphan-&-widow-protection
*/
minPresenceAhead?: number;
}
interface PageProps extends NodeProps {
/**
* Enable page wrapping for this page.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
size?: PageSize;
orientation?: Orientation;
dpi?: number;
bookmark?: Bookmark;
}
/**
* Represents single page inside the PDF document, or a subset of them if
* using the wrapping feature. A can contain as many pages as
* you want, but ensure not rendering a page inside any component besides
* Document.
*/
export class Page extends React.Component<
React.PropsWithChildren
> {}
interface ViewProps extends NodeProps {
id?: string;
/**
* Enable/disable page wrapping for element.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
render?: (props: {
pageNumber: number;
subPageNumber: number;
}) => React.ReactNode;
}
/**
* The most fundamental component for building a UI and is designed to be
* nested inside other views and can have 0 to many children.
*/
export class View extends React.Component<
React.PropsWithChildren
> {}
interface BaseImageProps extends NodeProps {
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
cache?: boolean;
}
interface ImageWithSrcProp extends BaseImageProps {
src: SourceObject;
}
interface ImageWithSourceProp extends BaseImageProps {
source: SourceObject;
}
type ImageProps = ImageWithSrcProp | ImageWithSourceProp;
/**
* A React component for displaying network or local (Node only) JPG or
* PNG images, as well as base64 encoded image strings.
*/
export class Image extends React.Component {}
interface TextProps extends NodeProps {
id?: string;
/**
* Enable/disable page wrapping for element.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
render?: (props: {
pageNumber: number;
totalPages: number;
subPageNumber: number;
subPageTotalPages: number;
}) => React.ReactNode;
/**
* Override the default hyphenation-callback
* @see https://react-pdf.org/fonts#registerhyphenationcallback
*/
hyphenationCallback?: HyphenationCallback;
/**
* Specifies the minimum number of lines in a text element that must be shown at the bottom of a page or its container.
* @see https://react-pdf.org/advanced#orphan-&-widow-protection
*/
orphans?: number;
/**
* Specifies the minimum number of lines in a text element that must be shown at the top of a page or its container..
* @see https://react-pdf.org/advanced#orphan-&-widow-protection
*/
widows?: number;
}
interface SVGTextProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
x: string | number;
y: string | number;
/**
* Override the default hyphenation-callback
* @see https://react-pdf.org/fonts#registerhyphenationcallback
*/
hyphenationCallback?: HyphenationCallback;
}
/**
* A React component for displaying text. Text supports nesting of other
* Text or Link components to create inline styling.
*/
export class Text extends React.Component<
React.PropsWithChildren | SVGTextProps
> {}
interface LinkProps extends NodeProps {
/**
* Enable/disable page wrapping for element.
* @see https://react-pdf.org/components#page-wrapping
*/
wrap?: boolean;
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
href?: string;
src?: string;
}
/**
* A React component for displaying a hyperlink. Link’s can be nested
* inside a Text component, or being inside any other valid primitive.
*/
export class Link extends React.Component<
React.PropsWithChildren
> {}
interface FormCommonProps extends NodeProps {
name?: string;
required?: boolean;
noExport?: boolean;
readOnly?: boolean;
value?: number | string;
defaultValue?: number | string;
}
interface FieldSetProps extends NodeProps {
name: string;
}
export class FieldSet extends React.Component<
React.PropsWithChildren
> {}
// see http://pdfkit.org/docs/forms.html#text_field_formatting
interface TextInputFormatting {
type:
| 'date'
| 'time'
| 'percent'
| 'number'
| 'zip'
| 'zipPlus4'
| 'phone'
| 'ssn';
param?: string;
nDec?: number;
sepComma?: boolean;
negStyle?: 'MinusBlack' | 'Red' | 'ParensBlack' | 'ParensRed';
currency?: string;
currencyPrepend?: boolean;
}
// see http://pdfkit.org/docs/forms.html#text_field_formatting
interface TextInputProps extends FormCommonProps {
align?: 'left' | 'center' | 'right';
multiline?: boolean;
/**
* The text will be masked (e.g. with asterisks).
*/
password?: boolean;
/**
* If set, text entered in the field is not spell-checked
*/
noSpell?: boolean;
format?: TextInputFormatting;
/**
* Sets the fontSize (default or 0 means auto sizing)
*/
fontSize?: number;
/**
* Sets the maximum length (characters) of the text in the field
*/
maxLength?: number;
}
export class TextInput extends React.Component {}
interface CheckboxProps extends FormCommonProps {
backgroundColor?: string;
borderColor?: string;
checked?: boolean;
onState?: string;
offState?: string;
xMark?: boolean;
}
export class Checkbox extends React.Component {}
interface SelectAndListPropsBase extends FormCommonProps {
sort?: boolean;
edit?: boolean;
multiSelect?: boolean;
noSpell?: boolean;
select?: string[];
}
type SelectAndListPropsWithEdit = SelectAndListPropsBase & {
edit: true | false;
noSpell: boolean;
};
type SelectAndListPropsWithNoSpell = SelectAndListPropsBase & {
edit: boolean;
noSpell: true | false;
};
type SelectAndListProps =
| SelectAndListPropsWithEdit
| SelectAndListPropsWithNoSpell;
export class Select extends React.Component {}
export class List extends React.Component {}
interface NoteProps extends NodeProps {
children: string;
}
export class Note extends React.Component {}
interface CanvasProps extends NodeProps {
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
paint: (
painter: any,
availableWidth: number,
availableHeight: number,
) => null;
}
export class Canvas extends React.Component {}
interface SVGProps extends NodeProps, SVGPresentationAttributes {
/**
* Enables debug mode on page bounding box.
* @see https://react-pdf.org/advanced#debugging
*/
debug?: boolean;
width?: string | number;
height?: string | number;
viewBox?: string;
preserveAspectRatio?: string;
}
/**
* The element is a container that defines a new coordinate system and viewport. It is used as the outermost element of SVG documents.
*/
export class Svg extends React.Component> {}
interface LineProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
x1: string | number;
x2: string | number;
y1: string | number;
y2: string | number;
}
/**
* The element is used to create a line.
*/
export class Line extends React.Component<
React.PropsWithChildren
> {}
interface PolylineProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
points: string;
}
/**
* The element is used to create any shape that consists of only straight lines (that is connected at several points).
*/
export class Polyline extends React.Component<
React.PropsWithChildren
> {}
interface PolygonProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
points: string;
}
/**
* The element is used to create a graphic that contains at least three sides.
* Polygons are made of straight lines, and the shape is "closed" (all the lines connect up).
*/
export class Polygon extends React.Component<
React.PropsWithChildren
> {}
interface PathProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
d: string;
}
/**
* The element is the most powerful element in the SVG library of basic shapes. It can be used to create lines, curves, arcs, and more.
*/
export class Path extends React.Component<
React.PropsWithChildren
> {}
interface RectProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
x?: string | number;
y?: string | number;
width: string | number;
height: string | number;
rx?: string | number;
ry?: string | number;
}
/**
* The element is used to create a rectangle and variations of a rectangle shape.
*/
export class Rect extends React.Component<
React.PropsWithChildren
> {}
interface CircleProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
cx?: string | number;
cy?: string | number;
r: string | number;
}
/**
* The element is used to create a circle.
*/
export class Circle extends React.Component<
React.PropsWithChildren
> {}
interface EllipseProps extends SVGPresentationAttributes {
style?: SVGPresentationAttributes;
cx?: string | number;
cy?: string | number;
rx: string | number;
ry: string | number;
}
/**
* The element is used to create an ellipse.
* An ellipse is closely related to a circle. The difference is that an ellipse has an x and a y radius that differs from each other, while a circle has equal x and y radius.
*/
export class Ellipse extends React.Component<
React.PropsWithChildren
> {}
interface TspanProps extends SVGPresentationAttributes {
x?: string | number;
y?: string | number;
}
/**
* The element defines a subtext within a element or another element.
* It allows for adjustment of the style and/or position of that subtext as needed.
*/
export class Tspan extends React.Component<
React.PropsWithChildren
> {}
interface GProps extends SVGPresentationAttributes {
style?: Style;
}
/**
* The SVG element is a container used to group other SVG elements.
* Transformations applied to the element are performed on its child elements, and its attributes are inherited by its children.
*/
export class G extends React.Component> {}
interface StopProps {
offset: string | number;
stopColor: string;
stopOpacity?: string | number;
}
/**
* The SVG element defines a color and its position to use on a gradient. This element is always a child of a or element
*/
export class Stop extends React.Component<
React.PropsWithChildren
> {}
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface DefsProps {}
/**
* The element is used to store graphical objects that will be used at a later time. Objects created inside a element are not rendered directly. To display them you have to reference them
*/
export class Defs extends React.Component<
React.PropsWithChildren
> {}
interface ClipPathProps {
id?: string;
}
/**
* The SVG element defines a clipping path, to be used by the clipPath property.
* A clipping path restricts the region to which paint can be applied. Conceptually, parts of the drawing that lie outside of the region bounded by the clipping path are not drawn.
*/
export class ClipPath extends React.Component<
React.PropsWithChildren
> {}
interface LinearGradientProps {
id: string;
x1?: string | number;
x2?: string | number;
y1?: string | number;
y2?: string | number;
xlinkHref?: string;
gradientTransform?: string;
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
}
/**
* The element lets authors define linear gradients that can be applied to fill or stroke of graphical elements.
*/
export class LinearGradient extends React.Component<
React.PropsWithChildren
> {}
interface RadialGradientProps {
id: string;
cx?: string | number;
cy?: string | number;
r?: string | number;
fx?: string | number;
fy?: string | number;
xlinkHref?: string;
gradientTransform?: string;
gradientUnits?: 'userSpaceOnUse' | 'objectBoundingBox';
}
/**
* The element lets authors define radial gradients that can be applied to fill or stroke of graphical elements.
*/
export class RadialGradient extends React.Component<
React.PropsWithChildren
> {}
interface BlobProviderParams {
blob: Blob | null;
url: string | null;
loading: boolean;
error: Error | null;
}
interface BlobProviderProps {
document: React.ReactElement;
children: (params: BlobProviderParams) => React.ReactNode;
}
/**
* Easy and declarative way of getting document's blob data without
* showing it on screen.
* @see https://react-pdf.org/advanced#on-the-fly-rendering
* @platform web
*/
export class BlobProvider extends React.Component {}
interface PDFViewerProps {
width?: number | string;
height?: number | string;
style?: Style | Style[];
className?: string;
children?: React.ReactElement;
innerRef?: React.Ref;
showToolbar?: boolean;
}
/**
* Iframe PDF viewer for client-side generated documents.
* @platform web
*/
export class PDFViewer extends React.Component {}
interface PDFDownloadLinkProps
extends Omit<
React.AnchorHTMLAttributes,
'href' | 'children'
> {
/** PDF filename. Alias for anchor tag `download` attribute. */
fileName?: string;
document: React.ReactElement;
children?: React.ReactNode | React.FC;
onClick?: React.AnchorHTMLAttributes['onClick'] &
((
event: React.MouseEvent,
instance: UsePDFInstance,
) => void);
ref?: React.Ref | undefined;
}
/**
* Anchor tag to enable generate and download PDF documents on the fly.
* @see https://react-pdf.org/advanced#on-the-fly-rendering
* @platform web
*/
export class PDFDownloadLink extends React.Component {}
interface UsePDFInstance {
loading: boolean;
blob: Blob | null;
url: string | null;
error: string | null;
}
/**
* React hook for creating and updating a PDF document instance
* @platform web
*/
export function usePDF(options?: {
document?: React.ReactElement;
}): [
UsePDFInstance,
(newDocument: React.ReactElement) => void,
];
export const Font: FontStore;
export const StyleSheet: {
create: (styles: T) => T;
};
export const version: any;
export const PDFRenderer: any;
export const pdf: (initialValue?: React.ReactElement) => {
container: any;
isDirty: () => boolean;
toString: () => string;
toBlob: () => Promise;
toBuffer: () => Promise;
on: (event: 'change', callback: () => void) => void;
updateContainer: (
document: React.ReactElement,
callback?: () => void,
) => void;
removeListener: (event: 'change', callback: () => void) => void;
};
export const renderToStream: (
document: React.ReactElement,
) => Promise;
/**
* @deprecated use the `renderToBuffer` method
*/
export const renderToString: (
document: React.ReactElement,
) => Promise;
export const renderToFile: (
document: React.ReactElement,
filePath: string,
callback?: (output: NodeJS.ReadableStream, _filePath: string) => any,
) => Promise;
const render: typeof renderToFile;
/**
* Render document into a nodejs buffer
* @platform node
*/
export const renderToBuffer: (
document: React.ReactElement,
) => Promise;
}
================================================
FILE: packages/renderer/package.json
================================================
{
"name": "@react-pdf/renderer",
"version": "4.3.2",
"license": "MIT",
"description": "Create PDF files on the browser and server",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/react-pdf.js",
"browser": {
"./lib/react-pdf.js": "./lib/react-pdf.browser.js"
},
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/renderer"
},
"scripts": {
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"size": "size-limit",
"lint": "eslint src",
"test": "vitest && vitest --config vitest.browser.config.js"
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@react-pdf/fns": "3.1.2",
"@react-pdf/font": "^4.0.4",
"@react-pdf/layout": "^4.4.2",
"@react-pdf/pdfkit": "^4.1.0",
"@react-pdf/primitives": "^4.1.1",
"@react-pdf/reconciler": "^2.0.0",
"@react-pdf/render": "^4.3.2",
"@react-pdf/types": "^2.9.2",
"events": "^3.3.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"queue": "^6.0.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"lint-staged": {
"*.js": [
"yarn lint",
"prettier --write"
]
},
"files": [
"lib",
"index.d.ts"
],
"collective": {
"type": "opencollective",
"url": "https://opencollective.com/react-pdf",
"logo": "https://opencollective.com/opencollective/logo.txt"
},
"devDependencies": {
"@size-limit/preset-big-lib": "^11.0.1",
"assert": "^2.0.0",
"browserify-zlib": "^0.2.0",
"buffer": "^6.0.3",
"process": "^0.11.10",
"size-limit": "^11.0.1",
"util": "^0.12.4"
}
}
================================================
FILE: packages/renderer/rollup.config.js
================================================
import json from '@rollup/plugin-json';
import babel from '@rollup/plugin-babel';
import nodeResolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import ignore from 'rollup-plugin-ignore';
import terser from '@rollup/plugin-terser';
import commonjs from '@rollup/plugin-commonjs';
import copy from 'rollup-plugin-copy';
import pkg from './package.json' with { type: 'json' };
const nodeInput = './src/node/index.js';
const domInput = './src/dom/index.js';
const babelConfig = () => ({
babelrc: true,
exclude: 'node_modules/**',
babelHelpers: 'runtime',
presets: [['@babel/preset-react', { runtime: 'automatic' }]],
});
const getExternal = ({ browser }) => [
/@babel\/runtime/,
'react/jsx-runtime',
...(browser ? [] : ['fs', 'path', 'url']),
...Object.keys(pkg.dependencies),
...Object.keys(pkg.peerDependencies),
];
const getPlugins = ({ browser, declarationDests, minify = false }) => [
json(),
...(browser ? [ignore(['fs', 'path', 'url'])] : []),
babel(babelConfig()),
commonjs(),
nodeResolve({ browser, preferBuiltins: !browser }),
replace({
preventAssignment: true,
values: {
BROWSER: JSON.stringify(browser),
},
}),
copy({
targets: declarationDests.map((destPath) => {
const [dest, rename] = destPath.split('/');
return { src: 'index.d.ts', dest, rename };
}),
}),
...(minify ? [terser()] : []),
];
const serverConfig = {
input: nodeInput,
output: { file: 'lib/react-pdf.js', format: 'es', sourcemap: true },
external: getExternal({ browser: false }),
plugins: getPlugins({
browser: false,
declarationDests: ['lib/react-pdf.d.ts', 'lib/react-pdf.d.cts'],
}),
};
const serverProdConfig = {
input: nodeInput,
output: { file: 'lib/react-pdf.min.js', sourcemap: false, format: 'es' },
external: getExternal({ browser: false }),
plugins: getPlugins({
browser: false,
declarationDests: ['lib/react-pdf.min.d.ts', 'lib/react-pdf.min.d.cts'],
minify: true,
}),
};
const browserConfig = {
input: domInput,
output: { file: 'lib/react-pdf.browser.js', format: 'es', sourcemap: true },
external: getExternal({ browser: true }),
plugins: getPlugins({
browser: true,
declarationDests: [
'lib/react-pdf.browser.d.ts',
'lib/react-pdf.browser.d.cts',
],
}),
};
const browserProdConfig = {
input: domInput,
output: { file: 'lib/react-pdf.browser.min.js', format: 'es' },
external: getExternal({ browser: true }),
plugins: getPlugins({
browser: true,
declarationDests: [
'lib/react-pdf.browser.min.d.ts',
'lib/react-pdf.browser.min.d.cts',
],
minify: true,
}),
};
export default [
serverConfig,
serverProdConfig,
browserConfig,
browserProdConfig,
];
================================================
FILE: packages/renderer/src/dom/BlobProvider.js
================================================
import { useEffect } from 'react';
import usePDF from './usePDF';
export const BlobProvider = ({ document: doc, children }) => {
const [instance, updateInstance] = usePDF();
useEffect(() => updateInstance(doc), [doc]);
if (!doc) {
console.warn('You should pass a valid document to BlobProvider');
return null;
}
return children(instance);
};
export default BlobProvider;
================================================
FILE: packages/renderer/src/dom/PDFDownloadLink.js
================================================
import { forwardRef, useEffect } from 'react';
import usePDF from './usePDF';
const PDFDownloadLinkBase = (
{
fileName = 'document.pdf',
document: doc,
children,
onClick,
href,
...rest
},
ref,
) => {
const [instance, updateInstance] = usePDF();
useEffect(() => updateInstance(doc), [doc]);
if (!doc) {
console.warn('You should pass a valid document to PDFDownloadLink');
return null;
}
const handleDownloadIE = () => {
if (instance && window.navigator.msSaveBlob) {
// IE
window.navigator.msSaveBlob(instance.blob, fileName);
}
};
const handleClick = (event) => {
handleDownloadIE();
if (typeof onClick === 'function') onClick(event, instance);
};
return (
{typeof children === 'function' ? children(instance) : children}
);
};
export const PDFDownloadLink = forwardRef(PDFDownloadLinkBase);
export default PDFDownloadLink;
================================================
FILE: packages/renderer/src/dom/PDFViewer.js
================================================
import { useEffect } from 'react';
import usePDF from './usePDF';
export const PDFViewer = ({
title,
style,
className,
children,
innerRef,
showToolbar = true,
...props
}) => {
const [instance, updateInstance] = usePDF();
useEffect(() => updateInstance(children), [children]);
const src = instance.url
? `${instance.url}#toolbar=${showToolbar ? 1 : 0}`
: null;
return (
);
};
export default PDFViewer;
================================================
FILE: packages/renderer/src/dom/index.js
================================================
import * as primitives from '@react-pdf/primitives';
import usePDF from './usePDF';
import PDFViewer from './PDFViewer';
import BlobProvider from './BlobProvider';
import PDFDownloadLink from './PDFDownloadLink';
import { pdf, version, Font, StyleSheet } from '../index';
const throwEnvironmentError = (name) => {
throw new Error(
`${name} is a Node specific API. You're either using this method in a browser, or your bundler is not loading react-pdf from the appropriate web build.`,
);
};
export const renderToStream = () => {
throwEnvironmentError('renderToStream');
};
export const renderToBuffer = () => {
throwEnvironmentError('renderToBuffer');
};
export const renderToString = () => {
throwEnvironmentError('renderToString');
};
export const renderToFile = () => {
throwEnvironmentError('renderToFile');
};
export const render = () => {
throwEnvironmentError('render');
};
export * from '../index';
export * from './usePDF';
export * from './PDFViewer';
export * from './BlobProvider';
export * from './PDFDownloadLink';
export * from '@react-pdf/primitives';
// TODO: remove this default export in next major release because it breaks tree-shacking
export default {
pdf,
usePDF,
Font,
version,
StyleSheet,
PDFViewer,
BlobProvider,
PDFDownloadLink,
renderToStream,
renderToString,
renderToFile,
render,
...primitives,
};
================================================
FILE: packages/renderer/src/dom/usePDF.js
================================================
import queue from 'queue';
import { useState, useRef, useEffect, useCallback } from 'react';
import { pdf } from '../index';
/**
* PDF hook
*
* @param {Object} [options] hook options
* @returns {[Object, Function]} pdf state and update function
*/
export const usePDF = ({ document } = {}) => {
const pdfInstance = useRef(null);
const [state, setState] = useState({
url: null,
blob: null,
error: null,
loading: !!document,
});
// Setup rendering queue
useEffect(() => {
const renderQueue = queue({ autostart: true, concurrency: 1 });
const queueDocumentRender = () => {
setState((prev) => ({ ...prev, loading: true }));
renderQueue.splice(0, renderQueue.length, () =>
state.error ? Promise.resolve() : pdfInstance.current.toBlob(),
);
};
const onRenderFailed = (error) => {
console.error(error);
setState((prev) => ({ ...prev, loading: false, error }));
};
const onRenderSuccessful = (blob) => {
setState({
blob,
error: null,
loading: false,
url: URL.createObjectURL(blob),
});
};
pdfInstance.current = pdf();
pdfInstance.current.on('change', queueDocumentRender);
if (document) {
pdfInstance.current.updateContainer(document);
}
renderQueue.on('error', onRenderFailed);
renderQueue.on('success', onRenderSuccessful);
return () => {
renderQueue.end();
pdfInstance.current.removeListener('change', queueDocumentRender);
};
}, []);
// Revoke old unused url instances
useEffect(() => {
return () => {
if (state.url) {
URL.revokeObjectURL(state.url);
}
};
}, [state.url]);
const update = useCallback((newDoc) => {
pdfInstance.current.updateContainer(newDoc);
}, []);
return [state, update];
};
export default usePDF;
================================================
FILE: packages/renderer/src/index.js
================================================
import FontStore from '@react-pdf/font';
import renderPDF from '@react-pdf/render';
import PDFDocument from '@react-pdf/pdfkit';
import layoutDocument from '@react-pdf/layout';
import { upperFirst } from '@react-pdf/fns';
import { omitNils } from './utils';
import createRenderer from './renderer';
import packageJson from '../package.json';
const { version } = packageJson;
const fontStore = new FontStore();
// We must keep a single renderer instance, otherwise React will complain
let renderer;
// The pdf instance acts as an event emitter for DOM usage.
// We only want to trigger an update when PDF content changes
const events = {};
const pdf = (initialValue) => {
const onChange = () => {
const listeners = events.change?.slice() || [];
for (let i = 0; i < listeners.length; i += 1) listeners[i]();
};
const container = { type: 'ROOT', document: null };
renderer = renderer || createRenderer({ onChange });
const mountNode = renderer.createContainer(container);
const updateContainer = (doc, callback) => {
renderer.updateContainer(doc, mountNode, null, callback);
};
if (initialValue) updateContainer(initialValue);
const render = async (compress = true) => {
const props = container.document.props || {};
const {
pdfVersion,
language,
pageLayout,
pageMode,
title,
author,
subject,
keyboards,
creator = 'react-pdf',
producer = 'react-pdf',
creationDate = new Date(),
modificationDate,
} = props;
const ctx = new PDFDocument({
compress,
pdfVersion,
lang: language,
displayTitle: true,
autoFirstPage: false,
info: omitNils({
Title: title,
Author: author,
Subject: subject,
Keywords: keyboards,
Creator: creator,
Producer: producer,
CreationDate: creationDate,
ModificationDate: modificationDate,
}),
});
if (pageLayout) {
ctx._root.data.PageLayout = upperFirst(pageLayout);
}
if (pageMode) {
ctx._root.data.PageMode = upperFirst(pageMode);
}
const layout = await layoutDocument(container.document, fontStore);
const fileStream = renderPDF(ctx, layout);
return { layout, fileStream };
};
const callOnRender = (params = {}) => {
if (container.document.props.onRender) {
container.document.props.onRender(params);
}
};
const toBlob = async () => {
const chunks = [];
const { layout: _INTERNAL__LAYOUT__DATA_, fileStream: instance } =
await render();
return new Promise((resolve, reject) => {
instance.on('data', (chunk) => {
chunks.push(
chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk),
);
});
instance.on('end', () => {
try {
const blob = new Blob(chunks, { type: 'application/pdf' });
callOnRender({ blob, _INTERNAL__LAYOUT__DATA_ });
resolve(blob);
} catch (error) {
reject(error);
}
});
});
};
// TODO: rename this method to `toStream` in next major release, because it return stream not a buffer
const toBuffer = async () => {
const { layout: _INTERNAL__LAYOUT__DATA_, fileStream } = await render();
callOnRender({ _INTERNAL__LAYOUT__DATA_ });
return fileStream;
};
/*
* TODO: remove this method in next major release. it is buggy
* see
* - https://github.com/diegomura/react-pdf/issues/2112
* - https://github.com/diegomura/react-pdf/issues/2095
*/
const toString = async () => {
if (process.env.NODE_ENV === 'development') {
console.warn(
'`toString` is deprecated and will be removed in next major release',
);
}
let result = '';
const { fileStream: instance } = await render(false); // For some reason, when rendering to string if compress=true the document is blank
return new Promise((resolve, reject) => {
try {
instance.on('data', (buffer) => {
result += buffer;
});
instance.on('end', () => {
callOnRender();
resolve(result);
});
} catch (error) {
reject(error);
}
});
};
const on = (event, listener) => {
if (!events[event]) events[event] = [];
events[event].push(listener);
};
const removeListener = (event, listener) => {
if (!events[event]) return;
const idx = events[event].indexOf(listener);
if (idx > -1) events[event].splice(idx, 1);
};
return {
on,
container,
toBlob,
toBuffer,
toString,
removeListener,
updateContainer,
};
};
const Font = fontStore;
const StyleSheet = {
create: (s) => s,
};
export { version, Font, StyleSheet, pdf, createRenderer };
================================================
FILE: packages/renderer/src/node/index.js
================================================
import * as primitives from '@react-pdf/primitives';
import { renderToFile, renderToStream, renderToString } from './renderTo';
import { pdf, version, Font, StyleSheet } from '../index';
const throwEnvironmentError = (name) => {
throw new Error(
`${name} is a web specific API. You're either using this component on Node, or your bundler is not loading react-pdf from the appropriate web build.`,
);
};
export const usePDF = () => {
throwEnvironmentError('usePDF');
};
export const PDFViewer = () => {
throwEnvironmentError('PDFViewer');
};
export const PDFDownloadLink = () => {
throwEnvironmentError('PDFDownloadLink');
};
export const BlobProvider = () => {
throwEnvironmentError('BlobProvider');
};
export const render = renderToFile;
export * from '../index';
export * from './renderTo';
export * from '@react-pdf/primitives';
// TODO: remove this default export in next major release because it breaks tree-shacking
export default {
pdf,
Font,
version,
StyleSheet,
usePDF,
PDFViewer,
BlobProvider,
PDFDownloadLink,
renderToStream,
renderToString,
renderToFile,
render,
...primitives,
};
================================================
FILE: packages/renderer/src/node/renderTo.js
================================================
import fs from 'fs';
import { Buffer } from 'buffer';
import { pdf } from '../index';
/**
* @param {React.ReactElement} element
* @returns {Promise}
*/
export const renderToStream = async (element) => {
const instance = pdf(element);
const stream = await instance.toBuffer();
return stream;
};
/**
* @param {React.ReactElement} element
* @param {string} filePath
* @param {Function} [callback]
*/
export const renderToFile = async (element, filePath, callback) => {
const output = await renderToStream(element);
const stream = fs.createWriteStream(filePath);
output.pipe(stream);
return new Promise((resolve, reject) => {
stream.on('finish', () => {
if (callback) callback(output, filePath);
resolve(output);
});
stream.on('error', reject);
});
};
/**
* @param {React.ReactElement} element
* @returns {Promise}
*/
export const renderToBuffer = (element) =>
renderToStream(element).then(
(stream) =>
new Promise((resolve, reject) => {
const chunks = [];
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('end', () => resolve(Buffer.concat(chunks)));
stream.on('error', (error) => reject(error));
}),
);
export const renderToString = (element) => {
if (process.env.NODE_ENV === 'development') {
console.warn(
'`renderToString` is deprecated and will be removed in next major release, use `renderToBuffer` instead',
);
}
return renderToBuffer(element).then((buffer) => buffer.toString());
};
================================================
FILE: packages/renderer/src/renderer.js
================================================
import Reconciler from '@react-pdf/reconciler';
const createInstance = (type, { style, children, ...props }) => ({
type,
box: {},
style: style || {},
props: props || {},
children: [],
});
const createTextInstance = (text) => ({ type: 'TEXT_INSTANCE', value: text });
const appendChild = (parent, child) => {
const isParentText =
parent.type === 'TEXT' ||
parent.type === 'LINK' ||
parent.type === 'TSPAN' ||
parent.type === 'NOTE';
const isChildTextInstance = child.type === 'TEXT_INSTANCE';
const isOrphanTextInstance = isChildTextInstance && !isParentText;
// Ignore orphan text instances.
// Caused by cases such as <>{name && {name} }>
if (isOrphanTextInstance) {
console.warn(
`Invalid '${child.value}' string child outside component`,
);
return;
}
parent.children.push(child);
};
const appendChildToContainer = (parentInstance, child) => {
if (parentInstance.type === 'ROOT') {
parentInstance.document = child;
} else {
appendChild(parentInstance, child);
}
};
const insertBefore = (parentInstance, child, beforeChild) => {
const index = parentInstance.children?.indexOf(beforeChild);
if (index === undefined) return;
if (index !== -1 && child) parentInstance.children.splice(index, 0, child);
};
const removeChild = (parentInstance, child) => {
const index = parentInstance.children?.indexOf(child);
if (index === undefined) return;
if (index !== -1) parentInstance.children.splice(index, 1);
};
const removeChildFromContainer = (parentInstance, child) => {
const index = parentInstance.children?.indexOf(child);
if (index === undefined) return;
if (index !== -1) parentInstance.children.splice(index, 1);
};
const commitTextUpdate = (textInstance, oldText, newText) => {
textInstance.value = newText;
};
const commitUpdate = (instance, updatePayload, type, oldProps, newProps) => {
const { style, ...props } = newProps;
instance.props = props;
instance.style = style;
};
const createRenderer = ({ onChange = () => {} }) =>
Reconciler({
appendChild,
appendChildToContainer,
commitTextUpdate,
commitUpdate,
createInstance,
createTextInstance,
insertBefore,
removeChild,
removeChildFromContainer,
resetAfterCommit: onChange,
});
export default createRenderer;
================================================
FILE: packages/renderer/src/utils.js
================================================
export const omitNils = (object) =>
Object.fromEntries(
Object.entries(object).filter(([, value]) => value !== undefined),
);
================================================
FILE: packages/renderer/tests/components.test.jsx
================================================
// Note that this file is ran using a separate Vitest configuration
import { describe, expect, it, vi } from 'vitest';
import { render, waitFor, screen } from '@testing-library/react';
import {
BlobProvider,
PDFViewer,
PDFDownloadLink,
Document,
Page,
Text,
} from '@react-pdf/renderer';
const TestDocument = ({ title = 'Default' }) => (
Hello tests
);
describe('BlobProvider', () => {
it('calls render function', async () => {
const renderFunction = vi.fn();
render(
}>{renderFunction},
);
await waitFor(() => expect(renderFunction).toBeCalledTimes(3));
expect(renderFunction).toHaveBeenCalledWith(
expect.objectContaining({
blob: expect.anything(),
url: expect.anything(),
error: null,
loading: false,
}),
);
});
it('renders iframe', async () => {
const { container } = render(
,
);
await waitFor(() => expect(container.querySelector('iframe')).toBeTruthy());
});
});
describe('PDFDownloadLink', () => {
it('works', async () => {
render( }>test);
const link = await screen.findByText('test');
expect(link.getAttribute('download')).toBe('document.pdf');
});
});
================================================
FILE: packages/renderer/tests/debug.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, View, Text, Font } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
// pdf.js does not render default fonts in node and I use Open Sans (:
Font.register({
family: 'Open Sans',
src: 'https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-UFVZ0e.ttf',
});
describe('debug', () => {
test('should show size of Text component', async () => {
const image = await renderToImage(
hello
,
);
expect(image).toMatchImageSnapshot();
});
test('should show paddings and margins', async () => {
const image = await renderToImage(
a
b
c
,
);
expect(image).toMatchImageSnapshot();
});
test('should show origin pointer', async () => {
const image = await renderToImage(
hello
,
);
expect(image).toMatchImageSnapshot();
});
test('should not render debug if false passed', async () => {
const image = await renderToImage(
hello
,
);
expect(image).toMatchImageSnapshot();
});
test('should not render debug if undefined passed', async () => {
const image = await renderToImage(
hello
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/dom.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import ReactPDF from '@react-pdf/renderer';
describe('dom', () => {
test('should export font store', () => {
expect(ReactPDF.Font).toBeTruthy();
});
test('should export styleSheet', () => {
expect(ReactPDF.StyleSheet).toBeTruthy();
});
test('should export version info', () => {
expect(ReactPDF.version).toBeTruthy();
});
test('should throw error when trying to use renderToString', () => {
expect(() => ReactPDF.renderToString()).toThrow();
});
test('should throw error when trying to use renderToStream', () => {
expect(() => ReactPDF.renderToStream()).toThrow();
});
test('should throw error when trying to use renderToFile', () => {
expect(() => ReactPDF.renderToFile()).toThrow();
});
});
================================================
FILE: packages/renderer/tests/emoji.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, Text, Font } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
describe('emoji', () => {
test('should support builder function', async () => {
Font.registerEmojiSource({
builder: (code) =>
`https://cdn.jsdelivr.net/gh/shuding/fluentui-emoji-unicode/assets/${code.toLowerCase()}_3d.png`,
});
const image = await renderToImage(
💩
,
);
expect(image).toMatchImageSnapshot();
});
test('should support Unicode 13.0 emoji', async () => {
Font.registerEmojiSource({
format: 'png',
url: 'https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/',
});
const image = await renderToImage(
🦫
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/environment/jsdom.js
================================================
import { builtinEnvironments } from 'vitest/environments';
function patchGlobals() {
if (typeof global.TextEncoder === 'undefined') {
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
}
if (typeof global.TextDecoder === 'undefined') {
global.TextDecoder = TextDecoder;
}
if (typeof global.URL.createObjectURL === 'undefined') {
global.URL.createObjectURL = (blob) => `[Blob - ${blob.size}]`;
}
if (typeof global.URL.revokeObjectURL === 'undefined') {
global.URL.revokeObjectURL = () => undefined;
}
}
export default {
name: 'jsdom',
transformMode: 'web',
async setupVM({ jsdom = {} }) {
const superSetup = builtinEnvironments.jsdom.setupVM;
const result = await superSetup({ jsdom });
patchGlobals();
return result;
},
async setup(global, { jsdom = {} }) {
const superSetup = builtinEnvironments.jsdom.setup;
const result = await superSetup(global, { jsdom });
patchGlobals();
return result;
},
};
================================================
FILE: packages/renderer/tests/flex.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, View } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const mount = async (children) => {
const image = await renderToImage(
{children}
,
);
return image;
};
describe('flex shorthand', () => {
test('should support auto', async () => {
const image = await mount(
,
);
expect(image).toMatchImageSnapshot();
});
test('should support flex-basis auto', async () => {
const image = await mount(
,
);
expect(image).toMatchImageSnapshot();
});
test('should do not grow on default', async () => {
const image = await mount(
,
);
expect(image).toMatchImageSnapshot();
});
test('should shrink on default', async () => {
const image = await mount(
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/gap.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, View } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const mount = async (children) => {
const image = await renderToImage(
{children}
,
);
return image;
};
const items = [
'red',
'red',
'red',
'green',
'green',
'green',
'blue',
'blue',
'blue',
];
describe('flex', () => {
test('should support gap', async () => {
const image = await mount(
{items.map((color, index) => (
))}
,
);
expect(image).toMatchImageSnapshot();
});
test('should support percentage gap', async () => {
const image = await mount(
{items.map((color, index) => (
))}
,
);
expect(image).toMatchImageSnapshot();
});
test('should support rowGap and columnGap', async () => {
const image = await mount(
{items.slice(0, 4).map((color, index) => (
))}
,
);
expect(image).toMatchImageSnapshot();
});
test('should support percentage rowGap and columnGap', async () => {
const image = await mount(
{items.map((color, index) => (
))}
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/images.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import fs from 'fs';
import url from 'url';
import path from 'path';
import { Document, Page, View, Image } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
const Orientation1 = fs.readFileSync(`${__dirname}/images/orientation-1.jpeg`);
const Orientation2 = fs.readFileSync(`${__dirname}/images/orientation-2.jpeg`);
const Orientation3 = fs.readFileSync(`${__dirname}/images/orientation-3.jpeg`);
const Orientation4 = fs.readFileSync(`${__dirname}/images/orientation-4.jpeg`);
const Orientation5 = fs.readFileSync(`${__dirname}/images/orientation-5.jpeg`);
const Orientation6 = fs.readFileSync(`${__dirname}/images/orientation-6.jpeg`);
const Orientation7 = fs.readFileSync(`${__dirname}/images/orientation-7.jpeg`);
const Orientation8 = fs.readFileSync(`${__dirname}/images/orientation-8.jpeg`);
const mount = async (children) => {
const image = await renderToImage(
{children}
,
);
return image;
};
describe('Image', () => {
test('should render jpgs with different exif orientations', async () => {
const image = await mount(
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/link.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, Link, Font, Text } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
// pdf.js does not render default fonts in node and I use Open Sans (:
Font.register({
family: 'Open Sans',
src: 'https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-UFVZ0e.ttf',
});
const mount = async (children) => {
const image = await renderToImage(
{children}
,
);
return image;
};
describe('Link', () => {
test('should render text', async () => {
const image = await mount(
hello
,
);
expect(image).toMatchImageSnapshot();
});
test('should render TEXT component', async () => {
const image = await mount(
he
llo
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/namedDestinations.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Font, Link, Page, Text, View } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
Font.register({
family: 'Lato',
src: 'https://fonts.gstatic.com/s/lato/v16/S6uyw4BMUTPHjx4wWw.ttf',
});
const Doc = () => (
Click me to get to the named destination
Here is the named destination
);
describe('named destinations', () => {
test('should visually match snapshot', async () => {
const image = await renderToImage( );
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/node.test.jsx
================================================
import { describe, expect, test, vi } from 'vitest';
import fs from 'fs';
import path from 'path';
import url from 'url';
import ReactPDF from '../src/node';
const { Document, Page, View } = ReactPDF;
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
/**
* @param {Object} props
*/
const TestDocument = ({ onRender }) => {
return (
);
};
describe('node', () => {
test('should render to string', async () => {
const document = await ReactPDF.renderToString( );
expect(typeof document).toBe('string');
expect(document.indexOf('%PDF-1.3')).toBe(0);
});
test('should render to string call render callback', async () => {
const mock = vi.fn();
await ReactPDF.renderToString( );
expect(mock.mock.calls).toHaveLength(1);
});
test('should render to stream', async () => {
const document = await ReactPDF.renderToStream( );
expect(typeof document).toBe('object');
expect(typeof document.pipe).toBe('function');
});
test('should render to stream call render callback', async () => {
const mock = vi.fn();
await ReactPDF.renderToStream( );
expect(mock.mock.calls).toHaveLength(1);
});
test('should render to file', async () => {
const pdfPath = `${__dirname}/test.pdf`;
await ReactPDF.renderToFile( , pdfPath);
expect(fs.existsSync(pdfPath)).toBeTruthy();
fs.unlinkSync(pdfPath);
});
test('should export font store', () => {
expect(ReactPDF.Font).toBeTruthy();
});
test('should export styleSheet', () => {
expect(ReactPDF.StyleSheet).toBeTruthy();
});
test('should export version info', () => {
expect(ReactPDF.version).toBeTruthy();
});
test('should throw error when trying to use PDFViewer', () => {
expect(() => ReactPDF.PDFViewer()).toThrow();
});
test('should throw error when trying to use PDFDownloadLink', () => {
expect(() => ReactPDF.PDFDownloadLink()).toThrow();
});
test('should throw error when trying to use BlobProvider', () => {
expect(() => ReactPDF.BlobProvider()).toThrow();
});
test('should throw error when trying to use usePDF', () => {
expect(() => ReactPDF.usePDF()).toThrow();
});
test('should render a fragment', async () => {
const mock = vi.fn();
const doc = (
<>
>
);
await ReactPDF.renderToString(doc);
expect(mock.mock.calls).toHaveLength(1);
});
test('should render a fragment in render', async () => {
const renderMock = vi.fn().mockReturnValue(
<>
>,
);
const doc = (
);
await ReactPDF.renderToString(doc);
expect(renderMock.mock.calls).toHaveLength(2);
});
test('should render a child array', async () => {
const mock = vi.fn();
const children = [
,
,
];
const doc = (
{children}
);
await ReactPDF.renderToString(doc);
expect(mock.mock.calls).toHaveLength(1);
});
test('should render a child array in render', async () => {
const children = [
,
,
];
const renderMock = vi.fn().mockReturnValue(children);
const doc = (
);
await ReactPDF.renderToString(doc);
expect(renderMock.mock.calls).toHaveLength(2);
});
test('should render nested dynamic views', async () => {
const renderNode = (
);
const renderMock = vi.fn().mockReturnValue(renderNode);
const doc = (
{
return ;
}}
/>
{
return (
{
return ;
}}
/>
);
}}
/>
);
await ReactPDF.renderToString(doc);
expect(renderMock.mock.calls).toHaveLength(6);
});
});
================================================
FILE: packages/renderer/tests/orphanTexts.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Text, Document, Page } from '@react-pdf/primitives';
import renderToImage from './renderComponent';
const emptyString = '';
const mount = async (children) => {
const image = await renderToImage(
{children}
,
);
return image;
};
describe('renderer', () => {
test('empty string', async () => {
const image = await mount(<>{emptyString && {emptyString} }>);
expect(image).toMatchImageSnapshot();
});
test('string', async () => {
const image = await mount(<>{'text' || text }>);
expect(image).toMatchImageSnapshot();
});
test('boolean', async () => {
const image = await mount(<>{true || text }>);
expect(image).toMatchImageSnapshot();
});
test('zero', async () => {
const image = await mount(<>{0 && text }>);
expect(image).toMatchImageSnapshot();
});
test('numbers', async () => {
const image = await mount(<>{10 || text }>);
expect(image).toMatchImageSnapshot();
});
test('empty text element', async () => {
const image = await mount( );
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/pageWrap.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import {
Document,
Font,
Page,
Text,
Image,
StyleSheet,
} from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const styles = StyleSheet.create({
body: {
paddingTop: 35,
paddingBottom: 65,
paddingHorizontal: 35,
},
title: {
fontSize: 24,
textAlign: 'center',
fontFamily: 'Oswald',
},
author: {
fontSize: 12,
textAlign: 'center',
marginBottom: 40,
},
subtitle: {
fontSize: 18,
margin: 12,
fontFamily: 'Oswald',
},
text: {
fontFamily: 'Open Sans',
margin: 12,
fontSize: 14,
textAlign: 'justify',
},
image: {
marginVertical: 15,
marginHorizontal: 100,
},
header: {
fontFamily: 'Open Sans',
fontSize: 12,
marginBottom: 20,
textAlign: 'center',
color: 'grey',
},
pageNumber: {
fontFamily: 'Open Sans',
position: 'absolute',
fontSize: 12,
bottom: 30,
left: 0,
right: 0,
textAlign: 'center',
color: 'grey',
},
});
Font.register({
family: 'Oswald',
src: 'https://fonts.gstatic.com/s/oswald/v13/Y_TKV6o8WovbUd3m_X9aAA.ttf',
});
Font.register({
family: 'Open Sans',
src: 'https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-UFVZ0e.ttf',
});
const Subtitle = ({ children, ...props }) => (
{children}
);
const PageWrap = () => (
~ Created with react-pdf ~
Don Quijote de la Mancha
Miguel de Cervantes
Capítulo I: Que trata de la condición y ejercicio del famoso hidalgo D.
Quijote de la Mancha
En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha
mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga
antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que
carnero, salpicón las más noches, duelos y quebrantos los sábados,
lentejas los viernes, algún palomino de añadidura los domingos,
consumían las tres partes de su hacienda. El resto della concluían sayo
de velarte, calzas de velludo para las fiestas con sus pantuflos de lo
mismo, los días de entre semana se honraba con su vellori de lo más
fino. Tenía en su casa una ama que pasaba de los cuarenta, y una sobrina
que no llegaba a los veinte, y un mozo de campo y plaza, que así
ensillaba el rocín como tomaba la podadera. Frisaba la edad de nuestro
hidalgo con los cincuenta años, era de complexión recia, seco de carnes,
enjuto de rostro; gran madrugador y amigo de la caza. Quieren decir que
tenía el sobrenombre de Quijada o Quesada (que en esto hay alguna
diferencia en los autores que deste caso escriben), aunque por
conjeturas verosímiles se deja entender que se llama Quijana; pero esto
importa poco a nuestro cuento; basta que en la narración dél no se salga
un punto de la verdad.
Es, pues, de saber, que este sobredicho hidalgo, los ratos que estaba
ocioso (que eran los más del año) se daba a leer libros de caballerías
con tanta afición y gusto, que olvidó casi de todo punto el ejercicio de
la caza, y aun la administración de su hacienda; y llegó a tanto su
curiosidad y desatino en esto, que vendió muchas hanegas de tierra de
sembradura, para comprar libros de caballerías en que leer; y así llevó
a su casa todos cuantos pudo haber dellos; y de todos ningunos le
parecían tan bien como los que compuso el famoso Feliciano de Silva:
porque la claridad de su prosa, y aquellas intrincadas razones suyas, le
parecían de perlas; y más cuando llegaba a leer aquellos requiebros y
cartas de desafío, donde en muchas partes hallaba escrito: la razón de
la sinrazón que a mi razón se hace, de tal manera mi razón enflaquece,
que con razón me quejo.
Con estas y semejantes razones perdía el pobre caballero el juicio, y
desvelábase por entenderlas, y desentrañarles el sentido, que no se lo
sacara, ni las entendiera el mismo Aristóteles, si resucitara para sólo
ello. No estaba muy bien con las heridas que don Belianis daba y
recibía, porque se imaginaba que por grandes maestros que le hubiesen
curado, no dejaría de tener el rostro y todo el cuerpo lleno de
cicatrices y señales; pero con todo alababa en su autor aquel acabar su
libro con la promesa de aquella inacabable aventura, y muchas veces le
vino deseo de tomar la pluma, y darle fin al pie de la letra como allí
se promete; y sin duda alguna lo hiciera, y aun saliera con ello, si
otros mayores y continuos pensamientos no se lo estorbaran. Tuvo muchas
veces competencia con el cura de su lugar (que era hombre docto graduado
en Sigüenza), sobre cuál había sido mejor caballero, Palmerín de
Inglaterra o Amadís de Gaula; mas maese Nicolás, barbero del mismo
pueblo, decía que ninguno llegaba al caballero del Febo, y que si alguno
se le podía comparar, era don Galaor, hermano de Amadís de Gaula, porque
tenía muy acomodada condición para todo; que no era caballero
melindroso, ni tan llorón como su hermano, y que en lo de la valentía no
le iba en zaga.
En resolución, él se enfrascó tanto en su lectura, que se le pasaban las
noches leyendo de claro en claro, y los días de turbio en turbio, y así,
del poco dormir y del mucho leer, se le secó el cerebro, de manera que
vino a perder el juicio. Llenósele la fantasía de todo aquello que leía
en los libros, así de encantamientos, como de pendencias, batallas,
desafíos, heridas, requiebros, amores, tormentas y disparates
imposibles, y asentósele de tal modo en la imaginación que era verdad
toda aquella máquina de aquellas soñadas invenciones que leía, que para
él no había otra historia más cierta en el mundo.
Capítulo II: Que trata de la primera salida que de su tierra hizo el
ingenioso Don Quijote
Hechas, pues, estas prevenciones, no quiso aguardar más tiempo a poner
en efeto su pensamiento, apretándole a ello la falta que él pensaba que
hacía en el mundo su tardanza, según eran los agravios que pensaba
deshacer, tuertos que enderezar, sinrazones que emendar y abusos que
mejorar y deudas que satisfacer. Y así, sin dar parte a persona alguna
de su intención y sin que nadie le viese, una mañana, antes del día, que
era uno de los calurosos del mes de Julio, se armó de todas sus armas,
subió sobre Rocinante, puesta su mal compuesta celada, embrazó su
adarga, tomó su lanza y por la puerta falsa de un corral salió al campo
con grandísimo contento y alborozo de ver con cuánta facilidad había
dado principio a su buen deseo. Mas apenas se vio en el campo cuando le
asaltó un pensamiento terrible, y tal, que por poco le hiciera dejar la
comenzada empresa; y fue que le vino a la memoria que no era armado
caballero, y que, conforme a ley de caballería, ni podía ni debía tomar
armas con ningún caballero; y puesto que lo fuera, había de llevar armas
blancas, como novel caballero, sin empresa en el escudo, hasta que por
su esfuerzo la ganase. Estos pensamientos le hicieron titubear en su
propósito; mas pudiendo más su locura que otra razón alguna, propuso de
hacerse armar caballero del primero que topase, a imitación de otros
muchos que así lo hicieron, según él había leído en los libros que tal
le tenían. En lo de las armas blancas, pensaba limpiarlas de manera, en
teniendo lugar, que lo fuesen más que un arminio; y con esto se quietó y
prosiguió su camino, sin llevar otro que aquel que su caballo quería,
creyendo que en aquello consistía la fuerza de las aventuras
Yendo, pues, caminando nuestro flamante aventurero, iba hablando consigo
mesmo, y diciendo: —¿Quién duda, sino que en los venideros tiempos,
cuando salga a luz la verdadera historia de mis famosos hechos, que el
sabio que los escribiere no ponga, cuando llegue a contar esta mi
primera salida tan de mañana, desta manera?: Apenas había el rubicundo
Apolo tendido por la faz de la ancha y espaciosa tierra las doradas
hebras de sus hermosos cabellos, y apenas los pequeños y pintados
pajarillos con sus arpadas lenguas habían saludado con dulce y meliflua
armonía la venida de la rosada Aurora, que, dejando la blanda cama del
celoso marido, por las puertas y balcones del manchego horizonte a los
mortales se mostraba, cuando el famoso caballero don Quijote de la
Mancha, dejando las ociosas plumas, subió sobre su famoso caballo
Rocinante y comenzó a caminar por el antiguo y conocido Campo de
Montiel.
Y era la verdad que por él caminaba; y añadió diciendo: —Dichosa edad y
siglo dichoso aquel adonde saldrán a luz las famosas hazañas mías,
dignas de entallarse en bronces, esculpirse en mármoles y pintarse en
tablas, para memoria en lo futuro. ¡Oh tú, sabio encantador, quienquiera
que seas, a quien ha de tocar el ser coronista desta peregrina historia!
Ruégote que no te olvides de mi buen Rocinante, compañero eterno mío en
todos mis caminos y carreras.
Luego volvía diciendo, como si verdaderamente fuera enamorado: —¡Oh
princesa Dulcinea, señora deste cautivo corazón! Mucho agravio me
habedes fecho en despedirme y reprocharme con el riguroso afincamiento
de mandarme no parecer ante la vuestra fermosura. Plégaos, señora, de
membraros deste vuestro sujeto corazón, que tantas cuitas por vuestro
amor padece. Con estos iba ensartando otros disparates, todos al modo de
los que sus libros le habían enseñado, imitando en cuanto podía su
lenguaje. Con esto caminaba tan despacio, y el sol entraba tan apriesa y
con tanto ardor, que fuera bastante a derretirle los sesos, si algunos
tuviera
Casi todo aquel día caminó sin acontecerle cosa que de contar fuese, de
lo cual se desesperaba, porque quisiera topar luego luego con quien
hacer experiencia del valor de su fuerte brazo. Autores hay que dicen
que la primera aventura que le avino fue la del Puerto Lápice, otros
dicen que la de los molinos de viento; pero lo que yo he podido
averiguar en este caso, y lo que he hallado escrito en los anales de la
Mancha, es que él anduvo todo aquel día, y, al anochecer, su rocín y él
se hallaron cansados y muertos de hambre, y que, mirando a todas partes
por ver si descubriría algún castillo o alguna majada de pastores donde
recogerse y adonde pudiese remediar su mucha hambre y necesidad, vio, no
lejos del camino por donde iba, una venta, que fue como si viera una
estrella que, no a los portales, sino a los alcázares de su redención le
encaminaba. Diose priesa a caminar, y llegó a ella a tiempo que
anochecía.
`${pageNumber} / ${totalPages}`}
fixed
/>
);
describe('pageWrap', () => {
test('should match snapshot', async () => {
const image = await renderToImage( );
expect(image).toMatchImageSnapshot();
}, 30_000);
});
================================================
FILE: packages/renderer/tests/renderComponent.js
================================================
import Canvas from 'canvas';
import pdfjs from 'pdfjs-dist/legacy/build/pdf';
import { renderToBuffer } from '@react-pdf/renderer';
/**
* copy-pasted code from
* https://github.com/mozilla/pdf.js/blob/master/examples/node/pdf2png/pdf2png.js#L20-L49
*/
const NodeCanvasFactory = {
create(width, height) {
const canvas = Canvas.createCanvas(width, height);
const context = canvas.getContext('2d');
return {
canvas,
context,
};
},
reset(canvasAndContext, width, height) {
canvasAndContext.canvas.width = width;
canvasAndContext.canvas.height = height;
},
destroy(canvasAndContext) {
canvasAndContext.canvas.width = 0;
canvasAndContext.canvas.height = 0;
canvasAndContext.canvas = null;
canvasAndContext.context = null;
},
};
async function getCanvas(pagePromise) {
const page = await pagePromise;
const viewport = page.getViewport({ scale: 1.0 });
const canvasFactory = NodeCanvasFactory;
const { canvas, context } = canvasFactory.create(
viewport.width,
viewport.height,
);
const renderContext = {
canvasContext: context,
viewport,
canvasFactory,
};
const renderTask = page.render(renderContext);
await renderTask.promise;
return canvas;
}
const GAP = 10;
const composeCanvases = (canvases) => {
const [maxWidth, maxHeight] = canvases.reduce(
([width, height], canvas) => [
Math.max(width, canvas.width),
Math.max(height, canvas.height),
],
[0, 0],
);
const resultCanvas = Canvas.createCanvas(
maxWidth,
maxHeight * canvases.length + GAP * (canvases.length - 1),
);
const resultContext = resultCanvas.getContext('2d');
canvases.forEach((canvas, index) => {
if (index) {
resultContext.fillStyle = '#e2e2e2';
resultContext.fillRect(
0,
maxHeight * index + GAP * (index - 1),
maxWidth,
GAP,
);
}
resultContext.drawImage(canvas, 0, maxHeight * index + GAP * index);
});
return resultCanvas;
};
/**
* Generates a array with numbers from 0 to length-1
* @param {number} length — size of array
* @returns {number[]} array
*/
const range = (length) => Array.from({ length }, (_, index) => index);
const renderComponent = async (element) => {
const source = await renderToBuffer(element);
const document = await pdfjs.getDocument({
data: source,
verbosity: 0,
}).promise;
const pages = range(document.numPages).map((pageIndex) =>
document.getPage(pageIndex + 1),
);
if (pages.length === 1) {
return (await getCanvas(pages[0])).toBuffer();
}
const canvases = await Promise.all(pages.map((page) => getCanvas(page)));
const pageSnapshots = composeCanvases(canvases);
return pageSnapshots.toBuffer();
};
export default renderComponent;
================================================
FILE: packages/renderer/tests/resume.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import {
Link,
Text,
Font,
Page,
View,
Image,
Document,
StyleSheet,
} from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const headerStyles = StyleSheet.create({
container: {
flexDirection: 'row',
borderBottomWidth: 2,
borderBottomColor: '#112131',
borderBottomStyle: 'solid',
alignItems: 'stretch',
},
detailColumn: {
flexDirection: 'column',
flexGrow: 9,
textTransform: 'uppercase',
},
linkColumn: {
flexDirection: 'column',
flexGrow: 2,
alignSelf: 'flex-end',
justifySelf: 'flex-end',
},
name: {
fontSize: 24,
fontFamily: 'Lato Bold',
},
subtitle: {
fontSize: 10,
justifySelf: 'flex-end',
fontFamily: 'Lato',
},
link: {
fontFamily: 'Lato',
fontSize: 10,
color: 'black',
textDecoration: 'none',
alignSelf: 'flex-end',
justifySelf: 'flex-end',
},
});
const Header = () => (
Luke Skywalker
Jedi Master
luke@theforce.com
);
const titleStyles = StyleSheet.create({
title: {
fontFamily: 'Lato Bold',
fontSize: 14,
marginBottom: 10,
textTransform: 'uppercase',
},
});
const Title = ({ children }) => (
{children}
);
const listStyles = StyleSheet.create({
item: {
flexDirection: 'row',
marginBottom: 5,
},
bulletPoint: {
fontFamily: 'Lato',
width: 10,
fontSize: 10,
},
itemContent: {
flex: 1,
fontSize: 10,
fontFamily: 'Lato',
},
});
const List = ({ children }) => children;
const Item = ({ children }) => (
•
{children}
);
const skilsStyles = StyleSheet.create({
title: {
fontFamily: 'Lato Bold',
fontSize: 11,
marginBottom: 10,
},
skills: {
fontFamily: 'Lato',
fontSize: 10,
marginBottom: 10,
},
});
const SkillEntry = ({ name, skills }) => (
{name}
{skills.map((skill, i) => (
- {skill}
))}
);
const Skills = () => (
Skills
);
const educationStyles = StyleSheet.create({
container: {
marginBottom: 10,
},
school: {
fontFamily: 'Lato Bold',
fontSize: 10,
},
degree: {
fontFamily: 'Lato',
fontSize: 10,
},
candidate: {
fontFamily: 'Lato Italic',
fontSize: 10,
},
});
const Education = () => (
Education
Jedi Academy
Jedi Master
A long, long time ago
);
const expStyles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 30,
paddingLeft: 15,
'@media max-width: 400': {
paddingTop: 10,
paddingLeft: 0,
},
},
entryContainer: {
marginBottom: 10,
},
date: {
fontSize: 11,
fontFamily: 'Lato Italic',
},
detailLeftColumn: {
flexDirection: 'column',
marginLeft: 10,
marginRight: 10,
},
detailRightColumn: {
flexDirection: 'column',
flexGrow: 9,
},
bulletPoint: {
fontSize: 10,
},
details: {
fontSize: 10,
fontFamily: 'Lato',
},
headerContainer: {
flexDirection: 'row',
marginBottom: 10,
},
leftColumn: {
flexDirection: 'column',
flexGrow: 9,
},
rightColumn: {
flexDirection: 'column',
flexGrow: 1,
alignItems: 'flex-end',
justifySelf: 'flex-end',
},
title: {
fontSize: 11,
color: 'black',
textDecoration: 'none',
fontFamily: 'Lato Bold',
},
});
const ExperienceEntry = ({ company, details, position, date }) => {
const title = `${company} | ${position}`;
return (
{title}
{date}
{details.map((detail, i) => (
- {detail}
))}
);
};
const experienceData = [
{
company: 'Jedi Temple, Coruseant',
date: 'A long time ago...',
details: [
'Started a new Jedi Temple in order to train the next generation of Jedi Masters',
'Discovered and trained a new generation of Jedi Knights, which he recruited from within the New Republic',
'Communicates with decesased Jedi Masters such as Anakin Skywalker, Yoda, Obi-Wan Kenobi in order to learn the secrets of the Jedi Order',
],
position: 'Head Jedi Master',
},
{
company: 'Rebel Alliance',
date: 'A long time ago...',
details: [
'Lead legions of troops into battle while demonstrating bravery, competence and honor',
'Created complicated battle plans in conjunction with other Rebel leaders in order to ensure the greatest chance of success',
'Defeated Darth Vader in single-combat, and convinced him to betray his mentor, the Emperor',
],
position: 'General',
},
{
company: 'Rebel Alliance',
date: 'A long time ago...',
details: [
'Destroyed the Death Star by using the force to find its only weakness and delivering a torpedo into the center of the ship',
'Commanded of squadron of X-Wings into battle',
'Defeated an enemy AT-AT single handedly after his ship was destroyed',
'Awarded a medal for valor and bravery in battle for his successful destruction of the Death Star',
],
position: 'Lieutenant Commander',
},
{
company: 'Tatooine Moisture Refinery',
date: 'A long time ago...',
details: [
'Replaced damaged power converters',
'Performed menial labor thoughout the farm in order to ensure its continued operation',
],
position: 'Moisture Farmer',
},
];
const Experience = () => (
Experience
{experienceData.map(({ company, date, details, position }) => (
))}
);
const resumeStyles = StyleSheet.create({
page: {
padding: 30,
},
container: {
flex: 1,
flexDirection: 'row',
'@media max-width: 400': {
flexDirection: 'column',
},
},
image: {
marginBottom: 10,
},
leftColumn: {
flexDirection: 'column',
width: 170,
paddingTop: 30,
paddingRight: 15,
'@media max-width: 400': {
width: '100%',
paddingRight: 0,
},
'@media orientation: landscape': {
width: 200,
},
},
footer: {
fontSize: 12,
fontFamily: 'Lato Bold',
textAlign: 'center',
marginTop: 15,
paddingTop: 5,
borderWidth: 3,
borderColor: 'gray',
borderStyle: 'dashed',
'@media orientation: landscape': {
marginTop: 10,
},
},
});
Font.register({
family: 'Open Sans',
src: 'https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-UFVZ0e.ttf',
});
Font.register({
family: 'Lato',
src: 'https://fonts.gstatic.com/s/lato/v16/S6uyw4BMUTPHjx4wWw.ttf',
});
Font.register({
family: 'Lato Italic',
src: 'https://fonts.gstatic.com/s/lato/v16/S6u8w4BMUTPHjxsAXC-v.ttf',
});
Font.register({
family: 'Lato Bold',
src: 'https://fonts.gstatic.com/s/lato/v16/S6u9w4BMUTPHh6UVSwiPHA.ttf',
});
const Resume = (props) => (
This IS the candidate you are looking for
);
describe('resume', () => {
test('should match snapshot', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should match snapshot', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should match snapshot', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/svg.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, Svg, Font, Text, Tspan } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
import { Tiger, Chart, Chart2, Gradients, Dasharrays } from './svgs';
// pdf.js does not render default fonts in node and I use Open Sans (:
Font.register({
family: 'Open Sans',
src: 'https://fonts.gstatic.com/s/opensans/v17/mem8YaGs126MiZpBA-UFVZ0e.ttf',
});
describe('Svg', () => {
test('should render Tspan component', async () => {
const image = await renderToImage(
hello{' '}
world
,
);
expect(image).toMatchImageSnapshot();
});
test('should render Tiger', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should render Chart', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should render Chart2', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should render Gradients', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should render Dasharrays', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/svgs.jsx
================================================
import {
Svg,
G,
Polygon,
Rect,
Circle,
Path,
Text,
Tspan,
Defs,
ClipPath,
LinearGradient,
RadialGradient,
Stop,
Line,
} from '@react-pdf/renderer';
export const Tiger = () => (
);
export const Chart = () => (
USD
USD
EUR
EUR
CHF
CHF
);
export const Chart2 = () => (
2015
2016
2017
2018
2019
0%
5%
10%
15%
20%
25%
30%
35%
Zoom
YTD
All
From
Nov 17, 2014
To
Nov 22, 2019
);
export const Gradients = () => (
);
export const Dasharrays = () => (
);
================================================
FILE: packages/renderer/tests/text.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import {
Document,
Page,
View,
Text,
Link,
Font,
StyleSheet,
} from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const styles = StyleSheet.create({
title: {
margin: 20,
fontSize: 25,
textAlign: 'center',
backgroundColor: '#e4e4e4',
textTransform: 'uppercase',
fontFamily: 'Oswald',
},
body: {
flexGrow: 1,
},
row: {
flexGrow: 1,
flexDirection: 'row',
},
block: {
flexGrow: 1,
},
text: {
width: '60%',
margin: 10,
fontFamily: 'Oswald',
textAlign: 'justify',
},
fill1: {
width: '40%',
backgroundColor: '#e14427',
},
fill2: {
flexGrow: 2,
backgroundColor: '#e6672d',
},
fill3: {
flexGrow: 2,
backgroundColor: '#e78632',
},
fill4: {
flexGrow: 2,
backgroundColor: '#e29e37',
},
});
Font.register({
family: 'Oswald',
src: 'https://fonts.gstatic.com/s/oswald/v13/Y_TKV6o8WovbUd3m_X9aAA.ttf',
});
const TextTest = () => (
Lorem Ipsum
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum.
);
describe('text', () => {
test('should match snapshot', async () => {
const image = await renderToImage( );
expect(image).toMatchImageSnapshot();
});
test('should support verticalAlign super and sub', async () => {
const image = await renderToImage(
Lorem
ipsum
dolor
,
);
expect(image).toMatchImageSnapshot();
});
test('should hyphenate text with soft hyphen', async () => {
const shy = '\u00ad';
const style = {
text: {
fontFamily: 'Oswald',
fontSize: 20,
width: 100,
border: '1px solid red',
},
};
const image = await renderToImage(
{`Potentieel broeikas${shy}gas${shy}emissie${shy}rapport`}
{`Potentieel broeikas${shy}gasemissie${shy}rapport`}
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/transform.test.jsx
================================================
import { describe, expect, test } from 'vitest';
import { Document, Page, View } from '@react-pdf/renderer';
import renderToImage from './renderComponent';
const TestDocument = ({ transform, width = 20, height = 20 }) => {
return (
);
};
describe('transform', () => {
test('should scale with two args', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should scale with one arg', async () => {
const image = await renderToImage( );
expect(image).toMatchImageSnapshot();
});
test('should scale on X axis', async () => {
const image = await renderToImage( );
expect(image).toMatchImageSnapshot();
});
test('should scale on Y axis', async () => {
const image = await renderToImage( );
expect(image).toMatchImageSnapshot();
});
test('should translate to zero px', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should translate on X axis', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should translate on Y axis', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should translate on both axis', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
test('should rotate', async () => {
const image = await renderToImage(
,
);
expect(image).toMatchImageSnapshot();
});
});
================================================
FILE: packages/renderer/tests/usePDF.test.jsx
================================================
// Note that this file is ran using a separate Vitest configuration
import { expect, it } from 'vitest';
import { renderHook, waitFor, act } from '@testing-library/react';
import { usePDF, Document, Page, Text } from '@react-pdf/renderer';
const TestDocument = ({ title = 'Default' }) => (
Hello tests
);
it('returns value, updater tuple', () => {
const { result } = renderHook(() => usePDF({ document: undefined }));
expect(Array.isArray(result.current)).toBeTruthy();
expect(result.current[0]).toMatchObject(
expect.objectContaining({
url: null,
blob: null,
error: null,
loading: false,
}),
);
expect(typeof result.current[1]).toBe('function');
});
it('works with no args', () => {
const { result } = renderHook(() => usePDF());
expect(Array.isArray(result.current)).toBeTruthy();
expect(typeof result.current[0]).toBe('object');
expect(typeof result.current[1]).toBe('function');
});
it('renders document', async () => {
const { result } = renderHook(() => usePDF({ document: }));
await waitFor(() => expect(result.current[0].loading).toBeFalsy());
});
it('updates document', async () => {
const { result } = renderHook(() => usePDF({ document: }));
await waitFor(() => expect(result.current[0].loading).toBeFalsy());
const pdfSize = result.current[0].blob.size;
act(() => result.current[1]( ));
await waitFor(() => expect(result.current[0].loading).toBeFalsy());
expect(result.current[0].blob.size).not.toEqual(pdfSize);
});
================================================
FILE: packages/renderer/vitest.browser.config.js
================================================
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias:
process.env.REACT_VERSION && process.env.REACT_VERSION !== '18'
? [
{
find: 'react/jsx-dev-runtime',
replacement: `react-${process.env.REACT_VERSION}/jsx-dev-runtime`,
},
{
find: 'react',
replacement: `react-${process.env.REACT_VERSION}`,
},
{
find: 'react-dom',
replacement: `react-dom-${process.env.REACT_VERSION}`,
},
]
: undefined,
conditions: ['browser'],
mainFields: ['browser'],
},
test: {
environment: './tests/environment/jsdom.js',
setupFiles: ['vitest.setup.js'],
include: ['tests/{components,dom,usePDF}.test.*'],
watch: false,
},
});
================================================
FILE: packages/renderer/vitest.config.js
================================================
import { defineConfig, defaultExclude } from 'vitest/config';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias:
process.env.REACT_VERSION && process.env.REACT_VERSION !== '18'
? [
{
find: 'react/jsx-dev-runtime',
replacement: `react-${process.env.REACT_VERSION}/jsx-dev-runtime`,
},
{
find: 'react',
replacement: `react-${process.env.REACT_VERSION}`,
},
{
find: 'react-dom',
replacement: `react-dom-${process.env.REACT_VERSION}`,
},
]
: undefined,
},
test: {
// Necessary to avoid "Module did not self-register" error with canvas.node
pool: 'forks',
setupFiles: ['vitest.setup.js'],
include: ['tests/*.{test,spec}.?(c|m)[jt]s?(x)'],
exclude: [...defaultExclude, 'tests/{components,dom,usePDF}.test.*'],
watch: false,
},
});
================================================
FILE: packages/renderer/vitest.setup.js
================================================
import { expect } from 'vitest';
import path from 'path';
import url from 'url';
import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
import React from 'react';
import ReactDOM from 'react-dom';
console.log(`Using React ${React.version} + ReactDOM ${ReactDOM.version}`);
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
const toMatchImageSnapshot = configureToMatchImageSnapshot({
customSnapshotsDir: `${__dirname}/tests/snapshots`,
customDiffDir: `${__dirname}/tests/diffs`,
});
expect.extend({ toMatchImageSnapshot });
================================================
FILE: packages/stylesheet/.gitignore
================================================
lib
================================================
FILE: packages/stylesheet/CHANGELOG.md
================================================
# @react-pdf/stylesheet
## 6.1.2
### Patch Changes
- Updated dependencies []:
- @react-pdf/types@2.9.2
## 6.1.1
### Patch Changes
- Updated dependencies []:
- @react-pdf/types@2.9.1
## 6.1.0
### Minor Changes
- [#3112](https://github.com/diegomura/react-pdf/pull/3112) [`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a) Thanks [@diegomura](https://github.com/diegomura)! - feat: add xLinkHref, gradientTransform and gradientUnits support
### Patch Changes
- Updated dependencies [[`f89f75c1`](https://github.com/diegomura/react-pdf/commit/f89f75c1f132ba19b54847c3ac23efec675f8d0a)]:
- @react-pdf/types@2.9.0
## 6.0.2
### Patch Changes
- Updated dependencies []:
- @react-pdf/types@2.8.2
## 6.0.1
### Patch Changes
- [#3099](https://github.com/diegomura/react-pdf/pull/3099) [`2a4f1bfc`](https://github.com/diegomura/react-pdf/commit/2a4f1bfca6b84e6c6bbde683447ce8079a1febbe) Thanks [@diegomura](https://github.com/diegomura)! - refactor: stylesheet types
- [#3098](https://github.com/diegomura/react-pdf/pull/3098) [`bfb51ec0`](https://github.com/diegomura/react-pdf/commit/bfb51ec09b851c52659ce16fed1286173e9516a9) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert render package to TS
- [#3092](https://github.com/diegomura/react-pdf/pull/3092) [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8) Thanks [@diegomura](https://github.com/diegomura)! - refactor: convert layout package to TS
- Updated dependencies [[`7cd66e4f`](https://github.com/diegomura/react-pdf/commit/7cd66e4fc37cd1393adc6250a919fe2629812082), [`481b536f`](https://github.com/diegomura/react-pdf/commit/481b536f4ad145fb227829399b85a35838a506f8)]:
- @react-pdf/types@2.8.1
- @react-pdf/fns@3.1.2
## 6.0.0
### Major Changes
- [#3082](https://github.com/diegomura/react-pdf/pull/3082) [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45) Thanks [@diegomura](https://github.com/diegomura)! - feat: rework and type stylesheet package
### Patch Changes
- Updated dependencies [[`96c2464d`](https://github.com/diegomura/react-pdf/commit/96c2464dfaa7294e0d79b7ed64743bfd7b1a8c72), [`24fe4bf8`](https://github.com/diegomura/react-pdf/commit/24fe4bf894fff055121926488b30d0bf212a9c45), [`700535c5`](https://github.com/diegomura/react-pdf/commit/700535c57ff1b105d923be70f4fc4bfdf4479f91), [`442ce355`](https://github.com/diegomura/react-pdf/commit/442ce35534f916b9146a35fd03870387ed488d92), [`3007d34a`](https://github.com/diegomura/react-pdf/commit/3007d34ad3e10bf32ada3631938f5bb08e1c549f)]:
- @react-pdf/types@2.8.0
- @react-pdf/fns@3.1.1
## 5.2.2
### Patch Changes
- Updated dependencies [[`d36ace66`](https://github.com/diegomura/react-pdf/commit/d36ace66c77d57d845894e89772be7ae0cdd25ee)]:
- @react-pdf/fns@3.1.0
## 5.2.1
### Patch Changes
- Updated dependencies [[`01944231`](https://github.com/diegomura/react-pdf/commit/01944231a342d502b832aeecb4c313020b8360c8)]:
- @react-pdf/types@2.7.1
## 5.2.0
### Minor Changes
- [#2773](https://github.com/diegomura/react-pdf/pull/2773) [`18834efa`](https://github.com/diegomura/react-pdf/commit/18834efac2787a636c378718fee40cbe74f01ab8) Thanks [@nikischin](https://github.com/nikischin)! - Changed unit behavior according to PDF spec. Please note that all unitless values are considered as user unit which is a 72dpi equality of the value. This is according to PDF spec and ensures a consistent layout independent of the dpi setting.
## 5.1.0
### Minor Changes
- [#2955](https://github.com/diegomura/react-pdf/pull/2955) [`425f1183`](https://github.com/diegomura/react-pdf/commit/425f1183bba9a83fd5712a1371abb6cea2ed8fca) Thanks [@diegomura](https://github.com/diegomura)! - feat: support rem units
### Patch Changes
- [#2952](https://github.com/diegomura/react-pdf/pull/2952) [`2c3c887e`](https://github.com/diegomura/react-pdf/commit/2c3c887ea2d3aed2863f49bff375d08feaf975aa) Thanks [@diegomura](https://github.com/diegomura)! - feat: support multiple line-height units
## 5.0.1
### Patch Changes
- [#2950](https://github.com/diegomura/react-pdf/pull/2950) [`77e480cd`](https://github.com/diegomura/react-pdf/commit/77e480cdd161270ac07453525dfaf993e2d3f17f) Thanks [@diegomura](https://github.com/diegomura)! - feat: accept commas between transformations
## 5.0.0
### Major Changes
- [#2871](https://github.com/diegomura/react-pdf/pull/2871) [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119) Thanks [@diegomura](https://github.com/diegomura)! - feat!: drop cjs support
### Patch Changes
- Updated dependencies [[`46c3047d`](https://github.com/diegomura/react-pdf/commit/46c3047de56ae82f062b72c4910a4e6096eee99f), [`55973278`](https://github.com/diegomura/react-pdf/commit/55973278ac8bc8f703b63844f57d6f155ae8d86f), [`70f29a04`](https://github.com/diegomura/react-pdf/commit/70f29a0407b1d56e9a7932b25c0d69132e9b4119)]:
- @react-pdf/types@2.7.0
- @react-pdf/fns@3.0.0
## 4.3.0
### Minor Changes
- [#2771](https://github.com/diegomura/react-pdf/pull/2771) [`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2) Thanks [@nikischin](https://github.com/nikischin)! - fix: fix dpi
### Patch Changes
- Updated dependencies [[`8e6a832`](https://github.com/diegomura/react-pdf/commit/8e6a8320f86354aff950c296a96bc41a33e9dab2), [`4bafab8`](https://github.com/diegomura/react-pdf/commit/4bafab8455c9003759f48bad20a720baf4ed189b)]:
- @react-pdf/types@2.6.0
## 4.2.5
### Patch Changes
- Updated dependencies [[`22a34a9`](https://github.com/diegomura/react-pdf/commit/22a34a91b16a201cd8288e0dbea9368b12ca73f5)]:
- @react-pdf/types@2.5.0
## 4.2.4
### Patch Changes
- [#2605](https://github.com/diegomura/react-pdf/pull/2605) [`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - fix: fix CJS compatibility
- Updated dependencies [[`f7505ed`](https://github.com/diegomura/react-pdf/commit/f7505ed453a1a0ae960d0e5e4a1d155803861b71)]:
- @react-pdf/fns@2.2.1
## 4.2.3
### Patch Changes
- Updated dependencies [[`9af07fe`](https://github.com/diegomura/react-pdf/commit/9af07feb59c2fe9c1d8960ac95f6fa6e03d16235), [`8350154`](https://github.com/diegomura/react-pdf/commit/83501541e3a050021e18e112bb472b2dabc142a7)]:
- @react-pdf/types@2.4.1
- @react-pdf/fns@2.2.0
## 4.2.2
### Patch Changes
- Updated dependencies [[`fb5273d`](https://github.com/diegomura/react-pdf/commit/fb5273d8d80d919f7b9c214e02d67b79ce23fa19)]:
- @react-pdf/types@2.4.0
## 4.2.1
### Patch Changes
- Updated dependencies [[`9e5842b`](https://github.com/diegomura/react-pdf/commit/9e5842bbecca6e249af2c5fc50078bb7ddd5420f)]:
- @react-pdf/types@2.3.6
## 4.2.0
### Minor Changes
- [#2409](https://github.com/diegomura/react-pdf/pull/2409) [`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37) Thanks [@wojtekmaj](https://github.com/wojtekmaj)! - Add support for native ESM
### Patch Changes
- [#2498](https://github.com/diegomura/react-pdf/pull/2498) [`6bfe7e8`](https://github.com/diegomura/react-pdf/commit/6bfe7e8a30d96c04a1552800159992705f3605b1) Thanks [@diegomura](https://github.com/diegomura)! - fix: color parse error
- Updated dependencies [[`b6a14fd`](https://github.com/diegomura/react-pdf/commit/b6a14fd160fab26a49f798e5294b0e361e67fe37)]:
- @react-pdf/fns@2.1.0
## 4.1.9
### Patch Changes
- Updated dependencies [[`e5c8fde`](https://github.com/diegomura/react-pdf/commit/e5c8fde9379a9a85ecac7e3d6273953e39d65f8d), [`1f987cc`](https://github.com/diegomura/react-pdf/commit/1f987cc27c3fd1ef1b6748ebe58a289a78b538d2), [`4c40b14`](https://github.com/diegomura/react-pdf/commit/4c40b149cfed42f2513e1dd330a92ccc3363c04f)]:
- @react-pdf/types@2.3.5
## 4.1.8
### Patch Changes
- Updated dependencies [[`4a55c1b`](https://github.com/diegomura/react-pdf/commit/4a55c1b2ed19e460ccae6e749ed94c16729a23c4)]:
- @react-pdf/types@2.3.4
## 4.1.7
### Patch Changes
- Updated dependencies [[`1e1fbdc`](https://github.com/diegomura/react-pdf/commit/1e1fbdc3c33ced46d8c7ebba7a196733cb789d59), [`8636812`](https://github.com/diegomura/react-pdf/commit/86368122ed87621d19ae3bc248080e17703d9fcb)]:
- @react-pdf/types@2.3.3
## 4.1.6
### Patch Changes
- Updated dependencies [[`a25dbcb`](https://github.com/diegomura/react-pdf/commit/a25dbcb32b65c300f5b088e8b210bb0c1abca5c2)]:
- @react-pdf/types@2.3.2
## 4.1.5
### Patch Changes
- Updated dependencies [[`47e91cb`](https://github.com/diegomura/react-pdf/commit/47e91cbd8016046bb4e8389ba0d1c7ede9edce59)]:
- @react-pdf/types@2.3.1
## 4.1.4
### Patch Changes
- Updated dependencies [[`2db67a3`](https://github.com/diegomura/react-pdf/commit/2db67a38b9be98b7816a2b5aa4733446b95e3724), [`eff1ff0`](https://github.com/diegomura/react-pdf/commit/eff1ff0fefcd710994e4654904ef55843af76a17)]:
- @react-pdf/types@2.3.0
- @react-pdf/fns@2.0.1
## 4.1.3
### Patch Changes
- [#2205](https://github.com/diegomura/react-pdf/pull/2205) [`9a5e0be`](https://github.com/diegomura/react-pdf/commit/9a5e0befb89756db07ce053192a136df9d4ba905) Thanks [@jeetiss](https://github.com/jeetiss)! - update babel
## 4.1.2
### Patch Changes
- [#2191](https://github.com/diegomura/react-pdf/pull/2191) [`37c3d74`](https://github.com/diegomura/react-pdf/commit/37c3d741fc9ad7eb91508b5caf6a5a554243f7ff) Thanks [@jeetiss](https://github.com/jeetiss)! - revert flex shorthand defaults
## 4.1.1
### Patch Changes
- [#2186](https://github.com/diegomura/react-pdf/pull/2186) [`72435bd`](https://github.com/diegomura/react-pdf/commit/72435bd81afdada5b811a1d82af0c873cfb62fa0) Thanks [@jeetiss](https://github.com/jeetiss)! - update yoga-layout to support flexBasis auto
## 4.1.0
### Minor Changes
- [#2160](https://github.com/diegomura/react-pdf/pull/2160) [`a743c90`](https://github.com/diegomura/react-pdf/commit/a743c905fb5d201d2382bc9175fa36b83cc47284) Thanks [@jeetiss](https://github.com/jeetiss)! - implement flex gap
### Patch Changes
- Updated dependencies [[`a743c90`](https://github.com/diegomura/react-pdf/commit/a743c905fb5d201d2382bc9175fa36b83cc47284)]:
- @react-pdf/types@2.2.0
## 4.0.0
### Major Changes
- [#1891](https://github.com/diegomura/react-pdf/pull/1891) [`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81) Thanks [@carlobeltrame](https://github.com/carlobeltrame)! - feat: compatibility with modern web bundlers and browsers
### Patch Changes
- Updated dependencies [[`a5a933c`](https://github.com/diegomura/react-pdf/commit/a5a933c9733e4c77338ef76a2b3545b84a646a81)]:
- @react-pdf/fns@2.0.0
## 3.2.0
### Minor Changes
- [#1892](https://github.com/diegomura/react-pdf/pull/1892) [`035d3f8`](https://github.com/diegomura/react-pdf/commit/035d3f8d24fa4f4af9f350950d81b51547858367) Thanks [@diegomura](https://github.com/diegomura)! - feat: add skew transformation support
## 3.1.0
### Minor Changes
- [#1869](https://github.com/diegomura/react-pdf/pull/1869) [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57) Thanks [@diegomura](https://github.com/diegomura)! - feat: variable dpi
### Patch Changes
- Updated dependencies [[`1411d16`](https://github.com/diegomura/react-pdf/commit/1411d162e04ca237bad93729695c363fdf4bdbeb), [`4fadb48`](https://github.com/diegomura/react-pdf/commit/4fadb48983d7269452f89f80c7e341ece859aaee), [`ce8762f`](https://github.com/diegomura/react-pdf/commit/ce8762f6de5c796e69ec5a225c7f3ff9c619a960), [`5d2c308`](https://github.com/diegomura/react-pdf/commit/5d2c3088cf438a8abf1038b14a21117fecf59d57)]:
- @react-pdf/types@2.1.0
## 3.0.0
### Major Changes
- [#1829](https://github.com/diegomura/react-pdf/pull/1829) [`5458a00`](https://github.com/diegomura/react-pdf/commit/5458a00979d883341c6df094243cae859344d2b9) Thanks [@diegomura](https://github.com/diegomura)! - refactor: remove ramda from stylesheet package
### Patch Changes
- [#1838](https://github.com/diegomura/react-pdf/pull/1838) [`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de) Thanks [@diegomura](https://github.com/diegomura)! - feat: create fns package
- Updated dependencies [[`9bdb5c9`](https://github.com/diegomura/react-pdf/commit/9bdb5c934a822340754cd4c892d399f91f6218de), [`fe0f214`](https://github.com/diegomura/react-pdf/commit/fe0f214dbbf2f632b852ebfe65f886ecc4dd6953)]:
- @react-pdf/fns@1.0.0
- @react-pdf/types@2.0.9
## 2.1.0
### Minor Changes
- [#1535](https://github.com/diegomura/react-pdf/pull/1535) [`1f0eb6e`](https://github.com/diegomura/react-pdf/commit/1f0eb6e0d4e75480de6745a204924d5075859db7) Thanks [@jeetiss](https://github.com/jeetiss)! - fixed `margin: auto` parsing
* [#1654](https://github.com/diegomura/react-pdf/pull/1654) [`ccf3bf2`](https://github.com/diegomura/react-pdf/commit/ccf3bf22867a9bd49668cdd3543ec32492a40e4b) Thanks [@jeetiss](https://github.com/jeetiss)! - added `@babel/runtime` to dependencies
### Patch Changes
- [#1581](https://github.com/diegomura/react-pdf/pull/1581) [`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca) Thanks [@jeetiss](https://github.com/jeetiss)! - added changelog with changesets
- Updated dependencies [[`04449ab`](https://github.com/diegomura/react-pdf/commit/04449ab352db0cca2155024dd3e8c690e42193ca)]:
- @react-pdf/types@2.0.8
================================================
FILE: packages/stylesheet/README.md
================================================
# @react-pdf/stylesheet
Styles resolution engine for react-pdf. Transforms CSS-like style objects into normalized, resolved values ready for layout and rendering. Handles unit conversions, color parsing, shorthand expansion, media queries, and style flattening.
## Installation
```bash
yarn add @react-pdf/stylesheet
```
## Usage
```js
import stylesheet from '@react-pdf/stylesheet';
const container = {
width: 400,
height: 600,
orientation: 'portrait',
};
const style = {
margin: 20,
width: '50vw',
height: '20vh',
borderRadius: 5,
fontWeight: 'semibold',
borderBottom: '2 solid yellow',
'@media max-width: 500': {
backgroundColor: 'rgb(255, 0, 0)',
},
};
const computed = stylesheet(container, style);
// Result:
// {
// width: 200,
// height: 120,
// marginTop: 20,
// marginLeft: 20,
// marginRight: 20,
// marginBottom: 20,
// borderTopLeftRadius: 5,
// borderTopRightRadius: 5,
// borderBottomLeftRadius: 5,
// borderBottomRightRadius: 5,
// fontWeight: 600,
// borderBottomWidth: 2,
// borderBottomStyle: 'solid',
// borderBottomColor: 'yellow',
// backgroundColor: '#FF0000'
// }
```
## Features
### Style Flattening
Merges arrays of style objects into a single object. Supports nested arrays and filters out null/undefined values.
```js
import stylesheet, { flatten } from '@react-pdf/stylesheet';
const baseStyle = { margin: 10, padding: 5 };
const activeStyle = { backgroundColor: 'blue' };
// Pass an array of styles
const computed = stylesheet(container, [baseStyle, activeStyle]);
// Or use flatten directly
const merged = flatten([baseStyle, null, activeStyle, undefined]);
// => { margin: 10, padding: 5, backgroundColor: 'blue' }
```
### Media Queries
Apply styles conditionally based on container dimensions and orientation.
```js
const style = {
fontSize: 12,
'@media max-width: 500': {
fontSize: 10,
},
'@media orientation: landscape': {
flexDirection: 'row',
},
'@media min-width: 400 and max-width: 800': {
padding: 20,
},
};
```
Supported media features:
- `min-width` / `max-width`
- `min-height` / `max-height`
- `orientation` (`portrait` | `landscape`)
### Unit Conversion
Converts various CSS units to points (the PDF standard unit).
```js
const style = {
width: '2in', // 144pt (72pt per inch)
height: '50mm', // ~141.73pt
padding: '1cm', // ~28.35pt
margin: '10vh', // 10% of container height
fontSize: '5vw', // 5% of container width
gap: '2rem', // 36pt (default rem base: 18pt)
left: '100px', // ~100pt at 72dpi
};
```
| Unit | Description |
| ----- | ------------------------------------ |
| `pt` | Points (default, 1pt = 1/72 inch) |
| `in` | Inches (1in = 72pt) |
| `mm` | Millimeters |
| `cm` | Centimeters |
| `vh` | Percentage of container height |
| `vw` | Percentage of container width |
| `rem` | Relative to rem base (default 18pt) |
| `px` | Pixels (converted using DPI setting) |
### Color Transformation
Normalizes color values to hexadecimal format.
```js
import { transformColor } from '@react-pdf/stylesheet';
transformColor('rgb(255, 0, 0)'); // => '#FF0000'
transformColor('rgba(0, 0, 255, 0.5)'); // => '#0000FF80'
transformColor('hsl(120, 100%, 50%)'); // => '#00FF00'
transformColor('hsla(0, 100%, 50%, 0.8)'); // => '#FF0000CC'
transformColor('red'); // => 'red' (passed through)
```
### Shorthand Expansion
Expands CSS shorthand properties into their individual components.
#### Margin & Padding
```js
// Input
{ margin: '10 20 30 40' }
// Output
{
marginTop: 10,
marginRight: 20,
marginBottom: 30,
marginLeft: 40
}
// Also supports marginHorizontal/marginVertical
{ marginHorizontal: 20, marginVertical: 10 }
// Output
{
marginTop: 10,
marginRight: 20,
marginBottom: 10,
marginLeft: 20
}
```
#### Border
```js
// Input
{ border: '2 solid red' }
// Output
{
borderTopWidth: 2,
borderTopStyle: 'solid',
borderTopColor: 'red',
borderRightWidth: 2,
borderRightStyle: 'solid',
borderRightColor: 'red',
borderBottomWidth: 2,
borderBottomStyle: 'solid',
borderBottomColor: 'red',
borderLeftWidth: 2,
borderLeftStyle: 'solid',
borderLeftColor: 'red',
}
// Border radius expansion
{ borderRadius: 5 }
// Output
{
borderTopLeftRadius: 5,
borderTopRightRadius: 5,
borderBottomRightRadius: 5,
borderBottomLeftRadius: 5,
}
```
#### Flex
```js
// Input
{ flex: '1 0 auto' }
// Output
{
flexGrow: 1,
flexShrink: 0,
flexBasis: 'auto'
}
// Single value
{ flex: 1 }
// Output
{ flexGrow: 1 }
```
#### Gap
```js
// Input
{ gap: '10 20' }
// Output
{
rowGap: 10,
columnGap: 20
}
```
#### Object Position
```js
// Input
{ objectPosition: '50% 25%' }
// Output
{
objectPositionX: 0.5,
objectPositionY: 0.25
}
```
#### Transform Origin
```js
// Input
{ transformOrigin: 'center top' }
// Output
{
transformOriginX: '50%',
transformOriginY: '0%'
}
```
### Transform Parsing
Parses CSS transform strings into structured transform arrays.
```js
// Input
{
transform: 'translate(10, 20) rotate(45) scale(2)';
}
// Output
{
transform: [
{ operation: 'translate', value: [10, 20] },
{ operation: 'rotate', value: [45] },
{ operation: 'scale', value: [2, 2] },
];
}
```
Supported transform functions:
- `translate(x, y)` - Translation
- `translateX(x)` / `translateY(y)` - Single-axis translation
- `rotate(angle)` - Rotation in degrees
- `scale(x, y)` - Scaling (y defaults to x if omitted)
- `scaleX(x)` / `scaleY(y)` - Single-axis scaling
- `skew(x, y)` - Skewing in degrees
- `skewX(x)` / `skewY(y)` - Single-axis skewing
- `matrix(a, b, c, d, e, f)` - Full transformation matrix
### Font Weight Resolution
Converts font weight keywords to numeric values.
| Keyword | Numeric Value |
| -------------------------- | ------------- |
| `thin`, `hairline` | 100 |
| `ultralight`, `extralight` | 200 |
| `light` | 300 |
| `normal` | 400 |
| `medium` | 500 |
| `semibold`, `demibold` | 600 |
| `bold` | 700 |
| `ultrabold`, `extrabold` | 800 |
| `heavy`, `black` | 900 |
## API Reference
### Default Export
#### `stylesheet(container, style)`
Resolves styles for a given container.
**Parameters:**
- `container` - Container dimensions and settings
- `style` - Style object or array of style objects
**Returns:** Resolved style object with expanded shorthands and converted units
### Named Exports
#### `flatten(styles)`
Flattens an array of style objects into a single merged object.
```js
import { flatten } from '@react-pdf/stylesheet';
flatten([{ margin: 10 }, null, { padding: 5 }]);
// => { margin: 10, padding: 5 }
```
#### `transformColor(value)`
Transforms RGB/HSL color strings to hexadecimal format.
```js
import { transformColor } from '@react-pdf/stylesheet';
transformColor('rgb(255, 128, 0)'); // => '#FF8000'
```
## Types
### Container
```ts
type Container = {
width: number; // Container width in points
height: number; // Container height in points
dpi?: number; // DPI for px unit conversion (default: 72)
remBase?: number; // Base size for rem units (default: 18)
orientation?: 'landscape' | 'portrait';
};
```
### Style
The input style object supporting all CSS-like properties:
```ts
type Style = {
// Dimensions
width?: number | string;
height?: number | string;
minWidth?: number | string;
maxWidth?: number | string;
minHeight?: number | string;
maxHeight?: number | string;
// Flexbox
flex?: number | string;
flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
flexGrow?: number | string;
flexShrink?: number | string;
flexBasis?: number | string;
alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
alignSelf?:
| 'auto'
| 'flex-start'
| 'flex-end'
| 'center'
| 'baseline'
| 'stretch';
alignContent?:
| 'flex-start'
| 'flex-end'
| 'center'
| 'stretch'
| 'space-between'
| 'space-around'
| 'space-evenly';
justifyContent?:
| 'flex-start'
| 'flex-end'
| 'center'
| 'space-around'
| 'space-between'
| 'space-evenly';
// Gap
gap?: number | string;
rowGap?: number | string;
columnGap?: number | string;
// Spacing
margin?: number | string;
marginTop?: number | string;
marginRight?: number | string;
marginBottom?: number | string;
marginLeft?: number | string;
marginHorizontal?: number | string;
marginVertical?: number | string;
padding?: number | string;
paddingTop?: number | string;
paddingRight?: number | string;
paddingBottom?: number | string;
paddingLeft?: number | string;
paddingHorizontal?: number | string;
paddingVertical?: number | string;
// Borders
border?: number | string;
borderTop?: number | string;
borderRight?: number | string;
borderBottom?: number | string;
borderLeft?: number | string;
borderWidth?: number | string;
borderStyle?: 'solid' | 'dashed' | 'dotted';
borderColor?: string;
borderRadius?: number | string;
borderTopLeftRadius?: number | string;
borderTopRightRadius?: number | string;
borderBottomRightRadius?: number | string;
borderBottomLeftRadius?: number | string;
// ... and per-side border properties
// Layout
display?: 'flex' | 'none';
position?: 'absolute' | 'relative' | 'static';
top?: number | string;
right?: number | string;
bottom?: number | string;
left?: number | string;
zIndex?: number | string;
overflow?: 'hidden';
aspectRatio?: number | string;
// Colors
backgroundColor?: string;
color?: string;
opacity?: number | string;
// Text
fontFamily?: string | string[];
fontSize?: number | string;
fontStyle?: 'normal' | 'italic' | 'oblique';
fontWeight?: FontWeight;
letterSpacing?: number | string;
lineHeight?: number | string;
textAlign?: 'left' | 'right' | 'center' | 'justify';
textDecoration?:
| 'none'
| 'underline'
| 'line-through'
| 'underline line-through';
textDecorationColor?: string;
textDecorationStyle?: 'solid' | 'dashed' | 'dotted';
textTransform?:
| 'none'
| 'capitalize'
| 'lowercase'
| 'uppercase'
| 'upperfirst';
textOverflow?: 'ellipsis';
maxLines?: number | string;
// Transform
transform?: string | Transform[];
transformOrigin?: number | string;
transformOriginX?: number | string;
transformOriginY?: number | string;
// Object positioning (for images)
objectFit?: string;
objectPosition?: number | string;
objectPositionX?: number | string;
objectPositionY?: number | string;
// SVG
fill?: string;
stroke?: string;
strokeWidth?: string | number;
strokeDasharray?: string;
fillOpacity?: string | number;
strokeOpacity?: string | number;
fillRule?: 'nonzero' | 'evenodd';
textAnchor?: 'start' | 'middle' | 'end';
strokeLinecap?: 'butt' | 'round' | 'square';
strokeLinejoin?: 'miter' | 'round' | 'bevel';
visibility?: 'visible' | 'hidden' | 'collapse';
clipPath?: string;
dominantBaseline?:
| 'auto'
| 'middle'
| 'central'
| 'hanging'
| 'mathematical'
| 'text-after-edge'
| 'text-before-edge';
// Media queries
[key: `@media${string}`]: Style;
};
```
### SafeStyle
The resolved output style with normalized values:
```ts
type SafeStyle = {
// All shorthand properties expanded
// All units converted to points (numbers)
// All colors normalized
// Transforms parsed into structured arrays
};
```
### Transform
```ts
type Transform =
| { operation: 'translate'; value: [number, number] }
| { operation: 'rotate'; value: [number] }
| { operation: 'scale'; value: [number, number] }
| { operation: 'skew'; value: [number, number] }
| {
operation: 'matrix';
value: [number, number, number, number, number, number];
};
```
### FontWeight
```ts
type FontWeight =
| number
| 'thin'
| 'hairline'
| 'ultralight'
| 'extralight'
| 'light'
| 'normal'
| 'medium'
| 'semibold'
| 'demibold'
| 'bold'
| 'ultrabold'
| 'extrabold'
| 'heavy'
| 'black';
```
## License
MIT
================================================
FILE: packages/stylesheet/globals.d.ts
================================================
declare module 'hsl-to-hex';
declare module 'color-string';
declare module 'media-engine';
declare module 'postcss-value-parser/lib/parse.js';
declare module 'postcss-value-parser/lib/unit.js';
================================================
FILE: packages/stylesheet/jest.config.js
================================================
export default {
testRegex: 'tests/.*?(test)\\.js$',
};
================================================
FILE: packages/stylesheet/package.json
================================================
{
"name": "@react-pdf/stylesheet",
"version": "6.1.2",
"license": "MIT",
"description": "A styles engine for Node and the browser",
"author": "Diego Muracciole ",
"homepage": "https://github.com/diegomura/react-pdf#readme",
"type": "module",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/diegomura/react-pdf.git",
"directory": "packages/stylesheet"
},
"scripts": {
"test": "vitest",
"build": "rimraf ./lib && rollup -c",
"watch": "rimraf ./lib && rollup -c -w",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@react-pdf/fns": "3.1.2",
"@react-pdf/types": "^2.9.2",
"color-string": "^1.9.1",
"hsl-to-hex": "^1.0.0",
"media-engine": "^1.0.3",
"postcss-value-parser": "^4.1.0"
},
"files": [
"lib"
]
}
================================================
FILE: packages/stylesheet/rollup.config.js
================================================
import { dts } from 'rollup-plugin-dts';
import del from 'rollup-plugin-delete';
import typescript from '@rollup/plugin-typescript';
import localResolve from 'rollup-plugin-local-resolve';
import pkg from './package.json' with { type: 'json' };
const config = {
input: 'src/index.ts',
output: { format: 'es', file: 'lib/index.js' },
external: [...Object.keys(pkg.dependencies), /@react-pdf/],
plugins: [typescript(), localResolve()],
};
const dtsConfig = {
input: './lib/types/index.d.ts',
output: [{ file: 'lib/index.d.ts', format: 'es' }],
plugins: [dts(), del({ targets: 'lib/types', hook: 'buildEnd' })],
};
export default [config, dtsConfig];
================================================
FILE: packages/stylesheet/src/flatten/index.ts
================================================
import { compose, castArray } from '@react-pdf/fns';
import { Style } from '../types';
type StyleInput = Style | StyleInput[] | null | undefined;
/**
* Remove nil values from array
*
* @param array - Style array
* @returns Style array without nils
*/
const compact = (array: (T | null | undefined)[]): T[] =>
array.filter((item): item is T => item != null);
/**
* Merges style objects array
*
* @param styles - Style array
* @returns Merged style object
*/
const mergeStyles = (styles: StyleInput[]): Style =>
styles.reduce