@leafer-draw/worker 1.9.12 → 1.10.0

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/worker.cjs CHANGED
@@ -662,36 +662,19 @@ core.Platform.render = function(target, canvas, options) {
662
662
  if (options.topList.length) options.topList.forEach(item => item.__render(canvas, topOptions));
663
663
  };
664
664
 
665
- function fillText(ui, canvas) {
666
- const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
667
- if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
668
- let row;
669
- for (let i = 0, len = rows.length; i < len; i++) {
670
- row = rows[i];
671
- if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
672
- canvas.fillText(charData.char, charData.x, row.y);
673
- });
674
- }
675
- if (decorationY) {
676
- const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
677
- if (decorationColor) canvas.fillStyle = decorationColor;
678
- rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
679
- }
680
- }
681
-
682
- function fill(fill, ui, canvas) {
665
+ function fill(fill, ui, canvas, renderOptions) {
683
666
  canvas.fillStyle = fill;
684
- fillPathOrText(ui, canvas);
667
+ fillPathOrText(ui, canvas, renderOptions);
685
668
  }
686
669
 
687
- function fills(fills, ui, canvas) {
670
+ function fills(fills, ui, canvas, renderOptions) {
688
671
  let item;
689
672
  for (let i = 0, len = fills.length; i < len; i++) {
690
673
  item = fills[i];
691
674
  if (item.image) {
692
- if (draw.PaintImage.checkImage(ui, canvas, item, !ui.__.__font)) continue;
675
+ if (draw.PaintImage.checkImage(item, !ui.__.__font, ui, canvas, renderOptions)) continue;
693
676
  if (!item.style) {
694
- if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(canvas, item.image);
677
+ if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(item.image, canvas, renderOptions);
695
678
  continue;
696
679
  }
697
680
  }
@@ -704,60 +687,137 @@ function fills(fills, ui, canvas) {
704
687
  if (item.scaleFixed === true || item.scaleFixed === "zoom-in" && scaleX > 1 && scaleY > 1) canvas.scale(1 / scaleX, 1 / scaleY);
705
688
  }
706
689
  if (item.blendMode) canvas.blendMode = item.blendMode;
707
- fillPathOrText(ui, canvas);
690
+ fillPathOrText(ui, canvas, renderOptions);
708
691
  canvas.restore();
709
692
  } else {
710
693
  if (item.blendMode) {
711
694
  canvas.saveBlendMode(item.blendMode);
712
- fillPathOrText(ui, canvas);
695
+ fillPathOrText(ui, canvas, renderOptions);
713
696
  canvas.restoreBlendMode();
714
- } else fillPathOrText(ui, canvas);
697
+ } else fillPathOrText(ui, canvas, renderOptions);
698
+ }
699
+ }
700
+ }
701
+
702
+ function fillPathOrText(ui, canvas, renderOptions) {
703
+ ui.__.__font ? draw.Paint.fillText(ui, canvas, renderOptions) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
704
+ }
705
+
706
+ function fillText(ui, canvas, _renderOptions) {
707
+ const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
708
+ if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
709
+ let row;
710
+ for (let i = 0, len = rows.length; i < len; i++) {
711
+ row = rows[i];
712
+ if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
713
+ canvas.fillText(charData.char, charData.x, row.y);
714
+ });
715
+ }
716
+ if (decorationY) {
717
+ const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
718
+ if (decorationColor) canvas.fillStyle = decorationColor;
719
+ rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
720
+ }
721
+ }
722
+
723
+ function stroke(stroke, ui, canvas, renderOptions) {
724
+ const data = ui.__;
725
+ if (!data.__strokeWidth) return;
726
+ if (data.__font) {
727
+ draw.Paint.strokeText(stroke, ui, canvas, renderOptions);
728
+ } else {
729
+ switch (data.strokeAlign) {
730
+ case "center":
731
+ drawCenter$1(stroke, 1, ui, canvas, renderOptions);
732
+ break;
733
+
734
+ case "inside":
735
+ drawInside(stroke, ui, canvas, renderOptions);
736
+ break;
737
+
738
+ case "outside":
739
+ drawOutside(stroke, ui, canvas, renderOptions);
740
+ break;
715
741
  }
716
742
  }
717
743
  }
718
744
 
719
- function fillPathOrText(ui, canvas) {
720
- ui.__.__font ? fillText(ui, canvas) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
745
+ function strokes(strokes, ui, canvas, renderOptions) {
746
+ draw.Paint.stroke(strokes, ui, canvas, renderOptions);
747
+ }
748
+
749
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas, renderOptions) {
750
+ const data = ui.__;
751
+ if (core.isObject(stroke)) {
752
+ draw.Paint.drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas, renderOptions);
753
+ } else {
754
+ canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
755
+ canvas.stroke();
756
+ }
757
+ if (data.__useArrow) draw.Paint.strokeArrow(stroke, ui, canvas, renderOptions);
758
+ }
759
+
760
+ function drawInside(stroke, ui, canvas, renderOptions) {
761
+ canvas.save();
762
+ canvas.clipUI(ui);
763
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
764
+ canvas.restore();
721
765
  }
722
766
 
723
- function strokeText(stroke, ui, canvas) {
767
+ function drawOutside(stroke, ui, canvas, renderOptions) {
768
+ const data = ui.__;
769
+ if (data.__fillAfterStroke) {
770
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
771
+ } else {
772
+ const {renderBounds: renderBounds} = ui.__layout;
773
+ const out = canvas.getSameCanvas(true, true);
774
+ ui.__drawRenderPath(out);
775
+ drawCenter$1(stroke, 2, ui, out, renderOptions);
776
+ out.clipUI(data);
777
+ out.clearWorld(renderBounds);
778
+ core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
779
+ out.recycle(ui.__nowWorld);
780
+ }
781
+ }
782
+
783
+ function strokeText(stroke, ui, canvas, renderOptions) {
724
784
  switch (ui.__.strokeAlign) {
725
785
  case "center":
726
- drawCenter$1(stroke, 1, ui, canvas);
786
+ drawCenter(stroke, 1, ui, canvas, renderOptions);
727
787
  break;
728
788
 
729
789
  case "inside":
730
- drawAlign(stroke, "inside", ui, canvas);
790
+ drawAlign(stroke, "inside", ui, canvas, renderOptions);
731
791
  break;
732
792
 
733
793
  case "outside":
734
- ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, "outside", ui, canvas);
794
+ ui.__.__fillAfterStroke ? drawCenter(stroke, 2, ui, canvas, renderOptions) : drawAlign(stroke, "outside", ui, canvas, renderOptions);
735
795
  break;
736
796
  }
737
797
  }
