leafer-ui 1.9.11 → 1.10.0

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/web.cjs CHANGED
@@ -985,6 +985,7 @@ class Picker {
985
985
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
986
986
  if (child.isBranch) {
987
987
  if (hit || child.__ignoreHitWorld) {
988
+ if (child.isBranchLeaf && child.__.__clipAfterFill && !child.__hitWorld(point)) continue;
988
989
  if (child.topChildren) this.eachFind(child.topChildren, false);
989
990
  this.eachFind(child.children, child.__onlyHitMask);
990
991
  if (child.isBranchLeaf) this.hitChild(child, point);
@@ -1393,36 +1394,19 @@ class Interaction extends core$1.InteractionBase {
1393
1394
  }
1394
1395
  }
1395
1396
 
1396
- function fillText(ui, canvas) {
1397
- const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
1398
- if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
1399
- let row;
1400
- for (let i = 0, len = rows.length; i < len; i++) {
1401
- row = rows[i];
1402
- if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
1403
- canvas.fillText(charData.char, charData.x, row.y);
1404
- });
1405
- }
1406
- if (decorationY) {
1407
- const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
1408
- if (decorationColor) canvas.fillStyle = decorationColor;
1409
- rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
1410
- }
1411
- }
1412
-
1413
- function fill(fill, ui, canvas) {
1397
+ function fill(fill, ui, canvas, renderOptions) {
1414
1398
  canvas.fillStyle = fill;
1415
- fillPathOrText(ui, canvas);
1399
+ fillPathOrText(ui, canvas, renderOptions);
1416
1400
  }
1417
1401
 
1418
- function fills(fills, ui, canvas) {
1402
+ function fills(fills, ui, canvas, renderOptions) {
1419
1403
  let item;
1420
1404
  for (let i = 0, len = fills.length; i < len; i++) {
1421
1405
  item = fills[i];
1422
1406
  if (item.image) {
1423
- if (draw.PaintImage.checkImage(ui, canvas, item, !ui.__.__font)) continue;
1407
+ if (draw.PaintImage.checkImage(item, !ui.__.__font, ui, canvas, renderOptions)) continue;
1424
1408
  if (!item.style) {
1425
- if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(canvas, item.image);
1409
+ if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(item.image, canvas, renderOptions);
1426
1410
  continue;
1427
1411
  }
1428
1412
  }
@@ -1435,60 +1419,137 @@ function fills(fills, ui, canvas) {
1435
1419
  if (item.scaleFixed === true || item.scaleFixed === "zoom-in" && scaleX > 1 && scaleY > 1) canvas.scale(1 / scaleX, 1 / scaleY);
1436
1420
  }
1437
1421
  if (item.blendMode) canvas.blendMode = item.blendMode;
1438
- fillPathOrText(ui, canvas);
1422
+ fillPathOrText(ui, canvas, renderOptions);
1439
1423
  canvas.restore();
1440
1424
  } else {
1441
1425
  if (item.blendMode) {
1442
1426
  canvas.saveBlendMode(item.blendMode);
1443
- fillPathOrText(ui, canvas);
1427
+ fillPathOrText(ui, canvas, renderOptions);
1444
1428
  canvas.restoreBlendMode();
1445
- } else fillPathOrText(ui, canvas);
1429
+ } else fillPathOrText(ui, canvas, renderOptions);
1430
+ }
1431
+ }
1432
+ }
1433
+
1434
+ function fillPathOrText(ui, canvas, renderOptions) {
1435
+ ui.__.__font ? draw.Paint.fillText(ui, canvas, renderOptions) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
1436
+ }
1437
+
1438
+ function fillText(ui, canvas, _renderOptions) {
1439
+ const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
1440
+ if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
1441
+ let row;
1442
+ for (let i = 0, len = rows.length; i < len; i++) {
1443
+ row = rows[i];
1444
+ if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
1445
+ canvas.fillText(charData.char, charData.x, row.y);
1446
+ });
1447
+ }
1448
+ if (decorationY) {
1449
+ const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
1450
+ if (decorationColor) canvas.fillStyle = decorationColor;
1451
+ rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
1452
+ }
1453
+ }
1454
+
1455
+ function stroke(stroke, ui, canvas, renderOptions) {
1456
+ const data = ui.__;
1457
+ if (!data.__strokeWidth) return;
1458
+ if (data.__font) {
1459
+ draw.Paint.strokeText(stroke, ui, canvas, renderOptions);
1460
+ } else {
1461
+ switch (data.strokeAlign) {
1462
+ case "center":
1463
+ drawCenter$1(stroke, 1, ui, canvas, renderOptions);
1464
+ break;
1465
+
1466
+ case "inside":
1467
+ drawInside(stroke, ui, canvas, renderOptions);
1468
+ break;
1469
+
1470
+ case "outside":
1471
+ drawOutside(stroke, ui, canvas, renderOptions);
1472
+ break;
1446
1473
  }
1447
1474
  }
1448
1475
  }
1449
1476
 
1450
- function fillPathOrText(ui, canvas) {
1451
- ui.__.__font ? fillText(ui, canvas) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
1477
+ function strokes(strokes, ui, canvas, renderOptions) {
1478
+ draw.Paint.stroke(strokes, ui, canvas, renderOptions);
1479
+ }
1480
+
1481
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas, renderOptions) {
1482
+ const data = ui.__;
1483
+ if (core.isObject(stroke)) {
1484
+ draw.Paint.drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas, renderOptions);
1485
+ } else {
1486
+ canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
1487
+ canvas.stroke();
1488
+ }
1489
+ if (data.__useArrow) draw.Paint.strokeArrow(stroke, ui, canvas, renderOptions);
1490
+ }
1491
+
1492
+ function drawInside(stroke, ui, canvas, renderOptions) {
1493
+ canvas.save();
1494
+ canvas.clipUI(ui);
1495
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
1496
+ canvas.restore();
1452
1497
  }
1453
1498
 
