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