@leafer-draw/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,8 +1,8 @@
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, 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, 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
- 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, UI } from '@leafer-ui/draw';
5
+ 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, UI } from '@leafer-ui/draw';
6
6
  export * from '@leafer-ui/draw';
7
7
 
8
8
  /******************************************************************************
@@ -174,17 +174,15 @@ class Watcher {
174
174
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
175
175
  this.__updatedList = new LeafList();
176
176
  this.totalTimes++;
177
- this.changed = false;
178
- this.hasVisible = false;
179
- this.hasRemove = false;
180
- this.hasAdd = false;
177
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
181
178
  }
182
179
  __listenEvents() {
183
- const { target } = this;
184
180
  this.__eventIds = [
185
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
186
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
187
- target.on_(WatchEvent.REQUEST, this.__onRquestData, this)
181
+ this.target.on_([
182
+ [PropertyEvent.CHANGE, this.__onAttrChange, this],
183
+ [[ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this],
184
+ [WatchEvent.REQUEST, this.__onRquestData, this]
185
+ ])
188
186
  ];
189
187
  }
190
188
  __removeListenEvents() {
@@ -194,8 +192,7 @@ class Watcher {
194
192
  if (this.target) {
195
193
  this.stop();
196
194
  this.__removeListenEvents();
197
- this.target = null;
198
- this.__updatedList = null;
195
+ this.target = this.__updatedList = null;
199
196
  }
200
197
  }
201
198
  }
@@ -300,7 +297,7 @@ class Layouter {
300
297
  this.disabled = true;
301
298
  }
302
299
  layout() {
303
- if (!this.running)
300
+ if (this.layouting || !this.running)
304
301
  return;
305
302
  const { target } = this;
306
303
  this.times = 0;
@@ -383,12 +380,10 @@ class Layouter {
383
380
  }
384
381
  static fullLayout(target) {
385
382
  updateAllMatrix(target, true);
386
- if (target.isBranch) {
383
+ if (target.isBranch)
387
384
  BranchHelper.updateBounds(target);
388
- }
389
- else {
385
+ else
390
386
  LeafHelper.updateBounds(target);
391
- }
392
387
  updateAllChange(target);
393
388
  }
394
389
  addExtra(leaf) {
@@ -411,11 +406,12 @@ class Layouter {
411
406
  this.__updatedList = event.data.updatedList;
412
407
  }
413
408
  __listenEvents() {
414
- const { target } = this;
415
409
  this.__eventIds = [
416
- target.on_(LayoutEvent.REQUEST, this.layout, this),
417
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
418
- target.on_(WatchEvent.DATA, this.__onReceiveWatchData, this)
410
+ this.target.on_([
411
+ [LayoutEvent.REQUEST, this.layout, this],
412
+ [LayoutEvent.AGAIN, this.layoutAgain, this],
413
+ [WatchEvent.DATA, this.__onReceiveWatchData, this]
414
+ ])
419
415
  ];
420
416
  }
421
417
  __removeListenEvents() {
@@ -646,12 +642,13 @@ class Renderer {
646
642
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
647
643
  }
648
644
  __listenEvents() {
649
- const { target } = this;
650
645
  this.__eventIds = [
651
- target.on_(RenderEvent.REQUEST, this.update, this),
652
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
653
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
654
- target.on_(ResizeEvent.RESIZE, this.__onResize, this)
646
+ this.target.on_([
647
+ [RenderEvent.REQUEST, this.update, this],
648
+ [LayoutEvent.END, this.__onLayoutEnd, this],
649
+ [RenderEvent.AGAIN, this.renderAgain, this],
650
+ [ResizeEvent.RESIZE, this.__onResize, this]
651
+ ])
655
652
  ];
656
653
  }
657
654
  __removeListenEvents() {
@@ -738,35 +735,38 @@ function fillPathOrText(ui, canvas) {
738
735
  }
739
736
 
740
737
  function strokeText(stroke, ui, canvas) {
741
- const { strokeAlign } = ui.__;
742
- const isStrokes = typeof stroke !== 'string';
743
- switch (strokeAlign) {
738
+ switch (ui.__.strokeAlign) {
744
739
  case 'center':
745
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
746
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
740
+ drawCenter$1(stroke, 1, ui, canvas);
747
741
  break;
748
742
  case 'inside':
749
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
743
+ drawAlign(stroke, 'inside', ui, canvas);
750
744
  break;
751
745
  case 'outside':
752
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
746
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
753
747
  break;
754
748
  }
755
749
  }
756
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
757
- const { __strokeWidth, __font } = ui.__;
750
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
751
+ const data = ui.__;
752
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
753
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
754
+ }
755
+ function drawAlign(stroke, align, ui, canvas) {
758
756
  const out = canvas.getSameCanvas(true, true);
759
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
760
- out.font = __font;
761
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
757
+ out.font = ui.__.__font;
758
+ drawCenter$1(stroke, 2, ui, out);
762
759
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
763
760
  fillText(ui, out);
764
761
  out.blendMode = 'normal';
765
- if (ui.__worldFlipped)
762
+ copyWorld(canvas, out, ui);
763
+ out.recycle(ui.__nowWorld);
764
+ }
765
+ function copyWorld(canvas, out, ui) {
766
+ if (ui.__worldFlipped || Platform.fullImageShadow)
766
767
  canvas.copyWorldByReset(out, ui.__nowWorld);
767
768
  else
768
769
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
769
- out.recycle(ui.__nowWorld);
770
770
  }
771
771
  function drawTextStroke(ui, canvas) {
772
772
  let row, data = ui.__.__textDrawData;
@@ -804,90 +804,56 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
804
804
  }
805
805
 
806
806
  function stroke(stroke, ui, canvas) {
807
- const options = ui.__;
808
- const { __strokeWidth, strokeAlign, __font } = options;
809
- if (!__strokeWidth)
807
+ const data = ui.__;
808
+ if (!data.__strokeWidth)
810
809
  return;
811
- if (__font) {
810
+ if (data.__font) {
812
811
  strokeText(stroke, ui, canvas);
813
812
  }
814
813
  else {
815
- switch (strokeAlign) {
814
+ switch (data.strokeAlign) {
816
815
  case 'center':
817
- canvas.setStroke(stroke, __strokeWidth, options);
818
- canvas.stroke();
819
- if (options.__useArrow)
820
- strokeArrow(ui, canvas);
816
+ drawCenter(stroke, 1, ui, canvas);
821
817
  break;
822
818
  case 'inside':
823
- canvas.save();
824
- canvas.setStroke(stroke, __strokeWidth * 2, options);
825
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
826
- canvas.stroke();
827
- canvas.restore();
819
+ drawInside(stroke, ui, canvas);
828
820
  break;
829
821
  case 'outside':
830
- const out = canvas.getSameCanvas(true, true);
831
- out.setStroke(stroke, __strokeWidth * 2, options);
832
- ui.__drawRenderPath(out);
833
- out.stroke();
834
- options.windingRule ? out.clip(options.windingRule) : out.clip();
835
- out.clearWorld(ui.__layout.renderBounds);
836
- if (ui.__worldFlipped)
837
- canvas.copyWorldByReset(out, ui.__nowWorld);
838
- else
839
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
840
- out.recycle(ui.__nowWorld);
822
+ drawOutside(stroke, ui, canvas);
841
823
  break;
842
824
  }
843
825
  }
844
826
  }
845
827
  function strokes(strokes, ui, canvas) {
846
- const options = ui.__;
847
- const { __strokeWidth, strokeAlign, __font } = options;
848
- if (!__strokeWidth)
849
- return;
850
- if (__font) {
851
- strokeText(strokes, ui, canvas);
828
+ stroke(strokes, ui, canvas);
829
+ }
830
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
831
+ const data = ui.__;
832
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
833
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
834
+ if (data.__useArrow)
835
+ Paint.strokeArrow(stroke, ui, canvas);
836
+ }
837
+ function drawInside(stroke, ui, canvas) {
838
+ canvas.save();
839
+ canvas.clipUI(ui);
840
+ drawCenter(stroke, 2, ui, canvas);
841
+ canvas.restore();
842
+ }
843
+ function drawOutside(stroke, ui, canvas) {
844
+ const data = ui.__;
845
+ if (data.__fillAfterStroke) {
846
+ drawCenter(stroke, 2, ui, canvas);
852
847
  }
853
848
  else {
854
- switch (strokeAlign) {
855
- case 'center':
856
- canvas.setStroke(undefined, __strokeWidth, options);
857
- drawStrokesStyle(strokes, false, ui, canvas);
858
- if (options.__useArrow)
859
- strokeArrow(ui, canvas);
860
- break;
861
- case 'inside':
862
- canvas.save();
863
- canvas.setStroke(undefined, __strokeWidth * 2, options);
864
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
865
- drawStrokesStyle(strokes, false, ui, canvas);
866
- canvas.restore();
867
- break;
868
- case 'outside':
869
- const { renderBounds } = ui.__layout;
870
- const out = canvas.getSameCanvas(true, true);
871
- ui.__drawRenderPath(out);
872
- out.setStroke(undefined, __strokeWidth * 2, options);
873
- drawStrokesStyle(strokes, false, ui, out);
874
- options.windingRule ? out.clip(options.windingRule) : out.clip();
875
- out.clearWorld(renderBounds);
876
- if (ui.__worldFlipped)
877
- canvas.copyWorldByReset(out, ui.__nowWorld);
878
- else
879
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
880
- out.recycle(ui.__nowWorld);
881
- break;
882
- }
883
- }
884
- }
885
- function strokeArrow(ui, canvas) {
886
- if (ui.__.dashPattern) {
887
- canvas.beginPath();
888
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
889
- canvas.dashPattern = null;
890
- canvas.stroke();
849
+ const { renderBounds } = ui.__layout;
850
+ const out = canvas.getSameCanvas(true, true);
851
+ ui.__drawRenderPath(out);
852
+ drawCenter(stroke, 2, ui, out);
853
+ out.clipUI(data);
854
+ out.clearWorld(renderBounds);
855
+ copyWorld(canvas, out, ui);
856
+ out.recycle(ui.__nowWorld);
891
857
  }
892
858
  }
893
859
 
@@ -934,41 +900,66 @@ function shape(ui, current, options) {
934
900
  }
935
901
 
936
902
  let recycleMap;
903
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
937
904
  function compute(attrName, ui) {
938
905
  const data = ui.__, leafPaints = [];
939
- let paints = data.__input[attrName], hasOpacityPixel;
906
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
940
907
  if (!(paints instanceof Array))
941
908
  paints = [paints];
942
909
  recycleMap = PaintImage.recycleImage(attrName, data);
943
910
  for (let i = 0, len = paints.length, item; i < len; i++) {
944
- item = getLeafPaint(attrName, paints[i], ui);
945
- if (item)
946
- leafPaints.push(item);
911
+ (item = getLeafPaint(attrName, paints[i], ui)) && leafPaints.push(item);
947
912
  }
948
913
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
949
- if (leafPaints.length && leafPaints[0].image)
950
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
951
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
914
+ if (leafPaints.length) {
915
+ if (leafPaints.every(item => item.isTransparent)) {
916
+ if (leafPaints.some(item => item.image))
917
+ isAlphaPixel = true;
918
+ isTransparent = true;
919
+ }
920
+ }
921
+ if (attrName === 'fill') {
922
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
923
+ stintSet(data, '__isTransparentFill', isTransparent);
924
+ }
925
+ else {
926
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
927
+ stintSet(data, '__isTransparentStroke', isTransparent);
928
+ }
952
929
  }
953
930
  function getLeafPaint(attrName, paint, ui) {
954
931
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
955
932
  return undefined;
933
+ let data;
956
934
  const { boxBounds } = ui.__layout;
957
935
  switch (paint.type) {
958
- case 'solid':
959
- let { type, blendMode, color, opacity } = paint;
960
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
961
936
  case 'image':
962
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
937
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
938
+ break;
963
939
  case 'linear':
964
- return PaintGradient.linearGradient(paint, boxBounds);
940
+ data = PaintGradient.linearGradient(paint, boxBounds);
941
+ break;
965
942
  case 'radial':
966
- return PaintGradient.radialGradient(paint, boxBounds);
943
+ data = PaintGradient.radialGradient(paint, boxBounds);
944
+ break;
967
945
  case 'angular':
968
- return PaintGradient.conicGradient(paint, boxBounds);
946
+ data = PaintGradient.conicGradient(paint, boxBounds);
947
+ break;
948
+ case 'solid':
949
+ const { type, color, opacity } = paint;
950
+ data = { type, style: ColorConvert.string(color, opacity) };
951
+ break;
969
952
  default:
970
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
953
+ if (paint.r !== undefined)
954
+ data = { type: 'solid', style: ColorConvert.string(paint) };
971
955
  }
956
+ if (data) {
957
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
958
+ data.isTransparent = true;
959
+ if (paint.blendMode)
960
+ data.blendMode = paint.blendMode;
961
+ }
962
+ return data;
972
963
  }
973
964
 
974
965
  const PaintModule = {
@@ -1034,12 +1025,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1034
1025
 
1035
1026
  const { get: get$2, translate } = MatrixHelper;
1036
1027
  const tempBox = new Bounds();
1037
- const tempPoint = {};
1038
1028
  const tempScaleData = {};
1029
+ const tempImage = {};
1039
1030
  function createData(leafPaint, image, paint, box) {
1040
- const { blendMode, changeful, sync } = paint;
1041
- if (blendMode)
1042
- leafPaint.blendMode = blendMode;
1031
+ const { changeful, sync } = paint;
1043
1032
  if (changeful)
1044
1033
  leafPaint.changeful = changeful;
1045
1034
  if (sync)
@@ -1047,38 +1036,38 @@ function createData(leafPaint, image, paint, box) {
1047
1036
  leafPaint.data = getPatternData(paint, box, image);
1048
1037
  }
1049
1038
  function getPatternData(paint, box, image) {
1050
- let { width, height } = image;
1051
1039
  if (paint.padding)
1052
1040
  box = tempBox.set(box).shrink(paint.padding);
1053
1041
  if (paint.mode === 'strench')
1054
1042
  paint.mode = 'stretch';
1043
+ let { width, height } = image;
1055
1044
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1056
1045
  const sameBox = box.width === width && box.height === height;
1057
1046
  const data = { mode };
1058
1047
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1059
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1060
- let x = 0, y = 0, scaleX, scaleY;
1048
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1049
+ let scaleX, scaleY;
1061
1050
  if (!mode || mode === 'cover' || mode === 'fit') {
1062
1051
  if (!sameBox || rotation) {
1063
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1064
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1065
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1052
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1053
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1054
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1066
1055
  }
1067
1056
  }
1068
- else if (scale || size) {
1069
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1070
- scaleX = tempScaleData.scaleX;
1071
- scaleY = tempScaleData.scaleY;
1072
- }
1073
- if (align) {
1074
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1075
- if (scaleX)
1076
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1077
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1078
- x += tempPoint.x, y += tempPoint.y;
1057
+ else {
1058
+ if (scale || size) {
1059
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1060
+ scaleX = tempScaleData.scaleX;
1061
+ scaleY = tempScaleData.scaleY;
1062
+ }
1063
+ if (align) {
1064
+ if (scaleX)
1065
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1066
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1067
+ }
1079
1068
  }
1080
1069
  if (offset)
1081
- x += offset.x, y += offset.y;
1070
+ PointHelper.move(tempImage, offset);
1082
1071
  switch (mode) {
1083
1072
  case 'stretch':
1084
1073
  if (!sameBox)
@@ -1086,12 +1075,12 @@ function getPatternData(paint, box, image) {
1086
1075
  break;
1087
1076
  case 'normal':
1088
1077
  case 'clip':
1089
- if (x || y || scaleX || rotation)
1090
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1078
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1079
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1091
1080
  break;
1092
1081
  case 'repeat':
1093
1082
  if (!sameBox || scaleX || rotation)
1094
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1083
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1095
1084
  if (!repeat)
1096
1085
  data.repeat = 'repeat';
1097
1086
  break;
@@ -1099,7 +1088,7 @@ function getPatternData(paint, box, image) {
1099
1088
  case 'cover':
1100
1089
  default:
1101
1090
  if (scaleX)
1102
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1091
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1103
1092
  }
1104
1093
  if (!data.transform) {
1105
1094
  if (box.x || box.y) {
@@ -1132,6 +1121,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1132
1121
  }
1133
1122
  else {
1134
1123
  leafPaint = { type: paint.type, image };
1124
+ if (image.hasAlphaPixel)
1125
+ leafPaint.isTransparent = true;
1135
1126
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1136
1127
  }
1137
1128
  if (firstUse || image.loading)
@@ -1156,7 +1147,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1156
1147
  ignoreRender(ui, false);
1157
1148
  if (!ui.destroyed) {
1158
1149
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1159
- if (image.hasOpacityPixel)
1150
+ if (image.hasAlphaPixel)
1160
1151
  ui.__layout.hitCanvasChanged = true;
1161
1152
  ui.forceUpdate('surface');
1162
1153
  }
@@ -1168,13 +1159,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1168
1159
  onLoadError(ui, event, error);
1169
1160
  leafPaint.loadId = null;
1170
1161
  });
1171
- if (ui.placeholderColor)
1172
- setTimeout(() => {
1173
- if (!(image.ready || image.isPlacehold)) {
1174
- image.isPlacehold = true;
1175
- ui.forceUpdate('surface');
1176
- }
1177
- }, 100);
1162
+ if (ui.placeholderColor) {
1163
+ if (!ui.placeholderDelay)
1164
+ image.isPlacehold = true;
1165
+ else
1166
+ setTimeout(() => {
1167
+ if (!image.ready) {
1168
+ image.isPlacehold = true;
1169
+ ui.forceUpdate('surface');
1170
+ }
1171
+ }, ui.placeholderDelay);
1172
+ }
1178
1173
  }
1179
1174
  return leafPaint;
1180
1175
  }
@@ -1329,7 +1324,7 @@ function checkImage(ui, canvas, paint, allowDraw) {
1329
1324
  }
1330
1325
  function drawImage(ui, canvas, paint, data) {
1331
1326
  canvas.save();
1332
- ui.windingRule ? canvas.clip(ui.windingRule) : canvas.clip();
1327
+ canvas.clipUI(ui);
1333
1328
  if (paint.blendMode)
1334
1329
  canvas.blendMode = paint.blendMode;
1335
1330
  if (data.opacity)
@@ -1380,32 +1375,33 @@ const PaintImageModule = {
1380
1375
  repeatMode
1381
1376
  };
1382
1377
 
1383
- const { toPoint: toPoint$2 } = AroundHelper;
1378
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1384
1379
  const realFrom$2 = {};
1385
1380
  const realTo$2 = {};
1386
1381
  function linearGradient(paint, box) {
1387
- let { from, to, type, blendMode, opacity } = paint;
1382
+ let { from, to, type, opacity } = paint;
1388
1383
  toPoint$2(from || 'top', box, realFrom$2);
1389
1384
  toPoint$2(to || 'bottom', box, realTo$2);
1390
1385
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1391
- applyStops(style, paint.stops, opacity);
1392
1386
  const data = { type, style };
1393
- if (blendMode)
1394
- data.blendMode = blendMode;
1387
+ applyStops(data, style, paint.stops, opacity);
1395
1388
  return data;
1396
1389
  }
1397
- function applyStops(gradient, stops, opacity) {
1390
+ function applyStops(data, gradient, stops, opacity) {
1398
1391
  if (stops) {
1399
- let stop;
1392
+ let stop, color, offset, isTransparent;
1400
1393
  for (let i = 0, len = stops.length; i < len; i++) {
1401
1394
  stop = stops[i];
1402
- if (typeof stop === 'string') {
1403
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1404
- }
1405
- else {
1406
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1407
- }
1395
+ if (typeof stop === 'string')
1396
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1397
+ else
1398
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1399
+ gradient.addColorStop(offset, color);
1400
+ if (!isTransparent && hasTransparent(color))
1401
+ isTransparent = true;
1408
1402
  }
1403
+ if (isTransparent)
1404
+ data.isTransparent = true;
1409
1405
  }
1410
1406
  }
1411
1407
 
@@ -1415,17 +1411,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1415
1411
  const realFrom$1 = {};
1416
1412
  const realTo$1 = {};
1417
1413
  function radialGradient(paint, box) {
1418
- let { from, to, type, opacity, blendMode, stretch } = paint;
1414
+ let { from, to, type, opacity, stretch } = paint;
1419
1415
  toPoint$1(from || 'center', box, realFrom$1);
1420
1416
  toPoint$1(to || 'bottom', box, realTo$1);
1421
1417
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1422
- applyStops(style, paint.stops, opacity);
1423
1418
  const data = { type, style };
1419
+ applyStops(data, style, paint.stops, opacity);
1424
1420
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1425
1421
  if (transform)
1426
1422
  data.transform = transform;
1427
- if (blendMode)
1428
- data.blendMode = blendMode;
1429
1423
  return data;
1430
1424
  }
1431
1425
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1451,17 +1445,15 @@ const { toPoint } = AroundHelper;
1451
1445
  const realFrom = {};
1452
1446
  const realTo = {};
1453
1447
  function conicGradient(paint, box) {
1454
- let { from, to, type, opacity, blendMode, stretch } = paint;
1448
+ let { from, to, type, opacity, stretch } = paint;
1455
1449
  toPoint(from || 'center', box, realFrom);
1456
1450
  toPoint(to || 'bottom', box, realTo);
1457
1451
  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));
1458
- applyStops(style, paint.stops, opacity);
1459
1452
  const data = { type, style };
1453
+ applyStops(data, style, paint.stops, opacity);
1460
1454
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1461
1455
  if (transform)
1462
1456
  data.transform = transform;
1463
- if (blendMode)
1464
- data.blendMode = blendMode;
1465
1457
  return data;
1466
1458
  }
1467
1459
 
@@ -1497,12 +1489,10 @@ function shadow(ui, current, shape) {
1497
1489
  }
1498
1490
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1499
1491
  }
1500
- if (ui.__worldFlipped) {
1492
+ if (ui.__worldFlipped)
1501
1493
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1502
- }
1503
- else {
1494
+ else
1504
1495
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1505
- }
1506
1496
  if (end && index < end)
1507
1497
  other.clearWorld(copyBounds, true);
1508
1498
  });
@@ -1561,12 +1551,10 @@ function innerShadow(ui, current, shape) {
1561
1551
  copyBounds = bounds;
1562
1552
  }
1563
1553
  other.fillWorld(copyBounds, ColorConvert.string(item.color), 'source-in');
1564
- if (ui.__worldFlipped) {
1554
+ if (ui.__worldFlipped)
1565
1555
  current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1566
- }
1567
- else {
1556
+ else
1568
1557
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1569
- }
1570
1558
  if (end && index < end)
1571
1559
  other.clearWorld(copyBounds, true);
1572
1560
  });
@@ -1794,6 +1782,8 @@ function createRows(drawData, content, style) {
1794
1782
  lastCharType = null;
1795
1783
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1796
1784
  word = { data: [] }, row = { words: [] };
1785
+ if (__letterSpacing)
1786
+ content = [...content];
1797
1787
  for (let i = 0, len = content.length; i < len; i++) {
1798
1788
  char = content[i];
1799
1789
  if (char === '\n') {
@@ -2243,10 +2233,9 @@ const ExportModule = {
2243
2233
  else {
2244
2234
  let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2245
2235
  const { worldTransform, isLeafer, leafer, isFrame } = leaf;
2246
- const { slice, clip, trim, padding, onCanvas } = options;
2236
+ const { slice, clip, trim, screenshot, padding, onCanvas } = options;
2247
2237
  const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth;
2248
2238
  const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined);
2249
- const screenshot = options.screenshot || leaf.isApp;
2250
2239
  const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2251
2240
  const needFill = FileHelper$1.isOpaqueImage(filename) || fill, matrix = new Matrix();
2252
2241
  if (screenshot) {
@@ -2282,11 +2271,6 @@ const ExportModule = {
2282
2271
  const scaleData = { scaleX: 1, scaleY: 1 };
2283
2272
  MathHelper$1.getScaleData(options.scale, options.size, renderBounds, scaleData);
2284
2273
  let pixelRatio = options.pixelRatio || 1;
2285
- if (leaf.isApp) {
2286
- scaleData.scaleX *= pixelRatio;
2287
- scaleData.scaleY *= pixelRatio;
2288
- pixelRatio = leaf.app.pixelRatio;
2289
- }
2290
2274
  let { x, y, width, height } = new Bounds$1(renderBounds).scale(scaleData.scaleX, scaleData.scaleY);
2291
2275
  if (clip)
2292
2276
  x += clip.x, y += clip.y, width = clip.width, height = clip.height;