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