@leafer-ui/miniapp 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.
@@ -1,9 +1,9 @@
1
- import { LeaferCanvasBase, Platform, canvasPatch, DataHelper, canvasSizeAttrs, ResizeEvent, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, BoundsHelper, Plugin, MatrixHelper, MathHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4 } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, DataHelper, canvasSizeAttrs, ResizeEvent, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, BoundsHelper, Plugin, MatrixHelper, MathHelper, 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, HitCanvasManager } from '@leafer-ui/core';
5
5
  export * from '@leafer-ui/core';
6
- import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect, Leafer } from '@leafer-ui/draw';
6
+ import { PaintImage, Paint, ColorConvert, PaintGradient, Export, Group, TextConvert, Effect, Leafer } from '@leafer-ui/draw';
7
7
 
8
8
  class LeaferCanvas extends LeaferCanvasBase {
9
9
  get allowBackgroundColor() { return false; }
@@ -301,17 +301,15 @@ class Watcher {
301
301
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
302
302
  this.__updatedList = new LeafList();
303
303
  this.totalTimes++;
304
- this.changed = false;
305
- this.hasVisible = false;
306
- this.hasRemove = false;
307
- this.hasAdd = false;
304
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
308
305
  }
309
306
  __listenEvents() {
310
- const { target } = this;
311
307
  this.__eventIds = [
312
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
313
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
314
- target.on_(WatchEvent.REQUEST, this.__onRquestData, this)
308
+ this.target.on_([
309
+ [PropertyEvent.CHANGE, this.__onAttrChange, this],
310
+ [[ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this],
311
+ [WatchEvent.REQUEST, this.__onRquestData, this]
312
+ ])
315
313
  ];
316
314
  }
317
315
  __removeListenEvents() {
@@ -321,8 +319,7 @@ class Watcher {
321
319
  if (this.target) {
322
320
  this.stop();
323
321
  this.__removeListenEvents();
324
- this.target = null;
325
- this.__updatedList = null;
322
+ this.target = this.__updatedList = null;
326
323
  }
327
324
  }
328
325
  }
@@ -427,7 +424,7 @@ class Layouter {
427
424
  this.disabled = true;
428
425
  }
429
426
  layout() {
430
- if (!this.running)
427
+ if (this.layouting || !this.running)
431
428
  return;
432
429
  const { target } = this;
433
430
  this.times = 0;
@@ -510,12 +507,10 @@ class Layouter {
510
507
  }
511
508
  static fullLayout(target) {
512
509
  updateAllMatrix(target, true);
513
- if (target.isBranch) {
510
+ if (target.isBranch)
514
511
  BranchHelper.updateBounds(target);
515
- }
516
- else {
512
+ else
517
513
  LeafHelper.updateBounds(target);
518
- }
519
514
  updateAllChange(target);
520
515
  }
521
516
  addExtra(leaf) {
@@ -538,11 +533,12 @@ class Layouter {
538
533
  this.__updatedList = event.data.updatedList;
539
534
  }
540
535
  __listenEvents() {
541
- const { target } = this;
542
536
  this.__eventIds = [
543
- target.on_(LayoutEvent.REQUEST, this.layout, this),
544
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
545
- target.on_(WatchEvent.DATA, this.__onReceiveWatchData, this)
537
+ this.target.on_([
538
+ [LayoutEvent.REQUEST, this.layout, this],
539
+ [LayoutEvent.AGAIN, this.layoutAgain, this],
540
+ [WatchEvent.DATA, this.__onReceiveWatchData, this]
541
+ ])
546
542
  ];
547
543
  }
548
544
  __removeListenEvents() {
@@ -773,12 +769,13 @@ class Renderer {
773
769
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
774
770
  }
775
771
  __listenEvents() {
776
- const { target } = this;
777
772
  this.__eventIds = [
778
- target.on_(RenderEvent.REQUEST, this.update, this),
779
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
780
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
781
- target.on_(ResizeEvent.RESIZE, this.__onResize, this)
773
+ this.target.on_([
774
+ [RenderEvent.REQUEST, this.update, this],
775
+ [LayoutEvent.END, this.__onLayoutEnd, this],
776
+ [RenderEvent.AGAIN, this.renderAgain, this],
777
+ [ResizeEvent.RESIZE, this.__onResize, this]
778
+ ])
782
779
  ];
783
780
  }
784
781
  __removeListenEvents() {
@@ -1127,35 +1124,38 @@ function fillPathOrText(ui, canvas) {
1127
1124
  }
1128
1125
 
1129
1126
  function strokeText(stroke, ui, canvas) {
1130
- const { strokeAlign } = ui.__;
1131
- const isStrokes = typeof stroke !== 'string';
1132
- switch (strokeAlign) {
1127
+ switch (ui.__.strokeAlign) {
1133
1128
  case 'center':
1134
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1135
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1129
+ drawCenter$1(stroke, 1, ui, canvas);
1136
1130
  break;
1137
1131
  case 'inside':
1138
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1132
+ drawAlign(stroke, 'inside', ui, canvas);
1139
1133
  break;
1140
1134
  case 'outside':
1141
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1135
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
1142
1136
  break;
1143
1137
  }
1144
1138
  }
1145
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1146
- const { __strokeWidth, __font } = ui.__;
1139
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
1140
+ const data = ui.__;
1141
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
1142
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1143
+ }
1144
+ function drawAlign(stroke, align, ui, canvas) {
1147
1145
  const out = canvas.getSameCanvas(true, true);
1148
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1149
- out.font = __font;
1150
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1146
+ out.font = ui.__.__font;
1147
+ drawCenter$1(stroke, 2, ui, out);
1151
1148
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1152
1149
  fillText(ui, out);
1153
1150
  out.blendMode = 'normal';
1154
- if (ui.__worldFlipped)
1151
+ copyWorld(canvas, out, ui);
1152
+ out.recycle(ui.__nowWorld);
1153
+ }
1154
+ function copyWorld(canvas, out, ui) {
1155
+ if (ui.__worldFlipped || Platform.fullImageShadow)
1155
1156
  canvas.copyWorldByReset(out, ui.__nowWorld);
1156
1157
  else
1157
1158
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1158
- out.recycle(ui.__nowWorld);
1159
1159
  }
1160
1160
  function drawTextStroke(ui, canvas) {
1161
1161
  let row, data = ui.__.__textDrawData;
@@ -1193,90 +1193,56 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
1193
1193
  }
1194
1194
 
1195
1195
  function stroke(stroke, ui, canvas) {
1196
- const options = ui.__;
1197
- const { __strokeWidth, strokeAlign, __font } = options;
1198
- if (!__strokeWidth)
1196
+ const data = ui.__;
1197
+ if (!data.__strokeWidth)
1199
1198
  return;
1200
- if (__font) {
1199
+ if (data.__font) {
1201
1200
  strokeText(stroke, ui, canvas);
1202
1201
  }
1203
1202
  else {
1204
- switch (strokeAlign) {
1203
+ switch (data.strokeAlign) {
1205
1204
  case 'center':
1206
- canvas.setStroke(stroke, __strokeWidth, options);
1207
- canvas.stroke();
1208
- if (options.__useArrow)
1209
- strokeArrow(ui, canvas);
1205
+ drawCenter(stroke, 1, ui, canvas);
1210
1206
  break;
1211
1207
  case 'inside':
1212
- canvas.save();
1213
- canvas.setStroke(stroke, __strokeWidth * 2, options);
1214
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1215
- canvas.stroke();
1216
- canvas.restore();
1208
+ drawInside(stroke, ui, canvas);
1217
1209
  break;
1218
1210
  case 'outside':
1219
- const out = canvas.getSameCanvas(true, true);
1220
- out.setStroke(stroke, __strokeWidth * 2, options);
1221
- ui.__drawRenderPath(out);
1222
- out.stroke();
1223
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1224
- out.clearWorld(ui.__layout.renderBounds);
1225
- if (ui.__worldFlipped)
1226
- canvas.copyWorldByReset(out, ui.__nowWorld);
1227
- else
1228
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1229
- out.recycle(ui.__nowWorld);
1211
+ drawOutside(stroke, ui, canvas);
1230
1212
  break;
1231
1213
  }
1232
1214
  }
1233
1215
  }
1234
1216
  function strokes(strokes, ui, canvas) {
1235
- const options = ui.__;
1236
- const { __strokeWidth, strokeAlign, __font } = options;
1237
- if (!__strokeWidth)
1238
- return;
1239
- if (__font) {
1240
- strokeText(strokes, ui, canvas);
1217
+ stroke(strokes, ui, canvas);
1218
+ }
1219
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
1220
+ const data = ui.__;
1221
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
1222
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
1223
+ if (data.__useArrow)
1224
+ Paint.strokeArrow(stroke, ui, canvas);
1225
+ }
1226
+ function drawInside(stroke, ui, canvas) {
1227
+ canvas.save();
1228
+ canvas.clipUI(ui);
1229
+ drawCenter(stroke, 2, ui, canvas);
1230
+ canvas.restore();
1231
+ }
1232
+ function drawOutside(stroke, ui, canvas) {
1233
+ const data = ui.__;
1234
+ if (data.__fillAfterStroke) {
1235
+ drawCenter(stroke, 2, ui, canvas);
1241
1236
  }
1242
1237
  else {
1243
- switch (strokeAlign) {
1244
- case 'center':
1245
- canvas.setStroke(undefined, __strokeWidth, options);
1246
- drawStrokesStyle(strokes, false, ui, canvas);
1247
- if (options.__useArrow)
1248
- strokeArrow(ui, canvas);
1249
- break;
1250
- case 'inside':
1251
- canvas.save();
1252
- canvas.setStroke(undefined, __strokeWidth * 2, options);
1253
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1254
- drawStrokesStyle(strokes, false, ui, canvas);
1255
- canvas.restore();
1256
- break;
1257
- case 'outside':
1258
- const { renderBounds } = ui.__layout;
1259
- const out = canvas.getSameCanvas(true, true);
1260
- ui.__drawRenderPath(out);
1261
- out.setStroke(undefined, __strokeWidth * 2, options);
1262
- drawStrokesStyle(strokes, false, ui, out);
1263
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1264
- out.clearWorld(renderBounds);
1265
- if (ui.__worldFlipped)
1266
- canvas.copyWorldByReset(out, ui.__nowWorld);
1267
- else
1268
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1269
- out.recycle(ui.__nowWorld);
1270
- break;
1271
- }
1272
- }
1273
- }
1274
- function strokeArrow(ui, canvas) {
1275
- if (ui.__.dashPattern) {
1276
- canvas.beginPath();
1277
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1278
- canvas.dashPattern = null;
1279
- canvas.stroke();
1238
+ const { renderBounds } = ui.__layout;
1239
+ const out = canvas.getSameCanvas(true, true);
1240
+ ui.__drawRenderPath(out);
1241
+ drawCenter(stroke, 2, ui, out);
1242
+ out.clipUI(data);
1243
+ out.clearWorld(renderBounds);
1244
+ copyWorld(canvas, out, ui);
1245
+ out.recycle(ui.__nowWorld);
1280
1246
  }
1281
1247
  }
1282
1248
 
@@ -1323,41 +1289,66 @@ function shape(ui, current, options) {
1323
1289
  }
1324
1290
 
1325
1291
  let recycleMap;
1292
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
1326
1293
  function compute(attrName, ui) {
1327
1294
  const data = ui.__, leafPaints = [];
1328
- let paints = data.__input[attrName], hasOpacityPixel;
1295
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1329
1296
  if (!(paints instanceof Array))
1330
1297
  paints = [paints];
1331
1298
  recycleMap = PaintImage.recycleImage(attrName, data);
1332
1299
  for (let i = 0, len = paints.length, item; i < len; i++) {
1333
- item = getLeafPaint(attrName, paints[i], ui);
1334
- if (item)
1335
- leafPaints.push(item);
1300
+ (item = getLeafPaint(attrName, paints[i], ui)) && leafPaints.push(item);
1336
1301
  }
1337
1302
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1338
- if (leafPaints.length && leafPaints[0].image)
1339
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1340
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1303
+ if (leafPaints.length) {
1304
+ if (leafPaints.every(item => item.isTransparent)) {
1305
+ if (leafPaints.some(item => item.image))
1306
+ isAlphaPixel = true;
1307
+ isTransparent = true;
1308
+ }
1309
+ }
1310
+ if (attrName === 'fill') {
1311
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1312
+ stintSet(data, '__isTransparentFill', isTransparent);
1313
+ }
1314
+ else {
1315
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1316
+ stintSet(data, '__isTransparentStroke', isTransparent);
1317
+ }
1341
1318
  }
1342
1319
  function getLeafPaint(attrName, paint, ui) {
1343
1320
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1344
1321
  return undefined;
1322
+ let data;
1345
1323
  const { boxBounds } = ui.__layout;
1346
1324
  switch (paint.type) {
1347
- case 'solid':
1348
- let { type, blendMode, color, opacity } = paint;
1349
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
1350
1325
  case 'image':
1351
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1326
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1327
+ break;
1352
1328
  case 'linear':
1353
- return PaintGradient.linearGradient(paint, boxBounds);
1329
+ data = PaintGradient.linearGradient(paint, boxBounds);
1330
+ break;
1354
1331
  case 'radial':
1355
- return PaintGradient.radialGradient(paint, boxBounds);
1332
+ data = PaintGradient.radialGradient(paint, boxBounds);
1333
+ break;
1356
1334
  case 'angular':
1357
- return PaintGradient.conicGradient(paint, boxBounds);
1335
+ data = PaintGradient.conicGradient(paint, boxBounds);
1336
+ break;
1337
+ case 'solid':
1338
+ const { type, color, opacity } = paint;
1339
+ data = { type, style: ColorConvert.string(color, opacity) };
1340
+ break;
1358
1341
  default:
1359
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1342
+ if (paint.r !== undefined)
1343
+ data = { type: 'solid', style: ColorConvert.string(paint) };
1360
1344
  }
1345
+ if (data) {
1346
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1347
+ data.isTransparent = true;
1348
+ if (paint.blendMode)
1349
+ data.blendMode = paint.blendMode;
1350
+ }
1351
+ return data;
1361
1352
  }
1362
1353
 
1363
1354
  const PaintModule = {
@@ -1423,12 +1414,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1423
1414
 
1424
1415
  const { get: get$2, translate } = MatrixHelper;
1425
1416
  const tempBox = new Bounds();
1426
- const tempPoint = {};
1427
1417
  const tempScaleData = {};
1418
+ const tempImage = {};
1428
1419
  function createData(leafPaint, image, paint, box) {
1429
- const { blendMode, changeful, sync } = paint;
1430
- if (blendMode)
1431
- leafPaint.blendMode = blendMode;
1420
+ const { changeful, sync } = paint;
1432
1421
  if (changeful)
1433
1422
  leafPaint.changeful = changeful;
1434
1423
  if (sync)
@@ -1436,38 +1425,38 @@ function createData(leafPaint, image, paint, box) {
1436
1425
  leafPaint.data = getPatternData(paint, box, image);
1437
1426
  }
1438
1427
  function getPatternData(paint, box, image) {
1439
- let { width, height } = image;
1440
1428
  if (paint.padding)
1441
1429
  box = tempBox.set(box).shrink(paint.padding);
1442
1430
  if (paint.mode === 'strench')
1443
1431
  paint.mode = 'stretch';
1432
+ let { width, height } = image;
1444
1433
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1445
1434
  const sameBox = box.width === width && box.height === height;
1446
1435
  const data = { mode };
1447
1436
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1448
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1449
- let x = 0, y = 0, scaleX, scaleY;
1437
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1438
+ let scaleX, scaleY;
1450
1439
  if (!mode || mode === 'cover' || mode === 'fit') {
1451
1440
  if (!sameBox || rotation) {
1452
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1453
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1454
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1441
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1442
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1443
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1455
1444
  }
1456
1445
  }
1457
- else if (scale || size) {
1458
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1459
- scaleX = tempScaleData.scaleX;
1460
- scaleY = tempScaleData.scaleY;
1461
- }
1462
- if (align) {
1463
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1464
- if (scaleX)
1465
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1466
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1467
- x += tempPoint.x, y += tempPoint.y;
1446
+ else {
1447
+ if (scale || size) {
1448
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1449
+ scaleX = tempScaleData.scaleX;
1450
+ scaleY = tempScaleData.scaleY;
1451
+ }
1452
+ if (align) {
1453
+ if (scaleX)
1454
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1455
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1456
+ }
1468
1457
  }
1469
1458
  if (offset)
1470
- x += offset.x, y += offset.y;
1459
+ PointHelper.move(tempImage, offset);
1471
1460
  switch (mode) {
1472
1461
  case 'stretch':
1473
1462
  if (!sameBox)
@@ -1475,12 +1464,12 @@ function getPatternData(paint, box, image) {
1475
1464
  break;
1476
1465
  case 'normal':
1477
1466
  case 'clip':
1478
- if (x || y || scaleX || rotation)
1479
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1467
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1468
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1480
1469
  break;
1481
1470
  case 'repeat':
1482
1471
  if (!sameBox || scaleX || rotation)
1483
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1472
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1484
1473
  if (!repeat)
1485
1474
  data.repeat = 'repeat';
1486
1475
  break;
@@ -1488,7 +1477,7 @@ function getPatternData(paint, box, image) {
1488
1477
  case 'cover':
1489
1478
  default:
1490
1479
  if (scaleX)
1491
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1480
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1492
1481
  }
1493
1482
  if (!data.transform) {
1494
1483
  if (box.x || box.y) {
@@ -1521,6 +1510,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1521
1510
  }
1522
1511
  else {
1523
1512
  leafPaint = { type: paint.type, image };
1513
+ if (image.hasAlphaPixel)
1514
+ leafPaint.isTransparent = true;
1524
1515
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1525
1516
  }
1526
1517
  if (firstUse || image.loading)
@@ -1545,7 +1536,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1545
1536
  ignoreRender(ui, false);
1546
1537
  if (!ui.destroyed) {
1547
1538
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1548
- if (image.hasOpacityPixel)
1539
+ if (image.hasAlphaPixel)
1549
1540
  ui.__layout.hitCanvasChanged = true;
1550
1541
  ui.forceUpdate('surface');
1551
1542
  }
@@ -1557,13 +1548,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1557
1548
  onLoadError(ui, event, error);
1558
1549
  leafPaint.loadId = null;
1559
1550
  });
1560
- if (ui.placeholderColor)
1561
- setTimeout(() => {
1562
- if (!(image.ready || image.isPlacehold)) {
1563
- image.isPlacehold = true;
1564
- ui.forceUpdate('surface');
1565
- }
1566
- }, 100);
1551
+ if (ui.placeholderColor) {
1552
+ if (!ui.placeholderDelay)
1553
+ image.isPlacehold = true;
1554
+ else
1555
+ setTimeout(() => {
1556
+ if (!image.ready) {
1557
+ image.isPlacehold = true;
1558
+ ui.forceUpdate('surface');
1559
+ }
1560
+ }, ui.placeholderDelay);
1561
+ }
1567
1562
  }
1568
1563
  return leafPaint;
1569
1564
  }
@@ -1750,7 +1745,7 @@ function checkImage(ui, canvas, paint, allowDraw) {
1750
1745
  }
1751
1746
  function drawImage(ui, canvas, paint, data) {
1752
1747
  canvas.save();
1753
- ui.windingRule ? canvas.clip(ui.windingRule) : canvas.clip();
1748
+ canvas.clipUI(ui);
1754
1749
  if (paint.blendMode)
1755
1750
  canvas.blendMode = paint.blendMode;
1756
1751
  if (data.opacity)
@@ -1801,32 +1796,33 @@ const PaintImageModule = {
1801
1796
  repeatMode
1802
1797
  };
1803
1798
 
1804
- const { toPoint: toPoint$2 } = AroundHelper;
1799
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1805
1800
  const realFrom$2 = {};
1806
1801
  const realTo$2 = {};
1807
1802
  function linearGradient(paint, box) {
1808
- let { from, to, type, blendMode, opacity } = paint;
1803
+ let { from, to, type, opacity } = paint;
1809
1804
  toPoint$2(from || 'top', box, realFrom$2);
1810
1805
  toPoint$2(to || 'bottom', box, realTo$2);
1811
1806
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1812
- applyStops(style, paint.stops, opacity);
1813
1807
  const data = { type, style };
1814
- if (blendMode)
1815
- data.blendMode = blendMode;
1808
+ applyStops(data, style, paint.stops, opacity);
1816
1809
  return data;
1817
1810
  }
1818
- function applyStops(gradient, stops, opacity) {
1811
+ function applyStops(data, gradient, stops, opacity) {
1819
1812
  if (stops) {
1820
- let stop;
1813
+ let stop, color, offset, isTransparent;
1821
1814
  for (let i = 0, len = stops.length; i < len; i++) {
1822
1815
  stop = stops[i];
1823
- if (typeof stop === 'string') {
1824
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1825
- }
1826
- else {
1827
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1828
- }
1816
+ if (typeof stop === 'string')
1817
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1818
+ else
1819
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1820
+ gradient.addColorStop(offset, color);
1821
+ if (!isTransparent && hasTransparent(color))
1822
+ isTransparent = true;
1829
1823
  }
1824
+ if (isTransparent)
1825
+ data.isTransparent = true;
1830
1826
  }
1831
1827
  }
1832
1828
 
@@ -1836,17 +1832,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1836
1832
  const realFrom$1 = {};
1837
1833
  const realTo$1 = {};
1838
1834
  function radialGradient(paint, box) {
1839
- let { from, to, type, opacity, blendMode, stretch } = paint;
1835
+ let { from, to, type, opacity, stretch } = paint;
1840
1836
  toPoint$1(from || 'center', box, realFrom$1);
1841
1837
  toPoint$1(to || 'bottom', box, realTo$1);
1842
1838
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1843
- applyStops(style, paint.stops, opacity);
1844
1839
  const data = { type, style };
1840
+ applyStops(data, style, paint.stops, opacity);
1845
1841
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1846
1842
  if (transform)
1847
1843
  data.transform = transform;
1848
- if (blendMode)
1849
- data.blendMode = blendMode;
1850
1844
  return data;
1851
1845
  }
1852
1846
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1872,17 +1866,15 @@ const { toPoint } = AroundHelper;
1872
1866
  const realFrom = {};
1873
1867
  const realTo = {};
1874
1868
  function conicGradient(paint, box) {
1875
- let { from, to, type, opacity, blendMode, stretch } = paint;
1869
+ let { from, to, type, opacity, stretch } = paint;
1876
1870
  toPoint(from || 'center', box, realFrom);
1877
1871
  toPoint(to || 'bottom', box, realTo);
1878
1872
  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));
1879
- applyStops(style, paint.stops, opacity);
1880
1873
  const data = { type, style };
1874
+ applyStops(data, style, paint.stops, opacity);
1881
1875
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1882
1876
  if (transform)
1883
1877
  data.transform = transform;
1884
- if (blendMode)
1885
- data.blendMode = blendMode;
1886
1878
  return data;
1887
1879
  }
1888
1880
 
@@ -1918,12 +1910,10 @@ function shadow(ui, current, shape) {
1918
1910
  }
1919
1911
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1920
1912
  }
1921
- if (ui.__worldFlipped) {
1913
+ if (ui.__worldFlipped)
1922
1914
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1923
- }
1924
- else {
1915
+ else
1925
1916
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1926
- }
1927
1917
  if (end && index < end)
1928
1918
  other.clearWorld(copyBounds, true);
1929
1919
  });
@@ -1982,12 +1972,10 @@ function innerShadow(ui, current, shape) {
1982
1972
  copyBounds = bounds;
1983
1973
  }
1984
1974
  other.fillWorld(copyBounds, ColorConvert.string(item.color), 'source-in');
1985
- if (ui.__worldFlipped) {
1975
+ if (ui.__worldFlipped)
1986
1976
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1987
- }
1988
- else {
1977
+ else
1989
1978
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1990
- }
1991
1979
  if (end && index < end)
1992
1980
  other.clearWorld(copyBounds, true);
1993
1981
  });
@@ -2215,6 +2203,8 @@ function createRows(drawData, content, style) {
2215
2203
  lastCharType = null;
2216
2204
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
2217
2205
  word = { data: [] }, row = { words: [] };
2206
+ if (__letterSpacing)
2207
+ content = [...content];
2218
2208
  for (let i = 0, len = content.length; i < len; i++) {
2219
2209
  char = content[i];
2220
2210
  if (char === '\n') {