738
798
 
739
- function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
799
+ function drawCenter(stroke, strokeWidthScale, ui, canvas, renderOptions) {
740
800
  const data = ui.__;
741
801
  if (core.isObject(stroke)) {
742
- drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas);
802
+ draw.Paint.drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas, renderOptions);
743
803
  } else {
744
804
  canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
745
- drawTextStroke(ui, canvas);
805
+ draw.Paint.drawTextStroke(ui, canvas, renderOptions);
746
806
  }
747
807
  }
748
808
 
749
- function drawAlign(stroke, align, ui, canvas) {
809
+ function drawAlign(stroke, align, ui, canvas, renderOptions) {
750
810
  const out = canvas.getSameCanvas(true, true);
751
811
  out.font = ui.__.__font;
752
- drawCenter$1(stroke, 2, ui, out);
812
+ drawCenter(stroke, 2, ui, out, renderOptions);
753
813
  out.blendMode = align === "outside" ? "destination-out" : "destination-in";
754
- fillText(ui, out);
814
+ draw.Paint.fillText(ui, out, renderOptions);
755
815
  out.blendMode = "normal";
756
816
  core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
757
817
  out.recycle(ui.__nowWorld);
758
818
  }
759
819
 
760
- function drawTextStroke(ui, canvas) {
820
+ function drawTextStroke(ui, canvas, _renderOptions) {
761
821
  let row, data = ui.__.__textDrawData;
762
822
  const {rows: rows, decorationY: decorationY} = data;
763
823
  for (let i = 0, len = rows.length; i < len; i++) {
@@ -772,13 +832,13 @@ function drawTextStroke(ui, canvas) {
772
832
  }
773
833
  }
774
834
 
775
- function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
835
+ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas, renderOptions) {
776
836
  let item;
777
837
  const data = ui.__, {__hasMultiStrokeStyle: __hasMultiStrokeStyle} = data;
778
838
  __hasMultiStrokeStyle || canvas.setStroke(undefined, data.__strokeWidth * strokeWidthScale, data);
779
839
  for (let i = 0, len = strokes.length; i < len; i++) {
780
840
  item = strokes[i];
781
- if (item.image && draw.PaintImage.checkImage(ui, canvas, item, false)) continue;
841
+ if (item.image && draw.PaintImage.checkImage(item, false, ui, canvas, renderOptions)) continue;
782
842
  if (item.style) {
783
843
  if (__hasMultiStrokeStyle) {
784
844
  const {strokeStyle: strokeStyle} = item;
@@ -786,75 +846,15 @@ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
786
846
  } else canvas.strokeStyle = item.style;
787
847
  if (item.blendMode) {
788
848
  canvas.saveBlendMode(item.blendMode);
789
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
849
+ isText ? draw.Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
790
850
  canvas.restoreBlendMode();
791
851
  } else {
792
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
852
+ isText ? draw.Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
793
853
  }
794
854
  }
795
855
  }
796
856
  }
797
857
 
798
- function stroke(stroke, ui, canvas) {
799
- const data = ui.__;
800
- if (!data.__strokeWidth) return;
801
- if (data.__font) {
802
- strokeText(stroke, ui, canvas);
803
- } else {
804
- switch (data.strokeAlign) {
805
- case "center":
806
- drawCenter(stroke, 1, ui, canvas);
807
- break;
808
-
809
- case "inside":
810
- drawInside(stroke, ui, canvas);
811
- break;
812
-
813
- case "outside":
814
- drawOutside(stroke, ui, canvas);
815
- break;
816
- }
817
- }
818
- }
819
-
820
- function strokes(strokes, ui, canvas) {
821
- stroke(strokes, ui, canvas);
822
- }
823
-
824
- function drawCenter(stroke, strokeWidthScale, ui, canvas) {
825
- const data = ui.__;
826
- if (core.isObject(stroke)) {
827
- drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas);
828
- } else {
829
- canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
830
- canvas.stroke();
831
- }
832
- if (data.__useArrow) draw.Paint.strokeArrow(stroke, ui, canvas);
833
- }
834
-
835
- function drawInside(stroke, ui, canvas) {
836
- canvas.save();
837
- canvas.clipUI(ui);
838
- drawCenter(stroke, 2, ui, canvas);
839
- canvas.restore();
840
- }
841
-
842
- function drawOutside(stroke, ui, canvas) {
843
- const data = ui.__;
844
- if (data.__fillAfterStroke) {
845
- drawCenter(stroke, 2, ui, canvas);
846
- } else {
847
- const {renderBounds: renderBounds} = ui.__layout;
848
- const out = canvas.getSameCanvas(true, true);
849
- ui.__drawRenderPath(out);
850
- drawCenter(stroke, 2, ui, out);
851
- out.clipUI(data);
852
- out.clearWorld(renderBounds);
853
- core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
854
- out.recycle(ui.__nowWorld);
855
- }
856
- }
857
-
858
858
  const {getSpread: getSpread, copyAndSpread: copyAndSpread, toOuterOf: toOuterOf, getOuterOf: getOuterOf, getByMove: getByMove, move: move$1, getIntersectData: getIntersectData} = core.BoundsHelper;
859
859
 
860
860
  const tempBounds$1 = {};
@@ -1010,88 +1010,118 @@ const PaintModule = {
1010
1010
  strokes: strokes,
1011
1011
  strokeText: strokeText,
1012
1012
  drawTextStroke: drawTextStroke,
1013
+ drawStrokesStyle: drawStrokesStyle,
1013
1014
  shape: shape
1014
1015
  };
1015
1016
 
1016
- let origin = {}, tempMatrix$1 = core.getMatrixData();
1017
+ let cache, box = new core.Bounds;
1017
1018
 
1018
- const {get: get$3, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = core.MatrixHelper;
1019
+ const {isSame: isSame} = core.BoundsHelper;
1019
1020
 
1020
- function stretchMode(data, box, scaleX, scaleY) {
1021
- const transform = get$3();
1022
- translate$1(transform, box.x, box.y);
1023
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1024
- data.transform = transform;
1021
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1022
+ let leafPaint, event;
1023
+ const image = core.ImageManager.get(paint);
1024
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1025
+ leafPaint = cache.leafPaint;
1026
+ } else {
1027
+ leafPaint = {
1028
+ type: paint.type,
1029
+ image: image
1030
+ };
1031
+ if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1032
+ cache = image.use > 1 ? {
1033
+ leafPaint: leafPaint,
1034
+ paint: paint,
1035
+ boxBounds: box.set(boxBounds)
1036
+ } : null;
1037
+ }
1038
+ if (firstUse || image.loading) event = {
1039
+ image: image,
1040
+ attrName: attrName,
1041
+ attrValue: paint
1042
+ };
1043
+ if (image.ready) {
1044
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1045
+ if (firstUse) {
1046
+ onLoad(ui, event);
1047
+ onLoadSuccess(ui, event);
1048
+ }
1049
+ } else if (image.error) {
1050
+ if (firstUse) onLoadError(ui, event, image.error);
1051
+ } else {
1052
+ if (firstUse) {
1053
+ ignoreRender(ui, true);
1054
+ onLoad(ui, event);
1055
+ }
1056
+ leafPaint.loadId = image.load(() => {
1057
+ ignoreRender(ui, false);
1058
+ if (!ui.destroyed) {
1059
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1060
+ if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1061
+ ui.forceUpdate("surface");
1062
+ }
1063
+ onLoadSuccess(ui, event);
1064
+ }
1065
+ leafPaint.loadId = undefined;
1066
+ }, error => {
1067
+ ignoreRender(ui, false);
1068
+ onLoadError(ui, event, error);
1069
+ leafPaint.loadId = undefined;
1070
+ });
1071
+ if (ui.placeholderColor) {
1072
+ if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1073
+ if (!image.ready) {
1074
+ image.isPlacehold = true;
1075
+ ui.forceUpdate("surface");
1076
+ }
1077
+ }, ui.placeholderDelay);
1078
+ }
1079
+ }
1080
+ return leafPaint;
1025
1081
  }
