@leafer-draw/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.
package/dist/miniapp.cjs CHANGED
@@ -299,17 +299,15 @@ class Watcher {
299
299
  this.target.emitEvent(new core.WatchEvent(core.WatchEvent.DATA, { updatedList: this.updatedList }));
300
300
  this.__updatedList = new core.LeafList();
301
301
  this.totalTimes++;
302
- this.changed = false;
303
- this.hasVisible = false;
304
- this.hasRemove = false;
305
- this.hasAdd = false;
302
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
306
303
  }
307
304
  __listenEvents() {
308
- const { target } = this;
309
305
  this.__eventIds = [
310
- target.on_(core.PropertyEvent.CHANGE, this.__onAttrChange, this),
311
- target.on_([core.ChildEvent.ADD, core.ChildEvent.REMOVE], this.__onChildEvent, this),
312
- target.on_(core.WatchEvent.REQUEST, this.__onRquestData, this)
306
+ this.target.on_([
307
+ [core.PropertyEvent.CHANGE, this.__onAttrChange, this],
308
+ [[core.ChildEvent.ADD, core.ChildEvent.REMOVE], this.__onChildEvent, this],
309
+ [core.WatchEvent.REQUEST, this.__onRquestData, this]
310
+ ])
313
311
  ];
314
312
  }
315
313
  __removeListenEvents() {
@@ -319,8 +317,7 @@ class Watcher {
319
317
  if (this.target) {
320
318
  this.stop();
321
319
  this.__removeListenEvents();
322
- this.target = null;
323
- this.__updatedList = null;
320
+ this.target = this.__updatedList = null;
324
321
  }
325
322
  }
326
323
  }
@@ -425,7 +422,7 @@ class Layouter {
425
422
  this.disabled = true;
426
423
  }
