@leafer-draw/miniapp 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/miniapp.cjs CHANGED
@@ -815,36 +815,19 @@ core.Platform.render = function(target, canvas, options) {
815
815
  if (options.topList.length) options.topList.forEach(item => item.__render(canvas, topOptions));
816
816
  };
817
817
 
818
- function fillText(ui, canvas) {
819
- const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
820
- if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
821
- let row;
822
- for (let i = 0, len = rows.length; i < len; i++) {
823
- row = rows[i];
824
- if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
825
- canvas.fillText(charData.char, charData.x, row.y);
826
- });
827
- }
828
- if (decorationY) {
829
- const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
830
- if (decorationColor) canvas.fillStyle = decorationColor;
831
- rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
832
- }
833
- }
834
-
835
- function fill(fill, ui, canvas) {
818
+ function fill(fill, ui, canvas, renderOptions) {
836
819
  canvas.fillStyle = fill;
837
- fillPathOrText(ui, canvas);
820
+ fillPathOrText(ui, canvas, renderOptions);
838
821
  }
839
822
 
840
- function fills(fills, ui, canvas) {
823
+ function fills(fills, ui, canvas, renderOptions) {
841
824
  let item;
842
825
  for (let i = 0, len = fills.length; i < len; i++) {
843
826
  item = fills[i];
844
827
  if (item.image) {
845
- if (draw.PaintImage.checkImage(ui, canvas, item, !ui.__.__font)) continue;
828
+ if (draw.PaintImage.checkImage(item, !ui.__.__font, ui, canvas, renderOptions)) continue;
846
829
  if (!item.style) {
847
- if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(canvas, item.image);
830
+ if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(item.image, canvas, renderOptions);
848
831
  continue;
849
832
  }
850
833
  }
@@ -857,60 +840,137 @@ function fills(fills, ui, canvas) {
857
840
  if (item.scaleFixed === true || item.scaleFixed === "zoom-in" && scaleX > 1 && scaleY > 1) canvas.scale(1 / scaleX, 1 / scaleY);
858
841
  }
859
842
  if (item.blendMode) canvas.blendMode = item.blendMode;
860
- fillPathOrText(ui, canvas);
843
+ fillPathOrText(ui, canvas, renderOptions);
861
844
  canvas.restore();
862
845
  } else {
863
846
  if (item.blendMode) {
864
847
  canvas.saveBlendMode(item.blendMode);
865
- fillPathOrText(ui, canvas);
848
+ fillPathOrText(ui, canvas, renderOptions);
866
849
  canvas.restoreBlendMode();
867
- } else fillPathOrText(ui, canvas);
850
+ } else fillPathOrText(ui, canvas, renderOptions);
851
+ }
852
+ }
853
+ }
854
+
855
+ function fillPathOrText(ui, canvas, renderOptions) {
856
+ ui.__.__font ? draw.Paint.fillText(ui, canvas, renderOptions) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
857
+ }
858
+
859
+ function fillText(ui, canvas, _renderOptions) {
860
+ const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
861
+ if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
862
+ let row;
863
+ for (let i = 0, len = rows.length; i < len; i++) {
864
+ row = rows[i];
865
+ if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
866
+ canvas.fillText(charData.char, charData.x, row.y);
867
+ });
868
+ }
869
+ if (decorationY) {
870
+ const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
871
+ if (decorationColor) canvas.fillStyle = decorationColor;
872
+ rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
873
+ }
874
+ }
875
+
876
+ function stroke(stroke, ui, canvas, renderOptions) {
877
+ const data = ui.__;
878
+ if (!data.__strokeWidth) return;
879
+ if (data.__font) {
880
+ draw.Paint.strokeText(stroke, ui, canvas, renderOptions);
881
+ } else {
882
+ switch (data.strokeAlign) {
883
+ case "center":
884
+ drawCenter$1(stroke, 1, ui, canvas, renderOptions);
885
+ break;
886
+
887
+ case "inside":
888
+ drawInside(stroke, ui, canvas, renderOptions);
889
+ break;
890
+
891
+ case "outside":
892
+ drawOutside(stroke, ui, canvas, renderOptions);
893
+ break;
868
894
  }
869
895
  }
870
896
  }
871
897
 
872
- function fillPathOrText(ui, canvas) {
873
- ui.__.__font ? fillText(ui, canvas) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
898
+ function strokes(strokes, ui, canvas, renderOptions) {
899
+ draw.Paint.stroke(strokes, ui, canvas, renderOptions);
900
+ }
901
+
902
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas, renderOptions) {
903
+ const data = ui.__;
904
+ if (core.isObject(stroke)) {
905
+ draw.Paint.drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas, renderOptions);
906
+ } else {
907
+ canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
908
+ canvas.stroke();
909
+ }
910
+ if (data.__useArrow) draw.Paint.strokeArrow(stroke, ui, canvas, renderOptions);
911
+ }
912
+
913
+ function drawInside(stroke, ui, canvas, renderOptions) {
914
+ canvas.save();
915
+ canvas.clipUI(ui);
916
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
917
+ canvas.restore();
874
918
  }
875
919
 
876
- function strokeText(stroke, ui, canvas) {
920
+ function drawOutside(stroke, ui, canvas, renderOptions) {
921
+ const data = ui.__;
922
+ if (data.__fillAfterStroke) {
923
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
924
+ } else {
925
+ const {renderBounds: renderBounds} = ui.__layout;
926
+ const out = canvas.getSameCanvas(true, true);
927
+ ui.__drawRenderPath(out);
928
+ drawCenter$1(stroke, 2, ui, out, renderOptions);
929
+ out.clipUI(data);
930
+ out.clearWorld(renderBounds);
931
+ core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
932
+ out.recycle(ui.__nowWorld);
933
+ }
934
+ }
935
+
936
+ function strokeText(stroke, ui, canvas, renderOptions) {
877
937
  switch (ui.__.strokeAlign) {
878
938
  case "center":
879
- drawCenter$1(stroke, 1, ui, canvas);
939
+ drawCenter(stroke, 1, ui, canvas, renderOptions);
880
940
  break;
881
941
 
882
942
  case "inside":
883
- drawAlign(stroke, "inside", ui, canvas);
943
+ drawAlign(stroke, "inside", ui, canvas, renderOptions);
884
944
  break;
885
945
 
886
946
  case "outside":
887
- ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, "outside", ui, canvas);
947
+ ui.__.__fillAfterStroke ? drawCenter(stroke, 2, ui, canvas, renderOptions) : drawAlign(stroke, "outside", ui, canvas, renderOptions);
888
948
  break;
889
949
  }
890
950
  }