1026
1082
 
1027
- function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1028
- const transform = get$3();
1029
- translate$1(transform, box.x + x, box.y + y);
1030
- scaleHelper(transform, scaleX, scaleY);
1031
- if (rotation) rotateOfOuter$1(transform, {
1032
- x: box.x + box.width / 2,
1033
- y: box.y + box.height / 2
1034
- }, rotation);
1035
- data.transform = transform;
1083
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1084
+ if (attrName === "fill" && !ui.__.__naturalWidth) {
1085
+ const data = ui.__;
1086
+ data.__naturalWidth = image.width / data.pixelRatio;
1087
+ data.__naturalHeight = image.height / data.pixelRatio;
1088
+ if (data.__autoSide) {
1089
+ ui.forceUpdate("width");
1090
+ if (ui.__proxyData) {
1091
+ ui.setProxyAttr("width", data.width);
1092
+ ui.setProxyAttr("height", data.height);
1093
+ }
1094
+ return false;
1095
+ }
1096
+ }
1097
+ if (!leafPaint.data) draw.PaintImage.createData(leafPaint, image, paint, boxBounds);
1098
+ return true;
1036
1099
  }
1037
1100
 
1038
- function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1039
- const transform = get$3();
1040
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1041
- if (clipScaleX) {
1042
- if (rotation || skew) {
1043
- set(tempMatrix$1);
1044
- scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1045
- multiplyParent(transform, tempMatrix$1);
1046
- } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1047
- }
1048
- data.transform = transform;
1101
+ function onLoad(ui, event) {
1102
+ emit(ui, core.ImageEvent.LOAD, event);
1049
1103
  }
1050
1104
 
1051
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1052
- const transform = get$3();
1053
- if (freeTransform) {
1054
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1055
- } else {
1056
- if (rotation) {
1057
- if (align === "center") {
1058
- rotateOfOuter$1(transform, {
1059
- x: width / 2,
1060
- y: height / 2
1061
- }, rotation);
1062
- } else {
1063
- rotate(transform, rotation);
1064
- switch (rotation) {
1065
- case 90:
1066
- translate$1(transform, height, 0);
1067
- break;
1105
+ function onLoadSuccess(ui, event) {
1106
+ emit(ui, core.ImageEvent.LOADED, event);
1107
+ }
1068
1108
 
1069
- case 180:
1070
- translate$1(transform, width, height);
1071
- break;
1109
+ function onLoadError(ui, event, error) {
1110
+ event.error = error;
1111
+ ui.forceUpdate("surface");
1112
+ emit(ui, core.ImageEvent.ERROR, event);
1113
+ }
1072
1114
 
1073
- case 270:
1074
- translate$1(transform, 0, width);
1075
- break;
1076
- }
1077
- }
1078
- }
1079
- origin.x = box.x + x;
1080
- origin.y = box.y + y;
1081
- translate$1(transform, origin.x, origin.y);
1082
- if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1083
- }
1084
- data.transform = transform;
1115
+ function emit(ui, type, data) {
1116
+ if (ui.hasEvent(type)) ui.emitEvent(new core.ImageEvent(type, data));
1085
1117
  }
1086
1118
 
1087
- function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1088
- if (rotation) rotate(transform, rotation);
1089
- if (skew) skewHelper(transform, skew.x, skew.y);
1090
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1091
- translate$1(transform, box.x + x, box.y + y);
1119
+ function ignoreRender(ui, value) {
1120
+ const {leafer: leafer} = ui;
1121
+ if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1092
1122
  }
1093
1123
 
1094
- const {get: get$2, translate: translate} = core.MatrixHelper;
1124
+ const {get: get$3, translate: translate$1} = core.MatrixHelper;
1095
1125
 
1096
1126
  const tempBox = new core.Bounds;
1097
1127
 
@@ -1104,13 +1134,13 @@ function createData(leafPaint, image, paint, box) {
1104
1134
  if (changeful) leafPaint.changeful = changeful;
1105
1135
  if (sync) leafPaint.sync = sync;
1106
1136
  if (scaleFixed) leafPaint.scaleFixed = scaleFixed;
1107
- leafPaint.data = getPatternData(paint, box, image);
1137
+ leafPaint.data = draw.PaintImage.getPatternData(paint, box, image);
1108
1138
  }
1109
1139
 
1110
1140
  function getPatternData(paint, box, image) {
1111
1141
  if (paint.padding) box = tempBox.set(box).shrink(paint.padding);
1112
1142
  if (paint.mode === "strench") paint.mode = "stretch";
1113
- let {width: width, height: height} = image;
1143
+ const {width: width, height: height} = image;
1114
1144
  const {opacity: opacity, mode: mode, align: align, offset: offset, scale: scale, size: size, rotation: rotation, skew: skew, clipSize: clipSize, repeat: repeat, gap: gap, filters: filters} = paint;
1115
1145
  const sameBox = box.width === width && box.height === height;
1116
1146
  const data = {
@@ -1141,8 +1171,8 @@ function getPatternData(paint, box, image) {
1141
1171
  case "stretch":
1142
1172
  if (!sameBox) {
1143
1173
  scaleX = box.width / width, scaleY = box.height / height;
1144
- stretchMode(data, box, scaleX, scaleY);
1145
- }
1174
+ draw.PaintImage.stretchMode(data, box, scaleX, scaleY);
1175
+ } else if (scaleX) scaleX = scaleY = undefined;
1146
1176
  break;
1147
1177
 
1148
1178
  case "normal":
@@ -1150,13 +1180,13 @@ function getPatternData(paint, box, image) {
1150
1180
  if (tempImage.x || tempImage.y || scaleX || clipSize || rotation || skew) {
1151
1181
  let clipScaleX, clipScaleY;
1152
1182
  if (clipSize) clipScaleX = box.width / clipSize.width, clipScaleY = box.height / clipSize.height;
1153
- clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1183
+ draw.PaintImage.clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1154
1184
  if (clipScaleX) scaleX = scaleX ? scaleX * clipScaleX : clipScaleX, scaleY = scaleY ? scaleY * clipScaleY : clipScaleY;
1155
1185
  }
1156
1186
  break;
1157
1187
 
1158
1188
  case "repeat":
1159
- if (!sameBox || scaleX || rotation || skew) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1189
+ if (!sameBox || scaleX || rotation || skew) draw.PaintImage.repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1160
1190
  if (!repeat) data.repeat = "repeat";
1161
1191
  const count = core.isObject(repeat);
1162
1192
  if (gap || count) data.gap = getGapData(gap, count && repeat, tempImage.width, tempImage.height, box);
@@ -1165,18 +1195,16 @@ function getPatternData(paint, box, image) {
1165
1195
  case "fit":
1166
1196
  case "cover":
1167
1197
  default:
1168
- if (scaleX) fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1198
+ if (scaleX) draw.PaintImage.fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1169
1199
  }
1170
1200
  if (!data.transform) {
1171
- if (box.x || box.y) translate(data.transform = get$2(), box.x, box.y);
1201
+ if (box.x || box.y) translate$1(data.transform = get$3(), box.x, box.y);
1172
1202
  }
1173
- data.width = width;
1174
- data.height = height;
1175
1203
  if (scaleX) {
1176
1204
  data.scaleX = scaleX;
1177
1205
  data.scaleY = scaleY;
1178
1206
  }
1179
- if (opacity) data.opacity = opacity;
1207
+ if (opacity && opacity < 1) data.opacity = opacity;
1180
1208
  if (filters) data.filters = filters;
1181
1209
  if (repeat) data.repeat = core.isString(repeat) ? repeat === "x" ? "repeat-x" : "repeat-y" : "repeat";
1182
1210
  return data;
@@ -1198,180 +1226,82 @@ function getGapValue(gap, size, totalSize, rows) {
1198
1226
  return gap === "auto" ? value < 0 ? 0 : value : value;
1199
1227
  }
1200
1228
 
1201
- let cache, box = new core.Bounds;
1202
-
1203
- const {isSame: isSame} = core.BoundsHelper;
1204
-
1205
- function image(ui, attrName, paint, boxBounds, firstUse) {
1206
- let leafPaint, event;
1207
- const image = core.ImageManager.get(paint);
1208
- if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1209
- leafPaint = cache.leafPaint;
1210
- } else {
1211
- leafPaint = {
1212
- type: paint.type,
1213
- image: image
1214
- };
1215
- if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1216
- cache = image.use > 1 ? {
1217
- leafPaint: leafPaint,
1218
- paint: paint,
1219
- boxBounds: box.set(boxBounds)
1220
- } : null;
1221
- }
1222
- if (firstUse || image.loading) event = {
1223
- image: image,
1224
- attrName: attrName,
1225
- attrValue: paint
1226
- };
1227
- if (image.ready) {
1228
- checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1229
- if (firstUse) {
1230
- onLoad(ui, event);
1231
- onLoadSuccess(ui, event);
1232
- }
1233
- } else if (image.error) {
1234
- if (firstUse) onLoadError(ui, event, image.error);
1235
- } else {
1236
- if (firstUse) {
1237
- ignoreRender(ui, true);
1238
- onLoad(ui, event);
1239
- }
1240
- leafPaint.loadId = image.load(() => {
1241
- ignoreRender(ui, false);
1242
- if (!ui.destroyed) {
1243
- if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1244
- if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1245
- ui.forceUpdate("surface");
1246
- }
1247
- onLoadSuccess(ui, event);
1248
- }
1249
- leafPaint.loadId = undefined;
1250
- }, error => {
1251
- ignoreRender(ui, false);
1252
- onLoadError(ui, event, error);
1253
- leafPaint.loadId = undefined;
1254
- });
1255
- if (ui.placeholderColor) {
1256
- if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1257
- if (!image.ready) {
1258
- image.isPlacehold = true;
1259
- ui.forceUpdate("surface");
1260
- }
1261
- }, ui.placeholderDelay);
1262
- }
1263
- }
1264
- return leafPaint;
1265
- }
1266
-
1267
- function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1268
- if (attrName === "fill" && !ui.__.__naturalWidth) {
1269
- const data = ui.__;
1270
- data.__naturalWidth = image.width / data.pixelRatio;
1271
- data.__naturalHeight = image.height / data.pixelRatio;
1272
- if (data.__autoSide) {
1273
- ui.forceUpdate("width");
1274
- if (ui.__proxyData) {
1275
- ui.setProxyAttr("width", data.width);
1276
- ui.setProxyAttr("height", data.height);
1277
- }
1278
- return false;
1279
- }
1280
- }
1281
- if (!leafPaint.data) createData(leafPaint, image, paint, boxBounds);
1282
- return true;
1283
- }
1229
+ let origin = {}, tempMatrix$1 = core.getMatrixData();
1284
1230
 
1285
- function onLoad(ui, event) {
1286
- emit(ui, core.ImageEvent.LOAD, event);
1287
- }
1231
+ const {get: get$2, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = core.MatrixHelper;
1288
1232
 
1289
- function onLoadSuccess(ui, event) {
1290
- emit(ui, core.ImageEvent.LOADED, event);
1291
- }
1292
-
1293
- function onLoadError(ui, event, error) {
1294
- event.error = error;
1295
- ui.forceUpdate("surface");
1296
- emit(ui, core.ImageEvent.ERROR, event);
1233
+ function stretchMode(data, box, scaleX, scaleY) {
1234
+ const transform = get$2(), {x: x, y: y} = box;
1235
+ if (x || y) translate(transform, x, y); else transform.onlyScale = true;
1236
+ scaleHelper(transform, scaleX, scaleY);
1237
+ data.transform = transform;
1297
1238
  }
1298
1239
 
1299
- function emit(ui, type, data) {
1300
- if (ui.hasEvent(type)) ui.emitEvent(new core.ImageEvent(type, data));
1240
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1241
+ const transform = get$2();
1242
+ translate(transform, box.x + x, box.y + y);
1243
+ scaleHelper(transform, scaleX, scaleY);
1244
+ if (rotation) rotateOfOuter$1(transform, {
1245
+ x: box.x + box.width / 2,
1246
+ y: box.y + box.height / 2
1247
+ }, rotation);
1248
+ data.transform = transform;
1301
1249
  }
1302
1250
 
1303
- function ignoreRender(ui, value) {
1304
- const {leafer: leafer} = ui;
1305
- if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1251
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1252
+ const transform = get$2();
1253
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1254
+ if (clipScaleX) {
1255
+ if (rotation || skew) {
1256
+ set(tempMatrix$1);
1257
+ scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1258
+ multiplyParent(transform, tempMatrix$1);
1259
+ } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1260
+ }
1261
+ data.transform = transform;
1306
1262
  }
1307
1263
 
1308
- const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
1264
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1265
+ const transform = get$2();
1266
+ if (freeTransform) {
1267
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1268
+ } else {
1269
+ if (rotation) {
1270
+ if (align === "center") {
1271
+ rotateOfOuter$1(transform, {
1272
+ x: width / 2,
1273
+ y: height / 2
1274
+ }, rotation);
1275
+ } else {
1276
+ rotate(transform, rotation);
1277
+ switch (rotation) {
1278
+ case 90:
1279
+ translate(transform, height, 0);
1280
+ break;
1309
1281
 
1310
- const {floor: floor, ceil: ceil, max: max$1, abs: abs$1} = Math;
1282
+ case 180:
1283
+ translate(transform, width, height);
1284
+ break;
1311
1285
 
1312
- function createPattern(ui, paint, pixelRatio) {
1313
- let {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
1314
- const id = scaleX + "-" + scaleY + "-" + pixelRatio;
1315
- if (paint.patternId !== id && !ui.destroyed) {
1316
- const {image: image, data: data} = paint;
1317
- let imageScale, imageMatrix, {width: width, height: height, scaleX: sx, scaleY: sy, transform: transform, repeat: repeat, gap: gap} = data;
1318
- scaleX *= pixelRatio;
1319
- scaleY *= pixelRatio;
1320
- if (sx) {
1321
- sx = abs$1(sx);
1322
- sy = abs$1(sy);
1323
- imageMatrix = get$1();
1324
- copy$1(imageMatrix, transform);
1325
- scale(imageMatrix, 1 / sx, 1 / sy);
1326
- scaleX *= sx;
1327
- scaleY *= sy;
1328
- }
1329
- width *= scaleX;
1330
- height *= scaleY;
1331
- const size = width * height;
1332
- if (!repeat) {
1333
- if (size > core.Platform.image.maxCacheSize) return false;
1334
- }
1335
- let maxSize = core.Platform.image.maxPatternSize;
1336
- if (image.isSVG) {
1337
- const ws = width / image.width;
1338
- if (ws > 1) imageScale = ws / ceil(ws);
1339
- } else {
1340
- const imageSize = image.width * image.height;
1341
- if (maxSize > imageSize) maxSize = imageSize;
1342
- }
1343
- if (size > maxSize) imageScale = Math.sqrt(size / maxSize);
1344
- if (imageScale) {
1345
- scaleX /= imageScale;
1346
- scaleY /= imageScale;
1347
- width /= imageScale;
1348
- height /= imageScale;
1349
- }
1350
- if (sx) {
1351
- scaleX /= sx;
1352
- scaleY /= sy;
1353
- }
1354
- const xGap = gap && gap.x * scaleX;
1355
- const yGap = gap && gap.y * scaleY;
1356
- if (transform || scaleX !== 1 || scaleY !== 1) {
1357
- const canvasWidth = width + (xGap || 0);
1358
- const canvasHeight = height + (yGap || 0);
1359
- scaleX /= canvasWidth / max$1(floor(canvasWidth), 1);
1360
- scaleY /= canvasHeight / max$1(floor(canvasHeight), 1);
1361
- if (!imageMatrix) {
1362
- imageMatrix = get$1();
1363
- if (transform) copy$1(imageMatrix, transform);
1286
+ case 270:
1287
+ translate(transform, 0, width);
1288
+ break;
1289
+ }
1364
1290
  }
1365
- scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1366
1291
  }
1367
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1368
- const pattern = image.getPattern(canvas, repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1369
- paint.style = pattern;
1370
- paint.patternId = id;
1371
- return true;
1372
- } else {
1373
- return false;
1292
+ origin.x = box.x + x;
1293
+ origin.y = box.y + y;
1294
+ translate(transform, origin.x, origin.y);
1295
+ if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1374
1296
  }
1297
+ data.transform = transform;
1298
+ }
1299
+
1300
+ function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1301
+ if (rotation) rotate(transform, rotation);
1302
+ if (skew) skewHelper(transform, skew.x, skew.y);
1303
+ if (scaleX) scaleHelper(transform, scaleX, scaleY);
1304
+ translate(transform, box.x + x, box.y + y);
1375
1305
  }
1376
1306
 
1377
1307
  function __awaiter(thisArg, _arguments, P, generator) {
@@ -1407,58 +1337,116 @@ typeof SuppressedError === "function" ? SuppressedError : function(error, suppre
1407
1337
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1408
1338
  };
1409
1339
 
1410
- function checkImage(ui, canvas, paint, allowDraw) {
1411
- const {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
1412
- const {pixelRatio: pixelRatio} = canvas, {data: data} = paint;
1413
- if (!data || paint.patternId === scaleX + "-" + scaleY + "-" + pixelRatio && !draw.Export.running) {
1340
+ const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
1341
+
1342
+ const {getFloorScale: getFloorScale} = core.MathHelper, {abs: abs$1} = Math;
1343
+
1344
+ function createPatternTask(paint, ui, canvas, renderOptions) {
1345
+ if (!paint.patternTask) {
1346
+ paint.patternTask = core.ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
1347
+ paint.patternTask = null;
1348
+ if (canvas.bounds.hit(ui.__nowWorld)) draw.PaintImage.createPattern(paint, ui, canvas, renderOptions);
1349
+ ui.forceUpdate("surface");
1350
+ }), 300);
1351
+ }
1352
+ }
1353
+
1354
+ function createPattern(paint, ui, canvas, renderOptions) {
1355
+ let {scaleX: scaleX, scaleY: scaleY} = draw.PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions), id = scaleX + "-" + scaleY;
1356
+ if (paint.patternId !== id && !ui.destroyed) {
1357
+ if (!(core.Platform.image.isLarge(paint.image, scaleX, scaleY) && !paint.data.repeat)) {
1358
+ const {image: image, data: data} = paint, {transform: transform, gap: gap} = data, fixScale = draw.PaintImage.getPatternFixScale(paint, scaleX, scaleY);
1359
+ let imageMatrix, xGap, yGap, {width: width, height: height} = image;
1360
+ if (fixScale) scaleX *= fixScale, scaleY *= fixScale;
1361
+ width *= scaleX;
1362
+ height *= scaleY;
1363
+ if (gap) {
1364
+ xGap = gap.x * scaleX / abs$1(data.scaleX || 1);
1365
+ yGap = gap.y * scaleY / abs$1(data.scaleY || 1);
1366
+ }
1367
+ if (transform || scaleX !== 1 || scaleY !== 1) {
1368
+ scaleX *= getFloorScale(width + (xGap || 0));
1369
+ scaleY *= getFloorScale(height + (yGap || 0));
1370
+ imageMatrix = get$1();
1371
+ if (transform) copy$1(imageMatrix, transform);
1372
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1373
+ }
1374
+ const imageCanvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1375
+ const pattern = image.getPattern(imageCanvas, data.repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1376
+ paint.style = pattern;
1377
+ paint.patternId = id;
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ function getPatternFixScale(paint, imageScaleX, imageScaleY) {
1383
+ const {image: image} = paint;
1384
+ let fixScale, maxSize = core.Platform.image.maxPatternSize, imageSize = image.width * image.height;
1385
+ if (image.isSVG) {
1386
+ if (imageScaleX > 1) fixScale = Math.ceil(imageScaleX) / imageScaleX;
1387
+ } else {
1388
+ if (maxSize > imageSize) maxSize = imageSize;
1389
+ }
1390
+ if ((imageSize *= imageScaleX * imageScaleY) > maxSize) fixScale = Math.sqrt(maxSize / imageSize);
1391
+ return fixScale;
1392
+ }
1393
+
1394
+ function checkImage(paint, drawImage, ui, canvas, renderOptions) {
1395
+ const {scaleX: scaleX, scaleY: scaleY} = draw.PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions);
1396
+ const {image: image, data: data} = paint, {exporting: exporting} = renderOptions;
1397
+ if (!data || paint.patternId === scaleX + "-" + scaleY && !exporting) {
1414
1398
  return false;
1415
1399
  } else {
1416
- if (allowDraw) {
1400
+ if (drawImage) {
1417
1401
  if (data.repeat) {
1418
- allowDraw = false;
1419
- } else if (!(paint.changeful || core.Platform.name === "miniapp" && core.ResizeEvent.isResizing(ui) || draw.Export.running)) {
1420
- let {width: width, height: height} = data;
1421
- width *= scaleX * pixelRatio;
1422
- height *= scaleY * pixelRatio;
1423
- if (data.scaleX) {
1424
- width *= data.scaleX;
1425
- height *= data.scaleY;
1426
- }
1427
- allowDraw = width * height > core.Platform.image.maxCacheSize;
1402
+ drawImage = false;
1403
+ } else if (!(paint.changeful || core.Platform.name === "miniapp" && core.ResizeEvent.isResizing(ui) || exporting)) {
1404
+ drawImage = core.Platform.image.isLarge(image, scaleX, scaleY);
1428
1405
  }
1429
1406
  }
1430
- if (allowDraw) {
1407
+ if (drawImage) {
1431
1408
  if (ui.__.__isFastShadow) {
1432
1409
  canvas.fillStyle = paint.style || "#000";
1433
1410
  canvas.fill();
1434
1411
  }
1435
- drawImage(ui, canvas, paint, data);
1412
+ draw.PaintImage.drawImage(paint, scaleX, scaleY, ui, canvas, renderOptions);
1436
1413
  return true;
1437
1414
  } else {
1438
- if (!paint.style || paint.sync || draw.Export.running) {
1439
- createPattern(ui, paint, pixelRatio);
1440
- } else {
1441
- if (!paint.patternTask) {
1442
- paint.patternTask = core.ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
1443
- paint.patternTask = null;
1444
- if (canvas.bounds.hit(ui.__nowWorld)) createPattern(ui, paint, pixelRatio);
1445
- ui.forceUpdate("surface");
1446
- }), 300);
1447
- }
1448
- }
1415
+ if (!paint.style || paint.sync || exporting) draw.PaintImage.createPattern(paint, ui, canvas, renderOptions); else draw.PaintImage.createPatternTask(paint, ui, canvas, renderOptions);
1449
1416
  return false;
1450
1417
  }
1451
1418
  }
1452
1419
  }
1453
1420
 
1454
- function drawImage(ui, canvas, paint, data) {
1455
- canvas.save();
1456
- canvas.clipUI(ui);
1457
- if (paint.blendMode) canvas.blendMode = paint.blendMode;
1458
- if (data.opacity) canvas.opacity *= data.opacity;
1459
- if (data.transform) canvas.transform(data.transform);
1460
- canvas.drawImage(paint.image.getFull(data.filters), 0, 0, data.width, data.height);
1461
- canvas.restore();
1421
+ function drawImage(paint, _imageScaleX, _imageScaleY, ui, canvas, _renderOptions) {
1422
+ const {data: data, image: image, blendMode: blendMode} = paint, {opacity: opacity, transform: transform} = data, view = image.getFull(data.filters), u = ui.__;
1423
+ let {width: width, height: height} = image, clipUI;
1424
+ if (transform && !transform.onlyScale || (clipUI = u.path || u.cornerRadius) || opacity || blendMode) {
1425
+ canvas.save();
1426
+ clipUI && canvas.clipUI(ui);
1427
+ blendMode && (canvas.blendMode = blendMode);
1428
+ opacity && (canvas.opacity *= opacity);
1429
+ transform && canvas.transform(transform);
1430
+ canvas.drawImage(view, 0, 0, width, height);
1431
+ canvas.restore();
1432
+ } else {
1433
+ if (data.scaleX) width *= data.scaleX, height *= data.scaleY;
1434
+ canvas.drawImage(view, 0, 0, width, height);
1435
+ }
1436
+ }
1437
+
1438
+ function getImageRenderScaleData(paint, ui, canvas, _renderOptions) {
1439
+ const scaleData = ui.getRenderScaleData(true, paint.scaleFixed), {data: data} = paint;
1440
+ if (canvas) {
1441
+ const {pixelRatio: pixelRatio} = canvas;
1442
+ scaleData.scaleX *= pixelRatio;
1443
+ scaleData.scaleY *= pixelRatio;
1444
+ }
1445
+ if (data && data.scaleX) {
1446
+ scaleData.scaleX *= Math.abs(data.scaleX);
1447
+ scaleData.scaleY *= Math.abs(data.scaleY);
1448
+ }
1449
+ return scaleData;
1462
1450
  }
1463
1451
 
1464
1452
  function recycleImage(attrName, data) {
@@ -1490,8 +1478,12 @@ function recycleImage(attrName, data) {
1490
1478
  const PaintImageModule = {
1491
1479
  image: image,
1492
1480
  checkImage: checkImage,
1493
- createPattern: createPattern,
1481
+ drawImage: drawImage,
1482
+ getImageRenderScaleData: getImageRenderScaleData,
1494
1483
  recycleImage: recycleImage,
1484
+ createPatternTask: createPatternTask,
1485
+ createPattern: createPattern,
1486
+ getPatternFixScale: getPatternFixScale,
1495
1487
  createData: createData,
1496
1488
  getPatternData: getPatternData,
1497
1489
  stretchMode: stretchMode,
@@ -1947,10 +1939,8 @@ function createRows(drawData, content, style) {
1947
1939
  bounds = drawData.bounds;
1948
1940
  findMaxWidth = !bounds.width && !style.autoSizeAlign;
1949
1941
  const {__letterSpacing: __letterSpacing, paraIndent: paraIndent, textCase: textCase} = style;
1950
- const {canvas: canvas} = core.Platform;
1951
- const {width: width, height: height} = bounds;
1952
- const charMode = width || height || __letterSpacing || textCase !== "none";
1953
- if (charMode) {
1942
+ const {canvas: canvas} = core.Platform, {width: width} = bounds;
1943
+ if (style.__isCharMode) {
1954
1944
  const wrap = style.textWrap !== "none";
1955
1945
  const breakAll = style.textWrap === "break";
1956
1946
  paraStart = true;
@@ -2079,12 +2069,19 @@ const TextMode = 2;
2079
2069
  function layoutChar(drawData, style, width, _height) {
2080
2070
  const {rows: rows} = drawData;
2081
2071
  const {textAlign: textAlign, paraIndent: paraIndent, letterSpacing: letterSpacing} = style;
2082
- let charX, addWordWidth, indentWidth, mode, wordChar, wordsLength;
2072
+ const justifyLast = width && textAlign.includes("both");
2073
+ const justify = justifyLast || width && textAlign.includes("justify");
2074
+ const justifyLetter = justify && textAlign.includes("letter");
2075
+ let charX, remainingWidth, addWordWidth, addLetterWidth, indentWidth, mode, wordChar, wordsLength, isLastWord, canJustify;
2083
2076
  rows.forEach(row => {
2084
2077
  if (row.words) {
2085
2078
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0, wordsLength = row.words.length;
2086
- addWordWidth = width && (textAlign === "justify" || textAlign === "both") && wordsLength > 1 ? (width - row.width - indentWidth) / (wordsLength - 1) : 0;
2087
- mode = letterSpacing || row.isOverflow ? CharMode : addWordWidth > .01 ? WordMode : TextMode;
2079
+ if (justify) {
2080
+ canJustify = !row.paraEnd || justifyLast;
2081
+ remainingWidth = width - row.width - indentWidth;
2082
+ if (justifyLetter) addLetterWidth = remainingWidth / (row.words.reduce((total, item) => total + item.data.length, 0) - 1); else addWordWidth = wordsLength > 1 ? remainingWidth / (wordsLength - 1) : 0;
2083
+ }
2084
+ mode = letterSpacing || row.isOverflow || justifyLetter ? CharMode : addWordWidth ? WordMode : TextMode;
2088
2085
  if (row.isOverflow && !letterSpacing) row.textMode = true;
2089
2086
  if (mode === TextMode) {
2090
2087
  row.x += indentWidth;
@@ -2102,11 +2099,15 @@ function layoutChar(drawData, style, width, _height) {
2102
2099
  charX = toWordChar(word.data, charX, wordChar);
2103
2100
  if (row.isOverflow || wordChar.char !== " ") row.data.push(wordChar);
2104
2101
  } else {
2105
- charX = toChar(word.data, charX, row.data, row.isOverflow);
2102
+ charX = toChar(word.data, charX, row.data, row.isOverflow, canJustify && addLetterWidth);
2106
2103
  }
2107
- if (addWordWidth && (!row.paraEnd || textAlign === "both") && index !== wordsLength - 1) {
2108
- charX += addWordWidth;
2109
- row.width += addWordWidth;
2104
+ if (canJustify) {
2105
+ isLastWord = index === wordsLength - 1;
2106
+ if (addWordWidth) {
2107
+ if (!isLastWord) charX += addWordWidth, row.width += addWordWidth;
2108
+ } else if (addLetterWidth) {
2109
+ row.width += addLetterWidth * (word.data.length - (isLastWord ? 1 : 0));
2110
+ }
2110
2111
  }
2111
2112
  });
2112
2113
  }
@@ -2132,13 +2133,14 @@ function toWordChar(data, charX, wordChar) {
2132
2133
  return charX;
2133
2134
  }
2134
2135
 
2135
- function toChar(data, charX, rowData, isOverflow) {
2136
+ function toChar(data, charX, rowData, isOverflow, addLetterWidth) {
2136
2137
  data.forEach(char => {
2137
2138
  if (isOverflow || char.char !== " ") {
2138
2139
  char.x = charX;
2139
2140
  rowData.push(char);
2140
2141
  }
2141
2142
  charX += char.width;
2143
+ addLetterWidth && (charX += addLetterWidth);
2142
2144
  });
2143
2145
  return charX;
2144
2146
  }
@@ -2280,10 +2282,10 @@ function getDrawData(content, style) {
2280
2282
  let x = 0, y = 0;
2281
2283
  let width = style.__getInput("width") || 0;
2282
2284
  let height = style.__getInput("height") || 0;
2283
- const {textDecoration: textDecoration, __font: __font, __padding: padding} = style;
2285
+ const {__padding: padding} = style;
2284
2286
  if (padding) {
2285
- if (width) x = padding[left], width -= padding[right] + padding[left]; else if (!style.autoSizeAlign) x = padding[left];
2286
- if (height) y = padding[top], height -= padding[top] + padding[bottom]; else if (!style.autoSizeAlign) y = padding[top];
2287
+ if (width) x = padding[left], width -= padding[right] + padding[left], !width && (width = .01); else if (!style.autoSizeAlign) x = padding[left];
2288
+ if (height) y = padding[top], height -= padding[top] + padding[bottom], !height && (height = .01); else if (!style.autoSizeAlign) y = padding[top];
2287
2289
  }
2288
2290
  const drawData = {
2289
2291
  bounds: {
@@ -2294,14 +2296,14 @@ function getDrawData(content, style) {
2294
2296
  },
2295
2297
  rows: [],
2296
2298
  paraNumber: 0,
2297
- font: core.Platform.canvas.font = __font
2299
+ font: core.Platform.canvas.font = style.__font
2298
2300
  };
2299
2301
  createRows(drawData, content, style);
2300
2302
  if (padding) padAutoText(padding, drawData, style, width, height);
2301
2303
  layoutText(drawData, style);
2302
- layoutChar(drawData, style, width);
2304
+ if (style.__isCharMode) layoutChar(drawData, style, width);
2303
2305
  if (drawData.overflow) clipText(drawData, style, x, width);
2304
- if (textDecoration !== "none") decorationText(drawData, style);
2306
+ if (style.textDecoration !== "none") decorationText(drawData, style);
2305
2307
  return drawData;
2306
2308
  }
2307
2309