Bugfix: Handle TypedArrays and Buffers in deep-merge/clone#1744
Bugfix: Handle TypedArrays and Buffers in deep-merge/clone#1744ykw9263 wants to merge 13 commits into
Conversation
blikblum
left a comment
There was a problem hiding this comment.
While the font handling is not overhauled this seems a good workaround
- remove unnecessary isObject check - rename binary data check function Co-authored-by: Luiz Américo <camara_luiz@yahoo.com.br>
- font family name is not allowed for ttf fonts with no Variations
| // extract fonts | ||
| const { font: defaultFont, ...restDefaultStyle } = defaultColStyle || {}; | ||
| const { font: font, ...restStyle } = colStyle || {}; | ||
| const mergedFont = { | ||
| ...defaultFont, | ||
| ...font, | ||
| }; |
There was a problem hiding this comment.
Given that deepMerge was modified to handle binary data, why not use it?
There was a problem hiding this comment.
Just found a bug where merging fonts with font collections would cause problem
doc.table({
rowStyles: [{
font: { src: SOME_TTC_FONT, family: FONT_FAMILY },
}]
})
.row([
{ text: 'Hello World', font: { src: SOME_TTF_FONT } }
]);
// throws `Variations require a font with the fvar, gvar and glyf, or CFF2 tables`I think font src should be binded with its family and not be merged with other family names across styles
There was a problem hiding this comment.
This is another bug, independent of table, just using font, please open another issue
There was a problem hiding this comment.
The bug is caused by style merging in tables propagating font families to other font options. Other than tables the same error seems only be thrown on user errors when they put unsupported families in font options.
Manually assigning font properties and avoiding deepMerge on table fonts fixes this together.
There was a problem hiding this comment.
But the changes ignores font: {size}
This is a rabbit hole
@hollandjake how about we keep with the following font cell | row | col def:
font: string |buffer
fontSize: number
We kill most of the complexity and AFAIK still pretty flexible
There was a problem hiding this comment.
This is internal doc. Never publicized
In the final shape of this PR it introduces complexity not only in code, but in usage reasoning / documentation (must explain that font.family will not merge like other properties - is ignored without src).
In fact it breaks a valid use case:
defaultStyle: {font.src: 'fontCollection'}
cell1.font.family: 'family1'
cell2.font.family: 'family2'
IMO we should either treat font as an atomic setting or we embrace fully the current merging approach ( changing the type or not)
There was a problem hiding this comment.
In fact it breaks a valid use case:
defaultStyle: {font.src: 'fontCollection'} cell1.font.family: 'family1' cell2.font.family: 'family2'
This definitely sounds complex to handle inline. May actually need a dedicated utility function to merge fonts properly without making a mess
/**
* Merge font definitions. Front takes precedence
* @param {Font[]} fonts
* @returns {Font} merged font
*/
export function mergeFonts(...fonts) {
const mergedFont = {};
for (const font of fonts) {
if (!mergedFont.size) {
mergedFont.size = font?.size;
}
// ignore font src / family once src is found
if (!mergedFont.src){
// take the first defined family
if (!mergedFont.family){
mergedFont.family = font?.family;
}
if (font?.src) {
mergedFont.src = font.src;
}
}
// return when font src & size are both defined
if (mergedFont.src && mergedFont.size){
return mergedFont;
}
}
return mergedFont;
}
// const mergedFont = fontMerge(cell.font, rowStyle.font, colStyle.font)edited for cleaner branches
There was a problem hiding this comment.
IMO we should either treat font as an atomic setting or we embrace fully the current merging approach ( changing the type or not)
Agree that the font merging behaviour should be defined especially for partial options. If we choose the full merging approach while accounting the case in #1744 (comment), the cascading logic would need to work like
- The most specific src & size will apply
- if specificity of family >= specificity of src, family will also apply. Otherwise family is undefined.
There was a problem hiding this comment.
BTW seems that defaultStyle.font is never merged into the final font in the original implementation.
Line 96 in 0036303
Is this intentional?
There was a problem hiding this comment.
Yes, thats because the defaults get populated during the normalisation stuff
|
There is a minor changelog conflict |
| ...((cell.font?.src && cell.font) || | ||
| (rowStyle.font?.src && rowStyle.font) || | ||
| (colStyle.font?.src && colStyle.font)), | ||
| size: cell.font?.size || rowStyle.font?.size || colStyle.font?.size, | ||
| }; |
There was a problem hiding this comment.
This breaks the logic of merging
If you have a font: {size: 16} in row will be ignored with this last change
There was a problem hiding this comment.
Now i see the size. Forgive me
| // extract fonts | ||
| const { font: defaultFont, ...restDefaultStyle } = defaultColStyle || {}; | ||
| const { font: font, ...restStyle } = colStyle || {}; | ||
| const mergedFont = { | ||
| ...defaultFont, | ||
| ...font, | ||
| }; |
There was a problem hiding this comment.
But the changes ignores font: {size}
This is a rabbit hole
@hollandjake how about we keep with the following font cell | row | col def:
font: string |buffer
fontSize: number
We kill most of the complexity and AFAIK still pretty flexible
What kind of change does this PR introduce?
This fixes #1743 where providing font buffers crashes table generation.
In
lib\table\utils.js,deepMergeanddeepClone()copy properties key by key includingBufferandUint8Arraywithout inheriting the class. This causes the merged font buffer failing to be recognised byPDFFontFactorywhich relies oninstanceofto determine the type of font sources.Also fixes #1746 where table style merging falsely assign font families.
This PR changes:
deepMerge()anddeepClone()now clone TypedArrays and Buffers using.slice()andBuffer.from(buffer)respectively.Table style merging is modified to copy fonts by reference.
Additional unit tests (fonts in tables, deep-merging buffers) are added for the changes.
Checklist:
TODO: