leafer-draw 1.9.12 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/web.esm.js CHANGED
@@ -1,10 +1,10 @@
1
- import { Debug, LeaferCanvasBase, Platform, isString, isUndefined, DataHelper, canvasSizeAttrs, ResizeEvent, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, isArray, LeafLevelList, LayoutEvent, Run, ImageManager, isObject, BoundsHelper, FourNumberHelper, Matrix, getMatrixData, MatrixHelper, MathHelper, AlignHelper, PointHelper, ImageEvent, AroundHelper, Direction4, isNumber } from "@leafer/core";
1
+ import { Debug, LeaferCanvasBase, Platform, isString, isUndefined, DataHelper, canvasSizeAttrs, ResizeEvent, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, isArray, LeafLevelList, LayoutEvent, Run, ImageManager, isObject, BoundsHelper, FourNumberHelper, Matrix, 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
 
@@ -872,36 +872,19 @@ Platform.render = function(target, canvas, options) {
872
872
  if (options.topList.length) options.topList.forEach(item => item.__render(canvas, topOptions));
873
873
  };
874
874
 
875
- function fillText(ui, canvas) {
876
- const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
877
- if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
878
- let row;
879
- for (let i = 0, len = rows.length; i < len; i++) {
880
- row = rows[i];
881
- if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
882
- canvas.fillText(charData.char, charData.x, row.y);
883
- });
884
- }
885
- if (decorationY) {
886
- const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
887
- if (decorationColor) canvas.fillStyle = decorationColor;
888
- rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
889
- }
890
- }
891
-
892
- function fill(fill, ui, canvas) {
875
+ function fill(fill, ui, canvas, renderOptions) {
893
876
  canvas.fillStyle = fill;
894
- fillPathOrText(ui, canvas);
877
+ fillPathOrText(ui, canvas, renderOptions);
895
878
  }
896
879
 
897
- function fills(fills, ui, canvas) {
880
+ function fills(fills, ui, canvas, renderOptions) {
898
881
  let item;
899
882
  for (let i = 0, len = fills.length; i < len; i++) {
900
883
  item = fills[i];
901
884
  if (item.image) {
902
- if (PaintImage.checkImage(ui, canvas, item, !ui.__.__font)) continue;
885
+ if (PaintImage.checkImage(item, !ui.__.__font, ui, canvas, renderOptions)) continue;
903
886
  if (!item.style) {
904
- if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(canvas, item.image);
887
+ if (!i && item.image.isPlacehold) ui.drawImagePlaceholder(item.image, canvas, renderOptions);
905
888
  continue;
906
889
  }
907
890
  }
@@ -914,60 +897,137 @@ function fills(fills, ui, canvas) {
914
897
  if (item.scaleFixed === true || item.scaleFixed === "zoom-in" && scaleX > 1 && scaleY > 1) canvas.scale(1 / scaleX, 1 / scaleY);
915
898
  }
916
899
  if (item.blendMode) canvas.blendMode = item.blendMode;
917
- fillPathOrText(ui, canvas);
900
+ fillPathOrText(ui, canvas, renderOptions);
918
901
  canvas.restore();
919
902
  } else {
920
903
  if (item.blendMode) {
921
904
  canvas.saveBlendMode(item.blendMode);
922
- fillPathOrText(ui, canvas);
905
+ fillPathOrText(ui, canvas, renderOptions);
923
906
  canvas.restoreBlendMode();
924
- } else fillPathOrText(ui, canvas);
907
+ } else fillPathOrText(ui, canvas, renderOptions);
908
+ }
909
+ }
910
+ }
911
+
912
+ function fillPathOrText(ui, canvas, renderOptions) {
913
+ ui.__.__font ? Paint.fillText(ui, canvas, renderOptions) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
914
+ }
915
+
916
+ function fillText(ui, canvas, _renderOptions) {
917
+ const data = ui.__, {rows: rows, decorationY: decorationY} = data.__textDrawData;
918
+ if (data.__isPlacehold && data.placeholderColor) canvas.fillStyle = data.placeholderColor;
919
+ let row;
920
+ for (let i = 0, len = rows.length; i < len; i++) {
921
+ row = rows[i];
922
+ if (row.text) canvas.fillText(row.text, row.x, row.y); else if (row.data) row.data.forEach(charData => {
923
+ canvas.fillText(charData.char, charData.x, row.y);
924
+ });
925
+ }
926
+ if (decorationY) {
927
+ const {decorationColor: decorationColor, decorationHeight: decorationHeight} = data.__textDrawData;
928
+ if (decorationColor) canvas.fillStyle = decorationColor;
929
+ rows.forEach(row => decorationY.forEach(value => canvas.fillRect(row.x, row.y + value, row.width, decorationHeight)));
930
+ }
931
+ }
932
+
933
+ function stroke(stroke, ui, canvas, renderOptions) {
934
+ const data = ui.__;
935
+ if (!data.__strokeWidth) return;
936
+ if (data.__font) {
937
+ Paint.strokeText(stroke, ui, canvas, renderOptions);
938
+ } else {
939
+ switch (data.strokeAlign) {
940
+ case "center":
941
+ drawCenter$1(stroke, 1, ui, canvas, renderOptions);
942
+ break;
943
+
944
+ case "inside":
945
+ drawInside(stroke, ui, canvas, renderOptions);
946
+ break;
947
+
948
+ case "outside":
949
+ drawOutside(stroke, ui, canvas, renderOptions);
950
+ break;
925
951
  }
926
952
  }
927
953
  }
928
954
 
929
- function fillPathOrText(ui, canvas) {
930
- ui.__.__font ? fillText(ui, canvas) : ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill();
955
+ function strokes(strokes, ui, canvas, renderOptions) {
956
+ Paint.stroke(strokes, ui, canvas, renderOptions);
957
+ }
958
+
959
+ function drawCenter$1(stroke, strokeWidthScale, ui, canvas, renderOptions) {
960
+ const data = ui.__;
961
+ if (isObject(stroke)) {
962
+ Paint.drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas, renderOptions);
963
+ } else {
964
+ canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
965
+ canvas.stroke();
966
+ }
967
+ if (data.__useArrow) Paint.strokeArrow(stroke, ui, canvas, renderOptions);
968
+ }
969
+
970
+ function drawInside(stroke, ui, canvas, renderOptions) {
971
+ canvas.save();
972
+ canvas.clipUI(ui);
973
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
974
+ canvas.restore();
931
975
  }