891
951
 
892
- function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
952
+ function drawCenter(stroke, strokeWidthScale, ui, canvas, renderOptions) {
893
953
  const data = ui.__;
894
954
  if (core.isObject(stroke)) {
895
- drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas);
955
+ draw.Paint.drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas, renderOptions);
896
956
  } else {
897
957
  canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
898
- drawTextStroke(ui, canvas);
958
+ draw.Paint.drawTextStroke(ui, canvas, renderOptions);
899
959
  }
900
960
  }
901
961
 
902
- function drawAlign(stroke, align, ui, canvas) {
962
+ function drawAlign(stroke, align, ui, canvas, renderOptions) {
903
963
  const out = canvas.getSameCanvas(true, true);
904
964
  out.font = ui.__.__font;
905
- drawCenter$1(stroke, 2, ui, out);
965
+ drawCenter(stroke, 2, ui, out, renderOptions);
906
966
  out.blendMode = align === "outside" ? "destination-out" : "destination-in";
907
- fillText(ui, out);
967
+ draw.Paint.fillText(ui, out, renderOptions);
908
968
  out.blendMode = "normal";
909
969
  core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
910
970
  out.recycle(ui.__nowWorld);
911
971
  }
912
972
 
913
- function drawTextStroke(ui, canvas) {
973
+ function drawTextStroke(ui, canvas, _renderOptions) {
914
974
  let row, data = ui.__.__textDrawData;
915
975
  const {rows: rows, decorationY: decorationY} = data;
916
976
  for (let i = 0, len = rows.length; i < len; i++) {
@@ -925,13 +985,13 @@ function drawTextStroke(ui, canvas) {
925
985
  }
926
986
  }
927
987
 
928
- function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
988
+ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas, renderOptions) {
929
989
  let item;
930
990
  const data = ui.__, {__hasMultiStrokeStyle: __hasMultiStrokeStyle} = data;
931
991
  __hasMultiStrokeStyle || canvas.setStroke(undefined, data.__strokeWidth * strokeWidthScale, data);
932
992
  for (let i = 0, len = strokes.length; i < len; i++) {
933
993
  item = strokes[i];
934
- if (item.image && draw.PaintImage.checkImage(ui, canvas, item, false)) continue;
994
+ if (item.image && draw.PaintImage.checkImage(item, false, ui, canvas, renderOptions)) continue;
935
995
  if (item.style) {
936
996
  if (__hasMultiStrokeStyle) {
937
997
  const {strokeStyle: strokeStyle} = item;
@@ -939,75 +999,15 @@ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
939
999
  } else canvas.strokeStyle = item.style;
940
1000
  if (item.blendMode) {
941
1001
  canvas.saveBlendMode(item.blendMode);
942
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1002
+ isText ? draw.Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
943
1003
  canvas.restoreBlendMode();
944
1004
  } else {
945
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1005
+ isText ? draw.Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
946
1006
  }
947
1007
  }
948
1008
  }
949
1009
  }
950
1010
 
951
- function stroke(stroke, ui, canvas) {
952
- const data = ui.__;
953
- if (!data.__strokeWidth) return;
954
- if (data.__font) {
955
- strokeText(stroke, ui, canvas);
956
- } else {
957
- switch (data.strokeAlign) {
958
- case "center":
959
- drawCenter(stroke, 1, ui, canvas);
960
- break;
961
-
962
- case "inside":
963
- drawInside(stroke, ui, canvas);
964
- break;
965
-
966
- case "outside":
967
- drawOutside(stroke, ui, canvas);
968
- break;
969
- }
970
- }
971
- }
972
-
973
- function strokes(strokes, ui, canvas) {
974
- stroke(strokes, ui, canvas);
975
- }
976
-
977
- function drawCenter(stroke, strokeWidthScale, ui, canvas) {
978
- const data = ui.__;
979
- if (core.isObject(stroke)) {
980
- drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas);
981
- } else {
982
- canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
983
- canvas.stroke();
984
- }
985
- if (data.__useArrow) draw.Paint.strokeArrow(stroke, ui, canvas);
986
- }
987
-
988
- function drawInside(stroke, ui, canvas) {
989
- canvas.save();
990
- canvas.clipUI(ui);
991
- drawCenter(stroke, 2, ui, canvas);
992
- canvas.restore();
993
- }
994
-
995
- function drawOutside(stroke, ui, canvas) {
996
- const data = ui.__;
997
- if (data.__fillAfterStroke) {
998
- drawCenter(stroke, 2, ui, canvas);
999
- } else {
1000
- const {renderBounds: renderBounds} = ui.__layout;
1001
- const out = canvas.getSameCanvas(true, true);
1002
- ui.__drawRenderPath(out);
1003
- drawCenter(stroke, 2, ui, out);
1004
- out.clipUI(data);
1005
- out.clearWorld(renderBounds);
1006
- core.LeafHelper.copyCanvasByWorld(ui, canvas, out);
1007
- out.recycle(ui.__nowWorld);
1008
- }
1009
- }
1010
-
1011
1011
  const {getSpread: getSpread, copyAndSpread: copyAndSpread, toOuterOf: toOuterOf, getOuterOf: getOuterOf, getByMove: getByMove, move: move$1, getIntersectData: getIntersectData} = core.BoundsHelper;
1012
1012
 
1013
1013
  const tempBounds$1 = {};
@@ -1163,88 +1163,118 @@ const PaintModule = {
1163
1163
  strokes: strokes,
1164
1164
  strokeText: strokeText,
1165
1165
  drawTextStroke: drawTextStroke,
1166
+ drawStrokesStyle: drawStrokesStyle,
1166
1167
  shape: shape
1167
1168
  };
1168
1169
 
1169
- let origin = {}, tempMatrix$1 = core.getMatrixData();
1170
+ let cache, box = new core.Bounds;
1170
1171
 
1171
- 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;
1172
+ const {isSame: isSame} = core.BoundsHelper;
1172
1173
 
1173
- function stretchMode(data, box, scaleX, scaleY) {
1174
- const transform = get$3();
1175
- translate$1(transform, box.x, box.y);
1176
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1177
- data.transform = transform;
1174
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1175
+ let leafPaint, event;
1176
+ const image = core.ImageManager.get(paint);
1177
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1178
+ leafPaint = cache.leafPaint;
1179
+ } else {
1180
+ leafPaint = {
1181
+ type: paint.type,
1182
+ image: image
1183
+ };
1184
+ if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1185
+ cache = image.use > 1 ? {
1186
+ leafPaint: leafPaint,
1187
+ paint: paint,
1188
+ boxBounds: box.set(boxBounds)
1189
+ } : null;
1190
+ }
1191
+ if (firstUse || image.loading) event = {
1192
+ image: image,
1193
+ attrName: attrName,
1194
+ attrValue: paint
1195
+ };
1196
+ if (image.ready) {
1197
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1198
+ if (firstUse) {
1199
+ onLoad(ui, event);
1200
+ onLoadSuccess(ui, event);
1201
+ }
1202
+ } else if (image.error) {
1203
+ if (firstUse) onLoadError(ui, event, image.error);
1204
+ } else {
1205
+ if (firstUse) {
1206
+ ignoreRender(ui, true);
1207
+ onLoad(ui, event);
1208
+ }
1209
+ leafPaint.loadId = image.load(() => {
1210
+ ignoreRender(ui, false);
1211
+ if (!ui.destroyed) {
1212
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1213
+ if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1214
+ ui.forceUpdate("surface");
1215
+ }
1216
+ onLoadSuccess(ui, event);
1217
+ }
1218
+ leafPaint.loadId = undefined;
1219
+ }, error => {
1220
+ ignoreRender(ui, false);
1221
+ onLoadError(ui, event, error);
1222
+ leafPaint.loadId = undefined;
1223
+ });
1224
+ if (ui.placeholderColor) {
1225
+ if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1226
+ if (!image.ready) {
1227
+ image.isPlacehold = true;
1228
+ ui.forceUpdate("surface");
1229
+ }
1230
+ }, ui.placeholderDelay);
1231
+ }
1232
+ }
1233
+ return leafPaint;
1178
1234
  }