1454
- function strokeText(stroke, ui, canvas) {
1499
+ function drawOutside(stroke, ui, canvas, renderOptions) {
1500
+ const data = ui.__;
1501
+ if (data.__fillAfterStroke) {
1502
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
1503
+ } else {
1504
+ const {renderBounds: renderBounds} = ui.__layout;
1505
+ const out = canvas.getSameCanvas(true, true);
1506
+ ui.__drawRenderPath(out);
1507
+ drawCenter$1(stroke, 2, ui, out, renderOptions);
1508
+ out.clipUI(data);
1509
+ out.clearWorld(renderBounds);
1510
+ core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
1511
+ out.recycle(ui.__nowWorld);
1512
+ }
1513
+ }
1514
+
1515
+ function strokeText(stroke, ui, canvas, renderOptions) {
1455
1516
  switch (ui.__.strokeAlign) {
1456
1517
  case "center":
1457
- drawCenter$1(stroke, 1, ui, canvas);
1518
+ drawCenter(stroke, 1, ui, canvas, renderOptions);
1458
1519
  break;
1459
1520
 
1460
1521
  case "inside":
1461
- drawAlign(stroke, "inside", ui, canvas);
1522
+ drawAlign(stroke, "inside", ui, canvas, renderOptions);
1462
1523
  break;
1463
1524
 
1464
1525
  case "outside":
1465
- ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, "outside", ui, canvas);
1526
+ ui.__.__fillAfterStroke ? drawCenter(stroke, 2, ui, canvas, renderOptions) : drawAlign(stroke, "outside", ui, canvas, renderOptions);
1466
1527
  break;
1467
1528
  }
1468
1529
  }
1469
1530
 
1470
- function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
1531
+ function drawCenter(stroke, strokeWidthScale, ui, canvas, renderOptions) {
1471
1532
  const data = ui.__;
1472
1533
  if (core.isObject(stroke)) {
1473
- drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas);
1534
+ draw.Paint.drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas, renderOptions);
1474
1535
  } else {
1475
1536
  canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
1476
- drawTextStroke(ui, canvas);
1537
+ draw.Paint.drawTextStroke(ui, canvas, renderOptions);
1477
1538
  }
1478
1539
  }
1479
1540
 
1480
- function drawAlign(stroke, align, ui, canvas) {
1541
+ function drawAlign(stroke, align, ui, canvas, renderOptions) {
1481
1542
  const out = canvas.getSameCanvas(true, true);
1482
1543
  out.font = ui.__.__font;
1483
- drawCenter$1(stroke, 2, ui, out);
1544
+ drawCenter(stroke, 2, ui, out, renderOptions);
1484
1545
  out.blendMode = align === "outside" ? "destination-out" : "destination-in";
1485
- fillText(ui, out);
1546
+ draw.Paint.fillText(ui, out, renderOptions);
1486
1547
  out.blendMode = "normal";
1487
1548
  core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
1488
1549
  out.recycle(ui.__nowWorld);
1489
1550
  }
1490
1551
 
1491
- function drawTextStroke(ui, canvas) {
1552
+ function drawTextStroke(ui, canvas, _renderOptions) {
1492
1553
  let row, data = ui.__.__textDrawData;
1493
1554
  const {rows: rows, decorationY: decorationY} = data;
1494
1555
  for (let i = 0, len = rows.length; i < len; i++) {
@@ -1503,13 +1564,13 @@ function drawTextStroke(ui, canvas) {
1503
1564
  }
1504
1565
  }
1505
1566
 
1506
- function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
1567
+ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas, renderOptions) {
1507
1568
  let item;
1508
1569
  const data = ui.__, {__hasMultiStrokeStyle: __hasMultiStrokeStyle} = data;
1509
1570
  __hasMultiStrokeStyle || canvas.setStroke(undefined, data.__strokeWidth * strokeWidthScale, data);
1510
1571
  for (let i = 0, len = strokes.length; i < len; i++) {
1511
1572
  item = strokes[i];
1512
- if (item.image && draw.PaintImage.checkImage(ui, canvas, item, false)) continue;
1573
+ if (item.image && draw.PaintImage.checkImage(item, false, ui, canvas, renderOptions)) continue;
1513
1574
  if (item.style) {
1514
1575
  if (__hasMultiStrokeStyle) {
1515
1576
  const {strokeStyle: strokeStyle} = item;
@@ -1517,75 +1578,15 @@ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
1517
1578
  } else canvas.strokeStyle = item.style;
1518
1579
  if (item.blendMode) {
1519
1580
  canvas.saveBlendMode(item.blendMode);
1520
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1581
+ isText ? draw.Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
1521
1582
  canvas.restoreBlendMode();
1522
1583
  } else {
1523
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1584
+ isText ? draw.Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
1524
1585
  }
1525
1586
  }
1526
1587
  }
1527
1588
  }
1528
1589
 
1529
- function stroke(stroke, ui, canvas) {
1530
- const data = ui.__;
1531
- if (!data.__strokeWidth) return;
1532
- if (data.__font) {
1533
- strokeText(stroke, ui, canvas);
1534
- } else {
1535
- switch (data.strokeAlign) {
1536
- case "center":
1537
- drawCenter(stroke, 1, ui, canvas);
1538
- break;
1539
-
1540
- case "inside":
1541
- drawInside(stroke, ui, canvas);
1542
- break;
1543
-
1544
- case "outside":
1545
- drawOutside(stroke, ui, canvas);
1546
- break;
1547
- }
1548
- }
1549
- }
1550
-
1551
- function strokes(strokes, ui, canvas) {
1552
- stroke(strokes, ui, canvas);
1553
- }
1554
-
1555
- function drawCenter(stroke, strokeWidthScale, ui, canvas) {
1556
- const data = ui.__;
1557
- if (core.isObject(stroke)) {
1558
- drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas);
1559
- } else {
1560
- canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
1561
- canvas.stroke();
1562
- }
1563
- if (data.__useArrow) draw.Paint.strokeArrow(stroke, ui, canvas);
1564
- }
1565
-
1566
- function drawInside(stroke, ui, canvas) {
1567
- canvas.save();
1568
- canvas.clipUI(ui);
1569
- drawCenter(stroke, 2, ui, canvas);
1570
- canvas.restore();
1571
- }
1572
-
1573
- function drawOutside(stroke, ui, canvas) {
1574
- const data = ui.__;
1575
- if (data.__fillAfterStroke) {
1576
- drawCenter(stroke, 2, ui, canvas);
1577
- } else {
1578
- const {renderBounds: renderBounds} = ui.__layout;
1579
- const out = canvas.getSameCanvas(true, true);
1580
- ui.__drawRenderPath(out);
1581
- drawCenter(stroke, 2, ui, out);
1582
- out.clipUI(data);
1583
- out.clearWorld(renderBounds);
1584
- core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
1585
- out.recycle(ui.__nowWorld);
1586
- }
1587
- }
1588
-
1589
1590
  const {getSpread: getSpread, copyAndSpread: copyAndSpread, toOuterOf: toOuterOf, getOuterOf: getOuterOf, getByMove: getByMove, move: move$1, getIntersectData: getIntersectData} = core.BoundsHelper;
1590
1591
 
1591
1592
  const tempBounds$1 = {};
@@ -1741,88 +1742,118 @@ const PaintModule = {
1741
1742
  strokes: strokes,
1742
1743
  strokeText: strokeText,
1743
1744
  drawTextStroke: drawTextStroke,
1745
+ drawStrokesStyle: drawStrokesStyle,
1744
1746
  shape: shape
1745
1747
  };
1746
1748
 
1747
- let origin = {}, tempMatrix$1 = core.getMatrixData();
1749
+ let cache, box = new core.Bounds;
1748
1750
 
1749
- const {get: get$3, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = core.MatrixHelper;
1751
+ const {isSame: isSame} = core.BoundsHelper;
1750
1752
 
1751
- function stretchMode(data, box, scaleX, scaleY) {
1752
- const transform = get$3();
1753
- translate$1(transform, box.x, box.y);
1754
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1755
- data.transform = transform;
1753
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1754
+ let leafPaint, event;
1755
+ const image = core.ImageManager.get(paint);
1756
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1757
+ leafPaint = cache.leafPaint;
1758
+ } else {
1759
+ leafPaint = {
1760
+ type: paint.type,
1761
+ image: image
1762
+ };
1763
+ if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1764
+ cache = image.use > 1 ? {
1765
+ leafPaint: leafPaint,
1766
+ paint: paint,
1767
+ boxBounds: box.set(boxBounds)
1768
+ } : null;
1769
+ }
1770
+ if (firstUse || image.loading) event = {
1771
+ image: image,
1772
+ attrName: attrName,
1773
+ attrValue: paint
1774
+ };
1775
+ if (image.ready) {
1776
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1777
+ if (firstUse) {
1778
+ onLoad(ui, event);
1779
+ onLoadSuccess(ui, event);
1780
+ }
1781
+ } else if (image.error) {
1782
+ if (firstUse) onLoadError(ui, event, image.error);
1783
+ } else {
1784
+ if (firstUse) {
1785
+ ignoreRender(ui, true);
1786
+ onLoad(ui, event);
1787
+ }
1788
+ leafPaint.loadId = image.load(() => {
1789
+ ignoreRender(ui, false);
1790
+ if (!ui.destroyed) {
1791
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1792
+ if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1793
+ ui.forceUpdate("surface");
1794
+ }
1795
+ onLoadSuccess(ui, event);
1796
+ }
1797
+ leafPaint.loadId = undefined;
1798
+ }, error => {
1799
+ ignoreRender(ui, false);
1800
+ onLoadError(ui, event, error);
1801
+ leafPaint.loadId = undefined;
1802
+ });
1803
+ if (ui.placeholderColor) {
1804
+ if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1805
+ if (!image.ready) {
1806
+ image.isPlacehold = true;
1807
+ ui.forceUpdate("surface");
1808
+ }
1809
+ }, ui.placeholderDelay);
1810
+ }
1811
+ }
1812
+ return leafPaint;
1756
1813
  }
