@effing/canvas 0.18.4 → 0.18.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +198 -145
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -650,7 +650,7 @@ async function drawImage(ctx, src, x, y, width, height, style, preloadedImage) {
|
|
|
650
650
|
|
|
651
651
|
// src/jsx/draw/rect.ts
|
|
652
652
|
function drawRect(ctx, x, y, width, height, style) {
|
|
653
|
-
const borderRadius = getBorderRadius(style);
|
|
653
|
+
const borderRadius = getBorderRadius(style, width, height);
|
|
654
654
|
const hasRoundedCorners = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
655
655
|
if (style.boxShadow) {
|
|
656
656
|
drawBoxShadow(ctx, x, y, width, height, style.boxShadow, borderRadius);
|
|
@@ -677,16 +677,23 @@ function drawRect(ctx, x, y, width, height, style) {
|
|
|
677
677
|
}
|
|
678
678
|
drawBorders(ctx, x, y, width, height, style, borderRadius);
|
|
679
679
|
}
|
|
680
|
-
function
|
|
680
|
+
function resolveRadius(v, width, height) {
|
|
681
|
+
if (typeof v === "string" && v.endsWith("%")) {
|
|
682
|
+
const pct = parseFloat(v) / 100;
|
|
683
|
+
return pct * Math.min(width, height);
|
|
684
|
+
}
|
|
685
|
+
return toNumber(v);
|
|
686
|
+
}
|
|
687
|
+
function getBorderRadius(style, width, height) {
|
|
681
688
|
return {
|
|
682
|
-
topLeft:
|
|
683
|
-
topRight:
|
|
684
|
-
bottomRight:
|
|
685
|
-
bottomLeft:
|
|
689
|
+
topLeft: resolveRadius(style.borderTopLeftRadius, width, height),
|
|
690
|
+
topRight: resolveRadius(style.borderTopRightRadius, width, height),
|
|
691
|
+
bottomRight: resolveRadius(style.borderBottomRightRadius, width, height),
|
|
692
|
+
bottomLeft: resolveRadius(style.borderBottomLeftRadius, width, height)
|
|
686
693
|
};
|
|
687
694
|
}
|
|
688
|
-
function getBorderRadiusFromStyle(style) {
|
|
689
|
-
return getBorderRadius(style);
|
|
695
|
+
function getBorderRadiusFromStyle(style, width, height) {
|
|
696
|
+
return getBorderRadius(style, width, height);
|
|
690
697
|
}
|
|
691
698
|
function drawBorders(ctx, x, y, width, height, style, borderRadius) {
|
|
692
699
|
const hasRoundedCorners = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
@@ -951,9 +958,14 @@ function parsePoints(value) {
|
|
|
951
958
|
}
|
|
952
959
|
function applyFillAndStroke(ctx, props, path, inheritedFill, color) {
|
|
953
960
|
const fill = resolveCurrentColor(props.fill, color) ?? inheritedFill;
|
|
961
|
+
const fillRule = props.fillRule ?? props["fill-rule"];
|
|
962
|
+
const clipRule = props.clipRule ?? props["clip-rule"];
|
|
963
|
+
if (clipRule) {
|
|
964
|
+
ctx.clip(path, clipRule);
|
|
965
|
+
}
|
|
954
966
|
if (fill !== "none") {
|
|
955
967
|
ctx.fillStyle = fill;
|
|
956
|
-
ctx.fill(path);
|
|
968
|
+
ctx.fill(path, fillRule ?? "nonzero");
|
|
957
969
|
}
|
|
958
970
|
applyStroke(ctx, props, path, color);
|
|
959
971
|
}
|
|
@@ -1014,7 +1026,7 @@ async function loadEmoji(type, code) {
|
|
|
1014
1026
|
}
|
|
1015
1027
|
|
|
1016
1028
|
// src/jsx/text/emoji-split.ts
|
|
1017
|
-
function splitTextIntoRuns(text, measureText2, emojiSize) {
|
|
1029
|
+
function splitTextIntoRuns(text, measureText2, emojiSize, letterSpacing = 0) {
|
|
1018
1030
|
const runs = [];
|
|
1019
1031
|
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
1020
1032
|
let currentText = "";
|
|
@@ -1024,13 +1036,18 @@ function splitTextIntoRuns(text, measureText2, emojiSize) {
|
|
|
1024
1036
|
if (isEmojiGrapheme(segment)) {
|
|
1025
1037
|
if (currentText) {
|
|
1026
1038
|
const textWidth = measureText2(currentText);
|
|
1039
|
+
const graphemeCount = [
|
|
1040
|
+
...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(
|
|
1041
|
+
currentText
|
|
1042
|
+
)
|
|
1043
|
+
].length;
|
|
1027
1044
|
runs.push({
|
|
1028
1045
|
kind: "text",
|
|
1029
1046
|
text: currentText,
|
|
1030
1047
|
x: textStartX,
|
|
1031
|
-
width: textWidth
|
|
1048
|
+
width: textWidth + letterSpacing * graphemeCount
|
|
1032
1049
|
});
|
|
1033
|
-
currentX = textStartX + textWidth;
|
|
1050
|
+
currentX = textStartX + textWidth + letterSpacing * graphemeCount;
|
|
1034
1051
|
currentText = "";
|
|
1035
1052
|
}
|
|
1036
1053
|
runs.push({
|
|
@@ -1039,7 +1056,7 @@ function splitTextIntoRuns(text, measureText2, emojiSize) {
|
|
|
1039
1056
|
x: currentX,
|
|
1040
1057
|
width: emojiSize
|
|
1041
1058
|
});
|
|
1042
|
-
currentX += emojiSize;
|
|
1059
|
+
currentX += emojiSize + letterSpacing;
|
|
1043
1060
|
textStartX = currentX;
|
|
1044
1061
|
} else {
|
|
1045
1062
|
if (!currentText) textStartX = currentX;
|
|
@@ -1048,11 +1065,16 @@ function splitTextIntoRuns(text, measureText2, emojiSize) {
|
|
|
1048
1065
|
}
|
|
1049
1066
|
if (currentText) {
|
|
1050
1067
|
const textWidth = measureText2(currentText);
|
|
1068
|
+
const graphemeCount = [
|
|
1069
|
+
...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(
|
|
1070
|
+
currentText
|
|
1071
|
+
)
|
|
1072
|
+
].length;
|
|
1051
1073
|
runs.push({
|
|
1052
1074
|
kind: "text",
|
|
1053
1075
|
text: currentText,
|
|
1054
1076
|
x: textStartX,
|
|
1055
|
-
width: textWidth
|
|
1077
|
+
width: textWidth + letterSpacing * graphemeCount
|
|
1056
1078
|
});
|
|
1057
1079
|
}
|
|
1058
1080
|
return runs;
|
|
@@ -1103,20 +1125,29 @@ async function drawText(ctx, segments, offsetX, offsetY, textShadow, emojiStyle)
|
|
|
1103
1125
|
}
|
|
1104
1126
|
}
|
|
1105
1127
|
async function drawSegmentWithEmoji(ctx, seg, x, y, textShadow, emojiStyle) {
|
|
1128
|
+
const letterSpacing = seg.letterSpacing ?? 0;
|
|
1106
1129
|
const runs = splitTextIntoRuns(
|
|
1107
1130
|
seg.text,
|
|
1108
1131
|
(text) => {
|
|
1109
1132
|
setFont(ctx, seg.fontSize, seg.fontFamily, seg.fontWeight, seg.fontStyle);
|
|
1110
1133
|
return ctx.measureText(text).width;
|
|
1111
1134
|
},
|
|
1112
|
-
seg.fontSize
|
|
1135
|
+
seg.fontSize,
|
|
1136
|
+
letterSpacing
|
|
1113
1137
|
);
|
|
1114
1138
|
for (const run of runs) {
|
|
1115
1139
|
if (run.kind === "text") {
|
|
1116
|
-
if (
|
|
1117
|
-
|
|
1140
|
+
if (letterSpacing !== 0) {
|
|
1141
|
+
if (textShadow) {
|
|
1142
|
+
drawTextShadow(ctx, run.text, x + run.x, y, textShadow);
|
|
1143
|
+
}
|
|
1144
|
+
drawTextWithLetterSpacing(ctx, run.text, x + run.x, y, letterSpacing);
|
|
1145
|
+
} else {
|
|
1146
|
+
if (textShadow) {
|
|
1147
|
+
drawTextShadow(ctx, run.text, x + run.x, y, textShadow);
|
|
1148
|
+
}
|
|
1149
|
+
ctx.fillText(run.text, x + run.x, y);
|
|
1118
1150
|
}
|
|
1119
|
-
ctx.fillText(run.text, x + run.x, y);
|
|
1120
1151
|
} else {
|
|
1121
1152
|
const img = await loadEmojiImage(emojiStyle, run.char);
|
|
1122
1153
|
if (img) {
|
|
@@ -1291,84 +1322,91 @@ async function drawNode(ctx, node, parentX, parentY, debug, emojiStyle) {
|
|
|
1291
1322
|
}
|
|
1292
1323
|
const isClipped = style.overflow === "hidden" || style.overflowX === "hidden" || style.overflowY === "hidden";
|
|
1293
1324
|
if (isClipped) {
|
|
1294
|
-
const borderRadius = getBorderRadiusFromStyle(style);
|
|
1325
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1295
1326
|
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1296
1327
|
}
|
|
1297
1328
|
if (style.backgroundColor || style.borderTopWidth || style.borderRightWidth || style.borderBottomWidth || style.borderLeftWidth || style.boxShadow) {
|
|
1298
1329
|
drawRect(ctx, x, y, width, height, style);
|
|
1299
1330
|
}
|
|
1300
1331
|
if (style.backgroundImage) {
|
|
1301
|
-
const
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
x,
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1313
|
-
ctx.beginPath();
|
|
1314
|
-
roundedRect(
|
|
1315
|
-
ctx,
|
|
1316
|
-
x,
|
|
1317
|
-
y,
|
|
1318
|
-
width,
|
|
1319
|
-
height,
|
|
1320
|
-
borderRadius.topLeft,
|
|
1321
|
-
borderRadius.topRight,
|
|
1322
|
-
borderRadius.bottomRight,
|
|
1323
|
-
borderRadius.bottomLeft
|
|
1324
|
-
);
|
|
1325
|
-
ctx.fill();
|
|
1326
|
-
} else {
|
|
1327
|
-
ctx.fillRect(x, y, width, height);
|
|
1328
|
-
}
|
|
1329
|
-
} else {
|
|
1330
|
-
const urlMatch = style.backgroundImage.match(/url\(["']?(.*?)["']?\)/);
|
|
1331
|
-
if (urlMatch) {
|
|
1332
|
-
const borderRadius = getBorderRadiusFromStyle(style);
|
|
1333
|
-
const hasRadius2 = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
1334
|
-
if (hasRadius2) {
|
|
1335
|
-
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1336
|
-
}
|
|
1337
|
-
const image = await loadImage3(urlMatch[1]);
|
|
1338
|
-
const bgSize = style.backgroundSize;
|
|
1339
|
-
if (bgSize === "cover") {
|
|
1340
|
-
const r = computeCover(
|
|
1341
|
-
image.width,
|
|
1342
|
-
image.height,
|
|
1332
|
+
const layers = splitGradientArgs(style.backgroundImage);
|
|
1333
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
1334
|
+
const layer = layers[i].trim();
|
|
1335
|
+
const gradient = createGradientFromCSS(ctx, layer, x, y, width, height);
|
|
1336
|
+
if (gradient) {
|
|
1337
|
+
ctx.fillStyle = gradient;
|
|
1338
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1339
|
+
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1340
|
+
ctx.beginPath();
|
|
1341
|
+
roundedRect(
|
|
1342
|
+
ctx,
|
|
1343
1343
|
x,
|
|
1344
1344
|
y,
|
|
1345
1345
|
width,
|
|
1346
|
-
height
|
|
1346
|
+
height,
|
|
1347
|
+
borderRadius.topLeft,
|
|
1348
|
+
borderRadius.topRight,
|
|
1349
|
+
borderRadius.bottomRight,
|
|
1350
|
+
borderRadius.bottomLeft
|
|
1347
1351
|
);
|
|
1348
|
-
ctx.
|
|
1352
|
+
ctx.fill();
|
|
1349
1353
|
} else {
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1354
|
+
ctx.fillRect(x, y, width, height);
|
|
1355
|
+
}
|
|
1356
|
+
} else {
|
|
1357
|
+
const urlMatch = layer.match(/url\(["']?(.*?)["']?\)/);
|
|
1358
|
+
if (urlMatch) {
|
|
1359
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1360
|
+
const hasRadius2 = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
1361
|
+
if (hasRadius2) {
|
|
1362
|
+
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1363
|
+
}
|
|
1364
|
+
const image = await loadImage3(urlMatch[1]);
|
|
1365
|
+
const bgSize = style.backgroundSize;
|
|
1366
|
+
if (bgSize === "cover") {
|
|
1367
|
+
const r = computeCover(
|
|
1353
1368
|
image.width,
|
|
1354
1369
|
image.height,
|
|
1355
|
-
|
|
1356
|
-
|
|
1370
|
+
x,
|
|
1371
|
+
y,
|
|
1357
1372
|
width,
|
|
1358
1373
|
height
|
|
1359
1374
|
);
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1375
|
+
ctx.drawImage(
|
|
1376
|
+
image,
|
|
1377
|
+
r.sx,
|
|
1378
|
+
r.sy,
|
|
1379
|
+
r.sw,
|
|
1380
|
+
r.sh,
|
|
1381
|
+
r.dx,
|
|
1382
|
+
r.dy,
|
|
1383
|
+
r.dw,
|
|
1384
|
+
r.dh
|
|
1385
|
+
);
|
|
1365
1386
|
} else {
|
|
1366
|
-
tileW
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1387
|
+
let tileW, tileH;
|
|
1388
|
+
if (bgSize === "contain") {
|
|
1389
|
+
const r = computeContain(
|
|
1390
|
+
image.width,
|
|
1391
|
+
image.height,
|
|
1392
|
+
0,
|
|
1393
|
+
0,
|
|
1394
|
+
width,
|
|
1395
|
+
height
|
|
1396
|
+
);
|
|
1397
|
+
tileW = r.dw;
|
|
1398
|
+
tileH = r.dh;
|
|
1399
|
+
} else if (bgSize === "100% 100%") {
|
|
1400
|
+
tileW = width;
|
|
1401
|
+
tileH = height;
|
|
1402
|
+
} else {
|
|
1403
|
+
tileW = image.width;
|
|
1404
|
+
tileH = image.height;
|
|
1405
|
+
}
|
|
1406
|
+
for (let ty = y; ty < y + height; ty += tileH) {
|
|
1407
|
+
for (let tx = x; tx < x + width; tx += tileW) {
|
|
1408
|
+
ctx.drawImage(image, tx, ty, tileW, tileH);
|
|
1409
|
+
}
|
|
1372
1410
|
}
|
|
1373
1411
|
}
|
|
1374
1412
|
}
|
|
@@ -1416,7 +1454,7 @@ async function drawNode(ctx, node, parentX, parentY, debug, emojiStyle) {
|
|
|
1416
1454
|
const imgW = width - paddingLeft - paddingRight;
|
|
1417
1455
|
const imgH = height - paddingTop - paddingBottom;
|
|
1418
1456
|
if (!isClipped) {
|
|
1419
|
-
const borderRadius = getBorderRadiusFromStyle(style);
|
|
1457
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1420
1458
|
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1421
1459
|
applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);
|
|
1422
1460
|
}
|
|
@@ -1479,84 +1517,91 @@ async function drawNodeInner(ctx, node, parentX, parentY, offsetX, offsetY, debu
|
|
|
1479
1517
|
}
|
|
1480
1518
|
const isClipped = style.overflow === "hidden" || style.overflowX === "hidden" || style.overflowY === "hidden";
|
|
1481
1519
|
if (isClipped) {
|
|
1482
|
-
const borderRadius = getBorderRadiusFromStyle(style);
|
|
1520
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1483
1521
|
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1484
1522
|
}
|
|
1485
1523
|
if (style.backgroundColor || style.borderTopWidth || style.borderRightWidth || style.borderBottomWidth || style.borderLeftWidth || style.boxShadow) {
|
|
1486
1524
|
drawRect(ctx, x, y, width, height, style);
|
|
1487
1525
|
}
|
|
1488
1526
|
if (style.backgroundImage) {
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
x,
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1501
|
-
ctx.beginPath();
|
|
1502
|
-
roundedRect(
|
|
1503
|
-
ctx,
|
|
1504
|
-
x,
|
|
1505
|
-
y,
|
|
1506
|
-
width,
|
|
1507
|
-
height,
|
|
1508
|
-
borderRadius.topLeft,
|
|
1509
|
-
borderRadius.topRight,
|
|
1510
|
-
borderRadius.bottomRight,
|
|
1511
|
-
borderRadius.bottomLeft
|
|
1512
|
-
);
|
|
1513
|
-
ctx.fill();
|
|
1514
|
-
} else {
|
|
1515
|
-
ctx.fillRect(x, y, width, height);
|
|
1516
|
-
}
|
|
1517
|
-
} else {
|
|
1518
|
-
const urlMatch = style.backgroundImage.match(/url\(["']?(.*?)["']?\)/);
|
|
1519
|
-
if (urlMatch) {
|
|
1520
|
-
const borderRadius = getBorderRadiusFromStyle(style);
|
|
1521
|
-
const hasRadius2 = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
1522
|
-
if (hasRadius2) {
|
|
1523
|
-
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1524
|
-
}
|
|
1525
|
-
const image = await loadImage3(urlMatch[1]);
|
|
1526
|
-
const bgSize = style.backgroundSize;
|
|
1527
|
-
if (bgSize === "cover") {
|
|
1528
|
-
const r = computeCover(
|
|
1529
|
-
image.width,
|
|
1530
|
-
image.height,
|
|
1527
|
+
const layers = splitGradientArgs(style.backgroundImage);
|
|
1528
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
1529
|
+
const layer = layers[i].trim();
|
|
1530
|
+
const gradient = createGradientFromCSS(ctx, layer, x, y, width, height);
|
|
1531
|
+
if (gradient) {
|
|
1532
|
+
ctx.fillStyle = gradient;
|
|
1533
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1534
|
+
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1535
|
+
ctx.beginPath();
|
|
1536
|
+
roundedRect(
|
|
1537
|
+
ctx,
|
|
1531
1538
|
x,
|
|
1532
1539
|
y,
|
|
1533
1540
|
width,
|
|
1534
|
-
height
|
|
1541
|
+
height,
|
|
1542
|
+
borderRadius.topLeft,
|
|
1543
|
+
borderRadius.topRight,
|
|
1544
|
+
borderRadius.bottomRight,
|
|
1545
|
+
borderRadius.bottomLeft
|
|
1535
1546
|
);
|
|
1536
|
-
ctx.
|
|
1547
|
+
ctx.fill();
|
|
1537
1548
|
} else {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1549
|
+
ctx.fillRect(x, y, width, height);
|
|
1550
|
+
}
|
|
1551
|
+
} else {
|
|
1552
|
+
const urlMatch = layer.match(/url\(["']?(.*?)["']?\)/);
|
|
1553
|
+
if (urlMatch) {
|
|
1554
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1555
|
+
const hasRadius2 = borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0;
|
|
1556
|
+
if (hasRadius2) {
|
|
1557
|
+
applyClip(ctx, x, y, width, height, borderRadius);
|
|
1558
|
+
}
|
|
1559
|
+
const image = await loadImage3(urlMatch[1]);
|
|
1560
|
+
const bgSize = style.backgroundSize;
|
|
1561
|
+
if (bgSize === "cover") {
|
|
1562
|
+
const r = computeCover(
|
|
1541
1563
|
image.width,
|
|
1542
1564
|
image.height,
|
|
1543
|
-
|
|
1544
|
-
|
|
1565
|
+
x,
|
|
1566
|
+
y,
|
|
1545
1567
|
width,
|
|
1546
1568
|
height
|
|
1547
1569
|
);
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1570
|
+
ctx.drawImage(
|
|
1571
|
+
image,
|
|
1572
|
+
r.sx,
|
|
1573
|
+
r.sy,
|
|
1574
|
+
r.sw,
|
|
1575
|
+
r.sh,
|
|
1576
|
+
r.dx,
|
|
1577
|
+
r.dy,
|
|
1578
|
+
r.dw,
|
|
1579
|
+
r.dh
|
|
1580
|
+
);
|
|
1553
1581
|
} else {
|
|
1554
|
-
tileW
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1582
|
+
let tileW, tileH;
|
|
1583
|
+
if (bgSize === "contain") {
|
|
1584
|
+
const r = computeContain(
|
|
1585
|
+
image.width,
|
|
1586
|
+
image.height,
|
|
1587
|
+
0,
|
|
1588
|
+
0,
|
|
1589
|
+
width,
|
|
1590
|
+
height
|
|
1591
|
+
);
|
|
1592
|
+
tileW = r.dw;
|
|
1593
|
+
tileH = r.dh;
|
|
1594
|
+
} else if (bgSize === "100% 100%") {
|
|
1595
|
+
tileW = width;
|
|
1596
|
+
tileH = height;
|
|
1597
|
+
} else {
|
|
1598
|
+
tileW = image.width;
|
|
1599
|
+
tileH = image.height;
|
|
1600
|
+
}
|
|
1601
|
+
for (let ty = y; ty < y + height; ty += tileH) {
|
|
1602
|
+
for (let tx = x; tx < x + width; tx += tileW) {
|
|
1603
|
+
ctx.drawImage(image, tx, ty, tileW, tileH);
|
|
1604
|
+
}
|
|
1560
1605
|
}
|
|
1561
1606
|
}
|
|
1562
1607
|
}
|
|
@@ -1604,7 +1649,7 @@ async function drawNodeInner(ctx, node, parentX, parentY, offsetX, offsetY, debu
|
|
|
1604
1649
|
const imgW = width - paddingLeft - paddingRight;
|
|
1605
1650
|
const imgH = height - paddingTop - paddingBottom;
|
|
1606
1651
|
if (!isClipped) {
|
|
1607
|
-
const borderRadius = getBorderRadiusFromStyle(style);
|
|
1652
|
+
const borderRadius = getBorderRadiusFromStyle(style, width, height);
|
|
1608
1653
|
if (borderRadius.topLeft > 0 || borderRadius.topRight > 0 || borderRadius.bottomRight > 0 || borderRadius.bottomLeft > 0) {
|
|
1609
1654
|
applyClip(ctx, imgX, imgY, imgW, imgH, borderRadius);
|
|
1610
1655
|
}
|
|
@@ -1742,8 +1787,8 @@ function parseValue(v) {
|
|
|
1742
1787
|
if (v === void 0 || v === null) return void 0;
|
|
1743
1788
|
const s = String(v);
|
|
1744
1789
|
if (s === "auto") return "auto";
|
|
1745
|
-
const n =
|
|
1746
|
-
if (!isNaN(n)) return n;
|
|
1790
|
+
const n = Number(s);
|
|
1791
|
+
if (s !== "" && !isNaN(n)) return n;
|
|
1747
1792
|
return s;
|
|
1748
1793
|
}
|
|
1749
1794
|
function expandStyle(raw) {
|
|
@@ -1952,7 +1997,15 @@ var DIMENSION_PROPS = [
|
|
|
1952
1997
|
"paddingLeft",
|
|
1953
1998
|
"rowGap",
|
|
1954
1999
|
"columnGap",
|
|
1955
|
-
"flexBasis"
|
|
2000
|
+
"flexBasis",
|
|
2001
|
+
"borderTopWidth",
|
|
2002
|
+
"borderRightWidth",
|
|
2003
|
+
"borderBottomWidth",
|
|
2004
|
+
"borderLeftWidth",
|
|
2005
|
+
"borderTopLeftRadius",
|
|
2006
|
+
"borderTopRightRadius",
|
|
2007
|
+
"borderBottomRightRadius",
|
|
2008
|
+
"borderBottomLeftRadius"
|
|
1956
2009
|
];
|
|
1957
2010
|
function resolveUnit(value, viewportWidth, viewportHeight, fontSize, rootFontSize) {
|
|
1958
2011
|
if (value.endsWith("%") || value === "auto") return value;
|