1179
1235
 
1180
- function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1181
- const transform = get$3();
1182
- translate$1(transform, box.x + x, box.y + y);
1183
- scaleHelper(transform, scaleX, scaleY);
1184
- if (rotation) rotateOfOuter$1(transform, {
1185
- x: box.x + box.width / 2,
1186
- y: box.y + box.height / 2
1187
- }, rotation);
1188
- data.transform = transform;
1236
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1237
+ if (attrName === "fill" && !ui.__.__naturalWidth) {
1238
+ const data = ui.__;
1239
+ data.__naturalWidth = image.width / data.pixelRatio;
1240
+ data.__naturalHeight = image.height / data.pixelRatio;
1241
+ if (data.__autoSide) {
1242
+ ui.forceUpdate("width");
1243
+ if (ui.__proxyData) {
1244
+ ui.setProxyAttr("width", data.width);
1245
+ ui.setProxyAttr("height", data.height);
1246
+ }
1247
+ return false;
1248
+ }
1249
+ }
1250
+ if (!leafPaint.data) draw.PaintImage.createData(leafPaint, image, paint, boxBounds);
1251
+ return true;
1189
1252
  }
1190
1253
 
1191
- function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1192
- const transform = get$3();
1193
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1194
- if (clipScaleX) {
1195
- if (rotation || skew) {
1196
- set(tempMatrix$1);
1197
- scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1198
- multiplyParent(transform, tempMatrix$1);
1199
- } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1200
- }
1201
- data.transform = transform;
1254
+ function onLoad(ui, event) {
1255
+ emit(ui, core.ImageEvent.LOAD, event);
1202
1256
  }
1203
1257
 
1204
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1205
- const transform = get$3();
1206
- if (freeTransform) {
1207
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1208
- } else {
1209
- if (rotation) {
1210
- if (align === "center") {
1211
- rotateOfOuter$1(transform, {
1212
- x: width / 2,
1213
- y: height / 2
1214
- }, rotation);
1215
- } else {
1216
- rotate(transform, rotation);
1217
- switch (rotation) {
1218
- case 90:
1219
- translate$1(transform, height, 0);
1220
- break;
1258
+ function onLoadSuccess(ui, event) {
1259
+ emit(ui, core.ImageEvent.LOADED, event);
1260
+ }
1221
1261
 
1222
- case 180:
1223
- translate$1(transform, width, height);
1224
- break;
1262
+ function onLoadError(ui, event, error) {
1263
+ event.error = error;
1264
+ ui.forceUpdate("surface");
1265
+ emit(ui, core.ImageEvent.ERROR, event);
1266
+ }
1225
1267
 
1226
- case 270:
1227
- translate$1(transform, 0, width);
1228
- break;
1229
- }
1230
- }
1231
- }
1232
- origin.x = box.x + x;
1233
- origin.y = box.y + y;
1234
- translate$1(transform, origin.x, origin.y);
1235
- if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1236
- }
1237
- data.transform = transform;
1268
+ function emit(ui, type, data) {
1269
+ if (ui.hasEvent(type)) ui.emitEvent(new core.ImageEvent(type, data));
1238
1270
  }