1757
1814
 
1758
- function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1759
- const transform = get$3();
1760
- translate$1(transform, box.x + x, box.y + y);
1761
- scaleHelper(transform, scaleX, scaleY);
1762
- if (rotation) rotateOfOuter$1(transform, {
1763
- x: box.x + box.width / 2,
1764
- y: box.y + box.height / 2
1765
- }, rotation);
1766
- data.transform = transform;
1815
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1816
+ if (attrName === "fill" && !ui.__.__naturalWidth) {
1817
+ const data = ui.__;
1818
+ data.__naturalWidth = image.width / data.pixelRatio;
1819
+ data.__naturalHeight = image.height / data.pixelRatio;
1820
+ if (data.__autoSide) {
1821
+ ui.forceUpdate("width");
1822
+ if (ui.__proxyData) {
1823
+ ui.setProxyAttr("width", data.width);
1824
+ ui.setProxyAttr("height", data.height);
1825
+ }
1826
+ return false;
1827
+ }
1828
+ }
1829
+ if (!leafPaint.data) draw.PaintImage.createData(leafPaint, image, paint, boxBounds);
1830
+ return true;
1767
1831
  }
1768
1832
 
1769
- function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1770
- const transform = get$3();
1771
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1772
- if (clipScaleX) {
1773
- if (rotation || skew) {
1774
- set(tempMatrix$1);
1775
- scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1776
- multiplyParent(transform, tempMatrix$1);
1777
- } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1778
- }
1779
- data.transform = transform;
1833
+ function onLoad(ui, event) {
1834
+ emit(ui, core.ImageEvent.LOAD, event);
1780
1835
  }
1781
1836
 
