leafer-draw 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/web.esm.js CHANGED
@@ -1,8 +1,9 @@
1
- import { Debug, LeaferCanvasBase, Platform, DataHelper, canvasSizeAttrs, ResizeEvent, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, LeafLevelList, LayoutEvent, Run, ImageManager, BoundsHelper, MatrixHelper, MathHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4 } from '@leafer/core';
1
+ import { Debug, LeaferCanvasBase, Platform, DataHelper, canvasSizeAttrs, ResizeEvent, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, LeafLevelList, LayoutEvent, Run, ImageManager, 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
  const debug$2 = Debug.get('LeaferCanvas');
8
9
  class LeaferCanvas extends LeaferCanvasBase {
@@ -342,17 +343,15 @@ class Watcher {
342
343
  this.target.emitEvent(new WatchEvent(WatchEvent.DATA, { updatedList: this.updatedList }));
343
344
  this.__updatedList = new LeafList();
344
345
  this.totalTimes++;
345
- this.changed = false;
346
- this.hasVisible = false;
347
- this.hasRemove = false;
348
- this.hasAdd = false;
346
+ this.changed = this.hasVisible = this.hasRemove = this.hasAdd = false;
349
347
  }
350
348
  __listenEvents() {
351
- const { target } = this;
352
349
  this.__eventIds = [
353
- target.on_(PropertyEvent.CHANGE, this.__onAttrChange, this),
354
- target.on_([ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this),
355
- target.on_(WatchEvent.REQUEST, this.__onRquestData, this)
350
+ this.target.on_([
351
+ [PropertyEvent.CHANGE, this.__onAttrChange, this],
352
+ [[ChildEvent.ADD, ChildEvent.REMOVE], this.__onChildEvent, this],
353
+ [WatchEvent.REQUEST, this.__onRquestData, this]
354
+ ])
356
355
  ];
357
356
  }
358
357
  __removeListenEvents() {
@@ -362,13 +361,12 @@ class Watcher {
362
361
  if (this.target) {
363
362
  this.stop();
364
363
  this.__removeListenEvents();
365
- this.target = null;
366
- this.__updatedList = null;
364
+ this.target = this.__updatedList = null;
367
365
  }
368
366
  }
369
367
  }
370
368
 
371
- const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateAllWorldOpacity } = LeafHelper;
369
+ const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateChange: updateOneChange } = LeafHelper;
372
370
  const { pushAllChildBranch, pushAllParent } = BranchHelper;
373
371
  function updateMatrix(updateList, levelList) {
374
372
  let layout;
@@ -411,15 +409,7 @@ function updateBounds(boundsList) {
411
409
  });
412
410
  }
413
411
  function updateChange(updateList) {
414
- let layout;
415
- updateList.list.forEach(leaf => {
416
- layout = leaf.__layout;
417
- if (layout.opacityChanged)
418
- updateAllWorldOpacity(leaf);
419
- if (layout.stateStyleChanged)
420
- setTimeout(() => layout.stateStyleChanged && leaf.updateState());
421
- leaf.__updateChange();
422
- });
412
+ updateList.list.forEach(updateOneChange);
423
413
  }
424
414
 
425
415
  const { worldBounds } = LeafBoundsHelper;
@@ -476,7 +466,7 @@ class Layouter {
476
466
  this.disabled = true;
477
467
  }