1239
1271
 
1240
- function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1241
- if (rotation) rotate(transform, rotation);
1242
- if (skew) skewHelper(transform, skew.x, skew.y);
1243
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1244
- translate$1(transform, box.x + x, box.y + y);
1272
+ function ignoreRender(ui, value) {
1273
+ const {leafer: leafer} = ui;
1274
+ if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1245
1275
  }
1246
1276
 
1247
- const {get: get$2, translate: translate} = core.MatrixHelper;
1277
+ const {get: get$3, translate: translate$1} = core.MatrixHelper;
1248
1278
 
1249
1279
  const tempBox = new core.Bounds;
1250
1280
 
@@ -1257,13 +1287,13 @@ function createData(leafPaint, image, paint, box) {
1257
1287
  if (changeful) leafPaint.changeful = changeful;
1258
1288
  if (sync) leafPaint.sync = sync;
1259
1289
  if (scaleFixed) leafPaint.scaleFixed = scaleFixed;
1260
- leafPaint.data = getPatternData(paint, box, image);
1290
+ leafPaint.data = draw.PaintImage.getPatternData(paint, box, image);
1261
1291
  }
1262
1292
 
1263
1293
  function getPatternData(paint, box, image) {
1264
1294
  if (paint.padding) box = tempBox.set(box).shrink(paint.padding);
1265
1295
  if (paint.mode === "strench") paint.mode = "stretch";
1266
- let {width: width, height: height} = image;
1296
+ const {width: width, height: height} = image;
1267
1297
  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;
1268
1298
  const sameBox = box.width === width && box.height === height;
1269
1299
  const data = {
@@ -1294,8 +1324,8 @@ function getPatternData(paint, box, image) {
1294
1324
  case "stretch":
1295
1325
  if (!sameBox) {
1296
1326
  scaleX = box.width / width, scaleY = box.height / height;
1297
- stretchMode(data, box, scaleX, scaleY);
1298
- }
1327
+ draw.PaintImage.stretchMode(data, box, scaleX, scaleY);
1328
+ } else if (scaleX) scaleX = scaleY = undefined;
1299
1329
  break;
1300
1330
 
1301
1331
  case "normal":
@@ -1303,13 +1333,13 @@ function getPatternData(paint, box, image) {
1303
1333
  if (tempImage.x || tempImage.y || scaleX || clipSize || rotation || skew) {
1304
1334
  let clipScaleX, clipScaleY;
1305
1335
  if (clipSize) clipScaleX = box.width / clipSize.width, clipScaleY = box.height / clipSize.height;
1306
- clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1336
+ draw.PaintImage.clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1307
1337
  if (clipScaleX) scaleX = scaleX ? scaleX * clipScaleX : clipScaleX, scaleY = scaleY ? scaleY * clipScaleY : clipScaleY;
1308
1338
  }
1309
1339
  break;
1310
1340
 
1311
1341
  case "repeat":
1312
- if (!sameBox || scaleX || rotation || skew) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1342
+ if (!sameBox || scaleX || rotation || skew) draw.PaintImage.repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1313
1343
  if (!repeat) data.repeat = "repeat";
1314
1344
  const count = core.isObject(repeat);
1315
1345
  if (gap || count) data.gap = getGapData(gap, count && repeat, tempImage.width, tempImage.height, box);
@@ -1318,18 +1348,16 @@ function getPatternData(paint, box, image) {
1318
1348
  case "fit":
1319
1349
  case "cover":
1320
1350
  default:
1321
- if (scaleX) fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1351
+ if (scaleX) draw.PaintImage.fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1322
1352
  }
1323
1353
  if (!data.transform) {
1324
- if (box.x || box.y) translate(data.transform = get$2(), box.x, box.y);
1354
+ if (box.x || box.y) translate$1(data.transform = get$3(), box.x, box.y);
1325
1355
  }
1326
- data.width = width;
1327
- data.height = height;
1328
1356
  if (scaleX) {
1329
1357
  data.scaleX = scaleX;
1330
1358
  data.scaleY = scaleY;
1331
1359
  }
1332
- if (opacity) data.opacity = opacity;
1360
+ if (opacity && opacity < 1) data.opacity = opacity;
1333
1361
  if (filters) data.filters = filters;
1334
1362
  if (repeat) data.repeat = core.isString(repeat) ? repeat === "x" ? "repeat-x" : "repeat-y" : "repeat";
1335
1363
  return data;
@@ -1351,180 +1379,82 @@ function getGapValue(gap, size, totalSize, rows) {
1351
1379
  return gap === "auto" ? value < 0 ? 0 : value : value;
1352
1380
  }
1353
1381
 
1354
- let cache, box = new core.Bounds;
1355
-
1356
- const {isSame: isSame} = core.BoundsHelper;
1357
-
1358
- function image(ui, attrName, paint, boxBounds, firstUse) {
1359
- let leafPaint, event;
1360
- const image = core.ImageManager.get(paint);
1361
- if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1362
- leafPaint = cache.leafPaint;
1363
- } else {
1364
- leafPaint = {
1365
- type: paint.type,
1366
- image: image
1367
- };
1368
- if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1369
- cache = image.use > 1 ? {
1370
- leafPaint: leafPaint,
1371
- paint: paint,
1372
- boxBounds: box.set(boxBounds)
1373
- } : null;
1374
- }
1375
- if (firstUse || image.loading) event = {
1376
- image: image,
1377
- attrName: attrName,
1378
- attrValue: paint
1379
- };
1380
- if (image.ready) {
1381
- checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1382
- if (firstUse) {
1383
- onLoad(ui, event);
1384
- onLoadSuccess(ui, event);
1385
- }
1386
- } else if (image.error) {
1387
- if (firstUse) onLoadError(ui, event, image.error);
1388
- } else {
1389
- if (firstUse) {
1390
- ignoreRender(ui, true);
1391
- onLoad(ui, event);
1392
- }
1393
- leafPaint.loadId = image.load(() => {
1394
- ignoreRender(ui, false);
1395
- if (!ui.destroyed) {
1396
- if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1397
- if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1398
- ui.forceUpdate("surface");
1399
- }
1400
- onLoadSuccess(ui, event);
1401
- }
1402
- leafPaint.loadId = undefined;
1403
- }, error => {
1404
- ignoreRender(ui, false);
1405
- onLoadError(ui, event, error);
1406
- leafPaint.loadId = undefined;
1407
- });
1408
- if (ui.placeholderColor) {
1409
- if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1410
- if (!image.ready) {
1411
- image.isPlacehold = true;
1412
- ui.forceUpdate("surface");
1413
- }
1414
- }, ui.placeholderDelay);
1415
- }
1416
- }
1417
- return leafPaint;
1418
- }
1419
-
1420
- function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1421
- if (attrName === "fill" && !ui.__.__naturalWidth) {
1422
- const data = ui.__;
1423
- data.__naturalWidth = image.width / data.pixelRatio;
1424
- data.__naturalHeight = image.height / data.pixelRatio;
1425
- if (data.__autoSide) {
1426
- ui.forceUpdate("width");
1427
- if (ui.__proxyData) {
1428
- ui.setProxyAttr("width", data.width);
1429
- ui.setProxyAttr("height", data.height);
1430
- }
1431
- return false;
1432
- }
1433
- }
1434
- if (!leafPaint.data) createData(leafPaint, image, paint, boxBounds);
1435
- return true;
1436
- }
1437
-
1438
- function onLoad(ui, event) {
1439
- emit(ui, core.ImageEvent.LOAD, event);
1440
- }
1382
+ let origin = {}, tempMatrix$1 = core.getMatrixData();
1441
1383
 