932
976
 
933
- function strokeText(stroke, ui, canvas) {
977
+ function drawOutside(stroke, ui, canvas, renderOptions) {
978
+ const data = ui.__;
979
+ if (data.__fillAfterStroke) {
980
+ drawCenter$1(stroke, 2, ui, canvas, renderOptions);
981
+ } else {
982
+ const {renderBounds: renderBounds} = ui.__layout;
983
+ const out = canvas.getSameCanvas(true, true);
984
+ ui.__drawRenderPath(out);
985
+ drawCenter$1(stroke, 2, ui, out, renderOptions);
986
+ out.clipUI(data);
987
+ out.clearWorld(renderBounds);
988
+ LeafHelper.copyCanvasByWorld(ui, canvas, out);
989
+ out.recycle(ui.__nowWorld);
990
+ }
991
+ }
992
+
993
+ function strokeText(stroke, ui, canvas, renderOptions) {
934
994
  switch (ui.__.strokeAlign) {
935
995
  case "center":
936
- drawCenter$1(stroke, 1, ui, canvas);
996
+ drawCenter(stroke, 1, ui, canvas, renderOptions);
937
997
  break;
938
998
 
939
999
  case "inside":
940
- drawAlign(stroke, "inside", ui, canvas);
1000
+ drawAlign(stroke, "inside", ui, canvas, renderOptions);
941
1001
  break;
942
1002
 
943
1003
  case "outside":
944
- ui.__.__fillAfterStroke ? drawCenter$1(stroke, 2, ui, canvas) : drawAlign(stroke, "outside", ui, canvas);
1004
+ ui.__.__fillAfterStroke ? drawCenter(stroke, 2, ui, canvas, renderOptions) : drawAlign(stroke, "outside", ui, canvas, renderOptions);
945
1005
  break;
946
1006
  }
947
1007
  }
948
1008
 
949
- function drawCenter$1(stroke, strokeWidthScale, ui, canvas) {
1009
+ function drawCenter(stroke, strokeWidthScale, ui, canvas, renderOptions) {
950
1010
  const data = ui.__;
951
1011
  if (isObject(stroke)) {
952
- drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas);
1012
+ Paint.drawStrokesStyle(stroke, strokeWidthScale, true, ui, canvas, renderOptions);
953
1013
  } else {
954
1014
  canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
955
- drawTextStroke(ui, canvas);
1015
+ Paint.drawTextStroke(ui, canvas, renderOptions);
956
1016
  }
957
1017
  }
958
1018
 
959
- function drawAlign(stroke, align, ui, canvas) {
1019
+ function drawAlign(stroke, align, ui, canvas, renderOptions) {
960
1020
  const out = canvas.getSameCanvas(true, true);
961
1021
  out.font = ui.__.__font;
962
- drawCenter$1(stroke, 2, ui, out);
1022
+ drawCenter(stroke, 2, ui, out, renderOptions);
963
1023
  out.blendMode = align === "outside" ? "destination-out" : "destination-in";
964
- fillText(ui, out);
1024
+ Paint.fillText(ui, out, renderOptions);
965
1025
  out.blendMode = "normal";
966
1026
  LeafHelper.copyCanvasByWorld(ui, canvas, out);
967
1027
  out.recycle(ui.__nowWorld);
968
1028
  }
969
1029
 
970
- function drawTextStroke(ui, canvas) {
1030
+ function drawTextStroke(ui, canvas, _renderOptions) {
971
1031
  let row, data = ui.__.__textDrawData;
972
1032
  const {rows: rows, decorationY: decorationY} = data;
973
1033
  for (let i = 0, len = rows.length; i < len; i++) {
@@ -982,13 +1042,13 @@ function drawTextStroke(ui, canvas) {
982
1042
  }
983
1043
  }
984
1044
 
985
- function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
1045
+ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas, renderOptions) {
986
1046
  let item;
987
1047
  const data = ui.__, {__hasMultiStrokeStyle: __hasMultiStrokeStyle} = data;
988
1048
  __hasMultiStrokeStyle || canvas.setStroke(undefined, data.__strokeWidth * strokeWidthScale, data);
989
1049
  for (let i = 0, len = strokes.length; i < len; i++) {
990
1050
  item = strokes[i];
991
- if (item.image && PaintImage.checkImage(ui, canvas, item, false)) continue;
1051
+ if (item.image && PaintImage.checkImage(item, false, ui, canvas, renderOptions)) continue;
992
1052
  if (item.style) {
993
1053
  if (__hasMultiStrokeStyle) {
994
1054
  const {strokeStyle: strokeStyle} = item;
@@ -996,75 +1056,15 @@ function drawStrokesStyle(strokes, strokeWidthScale, isText, ui, canvas) {
996
1056
  } else canvas.strokeStyle = item.style;
997
1057
  if (item.blendMode) {
998
1058
  canvas.saveBlendMode(item.blendMode);
999
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1059
+ isText ? Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
1000
1060
  canvas.restoreBlendMode();
1001
1061
  } else {
1002
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1062
+ isText ? Paint.drawTextStroke(ui, canvas, renderOptions) : canvas.stroke();
1003
1063
  }
1004
1064
  }
1005
1065
  }
1006
1066
  }
1007
1067
 
1008
- function stroke(stroke, ui, canvas) {
1009
- const data = ui.__;
1010
- if (!data.__strokeWidth) return;
1011
- if (data.__font) {
1012
- strokeText(stroke, ui, canvas);
1013
- } else {
1014
- switch (data.strokeAlign) {
1015
- case "center":
1016
- drawCenter(stroke, 1, ui, canvas);
1017
- break;
1018
-
1019
- case "inside":
1020
- drawInside(stroke, ui, canvas);
1021
- break;
1022
-
1023
- case "outside":
1024
- drawOutside(stroke, ui, canvas);
1025
- break;
1026
- }
1027
- }
1028
- }
1029
-
1030
- function strokes(strokes, ui, canvas) {
1031
- stroke(strokes, ui, canvas);
1032
- }
1033
-
1034
- function drawCenter(stroke, strokeWidthScale, ui, canvas) {
1035
- const data = ui.__;
1036
- if (isObject(stroke)) {
1037
- drawStrokesStyle(stroke, strokeWidthScale, false, ui, canvas);
1038
- } else {
1039
- canvas.setStroke(stroke, data.__strokeWidth * strokeWidthScale, data);
1040
- canvas.stroke();
1041
- }
1042
- if (data.__useArrow) Paint.strokeArrow(stroke, ui, canvas);
1043
- }
1044
-
1045
- function drawInside(stroke, ui, canvas) {
1046
- canvas.save();
1047
- canvas.clipUI(ui);
1048
- drawCenter(stroke, 2, ui, canvas);
1049
- canvas.restore();
1050
- }
1051
-
1052
- function drawOutside(stroke, ui, canvas) {
1053
- const data = ui.__;
1054
- if (data.__fillAfterStroke) {
1055
- drawCenter(stroke, 2, ui, canvas);
1056
- } else {
1057
- const {renderBounds: renderBounds} = ui.__layout;
1058
- const out = canvas.getSameCanvas(true, true);
1059
- ui.__drawRenderPath(out);
1060
- drawCenter(stroke, 2, ui, out);
1061
- out.clipUI(data);
1062
- out.clearWorld(renderBounds);
1063
- LeafHelper.copyCanvasByWorld(ui, canvas, out);
1064
- out.recycle(ui.__nowWorld);
1065
- }
1066
- }
1067
-
1068
1068
  const {getSpread: getSpread, copyAndSpread: copyAndSpread, toOuterOf: toOuterOf, getOuterOf: getOuterOf, getByMove: getByMove, move: move$1, getIntersectData: getIntersectData} = BoundsHelper;
1069
1069
 
1070
1070
  const tempBounds$1 = {};
@@ -1220,88 +1220,118 @@ const PaintModule = {
1220
1220
  strokes: strokes,
1221
1221
  strokeText: strokeText,
1222
1222
  drawTextStroke: drawTextStroke,
1223
+ drawStrokesStyle: drawStrokesStyle,
1223
1224
  shape: shape
1224
1225
  };
1225
1226
 
1226
- let origin = {}, tempMatrix$1 = getMatrixData();
1227
+ let cache, box = new Bounds;
1227
1228
 
1228
- const {get: get$3, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = MatrixHelper;
1229
+ const {isSame: isSame} = BoundsHelper;
1229
1230
 
1230
- function stretchMode(data, box, scaleX, scaleY) {
1231
- const transform = get$3();
1232
- translate$1(transform, box.x, box.y);
1233
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1234
- data.transform = transform;
1231
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1232
+ let leafPaint, event;
1233
+ const image = ImageManager.get(paint);
1234
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1235
+ leafPaint = cache.leafPaint;
1236
+ } else {
1237
+ leafPaint = {
1238
+ type: paint.type,
1239
+ image: image
1240
+ };
1241
+ if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1242
+ cache = image.use > 1 ? {
1243
+ leafPaint: leafPaint,
1244
+ paint: paint,
1245
+ boxBounds: box.set(boxBounds)
1246
+ } : null;
1247
+ }
1248
+ if (firstUse || image.loading) event = {
1249
+ image: image,
1250
+ attrName: attrName,
1251
+ attrValue: paint
1252
+ };
1253
+ if (image.ready) {
1254
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1255
+ if (firstUse) {
1256
+ onLoad(ui, event);
1257
+ onLoadSuccess(ui, event);
1258
+ }
1259
+ } else if (image.error) {
1260
+ if (firstUse) onLoadError(ui, event, image.error);
1261
+ } else {
1262
+ if (firstUse) {
1263
+ ignoreRender(ui, true);
1264
+ onLoad(ui, event);
1265
+ }
1266
+ leafPaint.loadId = image.load(() => {
1267
+ ignoreRender(ui, false);
1268
+ if (!ui.destroyed) {
1269
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1270
+ if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1271
+ ui.forceUpdate("surface");
1272
+ }
1273
+ onLoadSuccess(ui, event);
1274
+ }
1275
+ leafPaint.loadId = undefined;
1276
+ }, error => {
1277
+ ignoreRender(ui, false);
1278
+ onLoadError(ui, event, error);
1279
+ leafPaint.loadId = undefined;
1280
+ });
1281
+ if (ui.placeholderColor) {
1282
+ if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1283
+ if (!image.ready) {
1284
+ image.isPlacehold = true;
1285
+ ui.forceUpdate("surface");
1286
+ }
1287
+ }, ui.placeholderDelay);
1288
+ }
1289
+ }
1290
+ return leafPaint;
1235
1291
  }
1236
1292
 
1237
- function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1238
- const transform = get$3();
1239
- translate$1(transform, box.x + x, box.y + y);
1240
- scaleHelper(transform, scaleX, scaleY);
1241
- if (rotation) rotateOfOuter$1(transform, {
1242
- x: box.x + box.width / 2,
1243
- y: box.y + box.height / 2
1244
- }, rotation);
1245
- data.transform = transform;
1293
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1294
+ if (attrName === "fill" && !ui.__.__naturalWidth) {
1295
+ const data = ui.__;
1296
+ data.__naturalWidth = image.width / data.pixelRatio;
1297
+ data.__naturalHeight = image.height / data.pixelRatio;
1298
+ if (data.__autoSide) {
1299
+ ui.forceUpdate("width");
1300
+ if (ui.__proxyData) {
1301
+ ui.setProxyAttr("width", data.width);
1302
+ ui.setProxyAttr("height", data.height);
1303
+ }
1304
+ return false;
1305
+ }
1306
+ }
1307
+ if (!leafPaint.data) PaintImage.createData(leafPaint, image, paint, boxBounds);
1308
+ return true;
1246
1309
  }
