leafer-ui 1.6.2 → 1.6.4

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
@@ -342,17 +342,15 @@ class Watcher {
342
342
  this.target.emitEvent(new core.WatchEvent(core.WatchEvent.DATA, { updatedList: this.updatedList }));
343
343
  this.__updatedList = new core.LeafList();
344
344
  this.totalTimes++;
345
- this.changed = false;
346
- this.hasVisible = false;
347
- this.hasRemove = false;
348
- this.hasAdd = false;
345
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
349
346
  }
350
347
  __listenEvents() {
351
- const { target } = this;
352
348
  this.__eventIds = [
353
- target.on_(core.PropertyEvent.CHANGE, this.__onAttrChange, this),
354
- target.on_([core.ChildEvent.ADD, core.ChildEvent.REMOVE], this.__onChildEvent, this),
355
- target.on_(core.WatchEvent.REQUEST, this.__onRquestData, this)
349
+ this.target.on_([
350
+ [core.PropertyEvent.CHANGE, this.__onAttrChange, this],
351
+ [[core.ChildEvent.ADD, core.ChildEvent.REMOVE], this.__onChildEvent, this],
352
+ [core.WatchEvent.REQUEST, this.__onRquestData, this]
353
+ ])
356
354
  ];
357
355
  }
358
356
  __removeListenEvents() {
@@ -362,8 +360,7 @@ class Watcher {
362
360
  if (this.target) {
363
361
  this.stop();
364
362
  this.__removeListenEvents();
365
- this.target = null;
366
- this.__updatedList = null;
363
+ this.target = this.__updatedList = null;
367
364
  }
368
365
  }
369
366
  }
@@ -468,7 +465,7 @@ class Layouter {
468
465
  this.disabled = true;
469
466
  }