1442
- function onLoadSuccess(ui, event) {
1443
- emit(ui, core.ImageEvent.LOADED, event);
1444
- }
1384
+ const {get: get$2, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = core.MatrixHelper;
1445
1385
 
1446
- function onLoadError(ui, event, error) {
1447
- event.error = error;
1448
- ui.forceUpdate("surface");
1449
- emit(ui, core.ImageEvent.ERROR, event);
1386
+ function stretchMode(data, box, scaleX, scaleY) {
1387
+ const transform = get$2(), {x: x, y: y} = box;
1388
+ if (x || y) translate(transform, x, y); else transform.onlyScale = true;
1389
+ scaleHelper(transform, scaleX, scaleY);
1390
+ data.transform = transform;
1450
1391
  }
1451
1392
 
1452
- function emit(ui, type, data) {
1453
- if (ui.hasEvent(type)) ui.emitEvent(new core.ImageEvent(type, data));
1393
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1394
+ const transform = get$2();
1395
+ translate(transform, box.x + x, box.y + y);
1396
+ scaleHelper(transform, scaleX, scaleY);
1397
+ if (rotation) rotateOfOuter$1(transform, {
1398
+ x: box.x + box.width / 2,
1399
+ y: box.y + box.height / 2
1400
+ }, rotation);
1401
+ data.transform = transform;
1454
1402
  }
1455
1403
 
1456
- function ignoreRender(ui, value) {
1457
- const {leafer: leafer} = ui;
1458
- if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1404
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1405
+ const transform = get$2();
1406
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1407
+ if (clipScaleX) {
1408
+ if (rotation || skew) {
1409
+ set(tempMatrix$1);
1410
+ scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1411
+ multiplyParent(transform, tempMatrix$1);
1412
+ } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1413
+ }
1414
+ data.transform = transform;
1459
1415
  }
1460
1416
 
1461
- const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
1417
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1418
+ const transform = get$2();
1419
+ if (freeTransform) {
1420
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1421
+ } else {
1422
+ if (rotation) {
1423
+ if (align === "center") {
1424
+ rotateOfOuter$1(transform, {
1425
+ x: width / 2,
1426
+ y: height / 2
1427
+ }, rotation);
1428
+ } else {
1429
+ rotate(transform, rotation);
1430
+ switch (rotation) {
1431
+ case 90:
1432
+ translate(transform, height, 0);
1433
+ break;
1462
1434
 
1463
- const {floor: floor, ceil: ceil, max: max$1, abs: abs$1} = Math;
1435
+ case 180:
1436
+ translate(transform, width, height);
1437
+ break;
1464
1438
 
1465
- function createPattern(ui, paint, pixelRatio) {
1466
- let {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
1467
- const id = scaleX + "-" + scaleY + "-" + pixelRatio;
1468
- if (paint.patternId !== id && !ui.destroyed) {
1469
- const {image: image, data: data} = paint;
1470
- let imageScale, imageMatrix, {width: width, height: height, scaleX: sx, scaleY: sy, transform: transform, repeat: repeat, gap: gap} = data;
1471
- scaleX *= pixelRatio;
1472
- scaleY *= pixelRatio;
1473
- if (sx) {
1474
- sx = abs$1(sx);
1475
- sy = abs$1(sy);
1476
- imageMatrix = get$1();
1477
- copy$1(imageMatrix, transform);
1478
- scale(imageMatrix, 1 / sx, 1 / sy);
1479
- scaleX *= sx;
1480
- scaleY *= sy;
1481
- }
1482
- width *= scaleX;
1483
- height *= scaleY;
1484
- const size = width * height;
1485
- if (!repeat) {
1486
- if (size > core.Platform.image.maxCacheSize) return false;
1487
- }
1488
- let maxSize = core.Platform.image.maxPatternSize;
1489
- if (image.isSVG) {
1490
- const ws = width / image.width;
1491
- if (ws > 1) imageScale = ws / ceil(ws);
1492
- } else {
1493
- const imageSize = image.width * image.height;
1494
- if (maxSize > imageSize) maxSize = imageSize;
1495
- }
1496
- if (size > maxSize) imageScale = Math.sqrt(size / maxSize);
1497
- if (imageScale) {
1498
- scaleX /= imageScale;
1499
- scaleY /= imageScale;
1500
- width /= imageScale;
1501
- height /= imageScale;
1502
- }
1503
- if (sx) {
1504
- scaleX /= sx;
1505
- scaleY /= sy;
1506
- }
1507
- const xGap = gap && gap.x * scaleX;
1508
- const yGap = gap && gap.y * scaleY;
1509
- if (transform || scaleX !== 1 || scaleY !== 1) {
1510
- const canvasWidth = width + (xGap || 0);
1511
- const canvasHeight = height + (yGap || 0);
1512
- scaleX /= canvasWidth / max$1(floor(canvasWidth), 1);
1513
- scaleY /= canvasHeight / max$1(floor(canvasHeight), 1);
1514
- if (!imageMatrix) {
1515
- imageMatrix = get$1();
1516
- if (transform) copy$1(imageMatrix, transform);
1439
+ case 270:
1440
+ translate(transform, 0, width);
1441
+ break;
1442
+ }
1517
1443
  }
1518
- scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1519
1444
  }
1520
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1521
- const pattern = image.getPattern(canvas, repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1522
- paint.style = pattern;
1523
- paint.patternId = id;
1524
- return true;
1525
- } else {
1526
- return false;
1445
+ origin.x = box.x + x;
1446
+ origin.y = box.y + y;
1447
+ translate(transform, origin.x, origin.y);
1448
+ if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1527
1449
  }
1450
+ data.transform = transform;
1451
+ }
1452
+
1453
+ function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1454
+ if (rotation) rotate(transform, rotation);
1455
+ if (skew) skewHelper(transform, skew.x, skew.y);
1456
+ if (scaleX) scaleHelper(transform, scaleX, scaleY);
1457
+ translate(transform, box.x + x, box.y + y);
1528
1458
  }
1529
1459
 
1530
1460
  function __awaiter(thisArg, _arguments, P, generator) {
@@ -1560,58 +1490,116 @@ typeof SuppressedError === "function" ? SuppressedError : function(error, suppre
1560
1490
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1561
1491
  };
1562
1492
 
1563
- function checkImage(ui, canvas, paint, allowDraw) {
1564
- const {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
1565
- const {pixelRatio: pixelRatio} = canvas, {data: data} = paint;
1566
- if (!data || paint.patternId === scaleX + "-" + scaleY + "-" + pixelRatio && !draw.Export.running) {
1493
+ const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
1494
+
1495
+ const {getFloorScale: getFloorScale} = core.MathHelper, {abs: abs$1} = Math;
1496
+
1497
+ function createPatternTask(paint, ui, canvas, renderOptions) {
1498
+ if (!paint.patternTask) {
1499
+ paint.patternTask = core.ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
1500
+ paint.patternTask = null;
1501
+ if (canvas.bounds.hit(ui.__nowWorld)) draw.PaintImage.createPattern(paint, ui, canvas, renderOptions);
1502
+ ui.forceUpdate("surface");
1503
+ }), 300);
1504
+ }
1505
+ }
1506
+
1507
+ function createPattern(paint, ui, canvas, renderOptions) {
1508
+ let {scaleX: scaleX, scaleY: scaleY} = draw.PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions), id = scaleX + "-" + scaleY;
1509
+ if (paint.patternId !== id && !ui.destroyed) {
1510
+ if (!(core.Platform.image.isLarge(paint.image, scaleX, scaleY) && !paint.data.repeat)) {
1511
+ const {image: image, data: data} = paint, {transform: transform, gap: gap} = data, fixScale = draw.PaintImage.getPatternFixScale(paint, scaleX, scaleY);
1512
+ let imageMatrix, xGap, yGap, {width: width, height: height} = image;
1513
+ if (fixScale) scaleX *= fixScale, scaleY *= fixScale;
1514
+ width *= scaleX;
1515
+ height *= scaleY;
1516
+ if (gap) {
1517
+ xGap = gap.x * scaleX / abs$1(data.scaleX || 1);
1518
+ yGap = gap.y * scaleY / abs$1(data.scaleY || 1);
1519
+ }
1520
+ if (transform || scaleX !== 1 || scaleY !== 1) {
1521
+ scaleX *= getFloorScale(width + (xGap || 0));
1522
+ scaleY *= getFloorScale(height + (yGap || 0));
1523
+ imageMatrix = get$1();
1524
+ if (transform) copy$1(imageMatrix, transform);
1525
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1526
+ }
1527
+ const imageCanvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1528
+ const pattern = image.getPattern(imageCanvas, data.repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1529
+ paint.style = pattern;
1530
+ paint.patternId = id;
1531
+ }
1532
+ }
1533
+ }
1534
+
1535
+ function getPatternFixScale(paint, imageScaleX, imageScaleY) {
1536
+ const {image: image} = paint;
1537
+ let fixScale, maxSize = core.Platform.image.maxPatternSize, imageSize = image.width * image.height;
1538
+ if (image.isSVG) {
1539
+ if (imageScaleX > 1) fixScale = Math.ceil(imageScaleX) / imageScaleX;
1540
+ } else {
1541
+ if (maxSize > imageSize) maxSize = imageSize;
1542
+ }
1543
+ if ((imageSize *= imageScaleX * imageScaleY) > maxSize) fixScale = Math.sqrt(maxSize / imageSize);
1544
+ return fixScale;
1545
+ }
1546
+
1547
+ function checkImage(paint, drawImage, ui, canvas, renderOptions) {
1548
+ const {scaleX: scaleX, scaleY: scaleY} = draw.PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions);
1549
+ const {image: image, data: data} = paint, {exporting: exporting} = renderOptions;
1550
+ if (!data || paint.patternId === scaleX + "-" + scaleY && !exporting) {
1567
1551
  return false;
1568
1552
  } else {
1569
- if (allowDraw) {
1553
+ if (drawImage) {
1570
1554
  if (data.repeat) {
1571
- allowDraw = false;
1572
- } else if (!(paint.changeful || core.Platform.name === "miniapp" && core.ResizeEvent.isResizing(ui) || draw.Export.running)) {
1573
- let {width: width, height: height} = data;
1574
- width *= scaleX * pixelRatio;
1575
- height *= scaleY * pixelRatio;
1576
- if (data.scaleX) {
1577
- width *= data.scaleX;
1578
- height *= data.scaleY;
1579
- }
1580
- allowDraw = width * height > core.Platform.image.maxCacheSize;
1555
+ drawImage = false;
1556
+ } else if (!(paint.changeful || core.Platform.name === "miniapp" && core.ResizeEvent.isResizing(ui) || exporting)) {
1557
+ drawImage = core.Platform.image.isLarge(image, scaleX, scaleY);
1581
1558
  }
1582
1559
  }
1583
- if (allowDraw) {
1560
+ if (drawImage) {
1584
1561
  if (ui.__.__isFastShadow) {
1585
1562
  canvas.fillStyle = paint.style || "#000";
1586
1563
  canvas.fill();
1587
1564
  }
1588
- drawImage(ui, canvas, paint, data);
1565
+ draw.PaintImage.drawImage(paint, scaleX, scaleY, ui, canvas, renderOptions);
1589
1566
  return true;
1590
1567
  } else {
1591
- if (!paint.style || paint.sync || draw.Export.running) {
1592
- createPattern(ui, paint, pixelRatio);
1593
- } else {
1594
- if (!paint.patternTask) {
1595
- paint.patternTask = core.ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
1596
- paint.patternTask = null;
1597
- if (canvas.bounds.hit(ui.__nowWorld)) createPattern(ui, paint, pixelRatio);
1598
- ui.forceUpdate("surface");
1599
- }), 300);
1600
- }
1601
- }
1568
+ if (!paint.style || paint.sync || exporting) draw.PaintImage.createPattern(paint, ui, canvas, renderOptions); else draw.PaintImage.createPatternTask(paint, ui, canvas, renderOptions);
1602
1569
  return false;
1603
1570
  }
1604
1571
  }
1605
1572
  }
1606
1573
 
1607
- function drawImage(ui, canvas, paint, data) {
1608
- canvas.save();
1609
- canvas.clipUI(ui);
1610
- if (paint.blendMode) canvas.blendMode = paint.blendMode;
1611
- if (data.opacity) canvas.opacity *= data.opacity;
1612
- if (data.transform) canvas.transform(data.transform);
1613
- canvas.drawImage(paint.image.getFull(data.filters), 0, 0, data.width, data.height);
1614
- canvas.restore();
1574
+ function drawImage(paint, _imageScaleX, _imageScaleY, ui, canvas, _renderOptions) {
1575
+ const {data: data, image: image, blendMode: blendMode} = paint, {opacity: opacity, transform: transform} = data, view = image.getFull(data.filters), u = ui.__;
1576
+ let {width: width, height: height} = image, clipUI;
1577
+ if (transform && !transform.onlyScale || (clipUI = u.path || u.cornerRadius) || opacity || blendMode) {
1578
+ canvas.save();
1579
+ clipUI && canvas.clipUI(ui);
1580
+ blendMode && (canvas.blendMode = blendMode);
1581
+ opacity && (canvas.opacity *= opacity);
1582
+ transform && canvas.transform(transform);
1583
+ canvas.drawImage(view, 0, 0, width, height);
1584
+ canvas.restore();
1585
+ } else {
1586
+ if (data.scaleX) width *= data.scaleX, height *= data.scaleY;
1587
+ canvas.drawImage(view, 0, 0, width, height);
1588
+ }
1589
+ }
1590
+
1591
+ function getImageRenderScaleData(paint, ui, canvas, _renderOptions) {
1592
+ const scaleData = ui.getRenderScaleData(true, paint.scaleFixed), {data: data} = paint;
1593
+ if (canvas) {
1594
+ const {pixelRatio: pixelRatio} = canvas;
1595
+ scaleData.scaleX *= pixelRatio;
1596
+ scaleData.scaleY *= pixelRatio;
1597
+ }
1598
+ if (data && data.scaleX) {
1599
+ scaleData.scaleX *= Math.abs(data.scaleX);
1600
+ scaleData.scaleY *= Math.abs(data.scaleY);
1601
+ }
1602
+ return scaleData;
1615
1603
  }
1616
1604
 
1617
1605
  function recycleImage(attrName, data) {
@@ -1643,8 +1631,12 @@ function recycleImage(attrName, data) {
1643
1631
  const PaintImageModule = {
1644
1632
  image: image,
1645
1633
  checkImage: checkImage,
1646
- createPattern: createPattern,
1634
+ drawImage: drawImage,
1635
+ getImageRenderScaleData: getImageRenderScaleData,
1647
1636
  recycleImage: recycleImage,
1637
+ createPatternTask: createPatternTask,
1638
+ createPattern: createPattern,
1639
+ getPatternFixScale: getPatternFixScale,
1648
1640
  createData: createData,
1649
1641
  getPatternData: getPatternData,
1650
1642
  stretchMode: stretchMode,
@@ -2100,10 +2092,8 @@ function createRows(drawData, content, style) {
2100
2092
  bounds = drawData.bounds;
2101
2093
  findMaxWidth = !bounds.width && !style.autoSizeAlign;
2102
2094
  const {__letterSpacing: __letterSpacing, paraIndent: paraIndent, textCase: textCase} = style;
2103
- const {canvas: canvas} = core.Platform;
2104
- const {width: width, height: height} = bounds;
2105
- const charMode = width || height || __letterSpacing || textCase !== "none";
2106
- if (charMode) {
2095
+ const {canvas: canvas} = core.Platform, {width: width} = bounds;
2096
+ if (style.__isCharMode) {
2107
2097
  const wrap = style.textWrap !== "none";
2108
2098
  const breakAll = style.textWrap === "break";
2109
2099
  paraStart = true;
@@ -2232,12 +2222,19 @@ const TextMode = 2;
2232
2222
  function layoutChar(drawData, style, width, _height) {
2233
2223
  const {rows: rows} = drawData;
2234
2224
  const {textAlign: textAlign, paraIndent: paraIndent, letterSpacing: letterSpacing} = style;
2235
- let charX, addWordWidth, indentWidth, mode, wordChar, wordsLength;
2225
+ const justifyLast = width && textAlign.includes("both");
2226
+ const justify = justifyLast || width && textAlign.includes("justify");
2227
+ const justifyLetter = justify && textAlign.includes("letter");
2228
+ let charX, remainingWidth, addWordWidth, addLetterWidth, indentWidth, mode, wordChar, wordsLength, isLastWord, canJustify;
2236
2229
  rows.forEach(row => {
2237
2230
  if (row.words) {
2238
2231
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0, wordsLength = row.words.length;
2239
- addWordWidth = width && (textAlign === "justify" || textAlign === "both") && wordsLength > 1 ? (width - row.width - indentWidth) / (wordsLength - 1) : 0;
2240
- mode = letterSpacing || row.isOverflow ? CharMode : addWordWidth > .01 ? WordMode : TextMode;
2232
+ if (justify) {
2233
+ canJustify = !row.paraEnd || justifyLast;
2234
+ remainingWidth = width - row.width - indentWidth;
2235
+ if (justifyLetter) addLetterWidth = remainingWidth / (row.words.reduce((total, item) => total + item.data.length, 0) - 1); else addWordWidth = wordsLength > 1 ? remainingWidth / (wordsLength - 1) : 0;
2236
+ }
2237
+ mode = letterSpacing || row.isOverflow || justifyLetter ? CharMode : addWordWidth ? WordMode : TextMode;
2241
2238
  if (row.isOverflow && !letterSpacing) row.textMode = true;
2242
2239
  if (mode === TextMode) {
2243
2240
  row.x += indentWidth;
@@ -2255,11 +2252,15 @@ function layoutChar(drawData, style, width, _height) {
2255
2252
  charX = toWordChar(word.data, charX, wordChar);
2256
2253
  if (row.isOverflow || wordChar.char !== " ") row.data.push(wordChar);
2257
2254
  } else {
2258
- charX = toChar(word.data, charX, row.data, row.isOverflow);
2255
+ charX = toChar(word.data, charX, row.data, row.isOverflow, canJustify && addLetterWidth);
2259
2256
  }
2260
- if (addWordWidth && (!row.paraEnd || textAlign === "both") && index !== wordsLength - 1) {
2261
- charX += addWordWidth;
2262
- row.width += addWordWidth;
2257
+ if (canJustify) {
2258
+ isLastWord = index === wordsLength - 1;
2259
+ if (addWordWidth) {
2260
+ if (!isLastWord) charX += addWordWidth, row.width += addWordWidth;
2261
+ } else if (addLetterWidth) {
2262
+ row.width += addLetterWidth * (word.data.length - (isLastWord ? 1 : 0));
2263
+ }
2263
2264
  }
2264
2265
  });
2265
2266
  }
@@ -2285,13 +2286,14 @@ function toWordChar(data, charX, wordChar) {
2285
2286
  return charX;
2286
2287
  }
2287
2288
 
2288
- function toChar(data, charX, rowData, isOverflow) {
2289
+ function toChar(data, charX, rowData, isOverflow, addLetterWidth) {
2289
2290
  data.forEach(char => {
2290
2291
  if (isOverflow || char.char !== " ") {
2291
2292
  char.x = charX;
2292
2293
  rowData.push(char);
2293
2294
  }
2294
2295
  charX += char.width;
2296
+ addLetterWidth && (charX += addLetterWidth);
2295
2297
  });
2296
2298
  return charX;
2297
2299
  }
@@ -2433,10 +2435,10 @@ function getDrawData(content, style) {
2433
2435
  let x = 0, y = 0;
2434
2436
  let width = style.__getInput("width") || 0;
2435
2437
  let height = style.__getInput("height") || 0;
2436
- const {textDecoration: textDecoration, __font: __font, __padding: padding} = style;
2438
+ const {__padding: padding} = style;
2437
2439
  if (padding) {
2438
- if (width) x = padding[left], width -= padding[right] + padding[left]; else if (!style.autoSizeAlign) x = padding[left];
2439
- if (height) y = padding[top], height -= padding[top] + padding[bottom]; else if (!style.autoSizeAlign) y = padding[top];
2440
+ if (width) x = padding[left], width -= padding[right] + padding[left], !width && (width = .01); else if (!style.autoSizeAlign) x = padding[left];
2441
+ if (height) y = padding[top], height -= padding[top] + padding[bottom], !height && (height = .01); else if (!style.autoSizeAlign) y = padding[top];
2440
2442
  }
2441
2443
  const drawData = {
2442
2444
  bounds: {
@@ -2447,14 +2449,14 @@ function getDrawData(content, style) {
2447
2449
  },
2448
2450
  rows: [],
2449
2451
  paraNumber: 0,
2450
- font: core.Platform.canvas.font = __font
2452
+ font: core.Platform.canvas.font = style.__font
2451
2453
  };
2452
2454
  createRows(drawData, content, style);
2453
2455
  if (padding) padAutoText(padding, drawData, style, width, height);
2454
2456
  layoutText(drawData, style);
2455
- layoutChar(drawData, style, width);
2457
+ if (style.__isCharMode) layoutChar(drawData, style, width);
2456
2458
  if (drawData.overflow) clipText(drawData, style, x, width);
2457
- if (textDecoration !== "none") decorationText(drawData, style);
2459
+ if (style.textDecoration !== "none") decorationText(drawData, style);
2458
2460
  return drawData;
2459
2461
  }
2460
2462