1782
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1783
- const transform = get$3();
1784
- if (freeTransform) {
1785
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1786
- } else {
1787
- if (rotation) {
1788
- if (align === "center") {
1789
- rotateOfOuter$1(transform, {
1790
- x: width / 2,
1791
- y: height / 2
1792
- }, rotation);
1793
- } else {
1794
- rotate(transform, rotation);
1795
- switch (rotation) {
1796
- case 90:
1797
- translate$1(transform, height, 0);
1798
- break;
1837
+ function onLoadSuccess(ui, event) {
1838
+ emit(ui, core.ImageEvent.LOADED, event);
1839
+ }
1799
1840
 
1800
- case 180:
1801
- translate$1(transform, width, height);
1802
- break;
1841
+ function onLoadError(ui, event, error) {
1842
+ event.error = error;
1843
+ ui.forceUpdate("surface");
1844
+ emit(ui, core.ImageEvent.ERROR, event);
1845
+ }
1803
1846
 
1804
- case 270:
1805
- translate$1(transform, 0, width);
1806
- break;
1807
- }
1808
- }
1809
- }
1810
- origin.x = box.x + x;
1811
- origin.y = box.y + y;
1812
- translate$1(transform, origin.x, origin.y);
1813
- if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1814
- }
1815
- data.transform = transform;
1847
+ function emit(ui, type, data) {
1848
+ if (ui.hasEvent(type)) ui.emitEvent(new core.ImageEvent(type, data));
1816
1849
  }
1817
1850
 
1818
- function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1819
- if (rotation) rotate(transform, rotation);
1820
- if (skew) skewHelper(transform, skew.x, skew.y);
1821
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1822
- translate$1(transform, box.x + x, box.y + y);
1851
+ function ignoreRender(ui, value) {
1852
+ const {leafer: leafer} = ui;
1853
+ if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1823
1854
  }
1824
1855
 
1825
- const {get: get$2, translate: translate} = core.MatrixHelper;
1856
+ const {get: get$3, translate: translate$1} = core.MatrixHelper;
1826
1857
 
1827
1858
  const tempBox = new core.Bounds;
1828
1859
 
@@ -1835,13 +1866,13 @@ function createData(leafPaint, image, paint, box) {
1835
1866
  if (changeful) leafPaint.changeful = changeful;
1836
1867
  if (sync) leafPaint.sync = sync;
1837
1868
  if (scaleFixed) leafPaint.scaleFixed = scaleFixed;
1838
- leafPaint.data = getPatternData(paint, box, image);
1869
+ leafPaint.data = draw.PaintImage.getPatternData(paint, box, image);
1839
1870
  }
1840
1871
 
1841
1872
  function getPatternData(paint, box, image) {
1842
1873
  if (paint.padding) box = tempBox.set(box).shrink(paint.padding);
1843
1874
  if (paint.mode === "strench") paint.mode = "stretch";
1844
- let {width: width, height: height} = image;
1875
+ const {width: width, height: height} = image;
1845
1876
  const {opacity: opacity, mode: mode, align: align, offset: offset, scale: scale, size: size, rotation: rotation, skew: skew, clipSize: clipSize, repeat: repeat, gap: gap, filters: filters} = paint;
1846
1877
  const sameBox = box.width === width && box.height === height;
1847
1878
  const data = {
@@ -1872,8 +1903,8 @@ function getPatternData(paint, box, image) {
1872
1903
  case "stretch":
1873
1904
  if (!sameBox) {
1874
1905
  scaleX = box.width / width, scaleY = box.height / height;
1875
- stretchMode(data, box, scaleX, scaleY);
1876
- }
1906
+ draw.PaintImage.stretchMode(data, box, scaleX, scaleY);
1907
+ } else if (scaleX) scaleX = scaleY = undefined;
1877
1908
  break;
1878
1909
 
1879
1910
  case "normal":
@@ -1881,13 +1912,13 @@ function getPatternData(paint, box, image) {
1881
1912
  if (tempImage.x || tempImage.y || scaleX || clipSize || rotation || skew) {
1882
1913
  let clipScaleX, clipScaleY;
1883
1914
  if (clipSize) clipScaleX = box.width / clipSize.width, clipScaleY = box.height / clipSize.height;
1884
- clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1915
+ draw.PaintImage.clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1885
1916
  if (clipScaleX) scaleX = scaleX ? scaleX * clipScaleX : clipScaleX, scaleY = scaleY ? scaleY * clipScaleY : clipScaleY;
1886
1917
  }
1887
1918
  break;
1888
1919
 
1889
1920
  case "repeat":
1890
- if (!sameBox || scaleX || rotation || skew) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1921
+ if (!sameBox || scaleX || rotation || skew) draw.PaintImage.repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1891
1922
  if (!repeat) data.repeat = "repeat";
1892
1923
  const count = core.isObject(repeat);
1893
1924
  if (gap || count) data.gap = getGapData(gap, count && repeat, tempImage.width, tempImage.height, box);
@@ -1896,18 +1927,16 @@ function getPatternData(paint, box, image) {
1896
1927
  case "fit":
1897
1928
  case "cover":
1898
1929
  default:
1899
- if (scaleX) fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1930
+ if (scaleX) draw.PaintImage.fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1900
1931
  }
1901
1932
  if (!data.transform) {
1902
- if (box.x || box.y) translate(data.transform = get$2(), box.x, box.y);
1933
+ if (box.x || box.y) translate$1(data.transform = get$3(), box.x, box.y);
1903
1934
  }
1904
- data.width = width;
1905
- data.height = height;
1906
1935
  if (scaleX) {
1907
1936
  data.scaleX = scaleX;
1908
1937
  data.scaleY = scaleY;
1909
1938
  }
1910
- if (opacity) data.opacity = opacity;
1939
+ if (opacity && opacity < 1) data.opacity = opacity;
1911
1940
  if (filters) data.filters = filters;
1912
1941
  if (repeat) data.repeat = core.isString(repeat) ? repeat === "x" ? "repeat-x" : "repeat-y" : "repeat";
1913
1942
  return data;
@@ -1929,180 +1958,82 @@ function getGapValue(gap, size, totalSize, rows) {
1929
1958
  return gap === "auto" ? value < 0 ? 0 : value : value;
1930
1959
  }
1931
1960
 
1932
- let cache, box = new core.Bounds;
1933
-
1934
- const {isSame: isSame} = core.BoundsHelper;
1935
-
1936
- function image(ui, attrName, paint, boxBounds, firstUse) {
1937
- let leafPaint, event;
1938
- const image = core.ImageManager.get(paint);
1939
- if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1940
- leafPaint = cache.leafPaint;
1941
- } else {
1942
- leafPaint = {
1943
- type: paint.type,
1944
- image: image
1945
- };
1946
- if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1947
- cache = image.use > 1 ? {
1948
- leafPaint: leafPaint,
1949
- paint: paint,
1950
- boxBounds: box.set(boxBounds)
1951
- } : null;
1952
- }
1953
- if (firstUse || image.loading) event = {
1954
- image: image,
1955
- attrName: attrName,
1956
- attrValue: paint
1957
- };
1958
- if (image.ready) {
1959
- checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1960
- if (firstUse) {
1961
- onLoad(ui, event);
1962
- onLoadSuccess(ui, event);
1963
- }
1964
- } else if (image.error) {
1965
- if (firstUse) onLoadError(ui, event, image.error);
1966
- } else {
1967
- if (firstUse) {
1968
- ignoreRender(ui, true);
1969
- onLoad(ui, event);
1970
- }
1971
- leafPaint.loadId = image.load(() => {
1972
- ignoreRender(ui, false);
1973
- if (!ui.destroyed) {
1974
- if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1975
- if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1976
- ui.forceUpdate("surface");
1977
- }
1978
- onLoadSuccess(ui, event);
1979
- }
1980
- leafPaint.loadId = undefined;
1981
- }, error => {
1982
- ignoreRender(ui, false);
1983
- onLoadError(ui, event, error);
1984
- leafPaint.loadId = undefined;
1985
- });
1986
- if (ui.placeholderColor) {
1987
- if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1988
- if (!image.ready) {
1989
- image.isPlacehold = true;
1990
- ui.forceUpdate("surface");
1991
- }
1992
- }, ui.placeholderDelay);
1993
- }
1994
- }
1995
- return leafPaint;
1996
- }
1997
-
1998
- function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1999
- if (attrName === "fill" && !ui.__.__naturalWidth) {
2000
- const data = ui.__;
2001
- data.__naturalWidth = image.width / data.pixelRatio;
2002
- data.__naturalHeight = image.height / data.pixelRatio;
2003
- if (data.__autoSide) {
2004
- ui.forceUpdate("width");
2005
- if (ui.__proxyData) {
2006
- ui.setProxyAttr("width", data.width);
2007
- ui.setProxyAttr("height", data.height);
2008
- }
2009
- return false;
2010
- }
2011
- }
2012
- if (!leafPaint.data) createData(leafPaint, image, paint, boxBounds);
2013
- return true;
2014
- }
2015
-
2016
- function onLoad(ui, event) {
2017
- emit(ui, core.ImageEvent.LOAD, event);
2018
- }
1961
+ let origin = {}, tempMatrix$1 = core.getMatrixData();
2019
1962
 
