@leafer-ui/worker 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.
@@ -1,9 +1,9 @@
1
- import { LeaferCanvasBase, Platform, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, ResizeEvent, BoundsHelper, Plugin, MatrixHelper, MathHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4 } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, ResizeEvent, 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
- import { HitCanvasManager, InteractionBase } from '@leafer-ui/core';
4
+ import { Platform as Platform$1, HitCanvasManager, InteractionBase } 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, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint as Paint$1, Effect } from '@leafer-ui/draw';
7
7
 
8
8
  class LeaferCanvas extends LeaferCanvasBase {
9
9
  get allowBackgroundColor() { return true; }
@@ -162,17 +162,15 @@ class Watcher {
162
162
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
163
163
  this.__updatedList = new LeafList();
164
164
  this.totalTimes++;
165
- this.changed = false;
166
- this.hasVisible = false;
167
- this.hasRemove = false;
168
- this.hasAdd = false;
165
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
169
166
  }
170
167
  __listenEvents() {
171
- const { target } = this;
172
168
  this.__eventIds = [
173
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
174
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
175
- target.on_(WatchEvent.REQUEST, this.__onRquestData, this)
169
+ this.target.on_([
170
+ [PropertyEvent.CHANGE, this.__onAttrChange, this],
171
+ [[ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this],
172
+ [WatchEvent.REQUEST, this.__onRquestData, this]
173
+ ])
176
174
  ];
177
175
  }
178
176
  __removeListenEvents() {
@@ -182,8 +180,7 @@ class Watcher {
182
180
  if (this.target) {
183
181
  this.stop();
184
182
  this.__removeListenEvents();
185
- this.target = null;
186
- this.__updatedList = null;
183
+ this.target = this.__updatedList = null;
187
184
  }
188
185
  }
189
186
  }
@@ -288,7 +285,7 @@ class Layouter {
288
285
  this.disabled = true;
289
286
  }
290
287
  layout() {
291
- if (!this.running)
288
+ if (this.layouting || !this.running)
292
289
  return;
293
290
  const { target } = this;
294
291
  this.times = 0;
@@ -371,12 +368,10 @@ class Layouter {
371
368
  }
372
369
  static fullLayout(target) {
373
370
  updateAllMatrix(target, true);
374
- if (target.isBranch) {
371
+ if (target.isBranch)
375
372
  BranchHelper.updateBounds(target);
376
- }
377
- else {
373
+ else
378
374
  LeafHelper.updateBounds(target);
379
- }
380
375
  updateAllChange(target);
381
376
  }
382
377
  addExtra(leaf) {
@@ -399,11 +394,12 @@ class Layouter {
399
394
  this.__updatedList = event.data.updatedList;
400
395
  }
401
396
  __listenEvents() {
402
- const { target } = this;
403
397
  this.__eventIds = [
404
- target.on_(LayoutEvent.REQUEST, this.layout, this),
405
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
406
- target.on_(WatchEvent.DATA, this.__onReceiveWatchData, this)
398
+ this.target.on_([
399
+ [LayoutEvent.REQUEST, this.layout, this],
400
+ [LayoutEvent.AGAIN, this.layoutAgain, this],
401
+ [WatchEvent.DATA, this.__onReceiveWatchData, this]
402
+ ])
407
403
  ];
408
404
  }
409
405
  __removeListenEvents() {
@@ -634,12 +630,13 @@ class Renderer {
634
630
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
635
631
  }
636
632
  __listenEvents() {
637
- const { target } = this;
638
633
  this.__eventIds = [
639
- target.on_(RenderEvent.REQUEST, this.update, this),
640
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
641
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
642
- target.on_(ResizeEvent.RESIZE, this.__onResize, this)
634
+ this.target.on_([
635
+ [RenderEvent.REQUEST, this.update, this],
636
+ [LayoutEvent.END, this.__onLayoutEnd, this],
637
+ [RenderEvent.AGAIN, this.renderAgain, this],
638
+ [ResizeEvent.RESIZE, this.__onResize, this]
639
+ ])
643
640
  ];
644
641
  }
645
642
  __removeListenEvents() {
@@ -882,32 +879,34 @@ function fillPathOrText(ui, canvas) {
882
879
  ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
883
880
  }
884
881
 
882
+ const Paint = {};
883
+
885
884
  function strokeText(stroke, ui, canvas) {
886
- const { strokeAlign } = ui.__;
887
- const isStrokes = typeof stroke !== 'string';
888
- switch (strokeAlign) {
885
+ switch (ui.__.strokeAlign) {
889
886
  case 'center':
890
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
891
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
887
+ drawCenter$1(stroke, 1, ui, canvas);
892
888
  break;
893
889
  case 'inside':
894
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
890
+ drawAlign(stroke, 'inside', ui, canvas);
895
891
  break;
896
892
  case 'outside':
897
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
893
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
898
894
  break;
899
895
  }
900
896
  }
901
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
902
- const { __strokeWidth, __font } = ui.__;
897
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
898
+ const data = ui.__;
899
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
900
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
901
+ }
902
+ function drawAlign(stroke, align, ui, canvas) {
903
903
  const out = canvas.getSameCanvas(true, true);
904
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
905
- out.font = __font;
906
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
904
+ out.font = ui.__.__font;
905
+ drawCenter$1(stroke, 2, ui, out);
907
906
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
908
907
  fillText(ui, out);
909
908
  out.blendMode = 'normal';
910
- if (ui.__worldFlipped)
909
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
911
910
  canvas.copyWorldByReset(out, ui.__nowWorld);
912
911
  else
913
912
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
@@ -949,90 +948,60 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
949
948
  }
950
949
 
951
950
  function stroke(stroke, ui, canvas) {
952
- const options = ui.__;
953
- const { __strokeWidth, strokeAlign, __font } = options;
954
- if (!__strokeWidth)
951
+ const data = ui.__;
952
+ if (!data.__strokeWidth)
955
953
  return;
956
- if (__font) {
954
+ if (data.__font) {
957
955
  strokeText(stroke, ui, canvas);
958
956
  }
959
957
  else {
960
- switch (strokeAlign) {
958
+ switch (data.strokeAlign) {
961
959
  case 'center':
962
- canvas.setStroke(stroke, __strokeWidth, options);
963
- canvas.stroke();
964
- if (options.__useArrow)
965
- strokeArrow(ui, canvas);
960
+ drawCenter(stroke, 1, ui, canvas);
966
961
  break;
967
962
  case 'inside':
968
- canvas.save();
969
- canvas.setStroke(stroke, __strokeWidth * 2, options);
970
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
971
- canvas.stroke();
972
- canvas.restore();
963
+ drawInside(stroke, ui, canvas);
973
964
  break;
974
965
  case 'outside':
975
- const out = canvas.getSameCanvas(true, true);
976
- out.setStroke(stroke, __strokeWidth * 2, options);
977
- ui.__drawRenderPath(out);
978
- out.stroke();
979
- options.windingRule ? out.clip(options.windingRule) : out.clip();
980
- out.clearWorld(ui.__layout.renderBounds);
981
- if (ui.__worldFlipped)
982
- canvas.copyWorldByReset(out, ui.__nowWorld);
983
- else
984
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
985
- out.recycle(ui.__nowWorld);
966
+ drawOutside(stroke, ui, canvas);
986
967
  break;
987
968
  }
988
969
  }
989
970
  }
990
971
  function strokes(strokes, ui, canvas) {
991
- const options = ui.__;
992
- const { __strokeWidth, strokeAlign, __font } = options;
993
- if (!__strokeWidth)
994
- return;
995
- if (__font) {
996
- strokeText(strokes, ui, canvas);
972
+ stroke(strokes, ui, canvas);
973
+ }
974
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
975
+ const data = ui.__;
976
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
977
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
978
+ if (data.__useArrow)
979
+ Paint.strokeArrow(stroke, ui, canvas);
980
+ }
981
+ function drawInside(stroke, ui, canvas) {
982
+ const data = ui.__;
983
+ canvas.save();
984
+ data.windingRule ? canvas.clip(data.windingRule) : canvas.clip();
985
+ drawCenter(stroke, 2, ui, canvas);
986
+ canvas.restore();
987
+ }
988
+ function drawOutside(stroke, ui, canvas) {
989
+ const data = ui.__;
990
+ if (data.__fillAfterStroke) {
991
+ drawCenter(stroke, 2, ui, canvas);
997
992
  }
998
993
  else {
999
- switch (strokeAlign) {
1000
- case 'center':
1001
- canvas.setStroke(undefined, __strokeWidth, options);
1002
- drawStrokesStyle(strokes, false, ui, canvas);
1003
- if (options.__useArrow)
1004
- strokeArrow(ui, canvas);
1005
- break;
1006
- case 'inside':
1007
- canvas.save();
1008
- canvas.setStroke(undefined, __strokeWidth * 2, options);
1009
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1010
- drawStrokesStyle(strokes, false, ui, canvas);
1011
- canvas.restore();
1012
- break;
1013
- case 'outside':
1014
- const { renderBounds } = ui.__layout;
1015
- const out = canvas.getSameCanvas(true, true);
1016
- ui.__drawRenderPath(out);
1017
- out.setStroke(undefined, __strokeWidth * 2, options);
1018
- drawStrokesStyle(strokes, false, ui, out);
1019
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1020
- out.clearWorld(renderBounds);
1021
- if (ui.__worldFlipped)
1022
- canvas.copyWorldByReset(out, ui.__nowWorld);
1023
- else
1024
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1025
- out.recycle(ui.__nowWorld);
1026
- break;
1027
- }
1028
- }
1029
- }
1030
- function strokeArrow(ui, canvas) {
1031
- if (ui.__.dashPattern) {
1032
- canvas.beginPath();
1033
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1034
- canvas.dashPattern = null;
1035
- canvas.stroke();
994
+ const { renderBounds } = ui.__layout;
995
+ const out = canvas.getSameCanvas(true, true);
996
+ ui.__drawRenderPath(out);
997
+ drawCenter(stroke, 2, ui, out);
998
+ data.windingRule ? out.clip(data.windingRule) : out.clip();
999
+ out.clearWorld(renderBounds);
1000
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
1001
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1002
+ else
1003
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1004
+ out.recycle(ui.__nowWorld);
1036
1005
  }
1037
1006
  }
1038
1007
 
@@ -1079,9 +1048,10 @@ function shape(ui, current, options) {
1079
1048
  }
1080
1049
 
1081
1050
  let recycleMap;
1051
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
1082
1052
  function compute(attrName, ui) {
1083
1053
  const data = ui.__, leafPaints = [];
1084
- let paints = data.__input[attrName], hasOpacityPixel;
1054
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1085
1055
  if (!(paints instanceof Array))
1086
1056
  paints = [paints];
1087
1057
  recycleMap = PaintImage.recycleImage(attrName, data);
@@ -1091,29 +1061,55 @@ function compute(attrName, ui) {
1091
1061
  leafPaints.push(item);
1092
1062
  }
1093
1063
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1094
- if (leafPaints.length && leafPaints[0].image)
1095
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1096
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1064
+ if (leafPaints.length) {
1065
+ if (leafPaints.every(item => item.isTransparent)) {
1066
+ if (leafPaints.some(item => item.image))
1067
+ isAlphaPixel = true;
1068
+ isTransparent = true;
1069
+ }
1070
+ }
1071
+ if (attrName === 'fill') {
1072
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1073
+ stintSet(data, '__isTransparentFill', isTransparent);
1074
+ }
1075
+ else {
1076
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1077
+ stintSet(data, '__isTransparentStroke', isTransparent);
1078
+ }
1097
1079
  }
1098
1080
  function getLeafPaint(attrName, paint, ui) {
1099
1081
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1100
1082
  return undefined;
1083
+ let data;
1101
1084
  const { boxBounds } = ui.__layout;
1102
1085
  switch (paint.type) {
1103
- case 'solid':
1104
- let { type, blendMode, color, opacity } = paint;
1105
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
1106
1086
  case 'image':
1107
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1087
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1088
+ break;
1108
1089
  case 'linear':
1109
- return PaintGradient.linearGradient(paint, boxBounds);
1090
+ data = PaintGradient.linearGradient(paint, boxBounds);
1091
+ break;
1110
1092
  case 'radial':
1111
- return PaintGradient.radialGradient(paint, boxBounds);
1093
+ data = PaintGradient.radialGradient(paint, boxBounds);
1094
+ break;
1112
1095
  case 'angular':
1113
- return PaintGradient.conicGradient(paint, boxBounds);
1096
+ data = PaintGradient.conicGradient(paint, boxBounds);
1097
+ break;
1098
+ case 'solid':
1099
+ const { type, blendMode, color, opacity } = paint;
1100
+ data = { type, blendMode, style: ColorConvert.string(color, opacity) };
1101
+ break;
1114
1102
  default:
1115
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1103
+ if (paint.r !== undefined)
1104
+ data = { type: 'solid', style: ColorConvert.string(paint) };
1116
1105
  }
1106
+ if (data) {
1107
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1108
+ data.isTransparent = true;
1109
+ if (paint.blendMode)
1110
+ data.blendMode = paint.blendMode;
1111
+ }
1112
+ return data;
1117
1113
  }
1118
1114
 
1119
1115
  const PaintModule = {
@@ -1179,12 +1175,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1179
1175
 
1180
1176
  const { get: get$2, translate } = MatrixHelper;
1181
1177
  const tempBox = new Bounds();
1182
- const tempPoint = {};
1183
1178
  const tempScaleData = {};
1179
+ const tempImage = {};
1184
1180
  function createData(leafPaint, image, paint, box) {
1185
- const { blendMode, changeful, sync } = paint;
1186
- if (blendMode)
1187
- leafPaint.blendMode = blendMode;
1181
+ const { changeful, sync } = paint;
1188
1182
  if (changeful)
1189
1183
  leafPaint.changeful = changeful;
1190
1184
  if (sync)
@@ -1192,38 +1186,38 @@ function createData(leafPaint, image, paint, box) {
1192
1186
  leafPaint.data = getPatternData(paint, box, image);
1193
1187
  }
1194
1188
  function getPatternData(paint, box, image) {
1195
- let { width, height } = image;
1196
1189
  if (paint.padding)
1197
1190
  box = tempBox.set(box).shrink(paint.padding);
1198
1191
  if (paint.mode === 'strench')
1199
1192
  paint.mode = 'stretch';
1193
+ let { width, height } = image;
1200
1194
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1201
1195
  const sameBox = box.width === width && box.height === height;
1202
1196
  const data = { mode };
1203
1197
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1204
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1205
- let x = 0, y = 0, scaleX, scaleY;
1198
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1199
+ let scaleX, scaleY;
1206
1200
  if (!mode || mode === 'cover' || mode === 'fit') {
1207
1201
  if (!sameBox || rotation) {
1208
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1209
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1210
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1202
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1203
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1204
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1211
1205
  }
1212
1206
  }
1213
- else if (scale || size) {
1214
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1215
- scaleX = tempScaleData.scaleX;
1216
- scaleY = tempScaleData.scaleY;
1217
- }
1218
- if (align) {
1219
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1220
- if (scaleX)
1221
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1222
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1223
- x += tempPoint.x, y += tempPoint.y;
1207
+ else {
1208
+ if (scale || size) {
1209
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1210
+ scaleX = tempScaleData.scaleX;
1211
+ scaleY = tempScaleData.scaleY;
1212
+ }
1213
+ if (align) {
1214
+ if (scaleX)
1215
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1216
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1217
+ }
1224
1218
  }
1225
1219
  if (offset)
1226
- x += offset.x, y += offset.y;
1220
+ PointHelper.move(tempImage, offset);
1227
1221
  switch (mode) {
1228
1222
  case 'stretch':
1229
1223
  if (!sameBox)
@@ -1231,12 +1225,12 @@ function getPatternData(paint, box, image) {
1231
1225
  break;
1232
1226
  case 'normal':
1233
1227
  case 'clip':
1234
- if (x || y || scaleX || rotation)
1235
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1228
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1229
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1236
1230
  break;
1237
1231
  case 'repeat':
1238
1232
  if (!sameBox || scaleX || rotation)
1239
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1233
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1240
1234
  if (!repeat)
1241
1235
  data.repeat = 'repeat';
1242
1236
  break;
@@ -1244,7 +1238,7 @@ function getPatternData(paint, box, image) {
1244
1238
  case 'cover':
1245
1239
  default:
1246
1240
  if (scaleX)
1247
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1241
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1248
1242
  }
1249
1243
  if (!data.transform) {
1250
1244
  if (box.x || box.y) {
@@ -1277,6 +1271,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1277
1271
  }
1278
1272
  else {
1279
1273
  leafPaint = { type: paint.type, image };
1274
+ if (image.hasAlphaPixel)
1275
+ leafPaint.isTransparent = true;
1280
1276
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1281
1277
  }
1282
1278
  if (firstUse || image.loading)
@@ -1301,7 +1297,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1301
1297
  ignoreRender(ui, false);
1302
1298
  if (!ui.destroyed) {
1303
1299
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1304
- if (image.hasOpacityPixel)
1300
+ if (image.hasAlphaPixel)
1305
1301
  ui.__layout.hitCanvasChanged = true;
1306
1302
  ui.forceUpdate('surface');
1307
1303
  }
@@ -1313,13 +1309,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1313
1309
  onLoadError(ui, event, error);
1314
1310
  leafPaint.loadId = null;
1315
1311
  });
1316
- if (ui.placeholderColor)
1317
- setTimeout(() => {
1318
- if (!(image.ready || image.isPlacehold)) {
1319
- image.isPlacehold = true;
1320
- ui.forceUpdate('surface');
1321
- }
1322
- }, 100);
1312
+ if (ui.placeholderColor) {
1313
+ if (!ui.placeholderDelay)
1314
+ image.isPlacehold = true;
1315
+ else
1316
+ setTimeout(() => {
1317
+ if (!image.ready) {
1318
+ image.isPlacehold = true;
1319
+ ui.forceUpdate('surface');
1320
+ }
1321
+ }, ui.placeholderDelay);
1322
+ }
1323
1323
  }
1324
1324
  return leafPaint;
1325
1325
  }
@@ -1557,32 +1557,33 @@ const PaintImageModule = {
1557
1557
  repeatMode
1558
1558
  };
1559
1559
 
1560
- const { toPoint: toPoint$2 } = AroundHelper;
1560
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1561
1561
  const realFrom$2 = {};
1562
1562
  const realTo$2 = {};
1563
1563
  function linearGradient(paint, box) {
1564
- let { from, to, type, blendMode, opacity } = paint;
1564
+ let { from, to, type, opacity } = paint;
1565
1565
  toPoint$2(from || 'top', box, realFrom$2);
1566
1566
  toPoint$2(to || 'bottom', box, realTo$2);
1567
1567
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1568
- applyStops(style, paint.stops, opacity);
1569
1568
  const data = { type, style };
1570
- if (blendMode)
1571
- data.blendMode = blendMode;
1569
+ applyStops(data, style, paint.stops, opacity);
1572
1570
  return data;
1573
1571
  }
1574
- function applyStops(gradient, stops, opacity) {
1572
+ function applyStops(data, gradient, stops, opacity) {
1575
1573
  if (stops) {
1576
- let stop;
1574
+ let stop, color, offset, isTransparent;
1577
1575
  for (let i = 0, len = stops.length; i < len; i++) {
1578
1576
  stop = stops[i];
1579
- if (typeof stop === 'string') {
1580
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1581
- }
1582
- else {
1583
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1584
- }
1577
+ if (typeof stop === 'string')
1578
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1579
+ else
1580
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1581
+ gradient.addColorStop(offset, color);
1582
+ if (!isTransparent && hasTransparent(color))
1583
+ isTransparent = true;
1585
1584
  }
1585
+ if (isTransparent)
1586
+ data.isTransparent = true;
1586
1587
  }
1587
1588
  }
1588
1589
 
@@ -1592,17 +1593,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1592
1593
  const realFrom$1 = {};
1593
1594
  const realTo$1 = {};
1594
1595
  function radialGradient(paint, box) {
1595
- let { from, to, type, opacity, blendMode, stretch } = paint;
1596
+ let { from, to, type, opacity, stretch } = paint;
1596
1597
  toPoint$1(from || 'center', box, realFrom$1);
1597
1598
  toPoint$1(to || 'bottom', box, realTo$1);
1598
1599
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1599
- applyStops(style, paint.stops, opacity);
1600
1600
  const data = { type, style };
1601
+ applyStops(data, style, paint.stops, opacity);
1601
1602
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1602
1603
  if (transform)
1603
1604
  data.transform = transform;
1604
- if (blendMode)
1605
- data.blendMode = blendMode;
1606
1605
  return data;
1607
1606
  }
1608
1607
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1628,17 +1627,15 @@ const { toPoint } = AroundHelper;
1628
1627
  const realFrom = {};
1629
1628
  const realTo = {};
1630
1629
  function conicGradient(paint, box) {
1631
- let { from, to, type, opacity, blendMode, stretch } = paint;
1630
+ let { from, to, type, opacity, stretch } = paint;
1632
1631
  toPoint(from || 'center', box, realFrom);
1633
1632
  toPoint(to || 'bottom', box, realTo);
1634
1633
  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));
1635
- applyStops(style, paint.stops, opacity);
1636
1634
  const data = { type, style };
1635
+ applyStops(data, style, paint.stops, opacity);
1637
1636
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1638
1637
  if (transform)
1639
1638
  data.transform = transform;
1640
- if (blendMode)
1641
- data.blendMode = blendMode;
1642
1639
  return data;
1643
1640
  }
1644
1641
 
@@ -1971,6 +1968,8 @@ function createRows(drawData, content, style) {
1971
1968
  lastCharType = null;
1972
1969
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1973
1970
  word = { data: [] }, row = { words: [] };
1971
+ if (__letterSpacing)
1972
+ content = [...content];
1974
1973
  for (let i = 0, len = content.length; i < len; i++) {
1975
1974
  char = content[i];
1976
1975
  if (char === '\n') {
@@ -2377,7 +2376,7 @@ const ColorConvertModule = {
2377
2376
 
2378
2377
  Object.assign(TextConvert, TextConvertModule);
2379
2378
  Object.assign(ColorConvert, ColorConvertModule);
2380
- Object.assign(Paint, PaintModule);
2379
+ Object.assign(Paint$1, PaintModule);
2381
2380
  Object.assign(PaintImage, PaintImageModule);
2382
2381
  Object.assign(PaintGradient, PaintGradientModule);
2383
2382
  Object.assign(Effect, EffectModule);