478
468
  layout() {
479
- if (!this.running)
469
+ if (this.layouting || !this.running)
480
470
  return;
481
471
  const { target } = this;
482
472
  this.times = 0;
@@ -559,12 +549,10 @@ class Layouter {
559
549
  }
560
550
  static fullLayout(target) {
561
551
  updateAllMatrix(target, true);
562
- if (target.isBranch) {
552
+ if (target.isBranch)
563
553
  BranchHelper.updateBounds(target);
564
- }
565
- else {
554
+ else
566
555
  LeafHelper.updateBounds(target);
567
- }
568
556
  updateAllChange(target);
569
557
  }
570
558
  addExtra(leaf) {
@@ -587,11 +575,12 @@ class Layouter {
587
575
  this.__updatedList = event.data.updatedList;
588
576
  }
589
577
  __listenEvents() {
590
- const { target } = this;
591
578
  this.__eventIds = [
592
- target.on_(LayoutEvent.REQUEST, this.layout, this),
593
- target.on_(LayoutEvent.AGAIN, this.layoutAgain, this),
594
- target.on_(WatchEvent.DATA, this.__onReceiveWatchData, this)
579
+ this.target.on_([
580
+ [LayoutEvent.REQUEST, this.layout, this],
581
+ [LayoutEvent.AGAIN, this.layoutAgain, this],
582
+ [WatchEvent.DATA, this.__onReceiveWatchData, this]
583
+ ])
595
584
  ];
596
585
  }
597
586
  __removeListenEvents() {
@@ -822,12 +811,13 @@ class Renderer {
822
811
  this.target.emitEvent(new RenderEvent(type, this.times, bounds, options));
823
812
  }
824
813
  __listenEvents() {
825
- const { target } = this;
826
814
  this.__eventIds = [
827
- target.on_(RenderEvent.REQUEST, this.update, this),
828
- target.on_(LayoutEvent.END, this.__onLayoutEnd, this),
829
- target.on_(RenderEvent.AGAIN, this.renderAgain, this),
830
- target.on_(ResizeEvent.RESIZE, this.__onResize, this)
815
+ this.target.on_([
816
+ [RenderEvent.REQUEST, this.update, this],
817
+ [LayoutEvent.END, this.__onLayoutEnd, this],
818
+ [RenderEvent.AGAIN, this.renderAgain, this],
819
+ [ResizeEvent.RESIZE, this.__onResize, this]
820
+ ])
831
821
  ];
832
822
  }
833
823
  __removeListenEvents() {
@@ -853,8 +843,10 @@ Object.assign(Creator, {
853
843
  Platform.layout = Layouter.fullLayout;
854
844
 
855
845
  function fillText(ui, canvas) {
856
- let row, data = ui.__.__textDrawData;
857
- const { rows, decorationY } = data;
846
+ const data = ui.__, { rows, decorationY } = data.__textDrawData;
847
+ if (data.__isPlacehold && data.placeholderColor)
848
+ canvas.fillStyle = data.placeholderColor;
849
+ let row;
858
850
  for (let i = 0, len = rows.length; i < len; i++) {
859
851
  row = rows[i];
860
852
  if (row.text)
@@ -863,7 +855,7 @@ function fillText(ui, canvas) {
863
855
  row.data.forEach(charData => { canvas.fillText(charData.char, charData.x, row.y); });
864
856
  }
865
857
  if (decorationY) {
866
- const { decorationColor, decorationHeight } = data;
858
+ const { decorationColor, decorationHeight } = data.__textDrawData;
867
859
  if (decorationColor)
868
860
  canvas.fillStyle = decorationColor;
869
861
  rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
@@ -872,65 +864,73 @@ function fillText(ui, canvas) {
872
864
 
873
865
  function fill(fill, ui, canvas) {
874
866
  canvas.fillStyle = fill;
875
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
867
+ fillPathOrText(ui, canvas);
876
868
  }
877
869
  function fills(fills, ui, canvas) {
878
870
  let item;
879
- const { windingRule, __font } = ui.__;
880
871
  for (let i = 0, len = fills.length; i < len; i++) {
881
872
  item = fills[i];
882
- if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
883
- continue;
884
- if (item.style) {
885
- canvas.fillStyle = item.style;
886
- if (item.transform) {
887
- canvas.save();
888
- canvas.transform(item.transform);
889
- if (item.blendMode)
890
- canvas.blendMode = item.blendMode;
891
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
892
- canvas.restore();
873
+ if (item.image) {
874
+ if (PaintImage.checkImage(ui, canvas, item, !ui.__.__font))
875
+ continue;
876
+ if (!item.style) {
877
+ if (!i && item.image.isPlacehold)
878
+ ui.drawImagePlaceholder(canvas, item.image);
879
+ continue;
893
880
  }
894
- else {
895
- if (item.blendMode) {
896
- canvas.saveBlendMode(item.blendMode);
897
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
898
- canvas.restoreBlendMode();
899
- }
900
- else {
901
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
902
- }
881
+ }
882
+ canvas.fillStyle = item.style;
883
+ if (item.transform) {
884
+ canvas.save();
885
+ canvas.transform(item.transform);
886
+ if (item.blendMode)
887
+ canvas.blendMode = item.blendMode;
888
+ fillPathOrText(ui, canvas);
889
+ canvas.restore();
890
+ }
891
+ else {
892
+ if (item.blendMode) {
893
+ canvas.saveBlendMode(item.blendMode);
894
+ fillPathOrText(ui, canvas);
895
+ canvas.restoreBlendMode();
903
896
  }
897
+ else
898
+ fillPathOrText(ui, canvas);
904
899
  }
905
900
  }
906
901
  }
902
+ function fillPathOrText(ui, canvas) {
903
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
904
+ }
905
+
906
+ const Paint = {};
907
907
 
908
908
  function strokeText(stroke, ui, canvas) {
909
- const { strokeAlign } = ui.__;
910
- const isStrokes = typeof stroke !== 'string';
911
- switch (strokeAlign) {
909
+ switch (ui.__.strokeAlign) {
912
910
  case 'center':
913
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
914
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
911
+ drawCenter$1(stroke, 1, ui, canvas);
915
912
  break;
916
913
  case 'inside':
917
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
914
+ drawAlign(stroke, 'inside', ui, canvas);
918
915
  break;
919
916
  case 'outside':
920
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
917
+ ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, 'outside', ui, canvas);
921
918
  break;
922
919
  }
923
920
  }
924
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
925
- const { __strokeWidth, __font } = ui.__;
921
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
922
+ const data = ui.__;
923
+ canvas.setStroke(!data.__isStrokes && stroke, data.strokeWidth * strokeWidthScale, data);
924
+ data.__isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
925
+ }
926
+ function drawAlign(stroke, align, ui, canvas) {
926
927
  const out = canvas.getSameCanvas(true, true);
927
- out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
928
- out.font = __font;
929
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
928
+ out.font = ui.__.__font;
929
+ drawCenter$1(stroke, 2, ui, out);
930
930
  out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
931
931
  fillText(ui, out);
932
932
  out.blendMode = 'normal';
933
- if (ui.__worldFlipped)
933
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
934
934
  canvas.copyWorldByReset(out, ui.__nowWorld);
935
935
  else
936
936
  canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
@@ -972,90 +972,60 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
972
972
  }
973
973
 
974
974
  function stroke(stroke, ui, canvas) {
975
- const options = ui.__;
976
- const { __strokeWidth, strokeAlign, __font } = options;
977
- if (!__strokeWidth)
975
+ const data = ui.__;
976
+ if (!data.__strokeWidth)
978
977
  return;
979
- if (__font) {
978
+ if (data.__font) {
980
979
  strokeText(stroke, ui, canvas);
981
980
  }
982
981
  else {
983
- switch (strokeAlign) {
982
+ switch (data.strokeAlign) {
984
983
  case 'center':
985
- canvas.setStroke(stroke, __strokeWidth, options);
986
- canvas.stroke();
987
- if (options.__useArrow)
988
- strokeArrow(ui, canvas);
984
+ drawCenter(stroke, 1, ui, canvas);
989
985
  break;
990
986
  case 'inside':
991
- canvas.save();
992
- canvas.setStroke(stroke, __strokeWidth * 2, options);
993
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
994
- canvas.stroke();
995
- canvas.restore();
987
+ drawInside(stroke, ui, canvas);
996
988
  break;
997
989
  case 'outside':
998
- const out = canvas.getSameCanvas(true, true);
999
- out.setStroke(stroke, __strokeWidth * 2, options);
1000
- ui.__drawRenderPath(out);
1001
- out.stroke();
1002
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1003
- out.clearWorld(ui.__layout.renderBounds);
1004
- if (ui.__worldFlipped)
1005
- canvas.copyWorldByReset(out, ui.__nowWorld);
1006
- else
1007
- canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1008
- out.recycle(ui.__nowWorld);
990
+ drawOutside(stroke, ui, canvas);
1009
991
  break;
1010
992
  }
1011
993
  }
1012
994
  }
1013
995
  function strokes(strokes, ui, canvas) {
1014
- const options = ui.__;
1015
- const { __strokeWidth, strokeAlign, __font } = options;
1016
- if (!__strokeWidth)
1017
- return;
1018
- if (__font) {
1019
- strokeText(strokes, ui, canvas);
996
+ stroke(strokes, ui, canvas);
997
+ }
998
+ function drawCenter(stroke, strokeWidthScale, ui, canvas) {
999
+ const data = ui.__;
1000
+ canvas.setStroke(!data.__isStrokes && stroke, data.__strokeWidth * strokeWidthScale, data);
1001
+ data.__isStrokes ? drawStrokesStyle(stroke, false, ui, canvas) : canvas.stroke();
1002
+ if (data.__useArrow)
1003
+ Paint.strokeArrow(stroke, ui, canvas);
1004
+ }
1005
+ function drawInside(stroke, ui, canvas) {
1006
+ const data = ui.__;
1007
+ canvas.save();
1008
+ data.windingRule ? canvas.clip(data.windingRule) : canvas.clip();
1009
+ drawCenter(stroke, 2, ui, canvas);
1010
+ canvas.restore();
1011
+ }
1012
+ function drawOutside(stroke, ui, canvas) {
1013
+ const data = ui.__;
1014
+ if (data.__fillAfterStroke) {
1015
+ drawCenter(stroke, 2, ui, canvas);
1020
1016
  }
1021
1017
  else {
1022
- switch (strokeAlign) {
1023
- case 'center':
1024
- canvas.setStroke(undefined, __strokeWidth, options);
1025
- drawStrokesStyle(strokes, false, ui, canvas);
1026
- if (options.__useArrow)
1027
- strokeArrow(ui, canvas);
1028
- break;
1029
- case 'inside':
1030
- canvas.save();
1031
- canvas.setStroke(undefined, __strokeWidth * 2, options);
1032
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1033
- drawStrokesStyle(strokes, false, ui, canvas);
1034
- canvas.restore();
1035
- break;
1036
- case 'outside':
1037
- const { renderBounds } = ui.__layout;
1038
- const out = canvas.getSameCanvas(true, true);
1039
- ui.__drawRenderPath(out);
1040
- out.setStroke(undefined, __strokeWidth * 2, options);
1041
- drawStrokesStyle(strokes, false, ui, out);
1042
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1043
- out.clearWorld(renderBounds);
1044
- if (ui.__worldFlipped)
1045
- canvas.copyWorldByReset(out, ui.__nowWorld);
1046
- else
1047
- canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1048
- out.recycle(ui.__nowWorld);
1049
- break;
1050
- }
1051
- }
1052
- }
1053
- function strokeArrow(ui, canvas) {
1054
- if (ui.__.dashPattern) {
1055
- canvas.beginPath();
1056
- ui.__drawPathByData(canvas, ui.__.__pathForArrow);
1057
- canvas.dashPattern = null;
1058
- canvas.stroke();
1018
+ const { renderBounds } = ui.__layout;
1019
+ const out = canvas.getSameCanvas(true, true);
1020
+ ui.__drawRenderPath(out);
1021
+ drawCenter(stroke, 2, ui, out);
1022
+ data.windingRule ? out.clip(data.windingRule) : out.clip();
1023
+ out.clearWorld(renderBounds);
1024
+ if (ui.__worldFlipped || Platform$1.fullImageShadow)
1025
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1026
+ else
1027
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1028
+ out.recycle(ui.__nowWorld);
1059
1029
  }
1060
1030
  }
1061
1031
 
@@ -1102,9 +1072,10 @@ function shape(ui, current, options) {
1102
1072
  }
1103
1073
 
1104
1074
  let recycleMap;
1075
+ const { stintSet } = DataHelper, { hasTransparent: hasTransparent$1 } = ColorConvert;
1105
1076
  function compute(attrName, ui) {
1106
1077
  const data = ui.__, leafPaints = [];
1107
- let paints = data.__input[attrName], hasOpacityPixel;
1078
+ let paints = data.__input[attrName], isAlphaPixel, isTransparent;
1108
1079
  if (!(paints instanceof Array))
1109
1080
  paints = [paints];
1110
1081
  recycleMap = PaintImage.recycleImage(attrName, data);
@@ -1114,35 +1085,62 @@ function compute(attrName, ui) {
1114
1085
  leafPaints.push(item);
1115
1086
  }
1116
1087
  data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1117
- if (leafPaints.length && leafPaints[0].image)
1118
- hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1119
- attrName === 'fill' ? data.__pixelFill = hasOpacityPixel : data.__pixelStroke = hasOpacityPixel;
1088
+ if (leafPaints.length) {
1089
+ if (leafPaints.every(item => item.isTransparent)) {
1090
+ if (leafPaints.some(item => item.image))
1091
+ isAlphaPixel = true;
1092
+ isTransparent = true;
1093
+ }
1094
+ }
1095
+ if (attrName === 'fill') {
1096
+ stintSet(data, '__isAlphaPixelFill', isAlphaPixel);
1097
+ stintSet(data, '__isTransparentFill', isTransparent);
1098
+ }
1099
+ else {
1100
+ stintSet(data, '__isAlphaPixelStroke', isAlphaPixel);
1101
+ stintSet(data, '__isTransparentStroke', isTransparent);
1102
+ }
1120
1103
  }
1121
1104
  function getLeafPaint(attrName, paint, ui) {
1122
1105
  if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1123
1106
  return undefined;
1107
+ let data;
1124
1108
  const { boxBounds } = ui.__layout;
1125
1109
  switch (paint.type) {
1126
- case 'solid':
1127
- let { type, blendMode, color, opacity } = paint;
1128
- return { type, blendMode, style: ColorConvert.string(color, opacity) };
1129
1110
  case 'image':
1130
- return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1111
+ data = PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1112
+ break;
1131
1113
  case 'linear':
1132
- return PaintGradient.linearGradient(paint, boxBounds);
1114
+ data = PaintGradient.linearGradient(paint, boxBounds);
1115
+ break;
1133
1116
  case 'radial':
1134
- return PaintGradient.radialGradient(paint, boxBounds);
1117
+ data = PaintGradient.radialGradient(paint, boxBounds);
1118
+ break;
1135
1119
  case 'angular':
1136
- return PaintGradient.conicGradient(paint, boxBounds);
1120
+ data = PaintGradient.conicGradient(paint, boxBounds);
1121
+ break;
1122
+ case 'solid':
1123
+ const { type, blendMode, color, opacity } = paint;
1124
+ data = { type, blendMode, style: ColorConvert.string(color, opacity) };
1125
+ break;
1137
1126
  default:
1138
- return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1127
+ if (paint.r !== undefined)
1128
+ data = { type: 'solid', style: ColorConvert.string(paint) };
1129
+ }
1130
+ if (data) {
1131
+ if (typeof data.style === 'string' && hasTransparent$1(data.style))
1132
+ data.isTransparent = true;
1133
+ if (paint.blendMode)
1134
+ data.blendMode = paint.blendMode;
1139
1135
  }
1136
+ return data;
1140
1137
  }
1141
1138
 
1142
1139
  const PaintModule = {
1143
1140
  compute,
1144
1141
  fill,
1145
1142
  fills,
1143
+ fillPathOrText,
1146
1144
  fillText,
1147
1145
  stroke,
1148
1146
  strokes,
@@ -1201,12 +1199,10 @@ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, al
1201
1199
 
1202
1200
  const { get: get$2, translate } = MatrixHelper;
1203
1201
  const tempBox = new Bounds();
1204
- const tempPoint = {};
1205
1202
  const tempScaleData = {};
1203
+ const tempImage = {};
1206
1204
  function createData(leafPaint, image, paint, box) {
1207
- const { blendMode, changeful, sync } = paint;
1208
- if (blendMode)
1209
- leafPaint.blendMode = blendMode;
1205
+ const { changeful, sync } = paint;
1210
1206
  if (changeful)
1211
1207
  leafPaint.changeful = changeful;
1212
1208
  if (sync)
@@ -1214,38 +1210,38 @@ function createData(leafPaint, image, paint, box) {
1214
1210
  leafPaint.data = getPatternData(paint, box, image);
1215
1211
  }
1216
1212
  function getPatternData(paint, box, image) {
1217
- let { width, height } = image;
1218
1213
  if (paint.padding)
1219
1214
  box = tempBox.set(box).shrink(paint.padding);
1220
1215
  if (paint.mode === 'strench')
1221
1216
  paint.mode = 'stretch';
1217
+ let { width, height } = image;
1222
1218
  const { opacity, mode, align, offset, scale, size, rotation, repeat, filters } = paint;
1223
1219
  const sameBox = box.width === width && box.height === height;
1224
1220
  const data = { mode };
1225
1221
  const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1226
- const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1227
- let x = 0, y = 0, scaleX, scaleY;
1222
+ BoundsHelper.set(tempImage, 0, 0, swapSize ? height : width, swapSize ? width : height);
1223
+ let scaleX, scaleY;
1228
1224
  if (!mode || mode === 'cover' || mode === 'fit') {
1229
1225
  if (!sameBox || rotation) {
1230
- const sw = box.width / swapWidth, sh = box.height / swapHeight;
1231
- scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1232
- x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1226
+ scaleX = scaleY = BoundsHelper.getFitScale(box, tempImage, mode !== 'fit');
1227
+ BoundsHelper.put(box, image, align, scaleX, false, tempImage);
1228
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1233
1229
  }
1234
1230
  }
1235
- else if (scale || size) {
1236
- MathHelper.getScaleData(scale, size, image, tempScaleData);
1237
- scaleX = tempScaleData.scaleX;
1238
- scaleY = tempScaleData.scaleY;
1239
- }
1240
- if (align) {
1241
- const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1242
- if (scaleX)
1243
- imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1244
- AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1245
- x += tempPoint.x, y += tempPoint.y;
1231
+ else {
1232
+ if (scale || size) {
1233
+ MathHelper.getScaleData(scale, size, image, tempScaleData);
1234
+ scaleX = tempScaleData.scaleX;
1235
+ scaleY = tempScaleData.scaleY;
1236
+ }
1237
+ if (align) {
1238
+ if (scaleX)
1239
+ BoundsHelper.scale(tempImage, scaleX, scaleY, true);
1240
+ AlignHelper.toPoint(align, tempImage, box, tempImage, true, true);
1241
+ }
1246
1242
  }
1247
1243
  if (offset)
1248
- x += offset.x, y += offset.y;
1244
+ PointHelper.move(tempImage, offset);
1249
1245
  switch (mode) {
1250
1246
  case 'stretch':
1251
1247
  if (!sameBox)
@@ -1253,12 +1249,12 @@ function getPatternData(paint, box, image) {
1253
1249
  break;
1254
1250
  case 'normal':
1255
1251
  case 'clip':
1256
- if (x || y || scaleX || rotation)
1257
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1252
+ if (tempImage.x || tempImage.y || scaleX || rotation)
1253
+ clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1258
1254
  break;
1259
1255
  case 'repeat':
1260
1256
  if (!sameBox || scaleX || rotation)
1261
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1257
+ repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, align);
1262
1258
  if (!repeat)
1263
1259
  data.repeat = 'repeat';
1264
1260
  break;
@@ -1266,7 +1262,7 @@ function getPatternData(paint, box, image) {
1266
1262
  case 'cover':
1267
1263
  default:
1268
1264
  if (scaleX)
1269
- fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1265
+ fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1270
1266
  }
1271
1267
  if (!data.transform) {
1272
1268
  if (box.x || box.y) {
@@ -1299,6 +1295,8 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1299
1295
  }
1300
1296
  else {
1301
1297
  leafPaint = { type: paint.type, image };
1298
+ if (image.hasAlphaPixel)
1299
+ leafPaint.isTransparent = true;
1302
1300
  cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1303
1301
  }
1304
1302
  if (firstUse || image.loading)
@@ -1323,7 +1321,7 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1323
1321
  ignoreRender(ui, false);
1324
1322
  if (!ui.destroyed) {
1325
1323
  if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1326
- if (image.hasOpacityPixel)
1324
+ if (image.hasAlphaPixel)
1327
1325
  ui.__layout.hitCanvasChanged = true;
1328
1326
  ui.forceUpdate('surface');
1329
1327
  }
@@ -1335,6 +1333,17 @@ function image(ui, attrName, paint, boxBounds, firstUse) {
1335
1333
  onLoadError(ui, event, error);
1336
1334
  leafPaint.loadId = null;
1337
1335
  });
1336
+ if (ui.placeholderColor) {
1337
+ if (!ui.placeholderDelay)
1338
+ image.isPlacehold = true;
1339
+ else
1340
+ setTimeout(() => {
1341
+ if (!image.ready) {
1342
+ image.isPlacehold = true;
1343
+ ui.forceUpdate('surface');
1344
+ }
1345
+ }, ui.placeholderDelay);
1346
+ }
1338
1347
  }
1339
1348
  return leafPaint;
1340
1349
  }
@@ -1572,32 +1581,33 @@ const PaintImageModule = {
1572
1581
  repeatMode
1573
1582
  };
1574
1583
 
1575
- const { toPoint: toPoint$2 } = AroundHelper;
1584
+ const { toPoint: toPoint$2 } = AroundHelper, { hasTransparent } = ColorConvert;
1576
1585
  const realFrom$2 = {};
1577
1586
  const realTo$2 = {};
1578
1587
  function linearGradient(paint, box) {
1579
- let { from, to, type, blendMode, opacity } = paint;
1588
+ let { from, to, type, opacity } = paint;
1580
1589
  toPoint$2(from || 'top', box, realFrom$2);
1581
1590
  toPoint$2(to || 'bottom', box, realTo$2);
1582
1591
  const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1583
- applyStops(style, paint.stops, opacity);
1584
1592
  const data = { type, style };
1585
- if (blendMode)
1586
- data.blendMode = blendMode;
1593
+ applyStops(data, style, paint.stops, opacity);
1587
1594
  return data;
1588
1595
  }
1589
- function applyStops(gradient, stops, opacity) {
1596
+ function applyStops(data, gradient, stops, opacity) {
1590
1597
  if (stops) {
1591
- let stop;
1598
+ let stop, color, offset, isTransparent;
1592
1599
  for (let i = 0, len = stops.length; i < len; i++) {
1593
1600
  stop = stops[i];
1594
- if (typeof stop === 'string') {
1595
- gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1596
- }
1597
- else {
1598
- gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1599
- }
1601
+ if (typeof stop === 'string')
1602
+ offset = i / (len - 1), color = ColorConvert.string(stop, opacity);
1603
+ else
1604
+ offset = stop.offset, color = ColorConvert.string(stop.color, opacity);
1605
+ gradient.addColorStop(offset, color);
1606
+ if (!isTransparent && hasTransparent(color))
1607
+ isTransparent = true;
1600
1608
  }
1609
+ if (isTransparent)
1610
+ data.isTransparent = true;
1601
1611
  }
1602
1612
  }
1603
1613
 
@@ -1607,17 +1617,15 @@ const { toPoint: toPoint$1 } = AroundHelper;
1607
1617
  const realFrom$1 = {};
1608
1618
  const realTo$1 = {};
1609
1619
  function radialGradient(paint, box) {
1610
- let { from, to, type, opacity, blendMode, stretch } = paint;
1620
+ let { from, to, type, opacity, stretch } = paint;
1611
1621
  toPoint$1(from || 'center', box, realFrom$1);
1612
1622
  toPoint$1(to || 'bottom', box, realTo$1);
1613
1623
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1614
- applyStops(style, paint.stops, opacity);
1615
1624
  const data = { type, style };
1625
+ applyStops(data, style, paint.stops, opacity);
1616
1626
  const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1617
1627
  if (transform)
1618
1628
  data.transform = transform;
1619
- if (blendMode)
1620
- data.blendMode = blendMode;
1621
1629
  return data;
1622
1630
  }
1623
1631
  function getTransform(box, from, to, stretch, rotate90) {
@@ -1643,17 +1651,15 @@ const { toPoint } = AroundHelper;
1643
1651
  const realFrom = {};
1644
1652
  const realTo = {};
1645
1653
  function conicGradient(paint, box) {
1646
- let { from, to, type, opacity, blendMode, stretch } = paint;
1654
+ let { from, to, type, opacity, stretch } = paint;
1647
1655
  toPoint(from || 'center', box, realFrom);
1648
1656
  toPoint(to || 'bottom', box, realTo);
1649
1657
  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));
1650
- applyStops(style, paint.stops, opacity);
1651
1658
  const data = { type, style };
1659
+ applyStops(data, style, paint.stops, opacity);
1652
1660
  const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1653
1661
  if (transform)
1654
1662
  data.transform = transform;
1655
- if (blendMode)
1656
- data.blendMode = blendMode;
1657
1663
  return data;
1658
1664
  }
1659
1665
 
@@ -1986,6 +1992,8 @@ function createRows(drawData, content, style) {
1986
1992
  lastCharType = null;
1987
1993
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1988
1994
  word = { data: [] }, row = { words: [] };
1995
+ if (__letterSpacing)
1996
+ content = [...content];
1989
1997
  for (let i = 0, len = content.length; i < len; i++) {
1990
1998
  char = content[i];
1991
1999
  if (char === '\n') {
@@ -2392,7 +2400,7 @@ const ColorConvertModule = {
2392
2400
 
2393
2401
  Object.assign(TextConvert, TextConvertModule);
2394
2402
  Object.assign(ColorConvert, ColorConvertModule);
2395
- Object.assign(Paint, PaintModule);
2403
+ Object.assign(Paint$1, PaintModule);
2396
2404
  Object.assign(PaintImage, PaintImageModule);
2397
2405
  Object.assign(PaintGradient, PaintGradientModule);
2398
2406
  Object.assign(Effect, EffectModule);
@@ -2400,4 +2408,3 @@ Object.assign(Effect, EffectModule);
2400
2408
  useCanvas();
2401
2409
 
2402
2410
  export { Layouter, LeaferCanvas, Renderer, Watcher, useCanvas };
2403
- //# sourceMappingURL=web.esm.js.map