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