From 44ce1a7363e0aca9871ae93799c1424514745904 Mon Sep 17 00:00:00 2001 From: Lynn Date: Sun, 23 Apr 2023 01:58:37 +0800 Subject: [PATCH] feat: Complete radial-gradient support (#454) - radial-gradient should support default value when missed according to [reference](https://w3c.github.io/csswg-drafts/css-images/#radial-gradients) - radial-gradient `` should support unit such as `vw`, `vh`,`em`, `rem`, `%` etc - support `rg-extent-keyword` such as `closest-corner`, `farthest-side`,`closest-side`, `farthest-corner` - support explicitly set rg-size like `radial-gradient(20% 20% at top left, yellow, blue)` Close https://github.com/vercel/satori/issues/453 Close https://github.com/vercel/satori/issues/222 Close https://github.com/vercel/satori/issues/456 you can check [it](https://satori-playground-git-fork-jackie1210-fix-453.vercel.sh/?share=XVLLbuMwDPwVgYtFdgE30TaOsxXSHPYBtIeeWqAXX-SIsdXKkiHLeTTIv5ey66LtSeQMySEpnmDjFIKAldK73DLWhqPB69Mp2oxVqMsqCDb5xfn3STKAe61C9QVTum2MPBK6NXgY0Wj_0x43QTtL3MaZrrYjK40u7W3Auo0U2oB-pJ66Nujt8a8j0Eb9z3QhN8-ld51Vt7UsUUy8VFqaizK-FPnDo0pY6RFtwgrT4c_3jqjivX5BweaXH6DHtzkzznv0fM7tOhqrdld-mPo6h-UihwHZadz_cQfCOONsuWDZO7XVxhD-jXM-QuNiWS19qeM2Yk5zmPRijPVyJNjIUDFFyXfz5XRxNb1cmHk2vaLq6c00SwfnIktfclivZjF6aHRGnQ4W_eRXtQfXCJZyklrfoDEuYY_OG7WaUSwljS8k4Jr4Vy2IE_QTg_hNO4HhEECk0VFYdCWIrTQtJoC1e9IPxyZeUdj3HtWJW_1fF6hABN_hOYEgC4qoovw-isP5FQ) while it can render now, but it seems diffs from result in html in opacity? worth to dig it. --- src/builder/background-image.ts | 226 ++++++++++++++++-- src/builder/rect.ts | 6 +- src/layout.ts | 9 +- src/vendor/gradient-parser/index.js | 123 ++++++---- ...nt-should-support-default-value-1-snap.png | Bin 0 -> 3256 bytes ...port-explicitly-setting-rg-size-1-snap.png | Bin 0 -> 778 bytes ...port-explicitly-setting-rg-size-2-snap.png | Bin 0 -> 1006 bytes ...t-should-support-releative-unit-1-snap.png | Bin 0 -> 3285 bytes ...t-should-support-releative-unit-2-snap.png | Bin 0 -> 3364 bytes ...t-should-support-releative-unit-3-snap.png | Bin 0 -> 2959 bytes ...t-should-support-releative-unit-4-snap.png | Bin 0 -> 2873 bytes ...-rg-size-with-rg-extent-keyword-1-snap.png | Bin 0 -> 5002 bytes ...-rg-size-with-rg-extent-keyword-2-snap.png | Bin 0 -> 5236 bytes ...-rg-size-with-rg-extent-keyword-3-snap.png | Bin 0 -> 2239 bytes test/error.test.tsx | 28 +++ test/gradient.test.tsx | 112 +++++++++ 16 files changed, 429 insertions(+), 75 deletions(-) create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-default-value-1-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-1-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-2-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-1-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-2-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-3-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-4-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-1-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-2-snap.png create mode 100644 test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-3-snap.png diff --git a/src/builder/background-image.ts b/src/builder/background-image.ts index b9a16de0..313a1e38 100644 --- a/src/builder/background-image.ts +++ b/src/builder/background-image.ts @@ -1,5 +1,5 @@ import CssDimension from '../vendor/parse-css-dimension/index.js' -import { buildXMLString } from '../utils.js' +import { buildXMLString, lengthToNumber } from '../utils.js' import gradient from '../vendor/gradient-parser/index.js' import { resolveImageData } from '../handler/image.js' @@ -167,7 +167,8 @@ export default async function backgroundImage( left, top, }: { id: string; width: number; height: number; left: number; top: number }, - { image, size, position, repeat }: Background + { image, size, position, repeat }: Background, + inheritableStyle: Record ): Promise { // Default to `repeat`. repeat = repeat || 'repeat' @@ -327,8 +328,16 @@ export default async function backgroundImage( if (!orientation.at) { // Defaults to center. } else if (orientation.at.type === 'position') { - cx = orientation.at.value.x.value - cy = orientation.at.value.y.value + const pos = calcRadialGradient( + orientation.at.value.x, + orientation.at.value.y, + xDelta, + yDelta, + inheritableStyle.fontSize as number, + inheritableStyle + ) + cx = pos.x + cy = pos.y } else { throw new Error( 'orientation.at.type not implemented: ' + orientation.at.type @@ -346,25 +355,14 @@ export default async function backgroundImage( // We currently only support `farthest-corner`: // https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/radial-gradient()#values - const spread: Record = {} - - // Farest corner. - const fx = Math.max(Math.abs(xDelta - cx), Math.abs(cx)) - const fy = Math.max(Math.abs(yDelta - cy), Math.abs(cy)) - if (shape === 'circle') { - spread.r = Math.sqrt(fx * fx + fy * fy) - } else if (shape === 'ellipse') { - // Spec: https://drafts.csswg.org/css-images/#typedef-size - // Get the aspect ratio of the closest-side size. - const ratio = fy !== 0 ? fx / fy : 1 - - // fx^2/a^2 + fy^2/b^2 = 1 - // fx^2/(b*ratio)^2 + fy^2/b^2 = 1 - // (fx^2+fy^2*ratio^2) = (b*ratio)^2 - // b = sqrt(fx^2+fy^2*ratio^2)/ratio - spread.ry = Math.sqrt(fx * fx + fy * fy * ratio * ratio) / ratio - spread.rx = spread.ry * ratio - } + const spread = calcRadius( + shape as Shape, + orientation.style, + inheritableStyle.fontSize as number, + { x: cx, y: cy }, + [xDelta, yDelta], + inheritableStyle + ) // TODO: check for repeat-x/repeat-y const defs = buildXMLString( @@ -404,6 +402,13 @@ export default async function backgroundImage( fill: '#fff', }) ) + + buildXMLString('rect', { + x: 0, + y: 0, + width: xDelta, + height: yDelta, + fill: stops.at(-1).color, + }) + buildXMLString(shape, { cx: cx, cy: cy, @@ -459,3 +464,178 @@ export default async function backgroundImage( throw new Error(`Invalid background image: "${image}"`) } + +type PositionKeyWord = 'center' | 'left' | 'right' | 'top' | 'bottom' +interface Position { + type: string + value: PositionKeyWord +} + +function calcRadialGradient( + cx: Position, + cy: Position, + xDelta: number, + yDelta: number, + baseFontSize: number, + style: Record +) { + const pos: { x: number; y: number } = { x: xDelta / 2, y: yDelta / 2 } + if (cx.type === 'position-keyword') { + Object.assign(pos, calcPos(cx.value, xDelta, yDelta, 'x')) + } else { + pos.x = lengthToNumber( + `${cx.value}${cx.type}`, + baseFontSize, + xDelta, + style, + true + ) + } + + if (cy.type === 'position-keyword') { + Object.assign(pos, calcPos(cy.value, xDelta, yDelta, 'y')) + } else { + pos.y = lengthToNumber( + `${cy.value}${cy.type}`, + baseFontSize, + yDelta, + style, + true + ) + } + + return pos +} + +function calcPos( + key: PositionKeyWord, + xDelta: number, + yDelta: number, + dir: 'x' | 'y' +) { + switch (key) { + case 'center': + return { [dir]: dir === 'x' ? xDelta / 2 : yDelta / 2 } + case 'left': + return { x: 0 } + case 'top': + return { y: 0 } + case 'right': + return { x: xDelta } + case 'bottom': + return { y: yDelta } + } +} + +type Shape = 'circle' | 'ellipse' +function calcRadius( + shape: Shape, + endingShape: Array<{ type: string; value: string }>, + baseFontSize: number, + centerAxis: { x: number; y: number }, + length: [number, number], + inheritableStyle: Record +) { + const [xDelta, yDelta] = length + const { x: cx, y: cy } = centerAxis + const spread: Record = {} + let fx = 0 + let fy = 0 + const isExtentKeyWord = endingShape.some((v) => v.type === 'extent-keyword') + + if (!isExtentKeyWord) { + if (endingShape.some((v) => v.value.startsWith('-'))) { + throw new Error( + 'disallow setting negative values to the size of the shape. Check https://w3c.github.io/csswg-drafts/css-images/#valdef-rg-size-length-0' + ) + } + if (shape === 'circle') { + return { + r: lengthToNumber( + `${endingShape[0].value}${endingShape[0].type}`, + baseFontSize, + xDelta, + inheritableStyle, + true + ), + } + } else { + return { + rx: lengthToNumber( + `${endingShape[0].value}${endingShape[0].type}`, + baseFontSize, + xDelta, + inheritableStyle, + true + ), + ry: lengthToNumber( + `${endingShape[1].value}${endingShape[1].type}`, + baseFontSize, + yDelta, + inheritableStyle, + true + ), + } + } + } + + switch (endingShape[0].value) { + case 'farthest-corner': + fx = Math.max(Math.abs(xDelta - cx), Math.abs(cx)) + fy = Math.max(Math.abs(yDelta - cy), Math.abs(cy)) + break + case 'closest-corner': + fx = Math.min(Math.abs(xDelta - cx), Math.abs(cx)) + fy = Math.min(Math.abs(yDelta - cy), Math.abs(cy)) + break + case 'farthest-side': + if (shape === 'circle') { + spread.r = Math.max( + Math.abs(xDelta - cx), + Math.abs(cx), + Math.abs(yDelta - cy), + Math.abs(cy) + ) + } else { + spread.rx = Math.max(Math.abs(xDelta - cx), Math.abs(cx)) + spread.ry = Math.max(Math.abs(yDelta - cy), Math.abs(cy)) + } + return spread + case 'closest-side': + if (shape === 'circle') { + spread.r = Math.min( + Math.abs(xDelta - cx), + Math.abs(cx), + Math.abs(yDelta - cy), + Math.abs(cy) + ) + } else { + spread.rx = Math.min(Math.abs(xDelta - cx), Math.abs(cx)) + spread.ry = Math.min(Math.abs(yDelta - cy), Math.abs(cy)) + } + + return spread + } + if (shape === 'circle') { + spread.r = Math.sqrt(fx * fx + fy * fy) + } else { + // Spec: https://drafts.csswg.org/css-images/#typedef-size + // Get the aspect ratio of the closest-side size. + const ratio = fy !== 0 ? fx / fy : 1 + + if (fx === 0) { + spread.rx = 0 + spread.ry = 0 + } else { + // fx^2/a^2 + fy^2/b^2 = 1 + // fx^2/(b*ratio)^2 + fy^2/b^2 = 1 + // (fx^2+fy^2*ratio^2) = (b*ratio)^2 + // b = sqrt(fx^2+fy^2*ratio^2)/ratio + + spread.ry = Math.sqrt(fx * fx + fy * fy * ratio * ratio) / ratio + spread.rx = spread.ry * ratio + } + } + + return spread +} diff --git a/src/builder/rect.ts b/src/builder/rect.ts index 147e8dc0..93e851bc 100644 --- a/src/builder/rect.ts +++ b/src/builder/rect.ts @@ -28,7 +28,8 @@ export default async function rect( src?: string debug?: boolean }, - style: Record + style: Record, + inheritableStyle: Record ) { if (style.display === 'none') return '' @@ -75,7 +76,8 @@ export default async function rect( const background = (style.backgroundImage as any)[index] const image = await backgroundImage( { id: id + '_' + index, width, height, left, top }, - background + background, + inheritableStyle ) if (image) { // Background images that come first in the array are rendered last. diff --git a/src/layout.ts b/src/layout.ts index 8398eef9..eb8d1d72 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -196,7 +196,8 @@ export default async function* layout( isInheritingTransform, debug, }, - computedStyle + computedStyle, + newInheritableStyle ) } else if (type === 'svg') { // When entering a node, we need to convert it to a with the @@ -214,7 +215,8 @@ export default async function* layout( isInheritingTransform, debug, }, - computedStyle + computedStyle, + newInheritableStyle ) } else { const display = style?.display @@ -231,7 +233,8 @@ export default async function* layout( } baseRenderResult = await rect( { id, left, top, width, height, isInheritingTransform, debug }, - computedStyle + computedStyle, + newInheritableStyle ) } diff --git a/src/vendor/gradient-parser/index.js b/src/vendor/gradient-parser/index.js index 0d370721..4ab417b7 100644 --- a/src/vendor/gradient-parser/index.js +++ b/src/vendor/gradient-parser/index.js @@ -23,7 +23,7 @@ GradientParser.parse = (function () { positionKeywords: /^(left|center|right|top|bottom)/i, pixelValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))px/, percentageValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))\%/, - emValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))em/, + emLikeValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))(r?em|vw|vh)/, angleValue: /^(-?(([0-9]*\.[0-9]+)|([0-9]+\.?)))deg/, zeroValue: /[0]/, startCall: /^\(/, @@ -84,6 +84,42 @@ GradientParser.parse = (function () { ) } + function getDefaultRadialGradient(orientation = {}) { + const res = { ...orientation } + + Object.assign(res, { + style: (res.style || []).length > 0 + ? res.style + : [{ type: 'extent-keyword', value: 'farthest-corner' }], + at: { + type: 'position', + value: { + x: { + type: 'position-keyword', + value: 'center', + ...(res.at?.value?.x || {}) + }, + y: { + type: 'position-keyword', + value: 'center', + ...(res.at?.value?.y || {}) + } + } + }} + ) + + if (!orientation.value) { + Object.assign(res, { + type: 'shape', + value: res.style.some(v => ['%', 'extent-keyword'].includes(v.type)) + ? 'ellipse' + : 'circle' + }) + } + + return res + } + function matchGradient( gradientType, pattern, @@ -102,7 +138,9 @@ GradientParser.parse = (function () { return { type: gradientType, - orientation: orientation, + orientation: gradientType.endsWith('radial-gradient') + ? orientation?.map(v => getDefaultRadialGradient(v)) ?? [getDefaultRadialGradient()] + : orientation, colorStops: matchListing(matchColorStop), } }) @@ -166,59 +204,40 @@ GradientParser.parse = (function () { } function matchRadialOrientation() { - var radialType = matchCircle() || matchEllipse() - if (radialType) { - radialType.at = matchAtPosition() - } else { - var extent = matchExtentKeyword() - if (extent) { - radialType = extent - var positionAt = matchAtPosition() - if (positionAt) { - radialType.at = positionAt - } - } else { - // If unspecified, it defaults to ellipse. - var positionAt = matchAtPosition() - if (positionAt) { - radialType = { - type: 'shape', - value: 'ellipse', - at: positionAt - } - } else { - var defaultPosition = matchPositioning() - if (defaultPosition) { - radialType = { - type: 'default-radial', - at: defaultPosition, - } - } - } - } - } + const pre = preMatchRadialOrientation() + const at = matchAtPosition() + + if (!pre && !at) return - return radialType + return { ...pre, at } } - function matchCircle() { - var circle = match('shape', /^(circle)/i, 0) + function preMatchRadialOrientation() { + let rgEndingShape = matchCircle() || matchEllipse() + let rgSize = matchExtentKeyword() || matchLength() || matchDistance() + const extra = match('%', tokens.percentageValue, 1) - if (circle) { - circle.style = matchLength() || matchExtentKeyword() + if (rgEndingShape) { + return { + ...rgEndingShape, + style: [rgSize, extra].filter(v => v) + } + } else if (rgSize){ + return { + style: [rgSize, extra].filter(v => v), + ...(matchCircle() || matchEllipse()) + } + } else { + // } + } - return circle + function matchCircle() { + return match('shape', /^(circle)/i, 0) } function matchEllipse() { - var ellipse = match('shape', /^(ellipse)/i, 0) - - if (ellipse) { - ellipse.style = matchDistance() || matchExtentKeyword() - } - - return ellipse + return match('shape', /^(ellipse)/i, 0) } function matchExtentKeyword() { @@ -337,7 +356,17 @@ GradientParser.parse = (function () { } function matchLength() { - return match('px', tokens.pixelValue, 1) || match('em', tokens.emValue, 1) + return match('px', tokens.pixelValue, 1) || matchRelativeLength(tokens.emLikeValue, 1) + } + + function matchRelativeLength(pattern, captureIndex) { + var captures = scan(pattern) + if (captures) { + return { + type: captures[5], + value: captures[captureIndex], + } + } } function match(type, pattern, captureIndex) { diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-default-value-1-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-default-value-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..2dff222f1bf5e93864a388a18fceef7b02994d2e GIT binary patch literal 3256 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 literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-1-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..9f0a7f5d766843af8266338587b5f91126f225ab GIT binary patch literal 778 zcmeAS@N?(olHy`uVBq!ia0vp^DIm%=C{H`>ZW1?X9eSSyC)z13E znd;RqwkjOfVrQSfd-dw@#hW*87iASV_Vn9zy*~>le~kS0<62uy%Cx{ax#{MO&7$2(WPp)Qb2q+&bCt;K^UJJ)3s! z44f~(=J8)M(czA3qQV#URlMtSa&r8Df*j1O9mfMKD%YP~wrStLy-gol7!Cy=Vr^z( zV`k>?W2iWLvLbi$>NRWs?qEH1fT5M~(18b^ETvi0>$8EP>)zerKE#m7+roH|ldV2^ z^V&6Q-uO96#7FW7Tyu~R;1Ri(y?MQk{{J-!Jw0X#cwkU>axeboFyt=akR{0J~*OlK=n! literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-2-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-explicitly-setting-rg-size-2-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..1f08ebc14c3ef0f7d6927bee73a074431f586422 GIT binary patch literal 1006 zcmeAS@N?(olHy`uVBq!ia0vp^DIm#p*UwSE z)F*@}ZS>F)>OO)(xde4Ke%Su>&6l(|GieTyTiWktT7KS}GU@D@@`@=BKV%!r)Jez0 z|ChLPrzZdEPvz%-|K3sX30k-A+3elB^_dqba63;s<}%kb@cH(0EH9VG#Qn>Wle6Q0 zrE%g?)>e-<*5&H2?wJ2PYv8$aM?{XCy!}?k58uAM*62tJ7dtiOYc@z@)u-8slZxv0 zU156|&mqLp*{BmxJWFSW=IiUV>1mgzET7LGd+O%RqQgZ$#GM503aPZDOq`{E^3cpp zb!&@XET1!P-4=5e&Zf(Y6i#266Y4sl#{NsNpI_K*X{QOlrYSg1U@g0vG;{sb^!B<_ zA3xr55lG4O5J>rXV&>8!x4AR7-u?b6`cQsr-KmQgtE7R(lnSUYZA$S?+39m-rsnST zsWbd6ZSG_=e+cj9YC1BZ#bMf-$kU5<2VYxX83vTHxRKNR;PHHg8@x>|4q|I=PF-5Q z{E6v)!DYeUzHeW~HnD4Ar%w20f7TW1^ZCyQfBUv=_VSy@Ca^djy^ykS)`>-?%RM=K z=gH1n{^s4gp1T4nY(h>#Oq>fkb)tn!)fj?5)m6;gw0ZOGdlU94tdN*>qR2FmdwsfY zVFgHh?_Tp=iZ{evgd8_j_@;cktNAl;M(?JrTkQ*-CrC_cRbtGF+@rSX&pyetGBdI4)Ujg^U$iM0P7v67#9`X~sYkOHC4HFl!RpknUl(ui zI*NI=L?wAlTYvJ=?#T)^%6sN*+E#X_+8LbB4cecIT&>&84GtF zNclNu<|Kw$9vo`(`SX{rSu>~au0YC44;J5P>pOMggFoH-^&>zh^|4%V zIrs3f#^=xBd(B;p1^?-$=Dl0@y{+Z{;mglvn|XXta6IE7U@UZ`hs98N=rMorItm+q UueVKI0L;e>p00i_>zopr05;pZtpET3 literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-1-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-releative-unit-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..0987c9c665b3c9913990f10c353c0937950f5b5e GIT binary patch literal 3285 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 literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-1-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..63a52e41679340cfda3be94e21fce6c99e87153c GIT binary patch literal 5002 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 HfM5O_1`;fJ literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-2-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-2-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d7c9293dea7b3eeb9508396f02dbcfe90dc43a GIT binary patch literal 5236 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 PM6rvOSI(E9J!AeCKQnD! literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-3-snap.png b/test/__image_snapshots__/gradient-test-tsx-test-gradient-test-tsx-gradient-radial-gradient-should-support-rg-size-with-rg-extent-keyword-3-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..614616028b3e8956b7c3c9a31fd82cc6794c1bf5 GIT binary patch literal 2239 zcmcgu{X5eO8)tOPm$YeUUeec*#zt9hSSQDK^HNDR)^yOYsV7R7_ms4@8EICbbaaGC z2YJaUJ9NA~lX)q1<;jF*mZNZxmsl;%`X`lbQBB30VT={$D;3_X#NOy z@IehXxK7-sPYW@l?3#+%n#q+rvM%f8_wQ~Q>6gyeUT|_3B105Kd6lmjN}V+It`23d zYGDLAirg{~Hh$2aR_6>`DDYOptr7F94EtF({K<)SsG6+)b>QHib(HP|W}&w%Fq|V?FtiS{=_i!rsfv@_+5aU4M~jZqVp5@ zBVidBBC1$;GpWq7Wn9t=y+B1=+bbk<`A|&tOE4^hgP03Z>bwPkOe2qH(f)iq3EbWq zx08PEJ|glodn!oCI%JOx00oZp@P}cga?qNDE;00wWKs~t*%PC8R5#87brw%z;-R1c z)!@(<2G&h?*xSweQ~Hdx083zohqPVY8vt%RdbY=RfeP+lm>nkZw=nAgg-fF@D&m&Q zBgp5Zts4mpO9})Z6HxP($c=(+HHT7uNTl%0^E0kOPhSS`hP_Df`Vtuhz=&FM#J{Jy zFJyYh2Q&~+=gzOi`f?F2FfM=D;(R{9(vf?4!I4ai!@Q`3c&zoP| zx~yy_zF;G+HeboMA}y9-NGM8^q^=CHY(YQuT;GHDl?_db9}!R`hGY&#nZA@xJw|*{ zh*-Wn;%vo+mtmND8igPbC$g8&f&~w$v5Z**7V%O>_9hw?j>n1bf*?_|&GI>p( z$?O4SXFe2ltKUEZwHX-OWGU8AW9y3XC4{i>zywVD%mc&SJHZ*9Wi+iD(L}PZ7Cdz5 za3W`oh=f>_7|!^;_9Q8}s@(-!xU7#Ft3Qr@OvqJ;D?$|&@IiNv6Bny4N7_kj;6Nq+ihzX>Ih9}0pc!PfuXxVev-LhSYB8_$rR zHoo1eZIc-Ek7<)6hAj0#Z%>Dr0wI`{LIjr;10TeU@1&q2XfmtB4s9-t7YgR2;3E4I z`1)XsblF~Z5va*-W%y@>mVC!PV1L?`J@NA=z;it~ZFb$nA3nho9u_~h=LdSl^ZXYP zWJMjbh|!sEmQOqc|5P#b?ZQdcpxo!dqzU7f{Aey$T(*4|Gi@-foSX+vD}BQ0P{@C)_|tPLxH7 z9XW+tE|2M1Vn=rg#Kl`VE;m;1`5$}`9cjl+7^3+d(VVoQU92I>_4p}tAMsrkVWxG@ z@ZEFLl!HNbj17~MJ{G@t{m2nt!q|)kA;tDO|4_W|(KT`qU2{_N+5Ssiw;bce~EH&eX!u6amrmkf+0P3h1SK~HEd zsn!}$Unq8SK(C{WZ6)LW#-G=#-8>Hqn-yJY4_2QK8CYvgx|)&u${fO7fN#>78fG=b zxc26e$^2+Kur50`ZSb-~=}km*Cnt&L*vRNg$k{FOnUy7FX=YaFZXDPP-So~n$mEe? z=Moa5*wszWPR$O_fg{Updy`u^rAl0~i80JYKy75m^(-h}Q}DV`Fnz2Oppw3&d~-Y* ztZvRdA42Q6?J%ajNc$+rsfjZKVqP&kf3EV6T&ZvAH>Xg17+u%@7j!P*EUwf7u8Q-$ zhKa}T*bJp-0c)j^>+lLt3hsY2;N2ae|!^h zqow`KHc)b;2J3+ap?y3AD3xw-Re#|i-e6XJbt`RPS$C{;8lU!Z-s_FOmHP6F`VyF) zv~-(kfYzj8DL%JcNdHWx%*C~Rrw*CqiB9AOqD!*XwM#WUg@~f1tXeFJOx7rxDuF}) z)fG%rwaBd!dCH1z1h;=ix_w%$?$viT4MD5&p2%;m1JhDo8-47l-I-gA<6;=u*+r{m zN9NMLE1J^h&NT-Q4t|&rm6V(?E2i+x@_RVR;bu^4WsJsQzWrs}V)|228HB6Clh6hu z+5#+BTs#D(h4+6&bKhGVtu*6IB5;dVwjtd`Z$@Pc`2N~`Ax;vR{wpgVsr&voSJi!l z@-_hOm@*Re8?=7`dRnxc2SBzV{gi5Y8RopU@AaT-0Dt#Up2c4yV50Y>wOD4#dgY(b z^cH_ { }) expect(typeof svg).toBe('string') }) + + it('should not allowed to set negative value to rg-size', async () => { + const result = satori( +
, + { + width: 100, + height: 100, + fonts, + } + ) + + expect(result).rejects.toThrowError( + 'disallow setting negative values to the size of the shape. Check https://w3c.github.io/csswg-drafts/css-images/#valdef-rg-size-length-0' + ) + }) }) diff --git a/test/gradient.test.tsx b/test/gradient.test.tsx index 3004a1af..06a2ed34 100644 --- a/test/gradient.test.tsx +++ b/test/gradient.test.tsx @@ -172,6 +172,118 @@ describe('Gradient', () => { ) expect(toImage(svg, 100)).toMatchImageSnapshot() }) + + it('should support default value', async () => { + const svg = await satori( +
, + { + width: 100, + height: 100, + fonts, + } + ) + expect(toImage(svg, 100)).toMatchImageSnapshot() + }) + + it('should support releative unit', async () => { + const svgs = await Promise.all( + [ + 'radial-gradient(ellipse at 1em 25px,blue, red)', + 'radial-gradient(circle at 1rem 25px,blue, red)', + 'radial-gradient(circle at 2vw 25px,blue, red)', + 'radial-gradient(circle at 1vh 50%,blue, red)', + ].map((backgroundImage) => + satori( +
, + { + width: 100, + height: 100, + fonts, + } + ) + ) + ) + svgs.forEach((svg) => { + expect(toImage(svg, 100)).toMatchImageSnapshot() + }) + }) + + it('should support rg-size with rg-extent-keyword', async () => { + const svgs = await Promise.all( + [ + 'radial-gradient(closest-corner at 50% 50%, yellow, green)', + 'radial-gradient(farthest-side at left bottom, red, yellow 50px, green)', + 'radial-gradient(closest-side at 20px 30px, red, yellow, green)', + ].map((backgroundImage) => + satori( +
, + { + width: 100, + height: 100, + fonts, + } + ) + ) + ) + + svgs.forEach((svg) => { + expect(toImage(svg, 100)).toMatchImageSnapshot() + }) + }) + + it('should support explicitly setting rg-size', async () => { + const svgs = await Promise.all( + [ + 'radial-gradient(20% 20% at top left, yellow, blue)', + 'radial-gradient(30px at top left, yellow, blue)', + ].map((backgroundImage) => + satori( +
, + { + width: 100, + height: 100, + fonts, + } + ) + ) + ) + + svgs.forEach((svg) => { + expect(toImage(svg, 100)).toMatchImageSnapshot() + }) + }) }) it('should support advanced usage', async () => {