@leafer-draw/node 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.esm.js CHANGED
@@ -1,9 +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, 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, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint as Paint$1, Effect, TwoPointBoundsHelper, Bounds as Bounds$1, FileHelper as FileHelper$1, Platform as Platform$2, 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
+ import { Platform as Platform$1 } from '@leafer-ui/core';
7
8
 
8
9
  /******************************************************************************
9
10
  Copyright (c) Microsoft Corporation.
@@ -174,17 +175,15 @@ class Watcher {
174
175
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
175
176
  this.__updatedList = new LeafList();
176
177
  this.totalTimes++;
177
- this.changed = false;
178
- this.hasVisible = false;
179
- this.hasRemove = false;
180
- this.hasAdd = false;
178
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
181
179
  }
182
180
  __listenEvents() {
183
- const { target } = this;
184
181
  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)
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
+ ])
188
187
  ];
189
188
  }
190
189
  __removeListenEvents() {
@@ -194,13 +193,12 @@ class Watcher {
194
193
  if (this.target) {
195
194
  this.stop();
196
195
  this.__removeListenEvents();
197
- this.target = null;
198
- this.__updatedList = null;
196
+ this.target = this.__updatedList = null;
199
197
  }
200
198
  }
201
199
  }
202
200
 
203
- const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateAllWorldOpacity } = LeafHelper;
201
+ const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateChange: updateOneChange } = LeafHelper;
204
202
  const { pushAllChildBranch, pushAllParent } = BranchHelper;
205
203
  function updateMatrix(updateList, levelList) {
206
204
  let layout;
@@ -243,15 +241,7 @@ function updateBounds(boundsList) {
243
241
  });
244
242
  }
245
243
  function updateChange(updateList) {
246
- let layout;
247
- updateList.list.forEach(leaf => {
248
- layout = leaf.__layout;
249
- if (layout.opacityChanged)
250
- updateAllWorldOpacity(leaf);
251
- if (layout.stateStyleChanged)
252
- setTimeout(() => layout.stateStyleChanged && leaf.updateState());
253
- leaf.__updateChange();
254
- });
244
+ updateList.list.forEach(updateOneChange);
255
245
  }
256
246
 
257
247
  const { worldBounds } = LeafBoundsHelper;
@@ -308,7 +298,7 @@ class Layouter {
308
298
  this.disabled = true;
309
299
  }
310
300
  layout() {
311
- if (!this.running)
301
+ if (this.layouting || !this.running)
312
302
  return;
313
303
  const { target } = this;
314
304
  this.times = 0;
@@ -391,12 +381,10 @@ class Layouter {
391
381
  }
392
382
  static fullLayout(target) {
393
383
  updateAllMatrix(target, true);
394
- if (target.isBranch) {
384
+ if (target.isBranch)
395
385
  BranchHelper.updateBounds(target);
396
- }
397
- else {
386
+ else
398
387
  LeafHelper.updateBounds(target);
399
- }
400
388
  updateAllChange(target);
401
389
  }
402
390
  addExtra(leaf) {
@@ -419,11 +407,12 @@ class Layouter {
419
407
  this.__updatedList = event.data.updatedList;
420
408
  }
421
409
  __listenEvents() {
422
- const { target } = this;
423
410
  this.__eventIds = [
424
- target.on_(LayoutEvent.REQUEST, this.layout, this),
425
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
426
- 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
+ ])
427
416
  ];
428
417
  }
429
418
  __removeListenEvents() {
@@ -654,12 +643,13 @@ class Renderer {
654
643
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
655
644
  }
656
645
  __listenEvents() {
657
- const { target } = this;
658
646
  this.__eventIds = [
659
- target.on_(RenderEvent.REQUEST, this.update, this),
660
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
661
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
662
- 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
+ ])
663
653
  ];
664
654
  }
665
655
  __removeListenEvents() {
@@ -685,8 +675,10 @@ Object.assign(Creator, {
685
675
  Platform.layout = Layouter.fullLayout;
686
676
 
687
677
  function fillText(ui, canvas) {
688
- let row, data = ui.__.__textDrawData;
689
- const { rows, decorationY } = data;
678
+ const data = ui.__, { rows, decorationY } = data.__textDrawData;
679
+ if (data.__isPlacehold && data.placeholderColor)
680
+ canvas.fillStyle = data.placeholderColor;
681
+ let row;
690
682
  for (let i = 0, len = rows.length; i < len; i++) {
691
683
  row = rows[i];
692
684
  if (row.text)
@@ -695,7 +687,7 @@ function fillText(ui, canvas) {
695
687
  row.data.forEach(charData => { canvas.fillText(charData.char, charData.x, row.y); });
696
688
  }
697
689
  if (decorationY) {
698
- const { decorationColor, decorationHeight } = data;
690
+ const { decorationColor, decorationHeight } = data.__textDrawData;
699
691
  if (decorationColor)
700
692
  canvas.fillStyle = decorationColor;
701
693
  rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
@@ -704,65 +696,73 @@ function fillText(ui, canvas) {
704
696
 
705
697
  function fill(fill, ui, canvas) {
706
698
  canvas.fillStyle = fill;
707
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
699
+ fillPathOrText(ui, canvas);
708
700
  }
709
701
  function fills(fills, ui, canvas) {
710
702
  let item;
711
- const { windingRule, __font } = ui.__;
712
703
  for (let i = 0, len = fills.length; i < len; i++) {
713
704
  item = fills[i];
714
- if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
715
- continue;
716
- if (item.style) {
717
- canvas.fillStyle = item.style;
718
- if (item.transform) {
719
- canvas.save();
720
- canvas.transform(item.transform);
721
- if (item.blendMode)
722
- canvas.blendMode = item.blendMode;
723
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
724
- canvas.restore();
705
+ if (item.image) {
706
+ if (PaintImage.checkImage(ui, canvas, item, !ui.__.__font))
707
+ continue;
708
+ if (!item.style) {
709
+ if (!i && item.image.isPlacehold)
710
+ ui.drawImagePlaceholder(canvas, item.image);
711
+ continue;
725
712
  }
726
- else {
727
- if (item.blendMode) {
728
- canvas.saveBlendMode(item.blendMode);
729
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
730
- canvas.restoreBlendMode();
731
- }
732
- else {
733
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
734
- }
713
+ }
714
+ canvas.fillStyle = item.style;
715
+ if (item.transform) {
716
+ canvas.save();
717
+ canvas.transform(item.transform);
718
+ if (item.blendMode)
719
+ canvas.blendMode = item.blendMode;
720
+ fillPathOrText(ui, canvas);
721
+ canvas.restore();
722
+ }
723
+ else {
724
+ if (item.blendMode) {
725
+ canvas.saveBlendMode(item.blendMode);
726
+ fillPathOrText(ui, canvas);
727
+ canvas.restoreBlendMode();
735
728
  }
729
+ else
730
+ fillPathOrText(ui, canvas);
736
731
  }
737
732
  }
738
733
  }
734
+ function fillPathOrText(ui, canvas) {
735
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
736
+ }
737
+
738
+ const Paint = {};
739
739
 
740
740
  function strokeText(stroke, ui, canvas) {
741
- const { strokeAlign } = ui.__;
742
- const isStrokes = typeof stroke !== 'string';
743
- switch (strokeAlign) {
741
+ switch (ui.__.strokeAlign) {
744
742
  case 'center':
745
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
746
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
743
+ drawCenter$1(stroke, 1, ui, canvas);
747
744
  break;
748
745
  case 'inside':
749
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
746
+ drawAlign(stroke, 'inside', ui, canvas);
750
747
  break;
751
748
  case 'outside':
752
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
749
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
753
750
  break;
754
751
  }
755
752
  }
756
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
757
- const { __strokeWidth, __font } = ui.__;
753
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
754
+ const data = ui.__;
755
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
756
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
757
+ }
758
+ function drawAlign(stroke, align, ui, canvas) {
758
759
  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);
760
+ out.font = ui.__.__font;
761
+ drawCenter$1(stroke, 2, ui, out);
762
762
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
763
763
  fillText(ui, out);
764
764
  out.blendMode = 'normal';
765
- if (ui.__worldFlipped)
765
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
766
766
  canvas.copyWorldByReset(out, ui.__nowWorld);
767
767
  else
768
768
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
@@ -804,90 +804,60 @@ 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
+ const data = ui.__;
839
+ canvas.save();
840
+ data.windingRule ? canvas.clip(data.windingRule) : canvas.clip();
841
+ drawCenter(stroke, 2, ui, canvas);
842
+ canvas.restore();
843
+ }
844
+ function drawOutside(stroke, ui, canvas) {
845
+ const data = ui.__;
846
+ if (data.__fillAfterStroke) {
847
+ drawCenter(stroke, 2, ui, canvas);
852
848
  }
853
849
  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();
850
+ const { renderBounds } = ui.__layout;
851
+ const out = canvas.getSameCanvas(true, true);
852
+ ui.__drawRenderPath(out);
853
+ drawCenter(stroke, 2, ui, out);
854
+ data.windingRule ? out.clip(data.windingRule) : out.clip();
855
+ out.clearWorld(renderBounds);
856
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
857
+ canvas.copyWorldByReset(out, ui.__nowWorld);
858
+ else
859
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
860
+ out.recycle(ui.__nowWorld);
891
861
  }
892
862
  }
893
863
 
@@ -934,9 +904,10 @@ function shape(ui, current, options) {
934
904
  }
935
905
 
936
906
  let recycleMap;
907
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
937
908
  function compute(attrName, ui) {
938
909
  const data = ui.__, leafPaints = [];
939
- let paints = data.__input[attrName], hasOpacityPixel;
910
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
940
911
  if (!(paints instanceof Array))
941
912
  paints = [paints];
942
913
  recycleMap = PaintImage.recycleImage(attrName, data);
@@ -946,35 +917,62 @@ function compute(attrName, ui) {
946
917
  leafPaints.push(item);
947
918
  }
948
919
  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;
920
+ if (leafPaints.length) {
921
+ if (leafPaints.every(item => item.isTransparent)) {
922
+ if (leafPaints.some(item => item.image))
923
+ isAlphaPixel = true;
924
+ isTransparent = true;
925
+ }
926
+ }
927
+ if (attrName === 'fill') {
928
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
929
+ stintSet(data, '__isTransparentFill', isTransparent);
930
+ }
931
+ else {
932
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
933
+ stintSet(data, '__isTransparentStroke', isTransparent);
934
+ }
952
935
  }
953
936
  function getLeafPaint(attrName, paint, ui) {
954
937
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
955
938
  return undefined;
939
+ let data;
956
940
  const { boxBounds } = ui.__layout;
957
941
  switch (paint.type) {
958
- case 'solid':
959
- let { type, blendMode, color, opacity } = paint;
960
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
961
942
  case 'image':
962
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
943
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
944
+ break;
963
945
  case 'linear':
964
- return PaintGradient.linearGradient(paint, boxBounds);
946
+ data = PaintGradient.linearGradient(paint, boxBounds);
947
+ break;
965
948
  case 'radial':
966
- return PaintGradient.radialGradient(paint, boxBounds);
949
+ data = PaintGradient.radialGradient(paint, boxBounds);
950
+ break;
967
951
  case 'angular':
968
- return PaintGradient.conicGradient(paint, boxBounds);
952
+ data = PaintGradient.conicGradient(paint, boxBounds);
953
+ break;
954
+ case 'solid':
955
+ const { type, blendMode, color, opacity } = paint;
956
+ data = { type, blendMode, style: ColorConvert.string(color, opacity) };
957
+ break;
969
958
  default:
970
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
959
+ if (paint.r !== undefined)
960
+ data = { type: 'solid', style: ColorConvert.string(paint) };
961
+ }
962
+ if (data) {
963
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
964
+ data.isTransparent = true;
965
+ if (paint.blendMode)
966
+ data.blendMode = paint.blendMode;
971
967
  }
968
+ return data;
972
969
  }
973
970
 
974
971
  const PaintModule = {
975
972
  compute,
976
973
  fill,
977
974
  fills,
975
+ fillPathOrText,
978
976
  fillText,
979
977
  stroke,
980
978
  strokes,
@@ -1033,12 +1031,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1033
1031
 
1034
1032
  const { get: get$2, translate } = MatrixHelper;
1035
1033
  const tempBox = new Bounds();
1036
- const tempPoint = {};
1037
1034
  const tempScaleData = {};
1035
+ const tempImage = {};
1038
1036
  function createData(leafPaint, image, paint, box) {
1039
- const { blendMode, changeful, sync } = paint;
1040
- if (blendMode)
1041
- leafPaint.blendMode = blendMode;
1037
+ const { changeful, sync } = paint;
1042
1038
  if (changeful)
1043
1039
  leafPaint.changeful = changeful;
1044
1040
  if (sync)
@@ -1046,38 +1042,38 @@ function createData(leafPaint, image, paint, box) {
1046
1042
  leafPaint.data = getPatternData(paint, box, image);
1047
1043
  }
1048
1044
  function getPatternData(paint, box, image) {
1049
- let { width, height } = image;
1050
1045
  if (paint.padding)
1051
1046
  box = tempBox.set(box).shrink(paint.padding);
1052
1047
  if (paint.mode === 'strench')
1053
1048
  paint.mode = 'stretch';
1049
+ let { width, height } = image;
1054
1050
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1055
1051
  const sameBox = box.width === width && box.height === height;
1056
1052
  const data = { mode };
1057
1053
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1058
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1059
- let x = 0, y = 0, scaleX, scaleY;
1054
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1055
+ let scaleX, scaleY;
1060
1056
  if (!mode || mode === 'cover' || mode === 'fit') {
1061
1057
  if (!sameBox || rotation) {
1062
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1063
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1064
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1058
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1059
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1060
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1065
1061
  }
1066
1062
  }
1067
- else if (scale || size) {
1068
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1069
- scaleX = tempScaleData.scaleX;
1070
- scaleY = tempScaleData.scaleY;
1071
- }
1072
- if (align) {
1073
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1074
- if (scaleX)
1075
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1076
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1077
- x += tempPoint.x, y += tempPoint.y;
1063
+ else {
1064
+ if (scale || size) {
1065
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1066
+ scaleX = tempScaleData.scaleX;
1067
+ scaleY = tempScaleData.scaleY;
1068
+ }
1069
+ if (align) {
1070
+ if (scaleX)
1071
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1072
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1073
+ }
1078
1074
  }
1079
1075
  if (offset)
1080
- x += offset.x, y += offset.y;
1076
+ PointHelper.move(tempImage, offset);
1081
1077
  switch (mode) {
1082
1078
  case 'stretch':
1083
1079
  if (!sameBox)
@@ -1085,12 +1081,12 @@ function getPatternData(paint, box, image) {
1085
1081
  break;
1086
1082
  case 'normal':
1087
1083
  case 'clip':
1088
- if (x || y || scaleX || rotation)
1089
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1084
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1085
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1090
1086
  break;
1091
1087
  case 'repeat':
1092
1088
  if (!sameBox || scaleX || rotation)
1093
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1089
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1094
1090
  if (!repeat)
1095
1091
  data.repeat = 'repeat';
1096
1092
  break;
@@ -1098,7 +1094,7 @@ function getPatternData(paint, box, image) {
1098
1094
  case 'cover':
1099
1095
  default:
1100
1096
  if (scaleX)
1101
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1097
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1102
1098
  }
1103
1099
  if (!data.transform) {
1104
1100
  if (box.x || box.y) {
@@ -1131,6 +1127,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1131
1127
  }
1132
1128
  else {
1133
1129
  leafPaint = { type: paint.type, image };
1130
+ if (image.hasAlphaPixel)
1131
+ leafPaint.isTransparent = true;
1134
1132
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1135
1133
  }
1136
1134
  if (firstUse || image.loading)
@@ -1155,7 +1153,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1155
1153
  ignoreRender(ui, false);
1156
1154
  if (!ui.destroyed) {
1157
1155
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1158
- if (image.hasOpacityPixel)
1156
+ if (image.hasAlphaPixel)
1159
1157
  ui.__layout.hitCanvasChanged = true;
1160
1158
  ui.forceUpdate('surface');
1161
1159
  }
@@ -1167,6 +1165,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1167
1165
  onLoadError(ui, event, error);
1168
1166
  leafPaint.loadId = null;
1169
1167
  });
1168
+ if (ui.placeholderColor) {
1169
+ if (!ui.placeholderDelay)
1170
+ image.isPlacehold = true;
1171
+ else
1172
+ setTimeout(() => {
1173
+ if (!image.ready) {
1174
+ image.isPlacehold = true;
1175
+ ui.forceUpdate('surface');
1176
+ }
1177
+ }, ui.placeholderDelay);
1178
+ }
1170
1179
  }
1171
1180
  return leafPaint;
1172
1181
  }
@@ -1372,32 +1381,33 @@ const PaintImageModule = {
1372
1381
  repeatMode
1373
1382
  };
1374
1383
 
1375
- const { toPoint: toPoint$2 } = AroundHelper;
1384
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1376
1385
  const realFrom$2 = {};
1377
1386
  const realTo$2 = {};
1378
1387
  function linearGradient(paint, box) {
1379
- let { from, to, type, blendMode, opacity } = paint;
1388
+ let { from, to, type, opacity } = paint;
1380
1389
  toPoint$2(from || 'top', box, realFrom$2);
1381
1390
  toPoint$2(to || 'bottom', box, realTo$2);
1382
1391
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1383
- applyStops(style, paint.stops, opacity);
1384
1392
  const data = { type, style };
1385
- if (blendMode)
1386
- data.blendMode = blendMode;
1393
+ applyStops(data, style, paint.stops, opacity);
1387
1394
  return data;
1388
1395
  }
1389
- function applyStops(gradient, stops, opacity) {
1396
+ function applyStops(data, gradient, stops, opacity) {
1390
1397
  if (stops) {
1391
- let stop;
1398
+ let stop, color, offset, isTransparent;
1392
1399
  for (let i = 0, len = stops.length; i < len; i++) {
1393
1400
  stop = stops[i];
1394
- if (typeof stop === 'string') {
1395
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1396
- }
1397
- else {
1398
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1399
- }
1401
+ if (typeof stop === 'string')
1402
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1403
+ else
1404
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1405
+ gradient.addColorStop(offset, color);
1406
+ if (!isTransparent && hasTransparent(color))
1407
+ isTransparent = true;
1400
1408
  }
1409
+ if (isTransparent)
1410
+ data.isTransparent = true;
1401
1411
  }
1402
1412
  }
1403
1413
 
@@ -1407,17 +1417,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1407
1417
  const realFrom$1 = {};
1408
1418
  const realTo$1 = {};
1409
1419
  function radialGradient(paint, box) {
1410
- let { from, to, type, opacity, blendMode, stretch } = paint;
1420
+ let { from, to, type, opacity, stretch } = paint;
1411
1421
  toPoint$1(from || 'center', box, realFrom$1);
1412
1422
  toPoint$1(to || 'bottom', box, realTo$1);
1413
1423
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1414
- applyStops(style, paint.stops, opacity);
1415
1424
  const data = { type, style };
1425
+ applyStops(data, style, paint.stops, opacity);
1416
1426
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1417
1427
  if (transform)
1418
1428
  data.transform = transform;
1419
- if (blendMode)
1420
- data.blendMode = blendMode;
1421
1429
  return data;
1422
1430
  }
1423
1431
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1443,17 +1451,15 @@ const { toPoint } = AroundHelper;
1443
1451
  const realFrom = {};
1444
1452
  const realTo = {};
1445
1453
  function conicGradient(paint, box) {
1446
- let { from, to, type, opacity, blendMode, stretch } = paint;
1454
+ let { from, to, type, opacity, stretch } = paint;
1447
1455
  toPoint(from || 'center', box, realFrom);
1448
1456
  toPoint(to || 'bottom', box, realTo);
1449
1457
  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));
1450
- applyStops(style, paint.stops, opacity);
1451
1458
  const data = { type, style };
1459
+ applyStops(data, style, paint.stops, opacity);
1452
1460
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1453
1461
  if (transform)
1454
1462
  data.transform = transform;
1455
- if (blendMode)
1456
- data.blendMode = blendMode;
1457
1463
  return data;
1458
1464
  }
1459
1465
 
@@ -1786,6 +1792,8 @@ function createRows(drawData, content, style) {
1786
1792
  lastCharType = null;
1787
1793
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1788
1794
  word = { data: [] }, row = { words: [] };
1795
+ if (__letterSpacing)
1796
+ content = [...content];
1789
1797
  for (let i = 0, len = content.length; i < len; i++) {
1790
1798
  char = content[i];
1791
1799
  if (char === '\n') {
@@ -2192,7 +2200,7 @@ const ColorConvertModule = {
2192
2200
 
2193
2201
  Object.assign(TextConvert, TextConvertModule);
2194
2202
  Object.assign(ColorConvert, ColorConvertModule);
2195
- Object.assign(Paint, PaintModule);
2203
+ Object.assign(Paint$1, PaintModule);
2196
2204
  Object.assign(PaintImage, PaintImageModule);
2197
2205
  Object.assign(PaintGradient, PaintGradientModule);
2198
2206
  Object.assign(Effect, EffectModule);
@@ -2222,8 +2230,8 @@ const ExportModule = {
2222
2230
  const fileType = FileHelper$1.fileType(filename);
2223
2231
  const isDownload = filename.includes('.');
2224
2232
  options = FileHelper$1.getExportOptions(options);
2225
- const { toURL } = Platform$1;
2226
- const { download } = Platform$1.origin;
2233
+ const { toURL } = Platform$2;
2234
+ const { download } = Platform$2.origin;
2227
2235
  if (fileType === 'json') {
2228
2236
  isDownload && download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename);
2229
2237
  result = { data: isDownload ? true : leaf.toJSON(options.json) };
@@ -2235,10 +2243,9 @@ const ExportModule = {
2235
2243
  else {
2236
2244
  let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2237
2245
  const { worldTransform, isLeafer, leafer, isFrame } = leaf;
2238
- const { slice, trim, padding, onCanvas } = options;
2246
+ const { slice, clip, trim, screenshot, padding, onCanvas } = options;
2239
2247
  const smooth = options.smooth === undefined ? (leafer ? leafer.config.smooth : true) : options.smooth;
2240
2248
  const contextSettings = options.contextSettings || (leafer ? leafer.config.contextSettings : undefined);
2241
- const screenshot = options.screenshot || leaf.isApp;
2242
2249
  const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2243
2250
  const needFill = FileHelper$1.isOpaqueImage(filename) || fill, matrix = new Matrix();
2244
2251
  if (screenshot) {
@@ -2274,12 +2281,9 @@ const ExportModule = {
2274
2281
  const scaleData = { scaleX: 1, scaleY: 1 };
2275
2282
  MathHelper$1.getScaleData(options.scale, options.size, renderBounds, scaleData);
2276
2283
  let pixelRatio = options.pixelRatio || 1;
2277
- if (leaf.isApp) {
2278
- scaleData.scaleX *= pixelRatio;
2279
- scaleData.scaleY *= pixelRatio;
2280
- pixelRatio = leaf.app.pixelRatio;
2281
- }
2282
- const { x, y, width, height } = new Bounds$1(renderBounds).scale(scaleData.scaleX, scaleData.scaleY);
2284
+ let { x, y, width, height } = new Bounds$1(renderBounds).scale(scaleData.scaleX, scaleData.scaleY);
2285
+ if (clip)
2286
+ x += clip.x, y += clip.y, width = clip.width, height = clip.height;
2283
2287
  const renderOptions = { matrix: matrix.scale(1 / scaleData.scaleX, 1 / scaleData.scaleY).invert().translate(-x, -y).withScale(1 / scaleX * scaleData.scaleX, 1 / scaleY * scaleData.scaleY) };
2284
2288
  let canvas = Creator$1.canvas({ width: Math.floor(width), height: Math.floor(height), pixelRatio, smooth, contextSettings });
2285
2289
  let sliceLeaf;
@@ -2330,7 +2334,7 @@ const ExportModule = {
2330
2334
  return addTask((success) => new Promise((resolve) => {
2331
2335
  const getResult = () => __awaiter(this, void 0, void 0, function* () {
2332
2336
  if (!Resource.isComplete)
2333
- return Platform$1.requestRender(getResult);
2337
+ return Platform$2.requestRender(getResult);
2334
2338
  const result = ExportModule.syncExport(leaf, filename, options);
2335
2339
  if (result.data instanceof Promise)
2336
2340
  result.data = yield result.data;
@@ -2375,7 +2379,7 @@ canvas.export = function (filename, options) {
2375
2379
  };
2376
2380
  canvas.toBlob = function (type, quality) {
2377
2381
  return new Promise((resolve) => {
2378
- Platform$1.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2382
+ Platform$2.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2379
2383
  resolve(blob);
2380
2384
  }).catch((e) => {
2381
2385
  debug.error(e);
@@ -2384,11 +2388,11 @@ canvas.toBlob = function (type, quality) {
2384
2388
  });
2385
2389
  };
2386
2390
  canvas.toDataURL = function (type, quality) {
2387
- return Platform$1.origin.canvasToDataURL(this.view, type, quality);
2391
+ return Platform$2.origin.canvasToDataURL(this.view, type, quality);
2388
2392
  };
2389
2393
  canvas.saveAs = function (filename, quality) {
2390
2394
  return new Promise((resolve) => {
2391
- Platform$1.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2395
+ Platform$2.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2392
2396
  resolve(true);
2393
2397
  }).catch((e) => {
2394
2398
  debug.error(e);
@@ -2407,4 +2411,3 @@ UI.prototype.syncExport = function (filename, options) {
2407
2411
  };
2408
2412
 
2409
2413
  export { Layouter, LeaferCanvas, Renderer, Watcher, useCanvas };
2410
- //# sourceMappingURL=node.esm.js.map