leafer-draw 1.6.2 → 1.6.3

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,8 +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, MatrixHelper, MathHelper, 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, MatrixHelper, MathHelper, AlignHelper, PointHelper, ImageEvent, AroundHelper, Direction4 } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
- import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
4
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint as Paint$1, Effect } from '@leafer-ui/draw';
5
5
  export * from '@leafer-ui/draw';
6
+ import { Platform as Platform$1 } from '@leafer-ui/core';
6
7
 
7
8
  const debug$2 = Debug.get('LeaferCanvas');
8
9
  class LeaferCanvas extends LeaferCanvasBase {
@@ -342,17 +343,15 @@ class Watcher {
342
343
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
343
344
  this.__updatedList = new LeafList();
344
345
  this.totalTimes++;
345
- this.changed = false;
346
- this.hasVisible = false;
347
- this.hasRemove = false;
348
- this.hasAdd = false;
346
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
349
347
  }
350
348
  __listenEvents() {
351
- const { target } = this;
352
349
  this.__eventIds = [
353
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
354
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
355
- 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
+ ])
356
355
  ];
357
356
  }
358
357
  __removeListenEvents() {
@@ -362,8 +361,7 @@ class Watcher {
362
361
  if (this.target) {
363
362
  this.stop();
364
363
  this.__removeListenEvents();
365
- this.target = null;
366
- this.__updatedList = null;
364
+ this.target = this.__updatedList = null;
367
365
  }
368
366
  }
369
367
  }
@@ -468,7 +466,7 @@ class Layouter {
468
466
  this.disabled = true;
469
467
  }
470
468
  layout() {
471
- if (!this.running)
469
+ if (this.layouting || !this.running)
472
470
  return;
473
471
  const { target } = this;
474
472
  this.times = 0;
@@ -551,12 +549,10 @@ class Layouter {
551
549
  }
552
550
  static fullLayout(target) {
553
551
  updateAllMatrix(target, true);
554
- if (target.isBranch) {
552
+ if (target.isBranch)
555
553
  BranchHelper.updateBounds(target);
556
- }
557
- else {
554
+ else
558
555
  LeafHelper.updateBounds(target);
559
- }
560
556
  updateAllChange(target);
561
557
  }
562
558
  addExtra(leaf) {
@@ -579,11 +575,12 @@ class Layouter {
579
575
  this.__updatedList = event.data.updatedList;
580
576
  }
581
577
  __listenEvents() {
582
- const { target } = this;
583
578
  this.__eventIds = [
584
- target.on_(LayoutEvent.REQUEST, this.layout, this),
585
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
586
- 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
+ ])
587
584
  ];
588
585
  }
589
586
  __removeListenEvents() {
@@ -814,12 +811,13 @@ class Renderer {
814
811
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
815
812
  }
816
813
  __listenEvents() {
817
- const { target } = this;
818
814
  this.__eventIds = [
819
- target.on_(RenderEvent.REQUEST, this.update, this),
820
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
821
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
822
- 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
+ ])
823
821
  ];
824
822
  }
