@leafer-draw/worker 1.6.2 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,9 @@
1
- import { LeaferCanvasBase, Platform, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, ResizeEvent, BoundsHelper, 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
- import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
4
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint as Paint$1, Effect } from '@leafer-ui/draw';
5
5
  export * from '@leafer-ui/draw';
6
+ import { Platform as Platform$1 } from '@leafer-ui/core';
6
7
 
7
8
  class LeaferCanvas extends LeaferCanvasBase {
8
9
  get allowBackgroundColor() { return true; }
@@ -161,17 +162,15 @@ class Watcher {
161
162
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
162
163
  this.__updatedList = new LeafList();
163
164
  this.totalTimes++;
164
- this.changed = false;
165
- this.hasVisible = false;
166
- this.hasRemove = false;
167
- this.hasAdd = false;
165
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
168
166
  }
169
167
  __listenEvents() {
170
- const { target } = this;
171
168
  this.__eventIds = [
172
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
173
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
174
- target.on_(WatchEvent.REQUEST, this.__onRquestData, this)
169
+ this.target.on_([
170
+ [PropertyEvent.CHANGE, this.__onAttrChange, this],
171
+ [[ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this],
172
+ [WatchEvent.REQUEST, this.__onRquestData, this]
173
+ ])
175
174
  ];
176
175
  }
177
176
  __removeListenEvents() {
@@ -181,8 +180,7 @@ class Watcher {
181
180
  if (this.target) {
182
181
  this.stop();
183
182
  this.__removeListenEvents();
184
- this.target = null;
185
- this.__updatedList = null;
183
+ this.target = this.__updatedList = null;
186
184
  }
187
185
  }
188
186
  }
@@ -287,7 +285,7 @@ class Layouter {
287
285
  this.disabled = true;
288
286
  }
289
287
  layout() {
290
- if (!this.running)
288
+ if (this.layouting || !this.running)
291
289
  return;
292
290
  const { target } = this;
293
291
  this.times = 0;
@@ -370,12 +368,10 @@ class Layouter {
370
368
  }
371
369
  static fullLayout(target) {
372
370
  updateAllMatrix(target, true);
373
- if (target.isBranch) {
371
+ if (target.isBranch)
374
372
  BranchHelper.updateBounds(target);
375
- }
376
- else {
373
+ else
377
374
  LeafHelper.updateBounds(target);
378
- }
379
375
  updateAllChange(target);
380
376
  }
381
377
  addExtra(leaf) {
@@ -398,11 +394,12 @@ class Layouter {
398
394
  this.__updatedList = event.data.updatedList;
399
395
  }
400
396
  __listenEvents() {
401
- const { target } = this;
402
397
  this.__eventIds = [
403
- target.on_(LayoutEvent.REQUEST, this.layout, this),
404
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
405
- target.on_(WatchEvent.DATA, this.__onReceiveWatchData, this)
398
+ this.target.on_([
399
+ [LayoutEvent.REQUEST, this.layout, this],
400
+ [LayoutEvent.AGAIN, this.layoutAgain, this],
401
+ [WatchEvent.DATA, this.__onReceiveWatchData, this]
402
+ ])
406
403
  ];
407
404
  }
408
405
  __removeListenEvents() {
@@ -633,12 +630,13 @@ class Renderer {
633
630
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
634
631
  }
635
632
  __listenEvents() {
636
- const { target } = this;
637
633
  this.__eventIds = [
638
- target.on_(RenderEvent.REQUEST, this.update, this),
639
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
640
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
641
- target.on_(ResizeEvent.RESIZE, this.__onResize, this)
634
+ this.target.on_([
635
+ [RenderEvent.REQUEST, this.update, this],
636
+ [LayoutEvent.END, this.__onLayoutEnd, this],
637
+ [RenderEvent.AGAIN, this.renderAgain, this],
638
+ [ResizeEvent.RESIZE, this.__onResize, this]
639
+ ])
642
640
  ];
643
641
  }
644
642
  __removeListenEvents() {
@@ -724,32 +722,34 @@ function fillPathOrText(ui, canvas) {
724
722
  ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
725
723
  }
726
724
 
725
+ const Paint = {};
726
+
727
727
  function strokeText(stroke, ui, canvas) {
728
- const { strokeAlign } = ui.__;
729
- const isStrokes = typeof stroke !== 'string';
730
- switch (strokeAlign) {
728
+ switch (ui.__.strokeAlign) {
731
729
  case 'center':
732
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
733
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
730
+ drawCenter$1(stroke, 1, ui, canvas);
734
731
  break;
735
732
  case 'inside':
736
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
733
+ drawAlign(stroke, 'inside', ui, canvas);
737
734
  break;
738
735
  case 'outside':
739
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
736
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
740
737
  break;
741
738
  }
742
739
  }
743
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
744
- const { __strokeWidth, __font } = ui.__;
740
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
741
+ const data = ui.__;
742
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
743
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
744
+ }
745
+ function drawAlign(stroke, align, ui, canvas) {
745
746
  const out = canvas.getSameCanvas(true, true);
746
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
747
- out.font = __font;
748
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
747
+ out.font = ui.__.__font;
748
+ drawCenter$1(stroke, 2, ui, out);
749
749
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
750
750
  fillText(ui, out);
751
751
  out.blendMode = 'normal';
752
- if (ui.__worldFlipped)
752
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
753
753
  canvas.copyWorldByReset(out, ui.__nowWorld);
754
754
  else
755
755
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
@@ -791,90 +791,60 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
791
791
  }
792
792
 
793
793
  function stroke(stroke, ui, canvas) {
794
- const options = ui.__;
795
- const { __strokeWidth, strokeAlign, __font } = options;
796
- if (!__strokeWidth)
794
+ const data = ui.__;
795
+ if (!data.__strokeWidth)
797
796
  return;
798
- if (__font) {
797
+ if (data.__font) {
799
798
  strokeText(stroke, ui, canvas);
800
799
  }
801
800
  else {
802
- switch (strokeAlign) {
801
+ switch (data.strokeAlign) {
803
802
  case 'center':
804
- canvas.setStroke(stroke, __strokeWidth, options);
805
- canvas.stroke();
806
- if (options.__useArrow)
807
- strokeArrow(ui, canvas);
803
+ drawCenter(stroke, 1, ui, canvas);
808
804
  break;
809
805
  case 'inside':
810
- canvas.save();
811
- canvas.setStroke(stroke, __strokeWidth * 2, options);
812
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
813
- canvas.stroke();
814
- canvas.restore();
806
+ drawInside(stroke, ui, canvas);
815
807
  break;
816
808
  case 'outside':
817
- const out = canvas.getSameCanvas(true, true);
818
- out.setStroke(stroke, __strokeWidth * 2, options);
819
- ui.__drawRenderPath(out);
820
- out.stroke();
821
- options.windingRule ? out.clip(options.windingRule) : out.clip();
822
- out.clearWorld(ui.__layout.renderBounds);
823
- if (ui.__worldFlipped)
824
- canvas.copyWorldByReset(out, ui.__nowWorld);
825
- else
826
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
827
- out.recycle(ui.__nowWorld);
809
+ drawOutside(stroke, ui, canvas);
828
810
  break;
829
811
  }
830
812
  }
831
813
  }
832
814
  function strokes(strokes, ui, canvas) {
833
- const options = ui.__;
834
- const { __strokeWidth, strokeAlign, __font } = options;
835
- if (!__strokeWidth)
836
- return;
837
- if (__font) {
838
- strokeText(strokes, ui, canvas);
815
+ stroke(strokes, ui, canvas);
816
+ }
817
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
818
+ const data = ui.__;
819
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
820
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
821
+ if (data.__useArrow)
822
+ Paint.strokeArrow(stroke, ui, canvas);
823
+ }
824
+ function drawInside(stroke, ui, canvas) {
825
+ const data = ui.__;
826
+ canvas.save();
827
+ data.windingRule ? canvas.clip(data.windingRule) : canvas.clip();
828
+ drawCenter(stroke, 2, ui, canvas);
829
+ canvas.restore();
830
+ }
831
+ function drawOutside(stroke, ui, canvas) {
832
+ const data = ui.__;
833
+ if (data.__fillAfterStroke) {
834
+ drawCenter(stroke, 2, ui, canvas);
839
835
  }
840
836
  else {
841
- switch (strokeAlign) {
842
- case 'center':
843
- canvas.setStroke(undefined, __strokeWidth, options);
844
- drawStrokesStyle(strokes, false, ui, canvas);
845
- if (options.__useArrow)
846
- strokeArrow(ui, canvas);
847
- break;
848
- case 'inside':
849
- canvas.save();
850
- canvas.setStroke(undefined, __strokeWidth * 2, options);
851
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
852
- drawStrokesStyle(strokes, false, ui, canvas);
853
- canvas.restore();
854
- break;
855
- case 'outside':
856
- const { renderBounds } = ui.__layout;
857
- const out = canvas.getSameCanvas(true, true);
858
- ui.__drawRenderPath(out);
859
- out.setStroke(undefined, __strokeWidth * 2, options);
860
- drawStrokesStyle(strokes, false, ui, out);
861
- options.windingRule ? out.clip(options.windingRule) : out.clip();
862
- out.clearWorld(renderBounds);
863
- if (ui.__worldFlipped)
864
- canvas.copyWorldByReset(out, ui.__nowWorld);
865
- else
866
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
867
- out.recycle(ui.__nowWorld);
868
- break;
869
- }
870
- }
871
- }
872
- function strokeArrow(ui, canvas) {
873
- if (ui.__.dashPattern) {
874
- canvas.beginPath();
875
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
876
- canvas.dashPattern = null;
877
- canvas.stroke();
837
+ const { renderBounds } = ui.__layout;
838
+ const out = canvas.getSameCanvas(true, true);
839
+ ui.__drawRenderPath(out);
840
+ drawCenter(stroke, 2, ui, out);
841
+ data.windingRule ? out.clip(data.windingRule) : out.clip();
842
+ out.clearWorld(renderBounds);
843
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
844
+ canvas.copyWorldByReset(out, ui.__nowWorld);
845
+ else
846
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
847
+ out.recycle(ui.__nowWorld);
878
848
  }
879
849
  }
880
850
 
@@ -921,9 +891,10 @@ function shape(ui, current, options) {
921
891
  }
922
892
 
923
893
  let recycleMap;
894
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
924
895
  function compute(attrName, ui) {
925
896
  const data = ui.__, leafPaints = [];
926
- let paints = data.__input[attrName], hasOpacityPixel;
897
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
927
898
  if (!(paints instanceof Array))
928
899
  paints = [paints];
929
900
  recycleMap = PaintImage.recycleImage(attrName, data);
@@ -933,29 +904,55 @@ function compute(attrName, ui) {
933
904
  leafPaints.push(item);
934
905
  }
935
906
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
936
- if (leafPaints.length && leafPaints[0].image)
937
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
938
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
907
+ if (leafPaints.length) {
908
+ if (leafPaints.every(item => item.isTransparent)) {
909
+ if (leafPaints.some(item => item.image))
910
+ isAlphaPixel = true;
911
+ isTransparent = true;
912
+ }
913
+ }
914
+ if (attrName === 'fill') {
915
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
916
+ stintSet(data, '__isTransparentFill', isTransparent);
917
+ }
918
+ else {
919
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
920
+ stintSet(data, '__isTransparentStroke', isTransparent);
921
+ }
939
922
  }
940
923
  function getLeafPaint(attrName, paint, ui) {
941
924
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
942
925
  return undefined;
926
+ let data;
943
927
  const { boxBounds } = ui.__layout;
944
928
  switch (paint.type) {
945
- case 'solid':
946
- let { type, blendMode, color, opacity } = paint;
947
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
948
929
  case 'image':
949
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
930
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
931
+ break;
950
932
  case 'linear':
951
- return PaintGradient.linearGradient(paint, boxBounds);
933
+ data = PaintGradient.linearGradient(paint, boxBounds);
934
+ break;
952
935
  case 'radial':
953
- return PaintGradient.radialGradient(paint, boxBounds);
936
+ data = PaintGradient.radialGradient(paint, boxBounds);
937
+ break;
954
938
  case 'angular':
955
- return PaintGradient.conicGradient(paint, boxBounds);
939
+ data = PaintGradient.conicGradient(paint, boxBounds);
940
+ break;
941
+ case 'solid':
942
+ const { type, blendMode, color, opacity } = paint;
943
+ data = { type, blendMode, style: ColorConvert.string(color, opacity) };
944
+ break;
956
945
  default:
957
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
946
+ if (paint.r !== undefined)
947
+ data = { type: 'solid', style: ColorConvert.string(paint) };
958
948
  }
949
+ if (data) {
950
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
951
+ data.isTransparent = true;
952
+ if (paint.blendMode)
953
+ data.blendMode = paint.blendMode;
954
+ }
955
+ return data;
959
956
  }
960
957
 
961
958
  const PaintModule = {
@@ -1021,12 +1018,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1021
1018
 
1022
1019
  const { get: get$2, translate } = MatrixHelper;
1023
1020
  const tempBox = new Bounds();
1024
- const tempPoint = {};
1025
1021
  const tempScaleData = {};
1022
+ const tempImage = {};
1026
1023
  function createData(leafPaint, image, paint, box) {
1027
- const { blendMode, changeful, sync } = paint;
1028
- if (blendMode)
1029
- leafPaint.blendMode = blendMode;
1024
+ const { changeful, sync } = paint;
1030
1025
  if (changeful)
1031
1026
  leafPaint.changeful = changeful;
1032
1027
  if (sync)
@@ -1034,38 +1029,38 @@ function createData(leafPaint, image, paint, box) {
1034
1029
  leafPaint.data = getPatternData(paint, box, image);
1035
1030
  }
1036
1031
  function getPatternData(paint, box, image) {
1037
- let { width, height } = image;
1038
1032
  if (paint.padding)
1039
1033
  box = tempBox.set(box).shrink(paint.padding);
1040
1034
  if (paint.mode === 'strench')
1041
1035
  paint.mode = 'stretch';
1036
+ let { width, height } = image;
1042
1037
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1043
1038
  const sameBox = box.width === width && box.height === height;
1044
1039
  const data = { mode };
1045
1040
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1046
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1047
- let x = 0, y = 0, scaleX, scaleY;
1041
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1042
+ let scaleX, scaleY;
1048
1043
  if (!mode || mode === 'cover' || mode === 'fit') {
1049
1044
  if (!sameBox || rotation) {
1050
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1051
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1052
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1045
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1046
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1047
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1053
1048
  }
1054
1049
  }
1055
- else if (scale || size) {
1056
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1057
- scaleX = tempScaleData.scaleX;
1058
- scaleY = tempScaleData.scaleY;
1059
- }
1060
- if (align) {
1061
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1062
- if (scaleX)
1063
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1064
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1065
- x += tempPoint.x, y += tempPoint.y;
1050
+ else {
1051
+ if (scale || size) {
1052
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1053
+ scaleX = tempScaleData.scaleX;
1054
+ scaleY = tempScaleData.scaleY;
1055
+ }
1056
+ if (align) {
1057
+ if (scaleX)
1058
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1059
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1060
+ }
1066
1061
  }
1067
1062
  if (offset)
1068
- x += offset.x, y += offset.y;
1063
+ PointHelper.move(tempImage, offset);
1069
1064
  switch (mode) {
1070
1065
  case 'stretch':
1071
1066
  if (!sameBox)
@@ -1073,12 +1068,12 @@ function getPatternData(paint, box, image) {
1073
1068
  break;
1074
1069
  case 'normal':
1075
1070
  case 'clip':
1076
- if (x || y || scaleX || rotation)
1077
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1071
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1072
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1078
1073
  break;
1079
1074
  case 'repeat':
1080
1075
  if (!sameBox || scaleX || rotation)
1081
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1076
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1082
1077
  if (!repeat)
1083
1078
  data.repeat = 'repeat';
1084
1079
  break;
@@ -1086,7 +1081,7 @@ function getPatternData(paint, box, image) {
1086
1081
  case 'cover':
1087
1082
  default:
1088
1083
  if (scaleX)
1089
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1084
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1090
1085
  }
1091
1086
  if (!data.transform) {
1092
1087
  if (box.x || box.y) {
@@ -1119,6 +1114,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1119
1114
  }
1120
1115
  else {
1121
1116
  leafPaint = { type: paint.type, image };
1117
+ if (image.hasAlphaPixel)
1118
+ leafPaint.isTransparent = true;
1122
1119
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1123
1120
  }
1124
1121
  if (firstUse || image.loading)
@@ -1143,7 +1140,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1143
1140
  ignoreRender(ui, false);
1144
1141
  if (!ui.destroyed) {
1145
1142
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1146
- if (image.hasOpacityPixel)
1143
+ if (image.hasAlphaPixel)
1147
1144
  ui.__layout.hitCanvasChanged = true;
1148
1145
  ui.forceUpdate('surface');
1149
1146
  }
@@ -1155,13 +1152,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1155
1152
  onLoadError(ui, event, error);
1156
1153
  leafPaint.loadId = null;
1157
1154
  });
1158
- if (ui.placeholderColor)
1159
- setTimeout(() => {
1160
- if (!(image.ready || image.isPlacehold)) {
1161
- image.isPlacehold = true;
1162
- ui.forceUpdate('surface');
1163
- }
1164
- }, 100);
1155
+ if (ui.placeholderColor) {
1156
+ if (!ui.placeholderDelay)
1157
+ image.isPlacehold = true;
1158
+ else
1159
+ setTimeout(() => {
1160
+ if (!image.ready) {
1161
+ image.isPlacehold = true;
1162
+ ui.forceUpdate('surface');
1163
+ }
1164
+ }, ui.placeholderDelay);
1165
+ }
1165
1166
  }
1166
1167
  return leafPaint;
1167
1168
  }
@@ -1399,32 +1400,33 @@ const PaintImageModule = {
1399
1400
  repeatMode
1400
1401
  };
1401
1402
 
1402
- const { toPoint: toPoint$2 } = AroundHelper;
1403
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1403
1404
  const realFrom$2 = {};
1404
1405
  const realTo$2 = {};
1405
1406
  function linearGradient(paint, box) {
1406
- let { from, to, type, blendMode, opacity } = paint;
1407
+ let { from, to, type, opacity } = paint;
1407
1408
  toPoint$2(from || 'top', box, realFrom$2);
1408
1409
  toPoint$2(to || 'bottom', box, realTo$2);
1409
1410
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1410
- applyStops(style, paint.stops, opacity);
1411
1411
  const data = { type, style };
1412
- if (blendMode)
1413
- data.blendMode = blendMode;
1412
+ applyStops(data, style, paint.stops, opacity);
1414
1413
  return data;
1415
1414
  }
1416
- function applyStops(gradient, stops, opacity) {
1415
+ function applyStops(data, gradient, stops, opacity) {
1417
1416
  if (stops) {
1418
- let stop;
1417
+ let stop, color, offset, isTransparent;
1419
1418
  for (let i = 0, len = stops.length; i < len; i++) {
1420
1419
  stop = stops[i];
1421
- if (typeof stop === 'string') {
1422
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1423
- }
1424
- else {
1425
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1426
- }
1420
+ if (typeof stop === 'string')
1421
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1422
+ else
1423
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1424
+ gradient.addColorStop(offset, color);
1425
+ if (!isTransparent && hasTransparent(color))
1426
+ isTransparent = true;
1427
1427
  }
1428
+ if (isTransparent)
1429
+ data.isTransparent = true;
1428
1430
  }
1429
1431
  }
1430
1432
 
@@ -1434,17 +1436,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1434
1436
  const realFrom$1 = {};
1435
1437
  const realTo$1 = {};
1436
1438
  function radialGradient(paint, box) {
1437
- let { from, to, type, opacity, blendMode, stretch } = paint;
1439
+ let { from, to, type, opacity, stretch } = paint;
1438
1440
  toPoint$1(from || 'center', box, realFrom$1);
1439
1441
  toPoint$1(to || 'bottom', box, realTo$1);
1440
1442
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1441
- applyStops(style, paint.stops, opacity);
1442
1443
  const data = { type, style };
1444
+ applyStops(data, style, paint.stops, opacity);
1443
1445
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1444
1446
  if (transform)
1445
1447
  data.transform = transform;
1446
- if (blendMode)
1447
- data.blendMode = blendMode;
1448
1448
  return data;
1449
1449
  }
1450
1450
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1470,17 +1470,15 @@ const { toPoint } = AroundHelper;
1470
1470
  const realFrom = {};
1471
1471
  const realTo = {};
1472
1472
  function conicGradient(paint, box) {
1473
- let { from, to, type, opacity, blendMode, stretch } = paint;
1473
+ let { from, to, type, opacity, stretch } = paint;
1474
1474
  toPoint(from || 'center', box, realFrom);
1475
1475
  toPoint(to || 'bottom', box, realTo);
1476
1476
  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));
1477
- applyStops(style, paint.stops, opacity);
1478
1477
  const data = { type, style };
1478
+ applyStops(data, style, paint.stops, opacity);
1479
1479
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1480
1480
  if (transform)
1481
1481
  data.transform = transform;
1482
- if (blendMode)
1483
- data.blendMode = blendMode;
1484
1482
  return data;
1485
1483
  }
1486
1484
 
@@ -1813,6 +1811,8 @@ function createRows(drawData, content, style) {
1813
1811
  lastCharType = null;
1814
1812
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1815
1813
  word = { data: [] }, row = { words: [] };
1814
+ if (__letterSpacing)
1815
+ content = [...content];
1816
1816
  for (let i = 0, len = content.length; i < len; i++) {
1817
1817
  char = content[i];
1818
1818
  if (char === '\n') {
@@ -2219,7 +2219,7 @@ const ColorConvertModule = {
2219
2219
 
2220
2220
  Object.assign(TextConvert, TextConvertModule);
2221
2221
  Object.assign(ColorConvert, ColorConvertModule);
2222
- Object.assign(Paint, PaintModule);
2222
+ Object.assign(Paint$1, PaintModule);
2223
2223
  Object.assign(PaintImage, PaintImageModule);
2224
2224
  Object.assign(PaintGradient, PaintGradientModule);
2225
2225
  Object.assign(Effect, EffectModule);