1247
1310
 
1248
- function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1249
- const transform = get$3();
1250
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1251
- if (clipScaleX) {
1252
- if (rotation || skew) {
1253
- set(tempMatrix$1);
1254
- scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1255
- multiplyParent(transform, tempMatrix$1);
1256
- } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1257
- }
1258
- data.transform = transform;
1311
+ function onLoad(ui, event) {
1312
+ emit(ui, ImageEvent.LOAD, event);
1259
1313
  }
1260
1314
 
1261
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1262
- const transform = get$3();
1263
- if (freeTransform) {
1264
- layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1265
- } else {
1266
- if (rotation) {
1267
- if (align === "center") {
1268
- rotateOfOuter$1(transform, {
1269
- x: width / 2,
1270
- y: height / 2
1271
- }, rotation);
1272
- } else {
1273
- rotate(transform, rotation);
1274
- switch (rotation) {
1275
- case 90:
1276
- translate$1(transform, height, 0);
1277
- break;
1315
+ function onLoadSuccess(ui, event) {
1316
+ emit(ui, ImageEvent.LOADED, event);
1317
+ }
1278
1318
 
1279
- case 180:
1280
- translate$1(transform, width, height);
1281
- break;
1319
+ function onLoadError(ui, event, error) {
1320
+ event.error = error;
1321
+ ui.forceUpdate("surface");
1322
+ emit(ui, ImageEvent.ERROR, event);
1323
+ }
1282
1324
 
1283
- case 270:
1284
- translate$1(transform, 0, width);
1285
- break;
1286
- }
1287
- }
1288
- }
1289
- origin.x = box.x + x;
1290
- origin.y = box.y + y;
1291
- translate$1(transform, origin.x, origin.y);
1292
- if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1293
- }
1294
- data.transform = transform;
1325
+ function emit(ui, type, data) {
1326
+ if (ui.hasEvent(type)) ui.emitEvent(new ImageEvent(type, data));
1295
1327
  }