825
823
  __removeListenEvents() {
@@ -905,32 +903,34 @@ function fillPathOrText(ui, canvas) {
905
903
  ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
906
904
  }
907
905
 
906
+ const Paint = {};
907
+
908
908
  function strokeText(stroke, ui, canvas) {
909
- const { strokeAlign } = ui.__;
910
- const isStrokes = typeof stroke !== 'string';
911
- switch (strokeAlign) {
909
+ switch (ui.__.strokeAlign) {
912
910
  case 'center':
913
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
914
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
911
+ drawCenter$1(stroke, 1, ui, canvas);
915
912
  break;
916
913
  case 'inside':
917
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
914
+ drawAlign(stroke, 'inside', ui, canvas);
918
915
  break;
919
916
  case 'outside':
920
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
917
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
921
918
  break;
922
919
  }
923
920
  }
924
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
925
- const { __strokeWidth, __font } = ui.__;
921
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
922
+ const data = ui.__;
923
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
924
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
925
+ }
926
+ function drawAlign(stroke, align, ui, canvas) {
926
927
  const out = canvas.getSameCanvas(true, true);
927
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
928
- out.font = __font;
929
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
928
+ out.font = ui.__.__font;
929
+ drawCenter$1(stroke, 2, ui, out);
930
930
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
931
931
  fillText(ui, out);
932
932
  out.blendMode = 'normal';
933
- if (ui.__worldFlipped)
933
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
934
934
  canvas.copyWorldByReset(out, ui.__nowWorld);
935
935
  else
936
936
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
@@ -972,90 +972,60 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
972
972
  }
973
973
 
974
974
  function stroke(stroke, ui, canvas) {
975
- const options = ui.__;
976
- const { __strokeWidth, strokeAlign, __font } = options;
977
- if (!__strokeWidth)
975
+ const data = ui.__;
976
+ if (!data.__strokeWidth)
978
977
  return;
979
- if (__font) {
978
+ if (data.__font) {
980
979
  strokeText(stroke, ui, canvas);
981
980
  }
982
981
  else {
983
- switch (strokeAlign) {
982
+ switch (data.strokeAlign) {
984
983
  case 'center':
985
- canvas.setStroke(stroke, __strokeWidth, options);
986
- canvas.stroke();
987
- if (options.__useArrow)
988
- strokeArrow(ui, canvas);
984
+ drawCenter(stroke, 1, ui, canvas);
989
985
  break;
990
986
  case 'inside':
991
- canvas.save();
992
- canvas.setStroke(stroke, __strokeWidth * 2, options);
993
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
994
- canvas.stroke();
995
- canvas.restore();
987
+ drawInside(stroke, ui, canvas);
996
988
  break;
997
989
  case 'outside':
998
- const out = canvas.getSameCanvas(true, true);
999
- out.setStroke(stroke, __strokeWidth * 2, options);
1000
- ui.__drawRenderPath(out);
1001
- out.stroke();
1002
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1003
- out.clearWorld(ui.__layout.renderBounds);
1004
- if (ui.__worldFlipped)
1005
- canvas.copyWorldByReset(out, ui.__nowWorld);
1006
- else
1007
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1008
- out.recycle(ui.__nowWorld);
990
+ drawOutside(stroke, ui, canvas);
1009
991
  break;
1010
992
  }
1011
993
  }
1012
994
  }
1013
995
  function strokes(strokes, ui, canvas) {
1014
- const options = ui.__;
1015
- const { __strokeWidth, strokeAlign, __font } = options;
1016
- if (!__strokeWidth)
1017
- return;
1018
- if (__font) {
1019
- strokeText(strokes, ui, canvas);
996
+ stroke(strokes, ui, canvas);
997
+ }
998
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
999
+ const data = ui.__;
1000
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
1001
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
1002
+ if (data.__useArrow)
1003
+ Paint.strokeArrow(stroke, ui, canvas);
1004
+ }
1005
+ function drawInside(stroke, ui, canvas) {
1006
+ const data = ui.__;
1007
+ canvas.save();
1008
+ data.windingRule ? canvas.clip(data.windingRule) : canvas.clip();
1009
+ drawCenter(stroke, 2, ui, canvas);
1010
+ canvas.restore();
1011
+ }
1012
+ function drawOutside(stroke, ui, canvas) {
1013
+ const data = ui.__;
1014
+ if (data.__fillAfterStroke) {
1015
+ drawCenter(stroke, 2, ui, canvas);
1020
1016
  }
1021
1017
  else {
1022
- switch (strokeAlign) {
1023
- case 'center':
1024
- canvas.setStroke(undefined, __strokeWidth, options);
1025
- drawStrokesStyle(strokes, false, ui, canvas);
1026
- if (options.__useArrow)
1027
- strokeArrow(ui, canvas);
1028
- break;
1029
- case 'inside':
1030
- canvas.save();
1031
- canvas.setStroke(undefined, __strokeWidth * 2, options);
1032
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1033
- drawStrokesStyle(strokes, false, ui, canvas);
1034
- canvas.restore();
1035
- break;
1036
- case 'outside':
1037
- const { renderBounds } = ui.__layout;
1038
- const out = canvas.getSameCanvas(true, true);
1039
- ui.__drawRenderPath(out);
1040
- out.setStroke(undefined, __strokeWidth * 2, options);
1041
- drawStrokesStyle(strokes, false, ui, out);
1042
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1043
- out.clearWorld(renderBounds);
1044
- if (ui.__worldFlipped)
1045
- canvas.copyWorldByReset(out, ui.__nowWorld);
1046
- else
1047
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1048
- out.recycle(ui.__nowWorld);
1049
- break;
1050
- }
1051
- }
1052
- }
1053
- function strokeArrow(ui, canvas) {
1054
- if (ui.__.dashPattern) {
1055
- canvas.beginPath();
1056
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1057
- canvas.dashPattern = null;
1058
- canvas.stroke();
1018
+ const { renderBounds } = ui.__layout;
1019
+ const out = canvas.getSameCanvas(true, true);
1020
+ ui.__drawRenderPath(out);
1021
+ drawCenter(stroke, 2, ui, out);
1022
+ data.windingRule ? out.clip(data.windingRule) : out.clip();
1023
+ out.clearWorld(renderBounds);
1024
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
1025
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1026
+ else
1027
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1028
+ out.recycle(ui.__nowWorld);
1059
1029
  }
1060
1030
  }
1061
1031
 
@@ -1102,9 +1072,10 @@ function shape(ui, current, options) {
1102
1072
  }
1103
1073
 
1104
1074
  let recycleMap;
1075
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
1105
1076
  function compute(attrName, ui) {
1106
1077
  const data = ui.__, leafPaints = [];
1107
- let paints = data.__input[attrName], hasOpacityPixel;
1078
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1108
1079
  if (!(paints instanceof Array))
1109
1080
  paints = [paints];
1110
1081
  recycleMap = PaintImage.recycleImage(attrName, data);
@@ -1114,29 +1085,55 @@ function compute(attrName, ui) {
1114
1085
  leafPaints.push(item);
1115
1086
  }
1116
1087
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1117
- if (leafPaints.length && leafPaints[0].image)
1118
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1119
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1088
+ if (leafPaints.length) {
1089
+ if (leafPaints.every(item => item.isTransparent)) {
1090
+ if (leafPaints.some(item => item.image))
1091
+ isAlphaPixel = true;
1092
+ isTransparent = true;
1093
+ }
1094
+ }
1095
+ if (attrName === 'fill') {
1096
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1097
+ stintSet(data, '__isTransparentFill', isTransparent);
1098
+ }
1099
+ else {
1100
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1101
+ stintSet(data, '__isTransparentStroke', isTransparent);
1102
+ }
1120
1103
  }
1121
1104
  function getLeafPaint(attrName, paint, ui) {
1122
1105
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1123
1106
  return undefined;
1107
+ let data;
1124
1108
  const { boxBounds } = ui.__layout;
1125
1109
  switch (paint.type) {
1126
- case 'solid':
1127
- let { type, blendMode, color, opacity } = paint;
1128
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
1129
1110
  case 'image':
1130
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1111
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1112
+ break;
1131
1113
  case 'linear':
1132
- return PaintGradient.linearGradient(paint, boxBounds);
1114
+ data = PaintGradient.linearGradient(paint, boxBounds);
1115
+ break;
1133
1116
  case 'radial':
1134
- return PaintGradient.radialGradient(paint, boxBounds);
1117
+ data = PaintGradient.radialGradient(paint, boxBounds);
1118
+ break;
1135
1119
  case 'angular':
1136
- return PaintGradient.conicGradient(paint, boxBounds);
1120
+ data = PaintGradient.conicGradient(paint, boxBounds);
1121
+ break;
1122
+ case 'solid':
1123
+ const { type, blendMode, color, opacity } = paint;
1124
+ data = { type, blendMode, style: ColorConvert.string(color, opacity) };
1125
+ break;
1137
1126
  default:
1138
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1127
+ if (paint.r !== undefined)
1128
+ data = { type: 'solid', style: ColorConvert.string(paint) };
1139
1129
  }
1130
+ if (data) {
1131
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1132
+ data.isTransparent = true;
1133
+ if (paint.blendMode)
1134
+ data.blendMode = paint.blendMode;
1135
+ }
1136
+ return data;
1140
1137
  }
1141
1138
 
1142
1139
  const PaintModule = {
@@ -1202,12 +1199,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1202
1199
 
1203
1200
  const { get: get$2, translate } = MatrixHelper;
1204
1201
  const tempBox = new Bounds();
1205
- const tempPoint = {};
1206
1202
  const tempScaleData = {};
1203
+ const tempImage = {};
1207
1204
  function createData(leafPaint, image, paint, box) {
1208
- const { blendMode, changeful, sync } = paint;
1209
- if (blendMode)
1210
- leafPaint.blendMode = blendMode;
1205
+ const { changeful, sync } = paint;
1211
1206
  if (changeful)
1212
1207
  leafPaint.changeful = changeful;
1213
1208
  if (sync)
@@ -1215,38 +1210,38 @@ function createData(leafPaint, image, paint, box) {
1215
1210
  leafPaint.data = getPatternData(paint, box, image);
1216
1211
  }
1217
1212
  function getPatternData(paint, box, image) {
1218
- let { width, height } = image;
1219
1213
  if (paint.padding)
1220
1214
  box = tempBox.set(box).shrink(paint.padding);
1221
1215
  if (paint.mode === 'strench')
1222
1216
  paint.mode = 'stretch';
1217
+ let { width, height } = image;
1223
1218
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1224
1219
  const sameBox = box.width === width && box.height === height;
1225
1220
  const data = { mode };
1226
1221
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1227
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1228
- let x = 0, y = 0, scaleX, scaleY;
1222
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1223
+ let scaleX, scaleY;
1229
1224
  if (!mode || mode === 'cover' || mode === 'fit') {
1230
1225
  if (!sameBox || rotation) {
1231
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1232
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1233
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1226
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1227
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1228
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1234
1229
  }
1235
1230
  }
1236
- else if (scale || size) {
1237
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1238
- scaleX = tempScaleData.scaleX;
1239
- scaleY = tempScaleData.scaleY;
1240
- }
1241
- if (align) {
1242
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1243
- if (scaleX)
1244
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1245
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1246
- x += tempPoint.x, y += tempPoint.y;
1231
+ else {
1232
+ if (scale || size) {
1233
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1234
+ scaleX = tempScaleData.scaleX;
1235
+ scaleY = tempScaleData.scaleY;
1236
+ }
1237
+ if (align) {
1238
+ if (scaleX)
1239
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1240
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1241
+ }
1247
1242
  }
1248
1243
  if (offset)
1249
- x += offset.x, y += offset.y;
1244
+ PointHelper.move(tempImage, offset);
1250
1245
  switch (mode) {
1251
1246
  case 'stretch':
1252
1247
  if (!sameBox)
@@ -1254,12 +1249,12 @@ function getPatternData(paint, box, image) {
1254
1249
  break;
1255
1250
  case 'normal':
1256
1251
  case 'clip':
1257
- if (x || y || scaleX || rotation)
1258
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1252
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1253
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1259
1254
  break;
1260
1255
  case 'repeat':
1261
1256
  if (!sameBox || scaleX || rotation)
1262
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1257
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1263
1258
  if (!repeat)
1264
1259
  data.repeat = 'repeat';
1265
1260
  break;
@@ -1267,7 +1262,7 @@ function getPatternData(paint, box, image) {
1267
1262
  case 'cover':
1268
1263
  default:
1269
1264
  if (scaleX)
1270
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1265
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1271
1266
  }
1272
1267
  if (!data.transform) {
1273
1268
  if (box.x || box.y) {
@@ -1300,6 +1295,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1300
1295
  }
1301
1296
  else {
1302
1297
  leafPaint = { type: paint.type, image };
1298
+ if (image.hasAlphaPixel)
1299
+ leafPaint.isTransparent = true;
1303
1300
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1304
1301
  }
1305
1302
  if (firstUse || image.loading)
@@ -1324,7 +1321,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1324
1321
  ignoreRender(ui, false);
1325
1322
  if (!ui.destroyed) {
1326
1323
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1327
- if (image.hasOpacityPixel)
1324
+ if (image.hasAlphaPixel)
1328
1325
  ui.__layout.hitCanvasChanged = true;
1329
1326
  ui.forceUpdate('surface');
1330
1327
  }
@@ -1336,13 +1333,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1336
1333
  onLoadError(ui, event, error);
1337
1334
  leafPaint.loadId = null;
1338
1335
  });
1339
- if (ui.placeholderColor)
1340
- setTimeout(() => {
1341
- if (!(image.ready || image.isPlacehold)) {
1342
- image.isPlacehold = true;
1343
- ui.forceUpdate('surface');
1344
- }
1345
- }, 100);
1336
+ if (ui.placeholderColor) {
1337
+ if (!ui.placeholderDelay)
1338
+ image.isPlacehold = true;
1339
+ else
1340
+ setTimeout(() => {
1341
+ if (!image.ready) {
1342
+ image.isPlacehold = true;
1343
+ ui.forceUpdate('surface');
1344
+ }
1345
+ }, ui.placeholderDelay);
1346
+ }
1346
1347
  }
1347
1348
  return leafPaint;
1348
1349
  }
@@ -1580,32 +1581,33 @@ const PaintImageModule = {
1580
1581
  repeatMode
1581
1582
  };
1582
1583
 
1583
- const { toPoint: toPoint$2 } = AroundHelper;
1584
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1584
1585
  const realFrom$2 = {};
1585
1586
  const realTo$2 = {};
1586
1587
  function linearGradient(paint, box) {
1587
- let { from, to, type, blendMode, opacity } = paint;
1588
+ let { from, to, type, opacity } = paint;
1588
1589
  toPoint$2(from || 'top', box, realFrom$2);
1589
1590
  toPoint$2(to || 'bottom', box, realTo$2);
1590
1591
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1591
- applyStops(style, paint.stops, opacity);
1592
1592
  const data = { type, style };
1593
- if (blendMode)
1594
- data.blendMode = blendMode;
1593
+ applyStops(data, style, paint.stops, opacity);
1595
1594
  return data;
1596
1595
  }
1597
- function applyStops(gradient, stops, opacity) {
1596
+ function applyStops(data, gradient, stops, opacity) {
1598
1597
  if (stops) {
1599
- let stop;
1598
+ let stop, color, offset, isTransparent;
1600
1599
  for (let i = 0, len = stops.length; i < len; i++) {
1601
1600
  stop = stops[i];
1602
- if (typeof stop === 'string') {
1603
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1604
- }
1605
- else {
1606
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1607
- }
1601
+ if (typeof stop === 'string')
1602
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1603
+ else
1604
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1605
+ gradient.addColorStop(offset, color);
1606
+ if (!isTransparent && hasTransparent(color))
1607
+ isTransparent = true;
1608
1608
  }
1609
+ if (isTransparent)
1610
+ data.isTransparent = true;
1609
1611
  }
1610
1612
  }
1611
1613
 
@@ -1615,17 +1617,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1615
1617
  const realFrom$1 = {};
1616
1618
  const realTo$1 = {};
1617
1619
  function radialGradient(paint, box) {
1618
- let { from, to, type, opacity, blendMode, stretch } = paint;
1620
+ let { from, to, type, opacity, stretch } = paint;
1619
1621
  toPoint$1(from || 'center', box, realFrom$1);
1620
1622
  toPoint$1(to || 'bottom', box, realTo$1);
1621
1623
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1622
- applyStops(style, paint.stops, opacity);
1623
1624
  const data = { type, style };
1625
+ applyStops(data, style, paint.stops, opacity);
1624
1626
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1625
1627
  if (transform)
1626
1628
  data.transform = transform;
1627
- if (blendMode)
1628
- data.blendMode = blendMode;
1629
1629
  return data;
1630
1630
  }
1631
1631
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1651,17 +1651,15 @@ const { toPoint } = AroundHelper;
1651
1651
  const realFrom = {};
1652
1652
  const realTo = {};
1653
1653
  function conicGradient(paint, box) {
1654
- let { from, to, type, opacity, blendMode, stretch } = paint;
1654
+ let { from, to, type, opacity, stretch } = paint;
1655
1655
  toPoint(from || 'center', box, realFrom);
1656
1656
  toPoint(to || 'bottom', box, realTo);
1657
1657
  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));
1658
- applyStops(style, paint.stops, opacity);
1659
1658
  const data = { type, style };
1659
+ applyStops(data, style, paint.stops, opacity);
1660
1660
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1661
1661
  if (transform)
1662
1662
  data.transform = transform;
1663
- if (blendMode)
1664
- data.blendMode = blendMode;
1665
1663
  return data;
1666
1664
  }
1667
1665
 
@@ -1994,6 +1992,8 @@ function createRows(drawData, content, style) {
1994
1992
  lastCharType = null;
1995
1993
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1996
1994
  word = { data: [] }, row = { words: [] };
1995
+ if (__letterSpacing)
1996
+ content = [...content];
1997
1997
  for (let i = 0, len = content.length; i < len; i++) {
1998
1998
  char = content[i];
1999
1999
  if (char === '\n') {
@@ -2400,7 +2400,7 @@ const ColorConvertModule = {
2400
2400
 
2401
2401
  Object.assign(TextConvert, TextConvertModule);
2402
2402
  Object.assign(ColorConvert, ColorConvertModule);
2403
- Object.assign(Paint, PaintModule);
2403
+ Object.assign(Paint$1, PaintModule);
2404
2404
  Object.assign(PaintImage, PaintImageModule);
2405
2405
  Object.assign(PaintGradient, PaintGradientModule);
2406
2406
  Object.assign(Effect, EffectModule);