2020
- function onLoadSuccess(ui, event) {
2021
- emit(ui, core.ImageEvent.LOADED, event);
2022
- }
1963
+ const {get: get$2, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = core.MatrixHelper;
2023
1964
 
2024
- function onLoadError(ui, event, error) {
2025
- event.error = error;
2026
- ui.forceUpdate("surface");
2027
- emit(ui, core.ImageEvent.ERROR, event);
1965
+ function stretchMode(data, box, scaleX, scaleY) {
1966
+ const transform = get$2(), {x: x, y: y} = box;
1967
+ if (x || y) translate(transform, x, y); else transform.onlyScale = true;
1968
+ scaleHelper(transform, scaleX, scaleY);
1969
+ data.transform = transform;
2028
1970
  }
2029
1971
 
2030
- function emit(ui, type, data) {
2031
- if (ui.hasEvent(type)) ui.emitEvent(new core.ImageEvent(type, data));
1972
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1973
+ const transform = get$2();
1974
+ translate(transform, box.x + x, box.y + y);
1975
+ scaleHelper(transform, scaleX, scaleY);
1976
+ if (rotation) rotateOfOuter$1(transform, {
1977
+ x: box.x + box.width / 2,
1978
+ y: box.y + box.height / 2
1979
+ }, rotation);
1980
+ data.transform = transform;
2032
1981
  }
2033
1982
 
2034
- function ignoreRender(ui, value) {
2035
- const {leafer: leafer} = ui;
2036
- if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1983
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1984
+ const transform = get$2();
1985
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1986
+ if (clipScaleX) {
1987
+ if (rotation || skew) {
1988
+ set(tempMatrix$1);
1989
+ scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1990
+ multiplyParent(transform, tempMatrix$1);
1991
+ } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1992
+ }
1993
+ data.transform = transform;
2037
1994
  }
2038
1995
 
2039
- const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
1996
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1997
+ const transform = get$2();
1998
+ if (freeTransform) {
1999
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
2000
+ } else {
2001
+ if (rotation) {
2002
+ if (align === "center") {
2003
+ rotateOfOuter$1(transform, {
2004
+ x: width / 2,
2005
+ y: height / 2
2006
+ }, rotation);
2007
+ } else {
2008
+ rotate(transform, rotation);
2009
+ switch (rotation) {
2010
+ case 90:
2011
+ translate(transform, height, 0);
2012
+ break;
2040
2013
 
2041
- const {floor: floor, ceil: ceil, max: max$1, abs: abs$1} = Math;
2014
+ case 180:
2015
+ translate(transform, width, height);
2016
+ break;
2042
2017
 
2043
- function createPattern(ui, paint, pixelRatio) {
2044
- let {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
2045
- const id = scaleX + "-" + scaleY + "-" + pixelRatio;
2046
- if (paint.patternId !== id && !ui.destroyed) {
2047
- const {image: image, data: data} = paint;
2048
- let imageScale, imageMatrix, {width: width, height: height, scaleX: sx, scaleY: sy, transform: transform, repeat: repeat, gap: gap} = data;
2049
- scaleX *= pixelRatio;
2050
- scaleY *= pixelRatio;
2051
- if (sx) {
2052
- sx = abs$1(sx);
2053
- sy = abs$1(sy);
2054
- imageMatrix = get$1();
2055
- copy$1(imageMatrix, transform);
2056
- scale(imageMatrix, 1 / sx, 1 / sy);
2057
- scaleX *= sx;
2058
- scaleY *= sy;
2059
- }
2060
- width *= scaleX;
2061
- height *= scaleY;
2062
- const size = width * height;
2063
- if (!repeat) {
2064
- if (size > core.Platform.image.maxCacheSize) return false;
2065
- }
2066
- let maxSize = core.Platform.image.maxPatternSize;
2067
- if (image.isSVG) {
2068
- const ws = width / image.width;
2069
- if (ws > 1) imageScale = ws / ceil(ws);
2070
- } else {
2071
- const imageSize = image.width * image.height;
2072
- if (maxSize > imageSize) maxSize = imageSize;
2073
- }
2074
- if (size > maxSize) imageScale = Math.sqrt(size / maxSize);
2075
- if (imageScale) {
2076
- scaleX /= imageScale;
2077
- scaleY /= imageScale;
2078
- width /= imageScale;
2079
- height /= imageScale;
2080
- }
2081
- if (sx) {
2082
- scaleX /= sx;
2083
- scaleY /= sy;
2084
- }
2085
- const xGap = gap && gap.x * scaleX;
2086
- const yGap = gap && gap.y * scaleY;
2087
- if (transform || scaleX !== 1 || scaleY !== 1) {
2088
- const canvasWidth = width + (xGap || 0);
2089
- const canvasHeight = height + (yGap || 0);
2090
- scaleX /= canvasWidth / max$1(floor(canvasWidth), 1);
2091
- scaleY /= canvasHeight / max$1(floor(canvasHeight), 1);
2092
- if (!imageMatrix) {
2093
- imageMatrix = get$1();
2094
- if (transform) copy$1(imageMatrix, transform);
2018
+ case 270:
2019
+ translate(transform, 0, width);
2020
+ break;
2021
+ }
2095
2022
  }
2096
- scale(imageMatrix, 1 / scaleX, 1 / scaleY);
2097
2023
  }
2098
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
2099
- const pattern = image.getPattern(canvas, repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
2100
- paint.style = pattern;
2101
- paint.patternId = id;
2102
- return true;
2103
- } else {
2104
- return false;
2024
+ origin.x = box.x + x;
2025
+ origin.y = box.y + y;
2026
+ translate(transform, origin.x, origin.y);
2027
+ if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
2105
2028
  }
2029
+ data.transform = transform;
2030
+ }
2031
+
2032
+ function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
2033
+ if (rotation) rotate(transform, rotation);
2034
+ if (skew) skewHelper(transform, skew.x, skew.y);
2035
+ if (scaleX) scaleHelper(transform, scaleX, scaleY);
2036
+ translate(transform, box.x + x, box.y + y);
2106
2037
  }
2107
2038
 
2108
2039
  function __awaiter(thisArg, _arguments, P, generator) {
@@ -2138,58 +2069,116 @@ typeof SuppressedError === "function" ? SuppressedError : function(error, suppre
2138
2069
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
2139
2070
  };
2140
2071
 
2141
- function checkImage(ui, canvas, paint, allowDraw) {
2142
- const {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
2143
- const {pixelRatio: pixelRatio} = canvas, {data: data} = paint;
2144
- if (!data || paint.patternId === scaleX + "-" + scaleY + "-" + pixelRatio && !draw.Export.running) {
2072
+ const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
2073
+
2074
+ const {getFloorScale: getFloorScale} = core.MathHelper, {abs: abs$1} = Math;
2075
+
2076
+ function createPatternTask(paint, ui, canvas, renderOptions) {
2077
+ if (!paint.patternTask) {
2078
+ paint.patternTask = core.ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
2079
+ paint.patternTask = null;
2080
+ if (canvas.bounds.hit(ui.__nowWorld)) draw.PaintImage.createPattern(paint, ui, canvas, renderOptions);
2081
+ ui.forceUpdate("surface");
2082
+ }), 300);
2083
+ }
2084
+ }
2085
+
2086
+ function createPattern(paint, ui, canvas, renderOptions) {
2087
+ let {scaleX: scaleX, scaleY: scaleY} = draw.PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions), id = scaleX + "-" + scaleY;
2088
+ if (paint.patternId !== id && !ui.destroyed) {
2089
+ if (!(core.Platform.image.isLarge(paint.image, scaleX, scaleY) && !paint.data.repeat)) {
2090
+ const {image: image, data: data} = paint, {transform: transform, gap: gap} = data, fixScale = draw.PaintImage.getPatternFixScale(paint, scaleX, scaleY);
2091
+ let imageMatrix, xGap, yGap, {width: width, height: height} = image;
2092
+ if (fixScale) scaleX *= fixScale, scaleY *= fixScale;
2093
+ width *= scaleX;
2094
+ height *= scaleY;
2095
+ if (gap) {
2096
+ xGap = gap.x * scaleX / abs$1(data.scaleX || 1);
2097
+ yGap = gap.y * scaleY / abs$1(data.scaleY || 1);
2098
+ }
2099
+ if (transform || scaleX !== 1 || scaleY !== 1) {
2100
+ scaleX *= getFloorScale(width + (xGap || 0));
2101
+ scaleY *= getFloorScale(height + (yGap || 0));
2102
+ imageMatrix = get$1();
2103
+ if (transform) copy$1(imageMatrix, transform);
2104
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
2105
+ }
2106
+ const imageCanvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
2107
+ const pattern = image.getPattern(imageCanvas, data.repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
2108
+ paint.style = pattern;
2109
+ paint.patternId = id;
2110
+ }
2111
+ }
2112
+ }
2113
+
2114
+ function getPatternFixScale(paint, imageScaleX, imageScaleY) {
2115
+ const {image: image} = paint;
2116
+ let fixScale, maxSize = core.Platform.image.maxPatternSize, imageSize = image.width * image.height;
2117
+ if (image.isSVG) {
2118
+ if (imageScaleX > 1) fixScale = Math.ceil(imageScaleX) / imageScaleX;
2119
+ } else {
2120
+ if (maxSize > imageSize) maxSize = imageSize;
2121
+ }
2122
+ if ((imageSize *= imageScaleX * imageScaleY) > maxSize) fixScale = Math.sqrt(maxSize / imageSize);
2123
+ return fixScale;
2124
+ }
2125
+
2126
+ function checkImage(paint, drawImage, ui, canvas, renderOptions) {
2127
+ const {scaleX: scaleX, scaleY: scaleY} = draw.PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions);
2128
+ const {image: image, data: data} = paint, {exporting: exporting} = renderOptions;
2129
+ if (!data || paint.patternId === scaleX + "-" + scaleY && !exporting) {
2145
2130
  return false;
2146
2131
  } else {
2147
- if (allowDraw) {
2132
+ if (drawImage) {
2148
2133
  if (data.repeat) {
2149
- allowDraw = false;
2150
- } else if (!(paint.changeful || core.Platform.name === "miniapp" && core.ResizeEvent.isResizing(ui) || draw.Export.running)) {
2151
- let {width: width, height: height} = data;
2152
- width *= scaleX * pixelRatio;
2153
- height *= scaleY * pixelRatio;
2154
- if (data.scaleX) {
2155
- width *= data.scaleX;
2156
- height *= data.scaleY;
2157
- }
2158
- allowDraw = width * height > core.Platform.image.maxCacheSize;
2134
+ drawImage = false;
2135
+ } else if (!(paint.changeful || core.Platform.name === "miniapp" && core.ResizeEvent.isResizing(ui) || exporting)) {
2136
+ drawImage = core.Platform.image.isLarge(image, scaleX, scaleY);
2159
2137
  }
2160
2138
  }
2161
- if (allowDraw) {
2139
+ if (drawImage) {
2162
2140
  if (ui.__.__isFastShadow) {
2163
2141
  canvas.fillStyle = paint.style || "#000";
2164
2142
  canvas.fill();
2165
2143
  }
2166
- drawImage(ui, canvas, paint, data);
2144
+ draw.PaintImage.drawImage(paint, scaleX, scaleY, ui, canvas, renderOptions);
2167
2145
  return true;
2168
2146
  } else {
2169
- if (!paint.style || paint.sync || draw.Export.running) {
2170
- createPattern(ui, paint, pixelRatio);
2171
- } else {
2172
- if (!paint.patternTask) {
2173
- paint.patternTask = core.ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
2174
- paint.patternTask = null;
2175
- if (canvas.bounds.hit(ui.__nowWorld)) createPattern(ui, paint, pixelRatio);
2176
- ui.forceUpdate("surface");
2177
- }), 300);
2178
- }
2179
- }
2147
+ if (!paint.style || paint.sync || exporting) draw.PaintImage.createPattern(paint, ui, canvas, renderOptions); else draw.PaintImage.createPatternTask(paint, ui, canvas, renderOptions);
2180
2148
  return false;
2181
2149
  }
2182
2150
  }
2183
2151
  }
2184
2152
 
2185
- function drawImage(ui, canvas, paint, data) {
2186
- canvas.save();
2187
- canvas.clipUI(ui);
2188
- if (paint.blendMode) canvas.blendMode = paint.blendMode;
2189
- if (data.opacity) canvas.opacity *= data.opacity;
2190
- if (data.transform) canvas.transform(data.transform);
2191
- canvas.drawImage(paint.image.getFull(data.filters), 0, 0, data.width, data.height);
2192
- canvas.restore();
2153
+ function drawImage(paint, _imageScaleX, _imageScaleY, ui, canvas, _renderOptions) {
2154
+ const {data: data, image: image, blendMode: blendMode} = paint, {opacity: opacity, transform: transform} = data, view = image.getFull(data.filters), u = ui.__;
2155
+ let {width: width, height: height} = image, clipUI;
2156
+ if (transform && !transform.onlyScale || (clipUI = u.path || u.cornerRadius) || opacity || blendMode) {
2157
+ canvas.save();
2158
+ clipUI && canvas.clipUI(ui);
2159
+ blendMode && (canvas.blendMode = blendMode);
2160
+ opacity && (canvas.opacity *= opacity);
2161
+ transform && canvas.transform(transform);
2162
+ canvas.drawImage(view, 0, 0, width, height);
2163
+ canvas.restore();
2164
+ } else {
2165
+ if (data.scaleX) width *= data.scaleX, height *= data.scaleY;
2166
+ canvas.drawImage(view, 0, 0, width, height);
2167
+ }
2168
+ }
2169
+
2170
+ function getImageRenderScaleData(paint, ui, canvas, _renderOptions) {
2171
+ const scaleData = ui.getRenderScaleData(true, paint.scaleFixed), {data: data} = paint;
2172
+ if (canvas) {
2173
+ const {pixelRatio: pixelRatio} = canvas;
2174
+ scaleData.scaleX *= pixelRatio;
2175
+ scaleData.scaleY *= pixelRatio;
2176
+ }
2177
+ if (data && data.scaleX) {
2178
+ scaleData.scaleX *= Math.abs(data.scaleX);
2179
+ scaleData.scaleY *= Math.abs(data.scaleY);
2180
+ }
2181
+ return scaleData;
2193
2182
  }
2194
2183
 
2195
2184
  function recycleImage(attrName, data) {
@@ -2221,8 +2210,12 @@ function recycleImage(attrName, data) {
2221
2210
  const PaintImageModule = {
2222
2211
  image: image,
2223
2212
  checkImage: checkImage,
2224
- createPattern: createPattern,
2213
+ drawImage: drawImage,
2214
+ getImageRenderScaleData: getImageRenderScaleData,
2225
2215
  recycleImage: recycleImage,
2216
+ createPatternTask: createPatternTask,
2217
+ createPattern: createPattern,
2218
+ getPatternFixScale: getPatternFixScale,
2226
2219
  createData: createData,
2227
2220
  getPatternData: getPatternData,
2228
2221
  stretchMode: stretchMode,
@@ -2678,10 +2671,8 @@ function createRows(drawData, content, style) {
2678
2671
  bounds = drawData.bounds;
2679
2672
  findMaxWidth = !bounds.width && !style.autoSizeAlign;
2680
2673
  const {__letterSpacing: __letterSpacing, paraIndent: paraIndent, textCase: textCase} = style;
2681
- const {canvas: canvas} = core.Platform;
2682
- const {width: width, height: height} = bounds;
2683
- const charMode = width || height || __letterSpacing || textCase !== "none";
2684
- if (charMode) {
2674
+ const {canvas: canvas} = core.Platform, {width: width} = bounds;
2675
+ if (style.__isCharMode) {
2685
2676
  const wrap = style.textWrap !== "none";
2686
2677
  const breakAll = style.textWrap === "break";
2687
2678
  paraStart = true;
@@ -2810,12 +2801,19 @@ const TextMode = 2;
2810
2801
  function layoutChar(drawData, style, width, _height) {
2811
2802
  const {rows: rows} = drawData;
2812
2803
  const {textAlign: textAlign, paraIndent: paraIndent, letterSpacing: letterSpacing} = style;
2813
- let charX, addWordWidth, indentWidth, mode, wordChar, wordsLength;
2804
+ const justifyLast = width && textAlign.includes("both");
2805
+ const justify = justifyLast || width && textAlign.includes("justify");
2806
+ const justifyLetter = justify && textAlign.includes("letter");
2807
+ let charX, remainingWidth, addWordWidth, addLetterWidth, indentWidth, mode, wordChar, wordsLength, isLastWord, canJustify;
2814
2808
  rows.forEach(row => {
2815
2809
  if (row.words) {
2816
2810
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0, wordsLength = row.words.length;
2817
- addWordWidth = width && (textAlign === "justify" || textAlign === "both") && wordsLength > 1 ? (width - row.width - indentWidth) / (wordsLength - 1) : 0;
2818
- mode = letterSpacing || row.isOverflow ? CharMode : addWordWidth > .01 ? WordMode : TextMode;
2811
+ if (justify) {
2812
+ canJustify = !row.paraEnd || justifyLast;
2813
+ remainingWidth = width - row.width - indentWidth;
2814
+ if (justifyLetter) addLetterWidth = remainingWidth / (row.words.reduce((total, item) => total + item.data.length, 0) - 1); else addWordWidth = wordsLength > 1 ? remainingWidth / (wordsLength - 1) : 0;
2815
+ }
2816
+ mode = letterSpacing || row.isOverflow || justifyLetter ? CharMode : addWordWidth ? WordMode : TextMode;
2819
2817
  if (row.isOverflow && !letterSpacing) row.textMode = true;
2820
2818
  if (mode === TextMode) {
2821
2819
  row.x += indentWidth;
@@ -2833,11 +2831,15 @@ function layoutChar(drawData, style, width, _height) {
2833
2831
  charX = toWordChar(word.data, charX, wordChar);
2834
2832
  if (row.isOverflow || wordChar.char !== " ") row.data.push(wordChar);
2835
2833
  } else {
2836
- charX = toChar(word.data, charX, row.data, row.isOverflow);
2834
+ charX = toChar(word.data, charX, row.data, row.isOverflow, canJustify && addLetterWidth);
2837
2835
  }
2838
- if (addWordWidth && (!row.paraEnd || textAlign === "both") && index !== wordsLength - 1) {
2839
- charX += addWordWidth;
2840
- row.width += addWordWidth;
2836
+ if (canJustify) {
2837
+ isLastWord = index === wordsLength - 1;
2838
+ if (addWordWidth) {
2839
+ if (!isLastWord) charX += addWordWidth, row.width += addWordWidth;
2840
+ } else if (addLetterWidth) {
2841
+ row.width += addLetterWidth * (word.data.length - (isLastWord ? 1 : 0));
2842
+ }
2841
2843
  }
2842
2844
  });
2843
2845
  }
@@ -2863,13 +2865,14 @@ function toWordChar(data, charX, wordChar) {
2863
2865
  return charX;
2864
2866
  }
2865
2867
 
2866
- function toChar(data, charX, rowData, isOverflow) {
2868
+ function toChar(data, charX, rowData, isOverflow, addLetterWidth) {
2867
2869
  data.forEach(char => {
2868
2870
  if (isOverflow || char.char !== " ") {
2869
2871
  char.x = charX;
2870
2872
  rowData.push(char);
2871
2873
  }
2872
2874
  charX += char.width;
2875
+ addLetterWidth && (charX += addLetterWidth);
2873
2876
  });
2874
2877
  return charX;
2875
2878
  }
@@ -3011,10 +3014,10 @@ function getDrawData(content, style) {
3011
3014
  let x = 0, y = 0;
3012
3015
  let width = style.__getInput("width") || 0;
3013
3016
  let height = style.__getInput("height") || 0;
3014
- const {textDecoration: textDecoration, __font: __font, __padding: padding} = style;
3017
+ const {__padding: padding} = style;
3015
3018
  if (padding) {
3016
- if (width) x = padding[left], width -= padding[right] + padding[left]; else if (!style.autoSizeAlign) x = padding[left];
3017
- if (height) y = padding[top], height -= padding[top] + padding[bottom]; else if (!style.autoSizeAlign) y = padding[top];
3019
+ if (width) x = padding[left], width -= padding[right] + padding[left], !width && (width = .01); else if (!style.autoSizeAlign) x = padding[left];
3020
+ if (height) y = padding[top], height -= padding[top] + padding[bottom], !height && (height = .01); else if (!style.autoSizeAlign) y = padding[top];
3018
3021
  }
3019
3022
  const drawData = {
3020
3023
  bounds: {
@@ -3025,14 +3028,14 @@ function getDrawData(content, style) {
3025
3028
  },
3026
3029
  rows: [],
3027
3030
  paraNumber: 0,
3028
- font: core.Platform.canvas.font = __font
3031
+ font: core.Platform.canvas.font = style.__font
3029
3032
  };
3030
3033
  createRows(drawData, content, style);
3031
3034
  if (padding) padAutoText(padding, drawData, style, width, height);
3032
3035
  layoutText(drawData, style);
3033
- layoutChar(drawData, style, width);
3036
+ if (style.__isCharMode) layoutChar(drawData, style, width);
3034
3037
  if (drawData.overflow) clipText(drawData, style, x, width);
3035
- if (textDecoration !== "none") decorationText(drawData, style);
3038
+ if (style.textDecoration !== "none") decorationText(drawData, style);
3036
3039
  return drawData;
3037
3040
  }
3038
3041