1296
1328
 
1297
- function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1298
- if (rotation) rotate(transform, rotation);
1299
- if (skew) skewHelper(transform, skew.x, skew.y);
1300
- if (scaleX) scaleHelper(transform, scaleX, scaleY);
1301
- translate$1(transform, box.x + x, box.y + y);
1329
+ function ignoreRender(ui, value) {
1330
+ const {leafer: leafer} = ui;
1331
+ if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1302
1332
  }
1303
1333
 
1304
- const {get: get$2, translate: translate} = MatrixHelper;
1334
+ const {get: get$3, translate: translate$1} = MatrixHelper;
1305
1335
 
1306
1336
  const tempBox = new Bounds;
1307
1337
 
@@ -1314,13 +1344,13 @@ function createData(leafPaint, image, paint, box) {
1314
1344
  if (changeful) leafPaint.changeful = changeful;
1315
1345
  if (sync) leafPaint.sync = sync;
1316
1346
  if (scaleFixed) leafPaint.scaleFixed = scaleFixed;
1317
- leafPaint.data = getPatternData(paint, box, image);
1347
+ leafPaint.data = PaintImage.getPatternData(paint, box, image);
1318
1348
  }
1319
1349
 
1320
1350
  function getPatternData(paint, box, image) {
1321
1351
  if (paint.padding) box = tempBox.set(box).shrink(paint.padding);
1322
1352
  if (paint.mode === "strench") paint.mode = "stretch";
1323
- let {width: width, height: height} = image;
1353
+ const {width: width, height: height} = image;
1324
1354
  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;
1325
1355
  const sameBox = box.width === width && box.height === height;
1326
1356
  const data = {
@@ -1351,8 +1381,8 @@ function getPatternData(paint, box, image) {
1351
1381
  case "stretch":
1352
1382
  if (!sameBox) {
1353
1383
  scaleX = box.width / width, scaleY = box.height / height;
1354
- stretchMode(data, box, scaleX, scaleY);
1355
- }
1384
+ PaintImage.stretchMode(data, box, scaleX, scaleY);
1385
+ } else if (scaleX) scaleX = scaleY = undefined;
1356
1386
  break;
1357
1387
 
1358
1388
  case "normal":
@@ -1360,13 +1390,13 @@ function getPatternData(paint, box, image) {
1360
1390
  if (tempImage.x || tempImage.y || scaleX || clipSize || rotation || skew) {
1361
1391
  let clipScaleX, clipScaleY;
1362
1392
  if (clipSize) clipScaleX = box.width / clipSize.width, clipScaleY = box.height / clipSize.height;
1363
- clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1393
+ PaintImage.clipMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY);
1364
1394
  if (clipScaleX) scaleX = scaleX ? scaleX * clipScaleX : clipScaleX, scaleY = scaleY ? scaleY * clipScaleY : clipScaleY;
1365
1395
  }
1366
1396
  break;
1367
1397
 
1368
1398
  case "repeat":
1369
- if (!sameBox || scaleX || rotation || skew) repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1399
+ if (!sameBox || scaleX || rotation || skew) PaintImage.repeatMode(data, box, width, height, tempImage.x, tempImage.y, scaleX, scaleY, rotation, skew, align, paint.freeTransform);
1370
1400
  if (!repeat) data.repeat = "repeat";
1371
1401
  const count = isObject(repeat);
1372
1402
  if (gap || count) data.gap = getGapData(gap, count && repeat, tempImage.width, tempImage.height, box);
@@ -1375,18 +1405,16 @@ function getPatternData(paint, box, image) {
1375
1405
  case "fit":
1376
1406
  case "cover":
1377
1407
  default:
1378
- if (scaleX) fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1408
+ if (scaleX) PaintImage.fillOrFitMode(data, box, tempImage.x, tempImage.y, scaleX, scaleY, rotation);
1379
1409
  }
1380
1410
  if (!data.transform) {
1381
- if (box.x || box.y) translate(data.transform = get$2(), box.x, box.y);
1411
+ if (box.x || box.y) translate$1(data.transform = get$3(), box.x, box.y);
1382
1412
  }
1383
- data.width = width;
1384
- data.height = height;
1385
1413
  if (scaleX) {
1386
1414
  data.scaleX = scaleX;
1387
1415
  data.scaleY = scaleY;
1388
1416
  }
1389
- if (opacity) data.opacity = opacity;
1417
+ if (opacity && opacity < 1) data.opacity = opacity;
1390
1418
  if (filters) data.filters = filters;
1391
1419
  if (repeat) data.repeat = isString(repeat) ? repeat === "x" ? "repeat-x" : "repeat-y" : "repeat";
1392
1420
  return data;
@@ -1408,180 +1436,82 @@ function getGapValue(gap, size, totalSize, rows) {
1408
1436
  return gap === "auto" ? value < 0 ? 0 : value : value;
1409
1437
  }
1410
1438
 
1411
- let cache, box = new Bounds;
1412
-
1413
- const {isSame: isSame} = BoundsHelper;
1414
-
1415
- function image(ui, attrName, paint, boxBounds, firstUse) {
1416
- let leafPaint, event;
1417
- const image = ImageManager.get(paint);
1418
- if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1419
- leafPaint = cache.leafPaint;
1420
- } else {
1421
- leafPaint = {
1422
- type: paint.type,
1423
- image: image
1424
- };
1425
- if (image.hasAlphaPixel) leafPaint.isTransparent = true;
1426
- cache = image.use > 1 ? {
1427
- leafPaint: leafPaint,
1428
- paint: paint,
1429
- boxBounds: box.set(boxBounds)
1430
- } : null;
1431
- }
1432
- if (firstUse || image.loading) event = {
1433
- image: image,
1434
- attrName: attrName,
1435
- attrValue: paint
1436
- };
1437
- if (image.ready) {
1438
- checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1439
- if (firstUse) {
1440
- onLoad(ui, event);
1441
- onLoadSuccess(ui, event);
1442
- }
1443
- } else if (image.error) {
1444
- if (firstUse) onLoadError(ui, event, image.error);
1445
- } else {
1446
- if (firstUse) {
1447
- ignoreRender(ui, true);
1448
- onLoad(ui, event);
1449
- }
1450
- leafPaint.loadId = image.load(() => {
1451
- ignoreRender(ui, false);
1452
- if (!ui.destroyed) {
1453
- if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1454
- if (image.hasAlphaPixel) ui.__layout.hitCanvasChanged = true;
1455
- ui.forceUpdate("surface");
1456
- }
1457
- onLoadSuccess(ui, event);
1458
- }
1459
- leafPaint.loadId = undefined;
1460
- }, error => {
1461
- ignoreRender(ui, false);
1462
- onLoadError(ui, event, error);
1463
- leafPaint.loadId = undefined;
1464
- });
1465
- if (ui.placeholderColor) {
1466
- if (!ui.placeholderDelay) image.isPlacehold = true; else setTimeout(() => {
1467
- if (!image.ready) {
1468
- image.isPlacehold = true;
1469
- ui.forceUpdate("surface");
1470
- }
1471
- }, ui.placeholderDelay);
1472
- }
1473
- }
1474
- return leafPaint;
1475
- }
1476
-
1477
- function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1478
- if (attrName === "fill" && !ui.__.__naturalWidth) {
1479
- const data = ui.__;
1480
- data.__naturalWidth = image.width / data.pixelRatio;
1481
- data.__naturalHeight = image.height / data.pixelRatio;
1482
- if (data.__autoSide) {
1483
- ui.forceUpdate("width");
1484
- if (ui.__proxyData) {
1485
- ui.setProxyAttr("width", data.width);
1486
- ui.setProxyAttr("height", data.height);
1487
- }
1488
- return false;
1489
- }
1490
- }
1491
- if (!leafPaint.data) createData(leafPaint, image, paint, boxBounds);
1492
- return true;
1493
- }
1494
-
1495
- function onLoad(ui, event) {
1496
- emit(ui, ImageEvent.LOAD, event);
1497
- }
1439
+ let origin = {}, tempMatrix$1 = getMatrixData();
1498
1440
 