470
467
  layout() {
471
- if (!this.running)
468
+ if (this.layouting || !this.running)
472
469
  return;
473
470
  const { target } = this;
474
471
  this.times = 0;
@@ -551,12 +548,10 @@ class Layouter {
551
548
  }
552
549
  static fullLayout(target) {
553
550
  updateAllMatrix(target, true);
554
- if (target.isBranch) {
551
+ if (target.isBranch)
555
552
  core.BranchHelper.updateBounds(target);
556
- }
557
- else {
553
+ else
558
554
  core.LeafHelper.updateBounds(target);
559
- }
560
555
  updateAllChange(target);
561
556
  }
562
557
  addExtra(leaf) {
@@ -579,11 +574,12 @@ class Layouter {
579
574
  this.__updatedList = event.data.updatedList;
580
575
  }
581
576
  __listenEvents() {
582
- const { target } = this;
583
577
  this.__eventIds = [
584
- target.on_(core.LayoutEvent.REQUEST, this.layout, this),
585
- target.on_(core.LayoutEvent.AGAIN, this.layoutAgain, this),
586
- target.on_(core.WatchEvent.DATA, this.__onReceiveWatchData, this)
578
+ this.target.on_([
579
+ [core.LayoutEvent.REQUEST, this.layout, this],
580
+ [core.LayoutEvent.AGAIN, this.layoutAgain, this],
581
+ [core.WatchEvent.DATA, this.__onReceiveWatchData, this]
582
+ ])
587
583
  ];
588
584
  }
589
585
  __removeListenEvents() {
@@ -814,12 +810,13 @@ class Renderer {
814
810
  this.target.emitEvent(new core.RenderEvent(type, this.times, bounds, options));
815
811
  }
816
812
  __listenEvents() {
817
- const { target } = this;
818
813
  this.__eventIds = [
819
- target.on_(core.RenderEvent.REQUEST, this.update, this),
820
- target.on_(core.LayoutEvent.END, this.__onLayoutEnd, this),
821
- target.on_(core.RenderEvent.AGAIN, this.renderAgain, this),
822
- target.on_(core.ResizeEvent.RESIZE, this.__onResize, this)
814
+ this.target.on_([
815
+ [core.RenderEvent.REQUEST, this.update, this],
816
+ [core.LayoutEvent.END, this.__onLayoutEnd, this],
817
+ [core.RenderEvent.AGAIN, this.renderAgain, this],
818
+ [core.ResizeEvent.RESIZE, this.__onResize, this]
819
+ ])
823
820
  ];
824
821
  }
825
822
  __removeListenEvents() {
@@ -1372,35 +1369,38 @@ function fillPathOrText(ui, canvas) {
1372
1369
  }
1373
1370
 
1374
1371
  function strokeText(stroke, ui, canvas) {
1375
- const { strokeAlign } = ui.__;
1376
- const isStrokes = typeof stroke !== 'string';
1377
- switch (strokeAlign) {
1372
+ switch (ui.__.strokeAlign) {
1378
1373
  case 'center':
1379
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1380
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1374
+ drawCenter$1(stroke, 1, ui, canvas);
1381
1375
  break;
1382
1376
  case 'inside':
1383
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1377
+ drawAlign(stroke, 'inside', ui, canvas);
1384
1378
  break;
1385
1379
  case 'outside':
1386
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1380
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
1387
1381
  break;
1388
1382
  }
1389
1383
  }
1390
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1391
- const { __strokeWidth, __font } = ui.__;
1384
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
1385
+ const data = ui.__;
1386
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
1387
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1388
+ }
1389
+ function drawAlign(stroke, align, ui, canvas) {
1392
1390
  const out = canvas.getSameCanvas(true, true);
1393
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1394
- out.font = __font;
1395
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1391
+ out.font = ui.__.__font;
1392
+ drawCenter$1(stroke, 2, ui, out);
1396
1393
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1397
1394
  fillText(ui, out);
1398
1395
  out.blendMode = 'normal';
1399
- if (ui.__worldFlipped)
1396
+ copyWorld(canvas, out, ui);
1397
+ out.recycle(ui.__nowWorld);
1398
+ }
1399
+ function copyWorld(canvas, out, ui) {
1400
+ if (ui.__worldFlipped || core.Platform.fullImageShadow)
1400
1401
  canvas.copyWorldByReset(out, ui.__nowWorld);
1401
1402
  else
1402
1403
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1403
- out.recycle(ui.__nowWorld);
1404
1404
  }
1405
1405
  function drawTextStroke(ui, canvas) {
1406
1406
  let row, data = ui.__.__textDrawData;
@@ -1438,90 +1438,56 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
1438
1438
  }
1439
1439
 
1440
1440
  function stroke(stroke, ui, canvas) {
1441
- const options = ui.__;
1442
- const { __strokeWidth, strokeAlign, __font } = options;
1443
- if (!__strokeWidth)
1441
+ const data = ui.__;
1442
+ if (!data.__strokeWidth)
1444
1443
  return;
1445
- if (__font) {
1444
+ if (data.__font) {
1446
1445
  strokeText(stroke, ui, canvas);
1447
1446
  }
1448
1447
  else {
1449
- switch (strokeAlign) {
1448
+ switch (data.strokeAlign) {
1450
1449
  case 'center':
1451
- canvas.setStroke(stroke, __strokeWidth, options);
1452
- canvas.stroke();
1453
- if (options.__useArrow)
1454
- strokeArrow(ui, canvas);
1450
+ drawCenter(stroke, 1, ui, canvas);
1455
1451
  break;
1456
1452
  case 'inside':
1457
- canvas.save();
1458
- canvas.setStroke(stroke, __strokeWidth * 2, options);
1459
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1460
- canvas.stroke();
1461
- canvas.restore();
1453
+ drawInside(stroke, ui, canvas);
1462
1454
  break;
1463
1455
  case 'outside':
1464
- const out = canvas.getSameCanvas(true, true);
1465
- out.setStroke(stroke, __strokeWidth * 2, options);
1466
- ui.__drawRenderPath(out);
1467
- out.stroke();
1468
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1469
- out.clearWorld(ui.__layout.renderBounds);
1470
- if (ui.__worldFlipped)
1471
- canvas.copyWorldByReset(out, ui.__nowWorld);
1472
- else
1473
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1474
- out.recycle(ui.__nowWorld);
1456
+ drawOutside(stroke, ui, canvas);
1475
1457
  break;
1476
1458
  }
1477
1459
  }
1478
1460
  }
1479
1461
  function strokes(strokes, ui, canvas) {
1480
- const options = ui.__;
1481
- const { __strokeWidth, strokeAlign, __font } = options;
1482
- if (!__strokeWidth)
1483
- return;
1484
- if (__font) {
1485
- strokeText(strokes, ui, canvas);
1462
+ stroke(strokes, ui, canvas);
1463
+ }
1464
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
1465
+ const data = ui.__;
1466
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
1467
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
1468
+ if (data.__useArrow)
1469
+ draw.Paint.strokeArrow(stroke, ui, canvas);
1470
+ }
1471
+ function drawInside(stroke, ui, canvas) {
1472
+ canvas.save();
1473
+ canvas.clipUI(ui);
1474
+ drawCenter(stroke, 2, ui, canvas);
1475
+ canvas.restore();
1476
+ }
1477
+ function drawOutside(stroke, ui, canvas) {
1478
+ const data = ui.__;
1479
+ if (data.__fillAfterStroke) {
1480
+ drawCenter(stroke, 2, ui, canvas);
1486
1481
  }
1487
1482
  else {
1488
- switch (strokeAlign) {
1489
- case 'center':
1490
- canvas.setStroke(undefined, __strokeWidth, options);
1491
- drawStrokesStyle(strokes, false, ui, canvas);
1492
- if (options.__useArrow)
1493
- strokeArrow(ui, canvas);
1494
- break;
1495
- case 'inside':
1496
- canvas.save();
1497
- canvas.setStroke(undefined, __strokeWidth * 2, options);
1498
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1499
- drawStrokesStyle(strokes, false, ui, canvas);
1500
- canvas.restore();
1501
- break;
1502
- case 'outside':
1503
- const { renderBounds } = ui.__layout;
1504
- const out = canvas.getSameCanvas(true, true);
1505
- ui.__drawRenderPath(out);
1506
- out.setStroke(undefined, __strokeWidth * 2, options);
1507
- drawStrokesStyle(strokes, false, ui, out);
1508
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1509
- out.clearWorld(renderBounds);
1510
- if (ui.__worldFlipped)
1511
- canvas.copyWorldByReset(out, ui.__nowWorld);
1512
- else
1513
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1514
- out.recycle(ui.__nowWorld);
1515
- break;
1516
- }
1517
- }
1518
- }
1519
- function strokeArrow(ui, canvas) {
1520
- if (ui.__.dashPattern) {
1521
- canvas.beginPath();
1522
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1523
- canvas.dashPattern = null;
1524
- canvas.stroke();
1483
+ const { renderBounds } = ui.__layout;
1484
+ const out = canvas.getSameCanvas(true, true);
1485
+ ui.__drawRenderPath(out);
1486
+ drawCenter(stroke, 2, ui, out);
1487
+ out.clipUI(data);
1488
+ out.clearWorld(renderBounds);
1489
+ copyWorld(canvas, out, ui);
1490
+ out.recycle(ui.__nowWorld);
1525
1491
  }
1526
1492
  }
1527
1493
 
@@ -1568,41 +1534,66 @@ function shape(ui, current, options) {
1568
1534
  }
1569
1535
 
1570
1536
  let recycleMap;
1537
+ const { stintSet } = core.DataHelper, { hasTransparent: hasTransparent$1 } = draw.ColorConvert;
1571
1538
  function compute(attrName, ui) {
1572
1539
  const data = ui.__, leafPaints = [];
1573
- let paints = data.__input[attrName], hasOpacityPixel;
1540
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1574
1541
  if (!(paints instanceof Array))
1575
1542
  paints = [paints];
1576
1543
  recycleMap = draw.PaintImage.recycleImage(attrName, data);
1577
1544
  for (let i = 0, len = paints.length, item; i < len; i++) {
1578
- item = getLeafPaint(attrName, paints[i], ui);
1579
- if (item)
1580
- leafPaints.push(item);
1545
+ (item = getLeafPaint(attrName, paints[i], ui)) && leafPaints.push(item);
1581
1546
  }
1582
1547
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1583
- if (leafPaints.length && leafPaints[0].image)
1584
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1585
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1548
+ if (leafPaints.length) {
1549
+ if (leafPaints.every(item => item.isTransparent)) {
1550
+ if (leafPaints.some(item => item.image))
1551
+ isAlphaPixel = true;
1552
+ isTransparent = true;
1553
+ }
1554
+ }
1555
+ if (attrName === 'fill') {
1556
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1557
+ stintSet(data, '__isTransparentFill', isTransparent);
1558
+ }
1559
+ else {
1560
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1561
+ stintSet(data, '__isTransparentStroke', isTransparent);
1562
+ }
1586
1563
  }
1587
1564
  function getLeafPaint(attrName, paint, ui) {
1588
1565
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1589
1566
  return undefined;
1567
+ let data;
1590
1568
  const { boxBounds } = ui.__layout;
1591
1569
  switch (paint.type) {
1592
- case 'solid':
1593
- let { type, blendMode, color, opacity } = paint;
1594
- return { type, blendMode, style: draw.ColorConvert.string(color, opacity) };
1595
1570
  case 'image':
1596
- return draw.PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1571
+ data = draw.PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1572
+ break;
1597
1573
  case 'linear':
1598
- return draw.PaintGradient.linearGradient(paint, boxBounds);
1574
+ data = draw.PaintGradient.linearGradient(paint, boxBounds);
1575
+ break;
1599
1576
  case 'radial':
1600
- return draw.PaintGradient.radialGradient(paint, boxBounds);
1577
+ data = draw.PaintGradient.radialGradient(paint, boxBounds);
1578
+ break;
1601
1579
  case 'angular':
1602
- return draw.PaintGradient.conicGradient(paint, boxBounds);
1580
+ data = draw.PaintGradient.conicGradient(paint, boxBounds);
1581
+ break;
1582
+ case 'solid':
1583
+ const { type, color, opacity } = paint;
1584
+ data = { type, style: draw.ColorConvert.string(color, opacity) };
1585
+ break;
1603
1586
  default:
1604
- return paint.r !== undefined ? { type: 'solid', style: draw.ColorConvert.string(paint) } : undefined;
1587
+ if (paint.r !== undefined)
1588
+ data = { type: 'solid', style: draw.ColorConvert.string(paint) };
1589
+ }
1590
+ if (data) {
1591
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1592
+ data.isTransparent = true;
1593
+ if (paint.blendMode)
1594
+ data.blendMode = paint.blendMode;
1605
1595
  }
1596
+ return data;
1606
1597
  }
1607
1598
 
1608
1599
  const PaintModule = {
@@ -1668,12 +1659,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1668
1659
 
1669
1660
  const { get: get$2, translate } = core.MatrixHelper;
1670
1661
  const tempBox = new core.Bounds();
1671
- const tempPoint = {};
1672
1662
  const tempScaleData = {};
1663
+ const tempImage = {};
1673
1664
  function createData(leafPaint, image, paint, box) {
1674
- const { blendMode, changeful, sync } = paint;
1675
- if (blendMode)
1676
- leafPaint.blendMode = blendMode;
1665
+ const { changeful, sync } = paint;
1677
1666
  if (changeful)
1678
1667
  leafPaint.changeful = changeful;
1679
1668
  if (sync)
@@ -1681,38 +1670,38 @@ function createData(leafPaint, image, paint, box) {
1681
1670
  leafPaint.data = getPatternData(paint, box, image);
1682
1671
  }
1683
1672
  function getPatternData(paint, box, image) {
1684
- let { width, height } = image;
1685
1673
  if (paint.padding)
1686
1674
  box = tempBox.set(box).shrink(paint.padding);
1687
1675
  if (paint.mode === 'strench')
1688
1676
  paint.mode = 'stretch';
1677
+ let { width, height } = image;
1689
1678
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1690
1679
  const sameBox = box.width === width && box.height === height;
1691
1680
  const data = { mode };
1692
1681
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1693
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1694
- let x = 0, y = 0, scaleX, scaleY;
1682
+ core.BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1683
+ let scaleX, scaleY;
1695
1684
  if (!mode || mode === 'cover' || mode === 'fit') {
1696
1685
  if (!sameBox || rotation) {
1697
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1698
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1699
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1686
+ scaleX = scaleY = core.BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1687
+ core.BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1688
+ core.BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1700
1689
  }
1701
1690
  }
1702
- else if (scale || size) {
1703
- core.MathHelper.getScaleData(scale, size, image, tempScaleData);
1704
- scaleX = tempScaleData.scaleX;
1705
- scaleY = tempScaleData.scaleY;
1706
- }
1707
- if (align) {
1708
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1709
- if (scaleX)
1710
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1711
- core.AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1712
- x += tempPoint.x, y += tempPoint.y;
1691
+ else {
1692
+ if (scale || size) {
1693
+ core.MathHelper.getScaleData(scale, size, image, tempScaleData);
1694
+ scaleX = tempScaleData.scaleX;
1695
+ scaleY = tempScaleData.scaleY;
1696
+ }
1697
+ if (align) {
1698
+ if (scaleX)
1699
+ core.BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1700
+ core.AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1701
+ }
1713
1702
  }
1714
1703
  if (offset)
1715
- x += offset.x, y += offset.y;
1704
+ core.PointHelper.move(tempImage, offset);
1716
1705
  switch (mode) {
1717
1706
  case 'stretch':
1718
1707
  if (!sameBox)
@@ -1720,12 +1709,12 @@ function getPatternData(paint, box, image) {
1720
1709
  break;
1721
1710
  case 'normal':
1722
1711
  case 'clip':
1723
- if (x || y || scaleX || rotation)
1724
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1712
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1713
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1725
1714
  break;
1726
1715
  case 'repeat':
1727
1716
  if (!sameBox || scaleX || rotation)
1728
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1717
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1729
1718
  if (!repeat)
1730
1719
  data.repeat = 'repeat';
1731
1720
  break;
@@ -1733,7 +1722,7 @@ function getPatternData(paint, box, image) {
1733
1722
  case 'cover':
1734
1723
  default:
1735
1724
  if (scaleX)
1736
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1725
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1737
1726
  }
1738
1727
  if (!data.transform) {
1739
1728
  if (box.x || box.y) {
@@ -1766,6 +1755,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1766
1755
  }
1767
1756
  else {
1768
1757
  leafPaint = { type: paint.type, image };
1758
+ if (image.hasAlphaPixel)
1759
+ leafPaint.isTransparent = true;
1769
1760
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1770
1761
  }
1771
1762
  if (firstUse || image.loading)
@@ -1790,7 +1781,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1790
1781
  ignoreRender(ui, false);
1791
1782
  if (!ui.destroyed) {
1792
1783
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1793
- if (image.hasOpacityPixel)
1784
+ if (image.hasAlphaPixel)
1794
1785
  ui.__layout.hitCanvasChanged = true;
1795
1786
  ui.forceUpdate('surface');
1796
1787
  }
@@ -1802,13 +1793,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1802
1793
  onLoadError(ui, event, error);
1803
1794
  leafPaint.loadId = null;
1804
1795
  });
1805
- if (ui.placeholderColor)
1806
- setTimeout(() => {
1807
- if (!(image.ready || image.isPlacehold)) {
1808
- image.isPlacehold = true;
1809
- ui.forceUpdate('surface');
1810
- }
1811
- }, 100);
1796
+ if (ui.placeholderColor) {
1797
+ if (!ui.placeholderDelay)
1798
+ image.isPlacehold = true;
1799
+ else
1800
+ setTimeout(() => {
1801
+ if (!image.ready) {
1802
+ image.isPlacehold = true;
1803
+ ui.forceUpdate('surface');
1804
+ }
1805
+ }, ui.placeholderDelay);
1806
+ }
1812
1807
  }
1813
1808
  return leafPaint;
1814
1809
  }
@@ -1995,7 +1990,7 @@ function checkImage(ui, canvas, paint, allowDraw) {
1995
1990
  }
1996
1991
  function drawImage(ui, canvas, paint, data) {
1997
1992
  canvas.save();
1998
- ui.windingRule ? canvas.clip(ui.windingRule) : canvas.clip();
1993
+ canvas.clipUI(ui);
1999
1994
  if (paint.blendMode)
2000
1995
  canvas.blendMode = paint.blendMode;
2001
1996
  if (data.opacity)
@@ -2046,32 +2041,33 @@ const PaintImageModule = {
2046
2041
  repeatMode
2047
2042
  };
2048
2043
 
2049
- const { toPoint: toPoint$2 } = core.AroundHelper;
2044
+ const { toPoint: toPoint$2 } = core.AroundHelper, { hasTransparent } = draw.ColorConvert;
2050
2045
  const realFrom$2 = {};
2051
2046
  const realTo$2 = {};
2052
2047
  function linearGradient(paint, box) {
2053
- let { from, to, type, blendMode, opacity } = paint;
2048
+ let { from, to, type, opacity } = paint;
2054
2049
  toPoint$2(from || 'top', box, realFrom$2);
2055
2050
  toPoint$2(to || 'bottom', box, realTo$2);
2056
2051
  const style = core.Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
2057
- applyStops(style, paint.stops, opacity);
2058
2052
  const data = { type, style };
2059
- if (blendMode)
2060
- data.blendMode = blendMode;
2053
+ applyStops(data, style, paint.stops, opacity);
2061
2054
  return data;
2062
2055
  }
2063
- function applyStops(gradient, stops, opacity) {
2056
+ function applyStops(data, gradient, stops, opacity) {
2064
2057
  if (stops) {
2065
- let stop;
2058
+ let stop, color, offset, isTransparent;
2066
2059
  for (let i = 0, len = stops.length; i < len; i++) {
2067
2060
  stop = stops[i];
2068
- if (typeof stop === 'string') {
2069
- gradient.addColorStop(i / (len - 1), draw.ColorConvert.string(stop, opacity));
2070
- }
2071
- else {
2072
- gradient.addColorStop(stop.offset, draw.ColorConvert.string(stop.color, opacity));
2073
- }
2061
+ if (typeof stop === 'string')
2062
+ offset = i / (len - 1), color = draw.ColorConvert.string(stop, opacity);
2063
+ else
2064
+ offset = stop.offset, color = draw.ColorConvert.string(stop.color, opacity);
2065
+ gradient.addColorStop(offset, color);
2066
+ if (!isTransparent && hasTransparent(color))
2067
+ isTransparent = true;
2074
2068
  }
2069
+ if (isTransparent)
2070
+ data.isTransparent = true;
2075
2071
  }
2076
2072
  }
2077
2073
 
@@ -2081,17 +2077,15 @@ const { toPoint: toPoint$1 } = core.AroundHelper;
2081
2077
  const realFrom$1 = {};
2082
2078
  const realTo$1 = {};
2083
2079
  function radialGradient(paint, box) {
2084
- let { from, to, type, opacity, blendMode, stretch } = paint;
2080
+ let { from, to, type, opacity, stretch } = paint;
2085
2081
  toPoint$1(from || 'center', box, realFrom$1);
2086
2082
  toPoint$1(to || 'bottom', box, realTo$1);
2087
2083
  const style = core.Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
2088
- applyStops(style, paint.stops, opacity);
2089
2084
  const data = { type, style };
2085
+ applyStops(data, style, paint.stops, opacity);
2090
2086
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
2091
2087
  if (transform)
2092
2088
  data.transform = transform;
2093
- if (blendMode)
2094
- data.blendMode = blendMode;
2095
2089
  return data;
2096
2090
  }
2097
2091
  function getTransform(box, from, to, stretch, rotate90) {
@@ -2117,17 +2111,15 @@ const { toPoint } = core.AroundHelper;
2117
2111
  const realFrom = {};
2118
2112
  const realTo = {};
2119
2113
  function conicGradient(paint, box) {
2120
- let { from, to, type, opacity, blendMode, stretch } = paint;
2114
+ let { from, to, type, opacity, stretch } = paint;
2121
2115
  toPoint(from || 'center', box, realFrom);
2122
2116
  toPoint(to || 'bottom', box, realTo);
2123
2117
  const style = core.Platform.conicGradientSupport ? core.Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : core.Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo));
2124
- applyStops(style, paint.stops, opacity);
2125
2118
  const data = { type, style };
2119
+ applyStops(data, style, paint.stops, opacity);
2126
2120
  const transform = getTransform(box, realFrom, realTo, stretch || 1, core.Platform.conicGradientRotate90);
2127
2121
  if (transform)
2128
2122
  data.transform = transform;
2129
- if (blendMode)
2130
- data.blendMode = blendMode;
2131
2123
  return data;
2132
2124
  }
2133
2125
 
@@ -2163,12 +2155,10 @@ function shadow(ui, current, shape) {
2163
2155
  }
2164
2156
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
2165
2157
  }
2166
- if (ui.__worldFlipped) {
2158
+ if (ui.__worldFlipped)
2167
2159
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
2168
- }
2169
- else {
2160
+ else
2170
2161
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
2171
- }
2172
2162
  if (end && index < end)
2173
2163
  other.clearWorld(copyBounds, true);
2174
2164
  });
@@ -2227,12 +2217,10 @@ function innerShadow(ui, current, shape) {
2227
2217
  copyBounds = bounds;
2228
2218
  }
2229
2219
  other.fillWorld(copyBounds, draw.ColorConvert.string(item.color), 'source-in');
2230
- if (ui.__worldFlipped) {
2220
+ if (ui.__worldFlipped)
2231
2221
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
2232
- }
2233
- else {
2222
+ else
2234
2223
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
2235
- }
2236
2224
  if (end && index < end)
2237
2225
  other.clearWorld(copyBounds, true);
2238
2226
  });
@@ -2460,6 +2448,8 @@ function createRows(drawData, content, style) {
2460
2448
  lastCharType = null;
2461
2449
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
2462
2450
  word = { data: [] }, row = { words: [] };
2451
+ if (__letterSpacing)
2452
+ content = [...content];
2463
2453
  for (let i = 0, len = content.length; i < len; i++) {
2464
2454
  char = content[i];
2465
2455
  if (char === '\n') {