@leafer-ui/node 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/node.esm.js CHANGED
@@ -1,10 +1,10 @@
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
4
  import { writeFileSync } from 'fs';
5
5
  import { HitCanvasManager, InteractionBase } from '@leafer-ui/core';
6
6
  export * from '@leafer-ui/core';
7
- import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect, TwoPointBoundsHelper, Bounds as Bounds$1, FileHelper as FileHelper$1, Platform as Platform$1, Matrix, MathHelper as MathHelper$1, Creator as Creator$1, TaskProcessor, Resource, LeaferCanvasBase as LeaferCanvasBase$1, Debug as Debug$1, Plugin as Plugin$1, UI } from '@leafer-ui/draw';
7
+ import { PaintImage, Paint, ColorConvert, PaintGradient, Export, Group, TextConvert, Effect, TwoPointBoundsHelper, Bounds as Bounds$1, FileHelper as FileHelper$1, Platform as Platform$1, Matrix, MathHelper as MathHelper$1, Creator as Creator$1, TaskProcessor, Resource, LeaferCanvasBase as LeaferCanvasBase$1, Debug as Debug$1, Plugin as Plugin$1, UI } from '@leafer-ui/draw';
8
8
 
9
9
  /******************************************************************************
10
10
  Copyright (c) Microsoft Corporation.
@@ -175,17 +175,15 @@ class Watcher {
175
175
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
176
176
  this.__updatedList = new LeafList();
177
177
  this.totalTimes++;
178
- this.changed = false;
179
- this.hasVisible = false;
180
- this.hasRemove = false;
181
- this.hasAdd = false;
178
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
182
179
  }
183
180
  __listenEvents() {
184
- const { target } = this;
185
181
  this.__eventIds = [
186
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
187
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
188
- target.on_(WatchEvent.REQUEST, this.__onRquestData, this)
182
+ this.target.on_([
183
+ [PropertyEvent.CHANGE, this.__onAttrChange, this],
184
+ [[ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this],
185
+ [WatchEvent.REQUEST, this.__onRquestData, this]
186
+ ])
189
187
  ];
190
188
  }
191
189
  __removeListenEvents() {
@@ -195,8 +193,7 @@ class Watcher {
195
193
  if (this.target) {
196
194
  this.stop();
197
195
  this.__removeListenEvents();
198
- this.target = null;
199
- this.__updatedList = null;
196
+ this.target = this.__updatedList = null;
200
197
  }
201
198
  }
202
199
  }
@@ -301,7 +298,7 @@ class Layouter {
301
298
  this.disabled = true;
302
299
  }
303
300
  layout() {
304
- if (!this.running)
301
+ if (this.layouting || !this.running)
305
302
  return;
306
303
  const { target } = this;
307
304
  this.times = 0;
@@ -384,12 +381,10 @@ class Layouter {
384
381
  }
385
382
  static fullLayout(target) {
386
383
  updateAllMatrix(target, true);
387
- if (target.isBranch) {
384
+ if (target.isBranch)
388
385
  BranchHelper.updateBounds(target);
389
- }
390
- else {
386
+ else
391
387
  LeafHelper.updateBounds(target);
392
- }
393
388
  updateAllChange(target);
394
389
  }
395
390
  addExtra(leaf) {
@@ -412,11 +407,12 @@ class Layouter {
412
407
  this.__updatedList = event.data.updatedList;
413
408
  }
414
409
  __listenEvents() {
415
- const { target } = this;
416
410
  this.__eventIds = [
417
- target.on_(LayoutEvent.REQUEST, this.layout, this),
418
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
419
- target.on_(WatchEvent.DATA, this.__onReceiveWatchData, this)
411
+ this.target.on_([
412
+ [LayoutEvent.REQUEST, this.layout, this],
413
+ [LayoutEvent.AGAIN, this.layoutAgain, this],
414
+ [WatchEvent.DATA, this.__onReceiveWatchData, this]
415
+ ])
420
416
  ];
421
417
  }
422
418
  __removeListenEvents() {
@@ -647,12 +643,13 @@ class Renderer {
647
643
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
648
644
  }
649
645
  __listenEvents() {
650
- const { target } = this;
651
646
  this.__eventIds = [
652
- target.on_(RenderEvent.REQUEST, this.update, this),
653
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
654
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
655
- target.on_(ResizeEvent.RESIZE, this.__onResize, this)
647
+ this.target.on_([
648
+ [RenderEvent.REQUEST, this.update, this],
649
+ [LayoutEvent.END, this.__onLayoutEnd, this],
650
+ [RenderEvent.AGAIN, this.renderAgain, this],
651
+ [ResizeEvent.RESIZE, this.__onResize, this]
652
+ ])
656
653
  ];
657
654
  }
658
655
  __removeListenEvents() {
@@ -896,35 +893,38 @@ function fillPathOrText(ui, canvas) {
896
893
  }
897
894
 
898
895
  function strokeText(stroke, ui, canvas) {
899
- const { strokeAlign } = ui.__;
900
- const isStrokes = typeof stroke !== 'string';
901
- switch (strokeAlign) {
896
+ switch (ui.__.strokeAlign) {
902
897
  case 'center':
903
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
904
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
898
+ drawCenter$1(stroke, 1, ui, canvas);
905
899
  break;
906
900
  case 'inside':
907
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
901
+ drawAlign(stroke, 'inside', ui, canvas);
908
902
  break;
909
903
  case 'outside':
910
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
904
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
911
905
  break;
912
906
  }
913
907
  }
914
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
915
- const { __strokeWidth, __font } = ui.__;
908
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
909
+ const data = ui.__;
910
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
911
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
912
+ }
913
+ function drawAlign(stroke, align, ui, canvas) {
916
914
  const out = canvas.getSameCanvas(true, true);
917
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
918
- out.font = __font;
919
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
915
+ out.font = ui.__.__font;
916
+ drawCenter$1(stroke, 2, ui, out);
920
917
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
921
918
  fillText(ui, out);
922
919
  out.blendMode = 'normal';
923
- if (ui.__worldFlipped)
920
+ copyWorld(canvas, out, ui);
921
+ out.recycle(ui.__nowWorld);
922
+ }
923
+ function copyWorld(canvas, out, ui) {
924
+ if (ui.__worldFlipped || Platform.fullImageShadow)
924
925
  canvas.copyWorldByReset(out, ui.__nowWorld);
925
926
  else
926
927
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
927
- out.recycle(ui.__nowWorld);
928
928
  }
929
929
  function drawTextStroke(ui, canvas) {
930
930
  let row, data = ui.__.__textDrawData;
@@ -962,90 +962,56 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
962
962
  }
963
963
 
964
964
  function stroke(stroke, ui, canvas) {
965
- const options = ui.__;
966
- const { __strokeWidth, strokeAlign, __font } = options;
967
- if (!__strokeWidth)
965
+ const data = ui.__;
966
+ if (!data.__strokeWidth)
968
967
  return;
969
- if (__font) {
968
+ if (data.__font) {
970
969
  strokeText(stroke, ui, canvas);
971
970
  }
972
971
  else {
973
- switch (strokeAlign) {
972
+ switch (data.strokeAlign) {
974
973
  case 'center':
975
- canvas.setStroke(stroke, __strokeWidth, options);
976
- canvas.stroke();
977
- if (options.__useArrow)
978
- strokeArrow(ui, canvas);
974
+ drawCenter(stroke, 1, ui, canvas);
979
975
  break;
980
976
  case 'inside':
981
- canvas.save();
982
- canvas.setStroke(stroke, __strokeWidth * 2, options);
983
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
984
- canvas.stroke();
985
- canvas.restore();
977
+ drawInside(stroke, ui, canvas);
986
978
  break;
987
979
  case 'outside':
988
- const out = canvas.getSameCanvas(true, true);
989
- out.setStroke(stroke, __strokeWidth * 2, options);
990
- ui.__drawRenderPath(out);
991
- out.stroke();
992
- options.windingRule ? out.clip(options.windingRule) : out.clip();
993
- out.clearWorld(ui.__layout.renderBounds);
994
- if (ui.__worldFlipped)
995
- canvas.copyWorldByReset(out, ui.__nowWorld);
996
- else
997
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
998
- out.recycle(ui.__nowWorld);
980
+ drawOutside(stroke, ui, canvas);
999
981
  break;
1000
982
  }
1001
983
  }
1002
984
  }
1003
985
  function strokes(strokes, ui, canvas) {
1004
- const options = ui.__;
1005
- const { __strokeWidth, strokeAlign, __font } = options;
1006
- if (!__strokeWidth)
1007
- return;
1008
- if (__font) {
1009
- strokeText(strokes, ui, canvas);
986
+ stroke(strokes, ui, canvas);
987
+ }
988
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
989
+ const data = ui.__;
990
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
991
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
992
+ if (data.__useArrow)
993
+ Paint.strokeArrow(stroke, ui, canvas);
994
+ }
995
+ function drawInside(stroke, ui, canvas) {
996
+ canvas.save();
997
+ canvas.clipUI(ui);
998
+ drawCenter(stroke, 2, ui, canvas);
999
+ canvas.restore();
1000
+ }
1001
+ function drawOutside(stroke, ui, canvas) {
1002
+ const data = ui.__;
1003
+ if (data.__fillAfterStroke) {
1004
+ drawCenter(stroke, 2, ui, canvas);
1010
1005
  }
1011
1006
  else {
1012
- switch (strokeAlign) {
1013
- case 'center':
1014
- canvas.setStroke(undefined, __strokeWidth, options);
1015
- drawStrokesStyle(strokes, false, ui, canvas);
1016
- if (options.__useArrow)
1017
- strokeArrow(ui, canvas);
1018
- break;
1019
- case 'inside':
1020
- canvas.save();
1021
- canvas.setStroke(undefined, __strokeWidth * 2, options);
1022
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1023
- drawStrokesStyle(strokes, false, ui, canvas);
1024
- canvas.restore();
1025
- break;
1026
- case 'outside':
1027
- const { renderBounds } = ui.__layout;
1028
- const out = canvas.getSameCanvas(true, true);
1029
- ui.__drawRenderPath(out);
1030
- out.setStroke(undefined, __strokeWidth * 2, options);
1031
- drawStrokesStyle(strokes, false, ui, out);
1032
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1033
- out.clearWorld(renderBounds);
1034
- if (ui.__worldFlipped)
1035
- canvas.copyWorldByReset(out, ui.__nowWorld);
1036
- else
1037
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1038
- out.recycle(ui.__nowWorld);
1039
- break;
1040
- }
1041
- }
1042
- }
1043
- function strokeArrow(ui, canvas) {
1044
- if (ui.__.dashPattern) {
1045
- canvas.beginPath();
1046
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1047
- canvas.dashPattern = null;
1048
- canvas.stroke();
1007
+ const { renderBounds } = ui.__layout;
1008
+ const out = canvas.getSameCanvas(true, true);
1009
+ ui.__drawRenderPath(out);
1010
+ drawCenter(stroke, 2, ui, out);
1011
+ out.clipUI(data);
1012
+ out.clearWorld(renderBounds);
1013
+ copyWorld(canvas, out, ui);
1014
+ out.recycle(ui.__nowWorld);
1049
1015
  }
1050
1016
  }
1051
1017
 
@@ -1092,41 +1058,66 @@ function shape(ui, current, options) {
1092
1058
  }
1093
1059
 
1094
1060
  let recycleMap;
1061
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
1095
1062
  function compute(attrName, ui) {
1096
1063
  const data = ui.__, leafPaints = [];
1097
- let paints = data.__input[attrName], hasOpacityPixel;
1064
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1098
1065
  if (!(paints instanceof Array))
1099
1066
  paints = [paints];
1100
1067
  recycleMap = PaintImage.recycleImage(attrName, data);
1101
1068
  for (let i = 0, len = paints.length, item; i < len; i++) {
1102
- item = getLeafPaint(attrName, paints[i], ui);
1103
- if (item)
1104
- leafPaints.push(item);
1069
+ (item = getLeafPaint(attrName, paints[i], ui)) && leafPaints.push(item);
1105
1070
  }
1106
1071
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1107
- if (leafPaints.length && leafPaints[0].image)
1108
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1109
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1072
+ if (leafPaints.length) {
1073
+ if (leafPaints.every(item => item.isTransparent)) {
1074
+ if (leafPaints.some(item => item.image))
1075
+ isAlphaPixel = true;
1076
+ isTransparent = true;
1077
+ }
1078
+ }
1079
+ if (attrName === 'fill') {
1080
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1081
+ stintSet(data, '__isTransparentFill', isTransparent);
1082
+ }
1083
+ else {
1084
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1085
+ stintSet(data, '__isTransparentStroke', isTransparent);
1086
+ }
1110
1087
  }
1111
1088
  function getLeafPaint(attrName, paint, ui) {
1112
1089
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1113
1090
  return undefined;
1091
+ let data;
1114
1092
  const { boxBounds } = ui.__layout;
1115
1093
  switch (paint.type) {
1116
- case 'solid':
1117
- let { type, blendMode, color, opacity } = paint;
1118
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
1119
1094
  case 'image':
1120
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1095
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1096
+ break;
1121
1097
  case 'linear':
1122
- return PaintGradient.linearGradient(paint, boxBounds);
1098
+ data = PaintGradient.linearGradient(paint, boxBounds);
1099
+ break;
1123
1100
  case 'radial':
1124
- return PaintGradient.radialGradient(paint, boxBounds);
1101
+ data = PaintGradient.radialGradient(paint, boxBounds);
1102
+ break;
1125
1103
  case 'angular':
1126
- return PaintGradient.conicGradient(paint, boxBounds);
1104
+ data = PaintGradient.conicGradient(paint, boxBounds);
1105
+ break;
1106
+ case 'solid':
1107
+ const { type, color, opacity } = paint;
1108
+ data = { type, style: ColorConvert.string(color, opacity) };
1109
+ break;
1127
1110
  default:
1128
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1111
+ if (paint.r !== undefined)
1112
+ data = { type: 'solid', style: ColorConvert.string(paint) };
1129
1113
  }
1114
+ if (data) {
1115
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1116
+ data.isTransparent = true;
1117
+ if (paint.blendMode)
1118
+ data.blendMode = paint.blendMode;
1119
+ }
1120
+ return data;
1130
1121
  }
1131
1122
 
1132
1123
  const PaintModule = {
@@ -1192,12 +1183,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1192
1183
 
1193
1184
  const { get: get$2, translate } = MatrixHelper;
1194
1185
  const tempBox = new Bounds();
1195
- const tempPoint = {};
1196
1186
  const tempScaleData = {};
1187
+ const tempImage = {};
1197
1188
  function createData(leafPaint, image, paint, box) {
1198
- const { blendMode, changeful, sync } = paint;
1199
- if (blendMode)
1200
- leafPaint.blendMode = blendMode;
1189
+ const { changeful, sync } = paint;
1201
1190
  if (changeful)
1202
1191
  leafPaint.changeful = changeful;
1203
1192
  if (sync)
@@ -1205,38 +1194,38 @@ function createData(leafPaint, image, paint, box) {
1205
1194
  leafPaint.data = getPatternData(paint, box, image);
1206
1195
  }
1207
1196
  function getPatternData(paint, box, image) {
1208
- let { width, height } = image;
1209
1197
  if (paint.padding)
1210
1198
  box = tempBox.set(box).shrink(paint.padding);
1211
1199
  if (paint.mode === 'strench')
1212
1200
  paint.mode = 'stretch';
1201
+ let { width, height } = image;
1213
1202
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1214
1203
  const sameBox = box.width === width && box.height === height;
1215
1204
  const data = { mode };
1216
1205
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1217
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1218
- let x = 0, y = 0, scaleX, scaleY;
1206
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1207
+ let scaleX, scaleY;
1219
1208
  if (!mode || mode === 'cover' || mode === 'fit') {
1220
1209
  if (!sameBox || rotation) {
1221
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1222
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1223
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1210
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1211
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1212
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1224
1213
  }
1225
1214
  }
1226
- else if (scale || size) {
1227
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1228
- scaleX = tempScaleData.scaleX;
1229
- scaleY = tempScaleData.scaleY;
1230
- }
1231
- if (align) {
1232
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1233
- if (scaleX)
1234
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1235
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1236
- x += tempPoint.x, y += tempPoint.y;
1215
+ else {
1216
+ if (scale || size) {
1217
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1218
+ scaleX = tempScaleData.scaleX;
1219
+ scaleY = tempScaleData.scaleY;
1220
+ }
1221
+ if (align) {
1222
+ if (scaleX)
1223
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1224
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1225
+ }
1237
1226
  }
1238
1227
  if (offset)
1239
- x += offset.x, y += offset.y;
1228
+ PointHelper.move(tempImage, offset);
1240
1229
  switch (mode) {
1241
1230
  case 'stretch':
1242
1231
  if (!sameBox)
@@ -1244,12 +1233,12 @@ function getPatternData(paint, box, image) {
1244
1233
  break;
1245
1234
  case 'normal':
1246
1235
  case 'clip':
1247
- if (x || y || scaleX || rotation)
1248
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1236
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1237
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1249
1238
  break;
1250
1239
  case 'repeat':
1251
1240
  if (!sameBox || scaleX || rotation)
1252
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1241
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1253
1242
  if (!repeat)
1254
1243
  data.repeat = 'repeat';
1255
1244
  break;
@@ -1257,7 +1246,7 @@ function getPatternData(paint, box, image) {
1257
1246
  case 'cover':
1258
1247
  default:
1259
1248
  if (scaleX)
1260
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1249
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1261
1250
  }
1262
1251
  if (!data.transform) {
1263
1252
  if (box.x || box.y) {
@@ -1290,6 +1279,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1290
1279
  }
1291
1280
  else {
1292
1281
  leafPaint = { type: paint.type, image };
1282
+ if (image.hasAlphaPixel)
1283
+ leafPaint.isTransparent = true;
1293
1284
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1294
1285
  }
1295
1286
  if (firstUse || image.loading)
@@ -1314,7 +1305,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1314
1305
  ignoreRender(ui, false);
1315
1306
  if (!ui.destroyed) {
1316
1307
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1317
- if (image.hasOpacityPixel)
1308
+ if (image.hasAlphaPixel)
1318
1309
  ui.__layout.hitCanvasChanged = true;
1319
1310
  ui.forceUpdate('surface');
1320
1311
  }
@@ -1326,13 +1317,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1326
1317
  onLoadError(ui, event, error);
1327
1318
  leafPaint.loadId = null;
1328
1319
  });
1329
- if (ui.placeholderColor)
1330
- setTimeout(() => {
1331
- if (!(image.ready || image.isPlacehold)) {
1332
- image.isPlacehold = true;
1333
- ui.forceUpdate('surface');
1334
- }
1335
- }, 100);
1320
+ if (ui.placeholderColor) {
1321
+ if (!ui.placeholderDelay)
1322
+ image.isPlacehold = true;
1323
+ else
1324
+ setTimeout(() => {
1325
+ if (!image.ready) {
1326
+ image.isPlacehold = true;
1327
+ ui.forceUpdate('surface');
1328
+ }
1329
+ }, ui.placeholderDelay);
1330
+ }
1336
1331
  }
1337
1332
  return leafPaint;
1338
1333
  }
@@ -1487,7 +1482,7 @@ function checkImage(ui, canvas, paint, allowDraw) {
1487
1482
  }
1488
1483
  function drawImage(ui, canvas, paint, data) {
1489
1484
  canvas.save();
1490
- ui.windingRule ? canvas.clip(ui.windingRule) : canvas.clip();
1485
+ canvas.clipUI(ui);
1491
1486
  if (paint.blendMode)
1492
1487
  canvas.blendMode = paint.blendMode;
1493
1488
  if (data.opacity)
@@ -1538,32 +1533,33 @@ const PaintImageModule = {
1538
1533
  repeatMode
1539
1534
  };
1540
1535
 
1541
- const { toPoint: toPoint$2 } = AroundHelper;
1536
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1542
1537
  const realFrom$2 = {};
1543
1538
  const realTo$2 = {};
1544
1539
  function linearGradient(paint, box) {
1545
- let { from, to, type, blendMode, opacity } = paint;
1540
+ let { from, to, type, opacity } = paint;
1546
1541
  toPoint$2(from || 'top', box, realFrom$2);
1547
1542
  toPoint$2(to || 'bottom', box, realTo$2);
1548
1543
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1549
- applyStops(style, paint.stops, opacity);
1550
1544
  const data = { type, style };
1551
- if (blendMode)
1552
- data.blendMode = blendMode;
1545
+ applyStops(data, style, paint.stops, opacity);
1553
1546
  return data;
1554
1547
  }
1555
- function applyStops(gradient, stops, opacity) {
1548
+ function applyStops(data, gradient, stops, opacity) {
1556
1549
  if (stops) {
1557
- let stop;
1550
+ let stop, color, offset, isTransparent;
1558
1551
  for (let i = 0, len = stops.length; i < len; i++) {
1559
1552
  stop = stops[i];
1560
- if (typeof stop === 'string') {
1561
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1562
- }
1563
- else {
1564
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1565
- }
1553
+ if (typeof stop === 'string')
1554
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1555
+ else
1556
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1557
+ gradient.addColorStop(offset, color);
1558
+ if (!isTransparent && hasTransparent(color))
1559
+ isTransparent = true;
1566
1560
  }
1561
+ if (isTransparent)
1562
+ data.isTransparent = true;
1567
1563
  }
1568
1564
  }
1569
1565
 
@@ -1573,17 +1569,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1573
1569
  const realFrom$1 = {};
1574
1570
  const realTo$1 = {};
1575
1571
  function radialGradient(paint, box) {
1576
- let { from, to, type, opacity, blendMode, stretch } = paint;
1572
+ let { from, to, type, opacity, stretch } = paint;
1577
1573
  toPoint$1(from || 'center', box, realFrom$1);
1578
1574
  toPoint$1(to || 'bottom', box, realTo$1);
1579
1575
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1580
- applyStops(style, paint.stops, opacity);
1581
1576
  const data = { type, style };
1577
+ applyStops(data, style, paint.stops, opacity);
1582
1578
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1583
1579
  if (transform)
1584
1580
  data.transform = transform;
1585
- if (blendMode)
1586
- data.blendMode = blendMode;
1587
1581
  return data;
1588
1582
  }
1589
1583
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1609,17 +1603,15 @@ const { toPoint } = AroundHelper;
1609
1603
  const realFrom = {};
1610
1604
  const realTo = {};
1611
1605
  function conicGradient(paint, box) {
1612
- let { from, to, type, opacity, blendMode, stretch } = paint;
1606
+ let { from, to, type, opacity, stretch } = paint;
1613
1607
  toPoint(from || 'center', box, realFrom);
1614
1608
  toPoint(to || 'bottom', box, realTo);
1615
1609
  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));
1616
- applyStops(style, paint.stops, opacity);
1617
1610
  const data = { type, style };
1611
+ applyStops(data, style, paint.stops, opacity);
1618
1612
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1619
1613
  if (transform)
1620
1614
  data.transform = transform;
1621
- if (blendMode)
1622
- data.blendMode = blendMode;
1623
1615
  return data;
1624
1616
  }
1625
1617
 
@@ -1655,12 +1647,10 @@ function shadow(ui, current, shape) {
1655
1647
  }
1656
1648
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1657
1649
  }
1658
- if (ui.__worldFlipped) {
1650
+ if (ui.__worldFlipped)
1659
1651
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1660
- }
1661
- else {
1652
+ else
1662
1653
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1663
- }
1664
1654
  if (end && index < end)
1665
1655
  other.clearWorld(copyBounds, true);
1666
1656
  });
@@ -1719,12 +1709,10 @@ function innerShadow(ui, current, shape) {
1719
1709
  copyBounds = bounds;
1720
1710
  }
1721
1711
  other.fillWorld(copyBounds, ColorConvert.string(item.color), 'source-in');
1722
- if (ui.__worldFlipped) {
1712
+ if (ui.__worldFlipped)
1723
1713
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1724
- }
1725
- else {
1714
+ else
1726
1715
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1727
- }
1728
1716
  if (end && index < end)
1729
1717
  other.clearWorld(copyBounds, true);
1730
1718
  });
@@ -1952,6 +1940,8 @@ function createRows(drawData, content, style) {
1952
1940
  lastCharType = null;
1953
1941
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1954
1942
  word = { data: [] }, row = { words: [] };
1943
+ if (__letterSpacing)
1944
+ content = [...content];
1955
1945
  for (let i = 0, len = content.length; i < len; i++) {
1956
1946
  char = content[i];
1957
1947
  if (char === '\n') {
@@ -2401,10 +2391,9 @@ const ExportModule = {
2401
2391
  else {
2402
2392
  let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2403
2393
  const { worldTransform, isLeafer, leafer, isFrame } = leaf;
2404
- const { slice, clip, trim, padding, onCanvas } = options;
2394
+ const { slice, clip, trim, screenshot, padding, onCanvas } = options;
2405
2395
  const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth;
2406
2396
  const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined);
2407
- const screenshot = options.screenshot || leaf.isApp;
2408
2397
  const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2409
2398
  const needFill = FileHelper$1.isOpaqueImage(filename) || fill, matrix = new Matrix();
2410
2399
  if (screenshot) {
@@ -2440,11 +2429,6 @@ const ExportModule = {
2440
2429
  const scaleData = { scaleX: 1, scaleY: 1 };
2441
2430
  MathHelper$1.getScaleData(options.scale, options.size, renderBounds, scaleData);
2442
2431
  let pixelRatio = options.pixelRatio || 1;
2443
- if (leaf.isApp) {
2444
- scaleData.scaleX *= pixelRatio;
2445
- scaleData.scaleY *= pixelRatio;
2446
- pixelRatio = leaf.app.pixelRatio;
2447
- }
2448
2432
  let { x, y, width, height } = new Bounds$1(renderBounds).scale(scaleData.scaleX, scaleData.scaleY);
2449
2433
  if (clip)
2450
2434
  x += clip.x, y += clip.y, width = clip.width, height = clip.height;