1499
- function onLoadSuccess(ui, event) {
1500
- emit(ui, ImageEvent.LOADED, event);
1501
- }
1441
+ const {get: get$2, set: set, rotateOfOuter: rotateOfOuter$1, translate: translate, scaleOfOuter: scaleOfOuter$1, multiplyParent: multiplyParent, scale: scaleHelper, rotate: rotate, skew: skewHelper} = MatrixHelper;
1502
1442
 
1503
- function onLoadError(ui, event, error) {
1504
- event.error = error;
1505
- ui.forceUpdate("surface");
1506
- emit(ui, ImageEvent.ERROR, event);
1443
+ function stretchMode(data, box, scaleX, scaleY) {
1444
+ const transform = get$2(), {x: x, y: y} = box;
1445
+ if (x || y) translate(transform, x, y); else transform.onlyScale = true;
1446
+ scaleHelper(transform, scaleX, scaleY);
1447
+ data.transform = transform;
1507
1448
  }
1508
1449
 
1509
- function emit(ui, type, data) {
1510
- if (ui.hasEvent(type)) ui.emitEvent(new ImageEvent(type, data));
1450
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1451
+ const transform = get$2();
1452
+ translate(transform, box.x + x, box.y + y);
1453
+ scaleHelper(transform, scaleX, scaleY);
1454
+ if (rotation) rotateOfOuter$1(transform, {
1455
+ x: box.x + box.width / 2,
1456
+ y: box.y + box.height / 2
1457
+ }, rotation);
1458
+ data.transform = transform;
1511
1459
  }
1512
1460
 
1513
- function ignoreRender(ui, value) {
1514
- const {leafer: leafer} = ui;
1515
- if (leafer && leafer.viewReady) leafer.renderer.ignore = value;
1461
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation, skew, clipScaleX, clipScaleY) {
1462
+ const transform = get$2();
1463
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1464
+ if (clipScaleX) {
1465
+ if (rotation || skew) {
1466
+ set(tempMatrix$1);
1467
+ scaleOfOuter$1(tempMatrix$1, box, clipScaleX, clipScaleY);
1468
+ multiplyParent(transform, tempMatrix$1);
1469
+ } else scaleOfOuter$1(transform, box, clipScaleX, clipScaleY);
1470
+ }
1471
+ data.transform = transform;
1516
1472
  }
1517
1473
 
1518
- const {get: get$1, scale: scale, copy: copy$1} = MatrixHelper;
1474
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, skew, align, freeTransform) {
1475
+ const transform = get$2();
1476
+ if (freeTransform) {
1477
+ layout(transform, box, x, y, scaleX, scaleY, rotation, skew);
1478
+ } else {
1479
+ if (rotation) {
1480
+ if (align === "center") {
1481
+ rotateOfOuter$1(transform, {
1482
+ x: width / 2,
1483
+ y: height / 2
1484
+ }, rotation);
1485
+ } else {
1486
+ rotate(transform, rotation);
1487
+ switch (rotation) {
1488
+ case 90:
1489
+ translate(transform, height, 0);
1490
+ break;
1519
1491
 
1520
- const {floor: floor, ceil: ceil, max: max$1, abs: abs$1} = Math;
1492
+ case 180:
1493
+ translate(transform, width, height);
1494
+ break;
1521
1495
 
1522
- function createPattern(ui, paint, pixelRatio) {
1523
- let {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
1524
- const id = scaleX + "-" + scaleY + "-" + pixelRatio;
1525
- if (paint.patternId !== id && !ui.destroyed) {
1526
- const {image: image, data: data} = paint;
1527
- let imageScale, imageMatrix, {width: width, height: height, scaleX: sx, scaleY: sy, transform: transform, repeat: repeat, gap: gap} = data;
1528
- scaleX *= pixelRatio;
1529
- scaleY *= pixelRatio;
1530
- if (sx) {
1531
- sx = abs$1(sx);
1532
- sy = abs$1(sy);
1533
- imageMatrix = get$1();
1534
- copy$1(imageMatrix, transform);
1535
- scale(imageMatrix, 1 / sx, 1 / sy);
1536
- scaleX *= sx;
1537
- scaleY *= sy;
1538
- }
1539
- width *= scaleX;
1540
- height *= scaleY;
1541
- const size = width * height;
1542
- if (!repeat) {
1543
- if (size > Platform.image.maxCacheSize) return false;
1544
- }
1545
- let maxSize = Platform.image.maxPatternSize;
1546
- if (image.isSVG) {
1547
- const ws = width / image.width;
1548
- if (ws > 1) imageScale = ws / ceil(ws);
1549
- } else {
1550
- const imageSize = image.width * image.height;
1551
- if (maxSize > imageSize) maxSize = imageSize;
1552
- }
1553
- if (size > maxSize) imageScale = Math.sqrt(size / maxSize);
1554
- if (imageScale) {
1555
- scaleX /= imageScale;
1556
- scaleY /= imageScale;
1557
- width /= imageScale;
1558
- height /= imageScale;
1559
- }
1560
- if (sx) {
1561
- scaleX /= sx;
1562
- scaleY /= sy;
1563
- }
1564
- const xGap = gap && gap.x * scaleX;
1565
- const yGap = gap && gap.y * scaleY;
1566
- if (transform || scaleX !== 1 || scaleY !== 1) {
1567
- const canvasWidth = width + (xGap || 0);
1568
- const canvasHeight = height + (yGap || 0);
1569
- scaleX /= canvasWidth / max$1(floor(canvasWidth), 1);
1570
- scaleY /= canvasHeight / max$1(floor(canvasHeight), 1);
1571
- if (!imageMatrix) {
1572
- imageMatrix = get$1();
1573
- if (transform) copy$1(imageMatrix, transform);
1496
+ case 270:
1497
+ translate(transform, 0, width);
1498
+ break;
1499
+ }
1574
1500
  }
1575
- scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1576
1501
  }
1577
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1578
- const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1579
- paint.style = pattern;
1580
- paint.patternId = id;
1581
- return true;
1582
- } else {
1583
- return false;
1502
+ origin.x = box.x + x;
1503
+ origin.y = box.y + y;
1504
+ translate(transform, origin.x, origin.y);
1505
+ if (scaleX) scaleOfOuter$1(transform, origin, scaleX, scaleY);
1584
1506
  }
1507
+ data.transform = transform;
1508
+ }
1509
+
1510
+ function layout(transform, box, x, y, scaleX, scaleY, rotation, skew) {
1511
+ if (rotation) rotate(transform, rotation);
1512
+ if (skew) skewHelper(transform, skew.x, skew.y);
1513
+ if (scaleX) scaleHelper(transform, scaleX, scaleY);
1514
+ translate(transform, box.x + x, box.y + y);
1585
1515
  }
1586
1516
 
1587
1517
  function __awaiter(thisArg, _arguments, P, generator) {
@@ -1617,58 +1547,116 @@ typeof SuppressedError === "function" ? SuppressedError : function(error, suppre
1617
1547
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1618
1548
  };
1619
1549
 
1620
- function checkImage(ui, canvas, paint, allowDraw) {
1621
- const {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
1622
- const {pixelRatio: pixelRatio} = canvas, {data: data} = paint;
1623
- if (!data || paint.patternId === scaleX + "-" + scaleY + "-" + pixelRatio && !Export.running) {
1550
+ const {get: get$1, scale: scale, copy: copy$1} = MatrixHelper;
1551
+
1552
+ const {getFloorScale: getFloorScale} = MathHelper, {abs: abs$1} = Math;
1553
+
1554
+ function createPatternTask(paint, ui, canvas, renderOptions) {
1555
+ if (!paint.patternTask) {
1556
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
1557
+ paint.patternTask = null;
1558
+ if (canvas.bounds.hit(ui.__nowWorld)) PaintImage.createPattern(paint, ui, canvas, renderOptions);
1559
+ ui.forceUpdate("surface");
1560
+ }), 300);
1561
+ }
1562
+ }
1563
+
1564
+ function createPattern(paint, ui, canvas, renderOptions) {
1565
+ let {scaleX: scaleX, scaleY: scaleY} = PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions), id = scaleX + "-" + scaleY;
1566
+ if (paint.patternId !== id && !ui.destroyed) {
1567
+ if (!(Platform.image.isLarge(paint.image, scaleX, scaleY) && !paint.data.repeat)) {
1568
+ const {image: image, data: data} = paint, {transform: transform, gap: gap} = data, fixScale = PaintImage.getPatternFixScale(paint, scaleX, scaleY);
1569
+ let imageMatrix, xGap, yGap, {width: width, height: height} = image;
1570
+ if (fixScale) scaleX *= fixScale, scaleY *= fixScale;
1571
+ width *= scaleX;
1572
+ height *= scaleY;
1573
+ if (gap) {
1574
+ xGap = gap.x * scaleX / abs$1(data.scaleX || 1);
1575
+ yGap = gap.y * scaleY / abs$1(data.scaleY || 1);
1576
+ }
1577
+ if (transform || scaleX !== 1 || scaleY !== 1) {
1578
+ scaleX *= getFloorScale(width + (xGap || 0));
1579
+ scaleY *= getFloorScale(height + (yGap || 0));
1580
+ imageMatrix = get$1();
1581
+ if (transform) copy$1(imageMatrix, transform);
1582
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1583
+ }
1584
+ const imageCanvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1585
+ const pattern = image.getPattern(imageCanvas, data.repeat || (Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1586
+ paint.style = pattern;
1587
+ paint.patternId = id;
1588
+ }
1589
+ }
1590
+ }
1591
+
1592
+ function getPatternFixScale(paint, imageScaleX, imageScaleY) {
1593
+ const {image: image} = paint;
1594
+ let fixScale, maxSize = Platform.image.maxPatternSize, imageSize = image.width * image.height;
1595
+ if (image.isSVG) {
1596
+ if (imageScaleX > 1) fixScale = Math.ceil(imageScaleX) / imageScaleX;
1597
+ } else {
1598
+ if (maxSize > imageSize) maxSize = imageSize;
1599
+ }
1600
+ if ((imageSize *= imageScaleX * imageScaleY) > maxSize) fixScale = Math.sqrt(maxSize / imageSize);
1601
+ return fixScale;
1602
+ }
1603
+
1604
+ function checkImage(paint, drawImage, ui, canvas, renderOptions) {
1605
+ const {scaleX: scaleX, scaleY: scaleY} = PaintImage.getImageRenderScaleData(paint, ui, canvas, renderOptions);
1606
+ const {image: image, data: data} = paint, {exporting: exporting} = renderOptions;
1607
+ if (!data || paint.patternId === scaleX + "-" + scaleY && !exporting) {
1624
1608
  return false;
1625
1609
  } else {
1626
- if (allowDraw) {
1610
+ if (drawImage) {
1627
1611
  if (data.repeat) {
1628
- allowDraw = false;
1629
- } else if (!(paint.changeful || Platform.name === "miniapp" && ResizeEvent.isResizing(ui) || Export.running)) {
1630
- let {width: width, height: height} = data;
1631
- width *= scaleX * pixelRatio;
1632
- height *= scaleY * pixelRatio;
1633
- if (data.scaleX) {
1634
- width *= data.scaleX;
1635
- height *= data.scaleY;
1636
- }
1637
- allowDraw = width * height > Platform.image.maxCacheSize;
1612
+ drawImage = false;
1613
+ } else if (!(paint.changeful || Platform.name === "miniapp" && ResizeEvent.isResizing(ui) || exporting)) {
1614
+ drawImage = Platform.image.isLarge(image, scaleX, scaleY);
1638
1615
  }
1639
1616
  }
1640
- if (allowDraw) {
1617
+ if (drawImage) {
1641
1618
  if (ui.__.__isFastShadow) {
1642
1619
  canvas.fillStyle = paint.style || "#000";
1643
1620
  canvas.fill();
1644
1621
  }
1645
- drawImage(ui, canvas, paint, data);
1622
+ PaintImage.drawImage(paint, scaleX, scaleY, ui, canvas, renderOptions);
1646
1623
  return true;
1647
1624
  } else {
1648
- if (!paint.style || paint.sync || Export.running) {
1649
- createPattern(ui, paint, pixelRatio);
1650
- } else {
1651
- if (!paint.patternTask) {
1652
- paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function*() {
1653
- paint.patternTask = null;
1654
- if (canvas.bounds.hit(ui.__nowWorld)) createPattern(ui, paint, pixelRatio);
1655
- ui.forceUpdate("surface");
1656
- }), 300);
1657
- }
1658
- }
1625
+ if (!paint.style || paint.sync || exporting) PaintImage.createPattern(paint, ui, canvas, renderOptions); else PaintImage.createPatternTask(paint, ui, canvas, renderOptions);
1659
1626
  return false;
1660
1627
  }
1661
1628
  }
1662
1629
  }
1663
1630
 
1664
- function drawImage(ui, canvas, paint, data) {
1665
- canvas.save();
1666
- canvas.clipUI(ui);
1667
- if (paint.blendMode) canvas.blendMode = paint.blendMode;
1668
- if (data.opacity) canvas.opacity *= data.opacity;
1669
- if (data.transform) canvas.transform(data.transform);
1670
- canvas.drawImage(paint.image.getFull(data.filters), 0, 0, data.width, data.height);
1671
- canvas.restore();
1631
+ function drawImage(paint, _imageScaleX, _imageScaleY, ui, canvas, _renderOptions) {
1632
+ const {data: data, image: image, blendMode: blendMode} = paint, {opacity: opacity, transform: transform} = data, view = image.getFull(data.filters), u = ui.__;
1633
+ let {width: width, height: height} = image, clipUI;
1634
+ if (transform && !transform.onlyScale || (clipUI = u.path || u.cornerRadius) || opacity || blendMode) {
1635
+ canvas.save();
1636
+ clipUI && canvas.clipUI(ui);
1637
+ blendMode && (canvas.blendMode = blendMode);
1638
+ opacity && (canvas.opacity *= opacity);
1639
+ transform && canvas.transform(transform);
1640
+ canvas.drawImage(view, 0, 0, width, height);
1641
+ canvas.restore();
1642
+ } else {
1643
+ if (data.scaleX) width *= data.scaleX, height *= data.scaleY;
1644
+ canvas.drawImage(view, 0, 0, width, height);
1645
+ }
1646
+ }
1647
+
1648
+ function getImageRenderScaleData(paint, ui, canvas, _renderOptions) {
1649
+ const scaleData = ui.getRenderScaleData(true, paint.scaleFixed), {data: data} = paint;
1650
+ if (canvas) {
1651
+ const {pixelRatio: pixelRatio} = canvas;
1652
+ scaleData.scaleX *= pixelRatio;
1653
+ scaleData.scaleY *= pixelRatio;
1654
+ }
1655
+ if (data && data.scaleX) {
1656
+ scaleData.scaleX *= Math.abs(data.scaleX);
1657
+ scaleData.scaleY *= Math.abs(data.scaleY);
1658
+ }
1659
+ return scaleData;
1672
1660
  }
1673
1661
 
1674
1662
  function recycleImage(attrName, data) {
@@ -1700,8 +1688,12 @@ function recycleImage(attrName, data) {
1700
1688
  const PaintImageModule = {
1701
1689
  image: image,
1702
1690
  checkImage: checkImage,
1703
- createPattern: createPattern,
1691
+ drawImage: drawImage,
1692
+ getImageRenderScaleData: getImageRenderScaleData,
1704
1693
  recycleImage: recycleImage,
1694
+ createPatternTask: createPatternTask,
1695
+ createPattern: createPattern,
1696
+ getPatternFixScale: getPatternFixScale,
1705
1697
  createData: createData,
1706
1698
  getPatternData: getPatternData,
1707
1699
  stretchMode: stretchMode,
@@ -2157,10 +2149,8 @@ function createRows(drawData, content, style) {
2157
2149
  bounds = drawData.bounds;
2158
2150
  findMaxWidth = !bounds.width && !style.autoSizeAlign;
2159
2151
  const {__letterSpacing: __letterSpacing, paraIndent: paraIndent, textCase: textCase} = style;
2160
- const {canvas: canvas} = Platform;
2161
- const {width: width, height: height} = bounds;
2162
- const charMode = width || height || __letterSpacing || textCase !== "none";
2163
- if (charMode) {
2152
+ const {canvas: canvas} = Platform, {width: width} = bounds;
2153
+ if (style.__isCharMode) {
2164
2154
  const wrap = style.textWrap !== "none";
2165
2155
  const breakAll = style.textWrap === "break";
2166
2156
  paraStart = true;
@@ -2289,12 +2279,19 @@ const TextMode = 2;
2289
2279
  function layoutChar(drawData, style, width, _height) {
2290
2280
  const {rows: rows} = drawData;
2291
2281
  const {textAlign: textAlign, paraIndent: paraIndent, letterSpacing: letterSpacing} = style;
2292
- let charX, addWordWidth, indentWidth, mode, wordChar, wordsLength;
2282
+ const justifyLast = width && textAlign.includes("both");
2283
+ const justify = justifyLast || width && textAlign.includes("justify");
2284
+ const justifyLetter = justify && textAlign.includes("letter");
2285
+ let charX, remainingWidth, addWordWidth, addLetterWidth, indentWidth, mode, wordChar, wordsLength, isLastWord, canJustify;
2293
2286
  rows.forEach(row => {
2294
2287
  if (row.words) {
2295
2288
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0, wordsLength = row.words.length;
2296
- addWordWidth = width && (textAlign === "justify" || textAlign === "both") && wordsLength > 1 ? (width - row.width - indentWidth) / (wordsLength - 1) : 0;
2297
- mode = letterSpacing || row.isOverflow ? CharMode : addWordWidth > .01 ? WordMode : TextMode;
2289
+ if (justify) {
2290
+ canJustify = !row.paraEnd || justifyLast;
2291
+ remainingWidth = width - row.width - indentWidth;
2292
+ if (justifyLetter) addLetterWidth = remainingWidth / (row.words.reduce((total, item) => total + item.data.length, 0) - 1); else addWordWidth = wordsLength > 1 ? remainingWidth / (wordsLength - 1) : 0;
2293
+ }
2294
+ mode = letterSpacing || row.isOverflow || justifyLetter ? CharMode : addWordWidth ? WordMode : TextMode;
2298
2295
  if (row.isOverflow && !letterSpacing) row.textMode = true;
2299
2296
  if (mode === TextMode) {
2300
2297
  row.x += indentWidth;
@@ -2312,11 +2309,15 @@ function layoutChar(drawData, style, width, _height) {
2312
2309
  charX = toWordChar(word.data, charX, wordChar);
2313
2310
  if (row.isOverflow || wordChar.char !== " ") row.data.push(wordChar);
2314
2311
  } else {
2315
- charX = toChar(word.data, charX, row.data, row.isOverflow);
2312
+ charX = toChar(word.data, charX, row.data, row.isOverflow, canJustify && addLetterWidth);
2316
2313
  }
2317
- if (addWordWidth && (!row.paraEnd || textAlign === "both") && index !== wordsLength - 1) {
2318
- charX += addWordWidth;
2319
- row.width += addWordWidth;
2314
+ if (canJustify) {
2315
+ isLastWord = index === wordsLength - 1;
2316
+ if (addWordWidth) {
2317
+ if (!isLastWord) charX += addWordWidth, row.width += addWordWidth;
2318
+ } else if (addLetterWidth) {
2319
+ row.width += addLetterWidth * (word.data.length - (isLastWord ? 1 : 0));
2320
+ }
2320
2321
  }
2321
2322
  });
2322
2323
  }
@@ -2342,13 +2343,14 @@ function toWordChar(data, charX, wordChar) {
2342
2343
  return charX;
2343
2344
  }
2344
2345
 
2345
- function toChar(data, charX, rowData, isOverflow) {
2346
+ function toChar(data, charX, rowData, isOverflow, addLetterWidth) {
2346
2347
  data.forEach(char => {
2347
2348
  if (isOverflow || char.char !== " ") {
2348
2349
  char.x = charX;
2349
2350
  rowData.push(char);
2350
2351
  }
2351
2352
  charX += char.width;
2353
+ addLetterWidth && (charX += addLetterWidth);
2352
2354
  });
2353
2355
  return charX;
2354
2356
  }
@@ -2490,10 +2492,10 @@ function getDrawData(content, style) {
2490
2492
  let x = 0, y = 0;
2491
2493
  let width = style.__getInput("width") || 0;
2492
2494
  let height = style.__getInput("height") || 0;
2493
- const {textDecoration: textDecoration, __font: __font, __padding: padding} = style;
2495
+ const {__padding: padding} = style;
2494
2496
  if (padding) {
2495
- if (width) x = padding[left], width -= padding[right] + padding[left]; else if (!style.autoSizeAlign) x = padding[left];
2496
- if (height) y = padding[top], height -= padding[top] + padding[bottom]; else if (!style.autoSizeAlign) y = padding[top];
2497
+ if (width) x = padding[left], width -= padding[right] + padding[left], !width && (width = .01); else if (!style.autoSizeAlign) x = padding[left];
2498
+ if (height) y = padding[top], height -= padding[top] + padding[bottom], !height && (height = .01); else if (!style.autoSizeAlign) y = padding[top];
2497
2499
  }
2498
2500
  const drawData = {
2499
2501
  bounds: {
@@ -2504,14 +2506,14 @@ function getDrawData(content, style) {
2504
2506
  },
2505
2507
  rows: [],
2506
2508
  paraNumber: 0,
2507
- font: Platform.canvas.font = __font
2509
+ font: Platform.canvas.font = style.__font
2508
2510
  };
2509
2511
  createRows(drawData, content, style);
2510
2512
  if (padding) padAutoText(padding, drawData, style, width, height);
2511
2513
  layoutText(drawData, style);
2512
- layoutChar(drawData, style, width);
2514
+ if (style.__isCharMode) layoutChar(drawData, style, width);
2513
2515
  if (drawData.overflow) clipText(drawData, style, x, width);
2514
- if (textDecoration !== "none") decorationText(drawData, style);
2516
+ if (style.textDecoration !== "none") decorationText(drawData, style);
2515
2517
  return drawData;
2516
2518
  }
2517
2519