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