427
424
  layout() {
428
- if (!this.running)
425
+ if (this.layouting || !this.running)
429
426
  return;
430
427
  const { target } = this;
431
428
  this.times = 0;
@@ -508,12 +505,10 @@ class Layouter {
508
505
  }
509
506
  static fullLayout(target) {
510
507
  updateAllMatrix(target, true);
511
- if (target.isBranch) {
508
+ if (target.isBranch)
512
509
  core.BranchHelper.updateBounds(target);
513
- }
514
- else {
510
+ else
515
511
  core.LeafHelper.updateBounds(target);
516
- }
517
512
  updateAllChange(target);
518
513
  }
519
514
  addExtra(leaf) {
@@ -536,11 +531,12 @@ class Layouter {
536
531
  this.__updatedList = event.data.updatedList;
537
532
  }
538
533
  __listenEvents() {
539
- const { target } = this;
540
534
  this.__eventIds = [
541
- target.on_(core.LayoutEvent.REQUEST, this.layout, this),
542
- target.on_(core.LayoutEvent.AGAIN, this.layoutAgain, this),
543
- target.on_(core.WatchEvent.DATA, this.__onReceiveWatchData, this)
535
+ this.target.on_([
536
+ [core.LayoutEvent.REQUEST, this.layout, this],
537
+ [core.LayoutEvent.AGAIN, this.layoutAgain, this],
538
+ [core.WatchEvent.DATA, this.__onReceiveWatchData, this]
539
+ ])
544
540
  ];
545
541
  }
546
542
  __removeListenEvents() {
@@ -771,12 +767,13 @@ class Renderer {
771
767
  this.target.emitEvent(new core.RenderEvent(type, this.times, bounds, options));
772
768
  }
773
769
  __listenEvents() {
774
- const { target } = this;
775
770
  this.__eventIds = [
776
- target.on_(core.RenderEvent.REQUEST, this.update, this),
777
- target.on_(core.LayoutEvent.END, this.__onLayoutEnd, this),
778
- target.on_(core.RenderEvent.AGAIN, this.renderAgain, this),
779
- target.on_(core.ResizeEvent.RESIZE, this.__onResize, this)
771
+ this.target.on_([
772
+ [core.RenderEvent.REQUEST, this.update, this],
773
+ [core.LayoutEvent.END, this.__onLayoutEnd, this],
774
+ [core.RenderEvent.AGAIN, this.renderAgain, this],
775
+ [core.ResizeEvent.RESIZE, this.__onResize, this]
776
+ ])
780
777
  ];
781
778
  }
782
779
  __removeListenEvents() {
@@ -863,35 +860,38 @@ function fillPathOrText(ui, canvas) {
863
860
  }
864
861
 
865
862
  function strokeText(stroke, ui, canvas) {
866
- const { strokeAlign } = ui.__;
867
- const isStrokes = typeof stroke !== 'string';
868
- switch (strokeAlign) {
863
+ switch (ui.__.strokeAlign) {
869
864
  case 'center':
870
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
871
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
865
+ drawCenter$1(stroke, 1, ui, canvas);
872
866
  break;
873
867
  case 'inside':
874
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
868
+ drawAlign(stroke, 'inside', ui, canvas);
875
869
  break;
876
870
  case 'outside':
877
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
871
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
878
872
  break;
879
873
  }
880
874
  }
881
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
882
- const { __strokeWidth, __font } = ui.__;
875
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
876
+ const data = ui.__;
877
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
878
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
879
+ }
880
+ function drawAlign(stroke, align, ui, canvas) {
883
881
  const out = canvas.getSameCanvas(true, true);
884
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
885
- out.font = __font;
886
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
882
+ out.font = ui.__.__font;
883
+ drawCenter$1(stroke, 2, ui, out);
887
884
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
888
885
  fillText(ui, out);
889
886
  out.blendMode = 'normal';
890
- if (ui.__worldFlipped)
887
+ copyWorld(canvas, out, ui);
888
+ out.recycle(ui.__nowWorld);
889
+ }
890
+ function copyWorld(canvas, out, ui) {
891
+ if (ui.__worldFlipped || core.Platform.fullImageShadow)
891
892
  canvas.copyWorldByReset(out, ui.__nowWorld);
892
893
  else
893
894
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
894
- out.recycle(ui.__nowWorld);
895
895
  }
896
896
  function drawTextStroke(ui, canvas) {
897
897
  let row, data = ui.__.__textDrawData;
@@ -929,90 +929,56 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
929
929
  }
930
930
 
931
931
  function stroke(stroke, ui, canvas) {
932
- const options = ui.__;
933
- const { __strokeWidth, strokeAlign, __font } = options;
934
- if (!__strokeWidth)
932
+ const data = ui.__;
933
+ if (!data.__strokeWidth)
935
934
  return;
936
- if (__font) {
935
+ if (data.__font) {
937
936
  strokeText(stroke, ui, canvas);
938
937
  }
939
938
  else {
940
- switch (strokeAlign) {
939
+ switch (data.strokeAlign) {
941
940
  case 'center':
942
- canvas.setStroke(stroke, __strokeWidth, options);
943
- canvas.stroke();
944
- if (options.__useArrow)
945
- strokeArrow(ui, canvas);
941
+ drawCenter(stroke, 1, ui, canvas);
946
942
  break;
947
943
  case 'inside':
948
- canvas.save();
949
- canvas.setStroke(stroke, __strokeWidth * 2, options);
950
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
951
- canvas.stroke();
952
- canvas.restore();
944
+ drawInside(stroke, ui, canvas);
953
945
  break;
954
946
  case 'outside':
955
- const out = canvas.getSameCanvas(true, true);
956
- out.setStroke(stroke, __strokeWidth * 2, options);
957
- ui.__drawRenderPath(out);
958
- out.stroke();
959
- options.windingRule ? out.clip(options.windingRule) : out.clip();
960
- out.clearWorld(ui.__layout.renderBounds);
961
- if (ui.__worldFlipped)
962
- canvas.copyWorldByReset(out, ui.__nowWorld);
963
- else
964
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
965
- out.recycle(ui.__nowWorld);
947
+ drawOutside(stroke, ui, canvas);
966
948
  break;
967
949
  }
968
950
  }
969
951
  }
970
952
  function strokes(strokes, ui, canvas) {
971
- const options = ui.__;
972
- const { __strokeWidth, strokeAlign, __font } = options;
973
- if (!__strokeWidth)
974
- return;
975
- if (__font) {
976
- strokeText(strokes, ui, canvas);
953
+ stroke(strokes, ui, canvas);
954
+ }
955
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
956
+ const data = ui.__;
957
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
958
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
959
+ if (data.__useArrow)
960
+ draw.Paint.strokeArrow(stroke, ui, canvas);
961
+ }
962
+ function drawInside(stroke, ui, canvas) {
963
+ canvas.save();
964
+ canvas.clipUI(ui);
965
+ drawCenter(stroke, 2, ui, canvas);
966
+ canvas.restore();
967
+ }
968
+ function drawOutside(stroke, ui, canvas) {
969
+ const data = ui.__;
970
+ if (data.__fillAfterStroke) {
971
+ drawCenter(stroke, 2, ui, canvas);
977
972
  }
978
973
  else {
979
- switch (strokeAlign) {
980
- case 'center':
981
- canvas.setStroke(undefined, __strokeWidth, options);
982
- drawStrokesStyle(strokes, false, ui, canvas);
983
- if (options.__useArrow)
984
- strokeArrow(ui, canvas);
985
- break;
986
- case 'inside':
987
- canvas.save();
988
- canvas.setStroke(undefined, __strokeWidth * 2, options);
989
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
990
- drawStrokesStyle(strokes, false, ui, canvas);
991
- canvas.restore();
992
- break;
993
- case 'outside':
994
- const { renderBounds } = ui.__layout;
995
- const out = canvas.getSameCanvas(true, true);
996
- ui.__drawRenderPath(out);
997
- out.setStroke(undefined, __strokeWidth * 2, options);
998
- drawStrokesStyle(strokes, false, ui, out);
999
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1000
- out.clearWorld(renderBounds);
1001
- if (ui.__worldFlipped)
1002
- canvas.copyWorldByReset(out, ui.__nowWorld);
1003
- else
1004
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1005
- out.recycle(ui.__nowWorld);
1006
- break;
1007
- }
1008
- }
1009
- }
1010
- function strokeArrow(ui, canvas) {
1011
- if (ui.__.dashPattern) {
1012
- canvas.beginPath();
1013
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1014
- canvas.dashPattern = null;
1015
- canvas.stroke();
974
+ const { renderBounds } = ui.__layout;
975
+ const out = canvas.getSameCanvas(true, true);
976
+ ui.__drawRenderPath(out);
977
+ drawCenter(stroke, 2, ui, out);
978
+ out.clipUI(data);
979
+ out.clearWorld(renderBounds);
980
+ copyWorld(canvas, out, ui);
981
+ out.recycle(ui.__nowWorld);
1016
982
  }
1017
983
  }
1018
984
 
@@ -1059,41 +1025,66 @@ function shape(ui, current, options) {
1059
1025
  }
1060
1026
 
1061
1027
  let recycleMap;
1028
+ const { stintSet } = core.DataHelper, { hasTransparent: hasTransparent$1 } = draw.ColorConvert;
1062
1029
  function compute(attrName, ui) {
1063
1030
  const data = ui.__, leafPaints = [];
1064
- let paints = data.__input[attrName], hasOpacityPixel;
1031
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1065
1032
  if (!(paints instanceof Array))
1066
1033
  paints = [paints];
1067
1034
  recycleMap = draw.PaintImage.recycleImage(attrName, data);
1068
1035
  for (let i = 0, len = paints.length, item; i < len; i++) {
1069
- item = getLeafPaint(attrName, paints[i], ui);
1070
- if (item)
1071
- leafPaints.push(item);
1036
+ (item = getLeafPaint(attrName, paints[i], ui)) && leafPaints.push(item);
1072
1037
  }
1073
1038
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1074
- if (leafPaints.length && leafPaints[0].image)
1075
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1076
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1039
+ if (leafPaints.length) {
1040
+ if (leafPaints.every(item => item.isTransparent)) {
1041
+ if (leafPaints.some(item => item.image))
1042
+ isAlphaPixel = true;
1043
+ isTransparent = true;
1044
+ }
1045
+ }
1046
+ if (attrName === 'fill') {
1047
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1048
+ stintSet(data, '__isTransparentFill', isTransparent);
1049
+ }
1050
+ else {
1051
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1052
+ stintSet(data, '__isTransparentStroke', isTransparent);
1053
+ }
1077
1054
  }
1078
1055
  function getLeafPaint(attrName, paint, ui) {
1079
1056
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1080
1057
  return undefined;
1058
+ let data;
1081
1059
  const { boxBounds } = ui.__layout;
1082
1060
  switch (paint.type) {
1083
- case 'solid':
1084
- let { type, blendMode, color, opacity } = paint;
1085
- return { type, blendMode, style: draw.ColorConvert.string(color, opacity) };
1086
1061
  case 'image':
1087
- return draw.PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1062
+ data = draw.PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1063
+ break;
1088
1064
  case 'linear':
1089
- return draw.PaintGradient.linearGradient(paint, boxBounds);
1065
+ data = draw.PaintGradient.linearGradient(paint, boxBounds);
1066
+ break;
1090
1067
  case 'radial':
1091
- return draw.PaintGradient.radialGradient(paint, boxBounds);
1068
+ data = draw.PaintGradient.radialGradient(paint, boxBounds);
1069
+ break;
1092
1070
  case 'angular':
1093
- return draw.PaintGradient.conicGradient(paint, boxBounds);
1071
+ data = draw.PaintGradient.conicGradient(paint, boxBounds);
1072
+ break;
1073
+ case 'solid':
1074
+ const { type, color, opacity } = paint;
1075
+ data = { type, style: draw.ColorConvert.string(color, opacity) };
1076
+ break;
1094
1077
  default:
1095
- return paint.r !== undefined ? { type: 'solid', style: draw.ColorConvert.string(paint) } : undefined;
1078
+ if (paint.r !== undefined)
1079
+ data = { type: 'solid', style: draw.ColorConvert.string(paint) };
1096
1080
  }
1081
+ if (data) {
1082
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1083
+ data.isTransparent = true;
1084
+ if (paint.blendMode)
1085
+ data.blendMode = paint.blendMode;
1086
+ }
1087
+ return data;
1097
1088
  }
1098
1089
 
1099
1090
  const PaintModule = {
@@ -1159,12 +1150,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1159
1150
 
1160
1151
  const { get: get$2, translate } = core.MatrixHelper;
1161
1152
  const tempBox = new core.Bounds();
1162
- const tempPoint = {};
1163
1153
  const tempScaleData = {};
1154
+ const tempImage = {};
1164
1155
  function createData(leafPaint, image, paint, box) {
1165
- const { blendMode, changeful, sync } = paint;
1166
- if (blendMode)
1167
- leafPaint.blendMode = blendMode;
1156
+ const { changeful, sync } = paint;
1168
1157
  if (changeful)
1169
1158
  leafPaint.changeful = changeful;
1170
1159
  if (sync)
@@ -1172,38 +1161,38 @@ function createData(leafPaint, image, paint, box) {
1172
1161
  leafPaint.data = getPatternData(paint, box, image);
1173
1162
  }
1174
1163
  function getPatternData(paint, box, image) {
1175
- let { width, height } = image;
1176
1164
  if (paint.padding)
1177
1165
  box = tempBox.set(box).shrink(paint.padding);
1178
1166
  if (paint.mode === 'strench')
1179
1167
  paint.mode = 'stretch';
1168
+ let { width, height } = image;
1180
1169
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1181
1170
  const sameBox = box.width === width && box.height === height;
1182
1171
  const data = { mode };
1183
1172
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1184
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1185
- let x = 0, y = 0, scaleX, scaleY;
1173
+ core.BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1174
+ let scaleX, scaleY;
1186
1175
  if (!mode || mode === 'cover' || mode === 'fit') {
1187
1176
  if (!sameBox || rotation) {
1188
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1189
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1190
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1177
+ scaleX = scaleY = core.BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1178
+ core.BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1179
+ core.BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1191
1180
  }
1192
1181
  }
1193
- else if (scale || size) {
1194
- core.MathHelper.getScaleData(scale, size, image, tempScaleData);
1195
- scaleX = tempScaleData.scaleX;
1196
- scaleY = tempScaleData.scaleY;
1197
- }
1198
- if (align) {
1199
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1200
- if (scaleX)
1201
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1202
- core.AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1203
- x += tempPoint.x, y += tempPoint.y;
1182
+ else {
1183
+ if (scale || size) {
1184
+ core.MathHelper.getScaleData(scale, size, image, tempScaleData);
1185
+ scaleX = tempScaleData.scaleX;
1186
+ scaleY = tempScaleData.scaleY;
1187
+ }
1188
+ if (align) {
1189
+ if (scaleX)
1190
+ core.BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1191
+ core.AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1192
+ }
1204
1193
  }
1205
1194
  if (offset)
1206
- x += offset.x, y += offset.y;
1195
+ core.PointHelper.move(tempImage, offset);
1207
1196
  switch (mode) {
1208
1197
  case 'stretch':
1209
1198
  if (!sameBox)
@@ -1211,12 +1200,12 @@ function getPatternData(paint, box, image) {
1211
1200
  break;
1212
1201
  case 'normal':
1213
1202
  case 'clip':
1214
- if (x || y || scaleX || rotation)
1215
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1203
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1204
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1216
1205
  break;
1217
1206
  case 'repeat':
1218
1207
  if (!sameBox || scaleX || rotation)
1219
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1208
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1220
1209
  if (!repeat)
1221
1210
  data.repeat = 'repeat';
1222
1211
  break;
@@ -1224,7 +1213,7 @@ function getPatternData(paint, box, image) {
1224
1213
  case 'cover':
1225
1214
  default:
1226
1215
  if (scaleX)
1227
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1216
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1228
1217
  }
1229
1218
  if (!data.transform) {
1230
1219
  if (box.x || box.y) {
@@ -1257,6 +1246,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1257
1246
  }
1258
1247
  else {
1259
1248
  leafPaint = { type: paint.type, image };
1249
+ if (image.hasAlphaPixel)
1250
+ leafPaint.isTransparent = true;
1260
1251
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1261
1252
  }
1262
1253
  if (firstUse || image.loading)
@@ -1281,7 +1272,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1281
1272
  ignoreRender(ui, false);
1282
1273
  if (!ui.destroyed) {
1283
1274
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1284
- if (image.hasOpacityPixel)
1275
+ if (image.hasAlphaPixel)
1285
1276
  ui.__layout.hitCanvasChanged = true;
1286
1277
  ui.forceUpdate('surface');
1287
1278
  }
@@ -1293,13 +1284,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1293
1284
  onLoadError(ui, event, error);
1294
1285
  leafPaint.loadId = null;
1295
1286
  });
1296
- if (ui.placeholderColor)
1297
- setTimeout(() => {
1298
- if (!(image.ready || image.isPlacehold)) {
1299
- image.isPlacehold = true;
1300
- ui.forceUpdate('surface');
1301
- }
1302
- }, 100);
1287
+ if (ui.placeholderColor) {
1288
+ if (!ui.placeholderDelay)
1289
+ image.isPlacehold = true;
1290
+ else
1291
+ setTimeout(() => {
1292
+ if (!image.ready) {
1293
+ image.isPlacehold = true;
1294
+ ui.forceUpdate('surface');
1295
+ }
1296
+ }, ui.placeholderDelay);
1297
+ }
1303
1298
  }
1304
1299
  return leafPaint;
1305
1300
  }
@@ -1486,7 +1481,7 @@ function checkImage(ui, canvas, paint, allowDraw) {
1486
1481
  }
1487
1482
  function drawImage(ui, canvas, paint, data) {
1488
1483
  canvas.save();
1489
- ui.windingRule ? canvas.clip(ui.windingRule) : canvas.clip();
1484
+ canvas.clipUI(ui);
1490
1485
  if (paint.blendMode)
1491
1486
  canvas.blendMode = paint.blendMode;
1492
1487
  if (data.opacity)
@@ -1537,32 +1532,33 @@ const PaintImageModule = {
1537
1532
  repeatMode
1538
1533
  };
1539
1534
 
1540
- const { toPoint: toPoint$2 } = core.AroundHelper;
1535
+ const { toPoint: toPoint$2 } = core.AroundHelper, { hasTransparent } = draw.ColorConvert;
1541
1536
  const realFrom$2 = {};
1542
1537
  const realTo$2 = {};
1543
1538
  function linearGradient(paint, box) {
1544
- let { from, to, type, blendMode, opacity } = paint;
1539
+ let { from, to, type, opacity } = paint;
1545
1540
  toPoint$2(from || 'top', box, realFrom$2);
1546
1541
  toPoint$2(to || 'bottom', box, realTo$2);
1547
1542
  const style = core.Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1548
- applyStops(style, paint.stops, opacity);
1549
1543
  const data = { type, style };
1550
- if (blendMode)
1551
- data.blendMode = blendMode;
1544
+ applyStops(data, style, paint.stops, opacity);
1552
1545
  return data;
1553
1546
  }
1554
- function applyStops(gradient, stops, opacity) {
1547
+ function applyStops(data, gradient, stops, opacity) {
1555
1548
  if (stops) {
1556
- let stop;
1549
+ let stop, color, offset, isTransparent;
1557
1550
  for (let i = 0, len = stops.length; i < len; i++) {
1558
1551
  stop = stops[i];
1559
- if (typeof stop === 'string') {
1560
- gradient.addColorStop(i / (len - 1), draw.ColorConvert.string(stop, opacity));
1561
- }
1562
- else {
1563
- gradient.addColorStop(stop.offset, draw.ColorConvert.string(stop.color, opacity));
1564
- }
1552
+ if (typeof stop === 'string')
1553
+ offset = i / (len - 1), color = draw.ColorConvert.string(stop, opacity);
1554
+ else
1555
+ offset = stop.offset, color = draw.ColorConvert.string(stop.color, opacity);
1556
+ gradient.addColorStop(offset, color);
1557
+ if (!isTransparent && hasTransparent(color))
1558
+ isTransparent = true;
1565
1559
  }
1560
+ if (isTransparent)
1561
+ data.isTransparent = true;
1566
1562
  }
1567
1563
  }
1568
1564
 
@@ -1572,17 +1568,15 @@ const { toPoint: toPoint$1 } = core.AroundHelper;
1572
1568
  const realFrom$1 = {};
1573
1569
  const realTo$1 = {};
1574
1570
  function radialGradient(paint, box) {
1575
- let { from, to, type, opacity, blendMode, stretch } = paint;
1571
+ let { from, to, type, opacity, stretch } = paint;
1576
1572
  toPoint$1(from || 'center', box, realFrom$1);
1577
1573
  toPoint$1(to || 'bottom', box, realTo$1);
1578
1574
  const style = core.Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1579
- applyStops(style, paint.stops, opacity);
1580
1575
  const data = { type, style };
1576
+ applyStops(data, style, paint.stops, opacity);
1581
1577
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1582
1578
  if (transform)
1583
1579
  data.transform = transform;
1584
- if (blendMode)
1585
- data.blendMode = blendMode;
1586
1580
  return data;
1587
1581
  }
1588
1582
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1608,17 +1602,15 @@ const { toPoint } = core.AroundHelper;
1608
1602
  const realFrom = {};
1609
1603
  const realTo = {};
1610
1604
  function conicGradient(paint, box) {
1611
- let { from, to, type, opacity, blendMode, stretch } = paint;
1605
+ let { from, to, type, opacity, stretch } = paint;
1612
1606
  toPoint(from || 'center', box, realFrom);
1613
1607
  toPoint(to || 'bottom', box, realTo);
1614
1608
  const style = core.Platform.conicGradientSupport ? core.Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : core.Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo));
1615
- applyStops(style, paint.stops, opacity);
1616
1609
  const data = { type, style };
1610
+ applyStops(data, style, paint.stops, opacity);
1617
1611
  const transform = getTransform(box, realFrom, realTo, stretch || 1, core.Platform.conicGradientRotate90);
1618
1612
  if (transform)
1619
1613
  data.transform = transform;
1620
- if (blendMode)
1621
- data.blendMode = blendMode;
1622
1614
  return data;
1623
1615
  }
1624
1616
 
@@ -1654,12 +1646,10 @@ function shadow(ui, current, shape) {
1654
1646
  }
1655
1647
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1656
1648
  }
1657
- if (ui.__worldFlipped) {
1649
+ if (ui.__worldFlipped)
1658
1650
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1659
- }
1660
- else {
1651
+ else
1661
1652
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1662
- }
1663
1653
  if (end && index < end)
1664
1654
  other.clearWorld(copyBounds, true);
1665
1655
  });
@@ -1718,12 +1708,10 @@ function innerShadow(ui, current, shape) {
1718
1708
  copyBounds = bounds;
1719
1709
  }
1720
1710
  other.fillWorld(copyBounds, draw.ColorConvert.string(item.color), 'source-in');
1721
- if (ui.__worldFlipped) {
1711
+ if (ui.__worldFlipped)
1722
1712
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1723
- }
1724
- else {
1713
+ else
1725
1714
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1726
- }
1727
1715
  if (end && index < end)
1728
1716
  other.clearWorld(copyBounds, true);
1729
1717
  });
@@ -1951,6 +1939,8 @@ function createRows(drawData, content, style) {
1951
1939
  lastCharType = null;
1952
1940
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1953
1941
  word = { data: [] }, row = { words: [] };
1942
+ if (__letterSpacing)
1943
+ content = [...content];
1954
1944
  for (let i = 0, len = content.length; i < len; i++) {
1955
1945
  char = content[i];
1956
1946
  if (char === '\n') {