From d047fa8613beb4d4481588fff7a0f4db6aa08905 Mon Sep 17 00:00:00 2001 From: andrew-spare Date: Wed, 8 May 2024 17:04:52 -0300 Subject: [PATCH 1/5] fix bug --- packages/layout/src/text/fontSubstitution.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/layout/src/text/fontSubstitution.js b/packages/layout/src/text/fontSubstitution.js index 9ddc982b6..7a5a91dd8 100644 --- a/packages/layout/src/text/fontSubstitution.js +++ b/packages/layout/src/text/fontSubstitution.js @@ -20,10 +20,7 @@ const getOrCreateFont = (name) => { const getFallbackFont = () => getOrCreateFont('Helvetica'); const pickFontFromFontStack = (codePoint, fontStack, lastFont) => { - const fontStackWithFallback = [...fontStack, getFallbackFont()]; - if (lastFont) { - fontStackWithFallback.unshift(lastFont); - } + const fontStackWithFallback = [...fontStack, lastFont, getFallbackFont()]; for (let i = 0; i < fontStackWithFallback.length; i += 1) { const font = fontStackWithFallback[i]; if ( @@ -55,6 +52,11 @@ const fontSubstitution = typeof font === 'string' ? getOrCreateFont(font) : font, ); + console.log( + 'defaultFontGlyphCount', + defaultFont[0].src?.font?.attributes.CharacterSet, + ); + if (string.length === 0) { res.push({ start: 0, end: 0, attributes: { font: defaultFont } }); break; From f8a10acf2cbebc8a2021168feb3b834fbe688582 Mon Sep 17 00:00:00 2001 From: andrew-spare Date: Wed, 8 May 2024 17:05:13 -0300 Subject: [PATCH 2/5] update example --- .../examples/src/fontFamilyFallback/index.jsx | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/packages/examples/src/fontFamilyFallback/index.jsx b/packages/examples/src/fontFamilyFallback/index.jsx index 148bdf034..eb4e93ffd 100644 --- a/packages/examples/src/fontFamilyFallback/index.jsx +++ b/packages/examples/src/fontFamilyFallback/index.jsx @@ -5,6 +5,9 @@ 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({ @@ -30,7 +33,18 @@ Font.register({ fonts: [ { src: RobotoFont, - fontWeight: 400, + fontStyle: 'normal', + fontWeight: 'normal', + }, + { + src: RobotItalicFont, + fontStyle: 'italic', + fontWeight: 'normal', + }, + { + src: RobotoBoldFont, + fontStyle: 'normal', + fontWeight: 'bold', }, ], }); @@ -48,19 +62,36 @@ Font.register({ 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 / امتحان + + Courier-Bold / امتحان + + + + The following is multiple font families, weights, and styles all on the + same line + + + Roboto Normal{' / '} + Roboto Bold + {' / '} + Roboto Italic + {' / '} + Courier + ); }; From dca7a09343259d9d0d0b44fe52efa9c337446174 Mon Sep 17 00:00:00 2001 From: andrew-spare Date: Wed, 8 May 2024 17:05:32 -0300 Subject: [PATCH 3/5] add tests --- .../tests/text/fontSubstitution.test.js | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 packages/layout/tests/text/fontSubstitution.test.js diff --git a/packages/layout/tests/text/fontSubstitution.test.js b/packages/layout/tests/text/fontSubstitution.test.js new file mode 100644 index 000000000..d6cc421df --- /dev/null +++ b/packages/layout/tests/text/fontSubstitution.test.js @@ -0,0 +1,90 @@ +import { describe, expect, test } from 'vitest'; +import fontSubstitution from '../../src/text/fontSubstitution'; + +const instance = fontSubstitution(); + +describe('FontSubstitution', () => { + test('should return empty array if no runs passed', () => { + const string = instance({ string: '', runs: [] }); + + expect(string).toHaveProperty('runs', []); + expect(string).toHaveProperty('string', ''); + }); + + test('should merge consecutive runs with same font', () => { + const run1 = { start: 0, end: 3, attributes: { font: ['Helvetica'] } }; + const run2 = { start: 3, end: 5, attributes: { font: ['Helvetica'] } }; + const string = instance({ string: 'Lorem', runs: [run1, run2] }); + + expect(string).toHaveProperty('string', 'Lorem'); + expect(string.runs).toHaveLength(1); + expect(string.runs[0]).toHaveProperty('start', 0); + expect(string.runs[0]).toHaveProperty('end', 5); + expect(string.runs[0].attributes.font.name).toBe('Helvetica'); + }); + + test('should substitute many runs', () => { + const run1 = { start: 0, end: 3, attributes: { font: ['Courier'] } }; + const run2 = { start: 3, end: 5, attributes: { font: ['Helvetica'] } }; + const string = instance({ string: 'Lorem', runs: [run1, run2] }); + + expect(string).toHaveProperty('string', 'Lorem'); + expect(string.runs).toHaveLength(2); + expect(string.runs[0]).toHaveProperty('start', 0); + expect(string.runs[0]).toHaveProperty('end', 3); + expect(string.runs[0].attributes.font.name).toBe('Courier'); + expect(string.runs[1]).toHaveProperty('start', 3); + expect(string.runs[1]).toHaveProperty('end', 5); + expect(string.runs[1].attributes.font.name).toBe('Helvetica'); + }); + + describe('Fallback Font', () => { + const SimplifiedChineseFont = { + name: 'SimplifiedChineseFont', + hasGlyphForCodePoint: (codePoint) => codePoint === 20320, + }; + + test('should utilize a fallback font that supports the provided glyph', () => { + const run = { + start: 0, + end: 1, + attributes: { + font: ['Courier', SimplifiedChineseFont], + }, + }; + + const string = instance({ string: '你', runs: [run] }); + + expect(string).toHaveProperty('string', '你'); + expect(string.runs).toHaveLength(1); + expect(string.runs[0]).toHaveProperty('start', 0); + expect(string.runs[0]).toHaveProperty('end', 1); + expect(string.runs[0].attributes.font.name).toBe( + SimplifiedChineseFont.name, + ); + }); + + test('should split a run when fallback font is used on a portion of the run', () => { + const run = { + start: 0, + end: 2, + attributes: { + font: ['Courier', SimplifiedChineseFont], + }, + }; + + const string = instance({ string: 'A你', runs: [run] }); + + expect(string).toHaveProperty('string', 'A你'); + expect(string.runs).toHaveLength(2); + expect(string.runs[0]).toHaveProperty('start', 0); + expect(string.runs[0]).toHaveProperty('end', 1); + expect(string.runs[0].attributes.font.name).toBe('Courier'); + expect(string.runs[1]).toHaveProperty('start', 1); + expect(string.runs[1]).toHaveProperty('end', 2); + expect(string.runs[1].attributes.font.name).toBe( + SimplifiedChineseFont.name, + ); + }); + }); +}); From e5f9602df1f56efac719d310dc933d1be6c0d160 Mon Sep 17 00:00:00 2001 From: andrew-spare Date: Wed, 8 May 2024 17:30:31 -0300 Subject: [PATCH 4/5] fix mistakes --- packages/examples/src/fontFamilyFallback/index.jsx | 2 +- packages/layout/src/text/fontSubstitution.js | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/examples/src/fontFamilyFallback/index.jsx b/packages/examples/src/fontFamilyFallback/index.jsx index eb4e93ffd..ce38bddf7 100644 --- a/packages/examples/src/fontFamilyFallback/index.jsx +++ b/packages/examples/src/fontFamilyFallback/index.jsx @@ -81,7 +81,7 @@ const MyDoc = () => { - The following is multiple font families, weights, and styles all on the + The following are multiple font families, weights, and styles all on the same line diff --git a/packages/layout/src/text/fontSubstitution.js b/packages/layout/src/text/fontSubstitution.js index 7a5a91dd8..40b8bafc8 100644 --- a/packages/layout/src/text/fontSubstitution.js +++ b/packages/layout/src/text/fontSubstitution.js @@ -52,11 +52,6 @@ const fontSubstitution = typeof font === 'string' ? getOrCreateFont(font) : font, ); - console.log( - 'defaultFontGlyphCount', - defaultFont[0].src?.font?.attributes.CharacterSet, - ); - if (string.length === 0) { res.push({ start: 0, end: 0, attributes: { font: defaultFont } }); break; From 89e8f827fe464cb1c936a00952ce73e0ac5a9b00 Mon Sep 17 00:00:00 2001 From: Diego Muracciole Date: Mon, 24 Jun 2024 07:56:03 +0200 Subject: [PATCH 5/5] Create nine-ways-walk.md --- .changeset/nine-ways-walk.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/nine-ways-walk.md diff --git a/.changeset/nine-ways-walk.md b/.changeset/nine-ways-walk.md new file mode 100644 index 000000000..d6a3b9a6d --- /dev/null +++ b/.changeset/nine-ways-walk.md @@ -0,0 +1,6 @@ +--- +"@react-pdf/examples": patch +"@react-pdf/layout": patch +--- + +fix: font selection regression