leafer-draw 1.9.4 → 1.9.6

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.cjs CHANGED
@@ -93,10 +93,22 @@ class LeaferCanvas extends core.LeaferCanvasBase {
93
93
  updateViewSize() {
94
94
  const {width: width, height: height, pixelRatio: pixelRatio} = this;
95
95
  const {style: style} = this.view;
96
- style.width = width + "px";
97
- style.height = height + "px";
98
- this.view.width = Math.ceil(width * pixelRatio);
99
- this.view.height = Math.ceil(height * pixelRatio);
96
+ if (this.unreal) {
97
+ const {config: config, autoWidthStr: autoWidthStr, autoHeightStr: autoHeightStr} = this;
98
+ if (config.width) {
99
+ if (core.isUndefined(autoWidthStr)) this.autoWidthStr = style.width || "";
100
+ style.width = config.width + "px";
101
+ } else if (!core.isUndefined(autoWidthStr)) style.width = autoWidthStr;
102
+ if (config.height) {
103
+ if (core.isUndefined(autoHeightStr)) this.autoHeightStr = style.height || "";
104
+ style.height = config.height + "px";
105
+ } else if (!core.isUndefined(autoHeightStr)) style.height = autoHeightStr;
106
+ } else {
107
+ style.width = width + "px";
108
+ style.height = height + "px";
109
+ this.view.width = Math.ceil(width * pixelRatio);
110
+ this.view.height = Math.ceil(height * pixelRatio);
111
+ }
100
112
  }
101
113
  updateClientBounds() {
102
114
  if (this.view.parentElement) this.clientBounds = this.view.getBoundingClientRect();
@@ -105,6 +117,7 @@ class LeaferCanvas extends core.LeaferCanvasBase {
105
117
  this.resizeListener = listener;
106
118
  if (autoBounds) {
107
119
  this.autoBounds = autoBounds;
120
+ if (this.resizeObserver) return;
108
121
  try {
109
122
  this.resizeObserver = new ResizeObserver(entries => {
110
123
  this.updateClientBounds();
@@ -121,18 +134,10 @@ class LeaferCanvas extends core.LeaferCanvasBase {
121
134
  } catch (_a) {
122
135
  this.imitateResizeObserver();
123
136
  }
137
+ this.stopListenPixelRatio();
124
138
  } else {
125
- window.addEventListener("resize", this.windowListener = () => {
126
- const pixelRatio = core.Platform.devicePixelRatio;
127
- if (!this.config.pixelRatio && this.pixelRatio !== pixelRatio) {
128
- const {width: width, height: height} = this;
129
- this.emitResize({
130
- width: width,
131
- height: height,
132
- pixelRatio: pixelRatio
133
- });
134
- }
135
- });
139
+ this.listenPixelRatio();
140
+ if (this.unreal) this.updateViewSize();
136
141
  }
137
142
  }
138
143
  imitateResizeObserver() {
@@ -141,6 +146,25 @@ class LeaferCanvas extends core.LeaferCanvasBase {
141
146
  core.Platform.requestRender(this.imitateResizeObserver.bind(this));
142
147
  }
143
148
  }
149
+ listenPixelRatio() {
150
+ if (!this.windowListener) window.addEventListener("resize", this.windowListener = () => {
151
+ const pixelRatio = core.Platform.devicePixelRatio;
152
+ if (!this.config.pixelRatio && this.pixelRatio !== pixelRatio) {
153
+ const {width: width, height: height} = this;
154
+ this.emitResize({
155
+ width: width,
156
+ height: height,
157
+ pixelRatio: pixelRatio
158
+ });
159
+ }
160
+ });
161
+ }
162
+ stopListenPixelRatio() {
163
+ if (this.windowListener) {
164
+ window.removeEventListener("resize", this.windowListener);
165
+ this.windowListener = null;
166
+ }
167
+ }
144
168
  checkAutoBounds(parentSize) {
145
169
  const view = this.view;
146
170
  const {x: x, y: y, width: width, height: height} = this.autoBounds.getBoundsFrom(parentSize);
@@ -178,10 +202,7 @@ class LeaferCanvas extends core.LeaferCanvasBase {
178
202
  destroy() {
179
203
  if (this.view) {
180
204
  this.stopAutoLayout();
181
- if (this.windowListener) {
182
- window.removeEventListener("resize", this.windowListener);
183
- this.windowListener = null;
184
- }
205
+ this.stopListenPixelRatio();
185
206
  if (!this.unreal) {
186
207
  const view = this.view;
187
208
  if (view.parentElement) view.remove();
@@ -610,7 +631,7 @@ class Renderer {
610
631
  this.times = 0;
611
632
  this.config = {
612
633
  usePartRender: true,
613
- maxFPS: 60
634
+ maxFPS: 120
614
635
  };
615
636
  this.target = target;
616
637
  this.canvas = canvas;
@@ -765,11 +786,15 @@ class Renderer {
765
786
  if (this.requestTime || !target) return;
766
787
  if (target.parentApp) return target.parentApp.requestRender(false);
767
788
  const requestTime = this.requestTime = Date.now();
768
- core.Platform.requestRender(() => {
769
- this.FPS = Math.min(60, Math.ceil(1e3 / (Date.now() - requestTime)));
789
+ const render = () => {
790
+ const nowFPS = 1e3 / (Date.now() - requestTime);
791
+ const {maxFPS: maxFPS} = this.config;
792
+ if (maxFPS && nowFPS > maxFPS - .5) return core.Platform.requestRender(render);
793
+ this.FPS = Math.min(120, Math.ceil(nowFPS));
770
794
  this.requestTime = 0;
771
795
  this.checkRender();
772
- });
796
+ };
797
+ core.Platform.requestRender(render);
773
798
  }
774
799
  __onResize(e) {
775
800
  if (this.canvas.unreal) return;
@@ -812,7 +837,8 @@ class Renderer {
812
837
  if (this.target) {
813
838
  this.stop();
814
839
  this.__removeListenEvents();
815
- this.target = this.canvas = this.config = null;
840
+ this.config = {};
841
+ this.target = this.canvas = null;
816
842
  }
817
843
  }
818
844
  }
@@ -1451,7 +1477,7 @@ function ignoreRender(ui, value) {
1451
1477
 
1452
1478
  const {get: get$1, scale: scale, copy: copy$1} = core.MatrixHelper;
1453
1479
 
1454
- const {floor: floor, max: max, abs: abs} = Math;
1480
+ const {floor: floor, ceil: ceil, max: max, abs: abs} = Math;
1455
1481
 
1456
1482
  function createPattern(ui, paint, pixelRatio) {
1457
1483
  let {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
@@ -1461,8 +1487,6 @@ function createPattern(ui, paint, pixelRatio) {
1461
1487
  let imageScale, imageMatrix, {width: width, height: height, scaleX: sx, scaleY: sy, transform: transform, repeat: repeat, gap: gap} = data;
1462
1488
  scaleX *= pixelRatio;
1463
1489
  scaleY *= pixelRatio;
1464
- const xGap = gap && gap.x * scaleX;
1465
- const yGap = gap && gap.y * scaleY;
1466
1490
  if (sx) {
1467
1491
  sx = abs(sx);
1468
1492
  sy = abs(sy);
@@ -1479,7 +1503,10 @@ function createPattern(ui, paint, pixelRatio) {
1479
1503
  if (size > core.Platform.image.maxCacheSize) return false;
1480
1504
  }
1481
1505
  let maxSize = core.Platform.image.maxPatternSize;
1482
- if (!image.isSVG) {
1506
+ if (image.isSVG) {
1507
+ const ws = width / image.width;
1508
+ if (ws > 1) imageScale = ws / ceil(ws);
1509
+ } else {
1483
1510
  const imageSize = image.width * image.height;
1484
1511
  if (maxSize > imageSize) maxSize = imageSize;
1485
1512
  }
@@ -1494,18 +1521,20 @@ function createPattern(ui, paint, pixelRatio) {
1494
1521
  scaleX /= sx;
1495
1522
  scaleY /= sy;
1496
1523
  }
1524
+ const xGap = gap && gap.x * scaleX;
1525
+ const yGap = gap && gap.y * scaleY;
1497
1526
  if (transform || scaleX !== 1 || scaleY !== 1) {
1527
+ const canvasWidth = width + (xGap || 0);
1528
+ const canvasHeight = height + (yGap || 0);
1529
+ scaleX /= canvasWidth / max(floor(canvasWidth), 1);
1530
+ scaleY /= canvasHeight / max(floor(canvasHeight), 1);
1498
1531
  if (!imageMatrix) {
1499
1532
  imageMatrix = get$1();
1500
1533
  if (transform) copy$1(imageMatrix, transform);
1501
1534
  }
1502
1535
  scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1503
1536
  }
1504
- if (imageMatrix) {
1505
- const canvasWidth = width + (xGap || 0), canvasHeight = height + (yGap || 0);
1506
- scale(imageMatrix, canvasWidth / max(floor(canvasWidth), 1), canvasHeight / max(floor(canvasHeight), 1));
1507
- }
1508
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap);
1537
+ const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1509
1538
  const pattern = image.getPattern(canvas, repeat || (core.Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1510
1539
  paint.style = pattern;
1511
1540
  paint.patternId = id;
@@ -1780,12 +1809,18 @@ function shadow(ui, current, shape) {
1780
1809
  }
1781
1810
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, "destination-out") : other.copyWorld(shape.canvas, shapeBounds, bounds, "destination-out");
1782
1811
  }
1783
- core.LeafHelper.copyCanvasByWorld(ui, current, other, copyBounds, item.blendMode);
1812
+ if (draw.Effect.isTransformShadow(item)) draw.Effect.renderTransformShadow(ui, current, other, copyBounds, item); else core.LeafHelper.copyCanvasByWorld(ui, current, other, copyBounds, item.blendMode);
1784
1813
  if (end && index < end) other.clearWorld(copyBounds);
1785
1814
  });
1786
1815
  other.recycle(copyBounds);
1787
1816
  }
1788
1817
 
1818
+ function getShadowSpread(_ui, shadow) {
1819
+ let width = 0;
1820
+ shadow.forEach(item => width = Math.max(width, Math.max(Math.abs(item.y), Math.abs(item.x)) + (item.spread > 0 ? item.spread : 0) + item.blur * 1.5));
1821
+ return width;
1822
+ }
1823
+
1789
1824
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1790
1825
  const {bounds: bounds, shapeBounds: shapeBounds} = shape;
1791
1826
  if (core.Platform.fullImageShadow) {
@@ -1863,7 +1898,11 @@ const EffectModule = {
1863
1898
  shadow: shadow,
1864
1899
  innerShadow: innerShadow,
1865
1900
  blur: blur,
1866
- backgroundBlur: backgroundBlur
1901
+ backgroundBlur: backgroundBlur,
1902
+ getShadowSpread: getShadowSpread,
1903
+ isTransformShadow(_shadow) {
1904
+ return undefined;
1905
+ }
1867
1906
  };
1868
1907
 
1869
1908
  const {excludeRenderBounds: excludeRenderBounds} = core.LeafBoundsHelper;
@@ -2371,16 +2410,17 @@ function toTextChar(row) {
2371
2410
  }
2372
2411
 
2373
2412
  function decorationText(drawData, style) {
2374
- let type;
2413
+ let type, offset = 0;
2375
2414
  const {fontSize: fontSize, textDecoration: textDecoration} = style;
2376
2415
  drawData.decorationHeight = fontSize / 11;
2377
2416
  if (core.isObject(textDecoration)) {
2378
2417
  type = textDecoration.type;
2379
2418
  if (textDecoration.color) drawData.decorationColor = draw.ColorConvert.string(textDecoration.color);
2419
+ if (textDecoration.offset) offset = Math.min(fontSize * .3, Math.max(textDecoration.offset, -fontSize * .15));
2380
2420
  } else type = textDecoration;
2381
2421
  switch (type) {
2382
2422
  case "under":
2383
- drawData.decorationY = [ fontSize * .15 ];
2423
+ drawData.decorationY = [ fontSize * .15 + offset ];
2384
2424
  break;
2385
2425
 
2386
2426
  case "delete":
@@ -2388,7 +2428,7 @@ function decorationText(drawData, style) {
2388
2428
  break;
2389
2429
 
2390
2430
  case "under-delete":
2391
- drawData.decorationY = [ fontSize * .15, -fontSize * .35 ];
2431
+ drawData.decorationY = [ fontSize * .15 + offset, -fontSize * .35 ];
2392
2432
  }
2393
2433
  }
2394
2434
 
package/dist/web.esm.js CHANGED
@@ -1,10 +1,10 @@
1
- import { Debug, LeaferCanvasBase, Platform, isString, DataHelper, canvasSizeAttrs, isUndefined, ResizeEvent, canvasPatch, FileHelper, Creator, LeaferImage, defineKey, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, LeafBoundsHelper, Bounds, isArray, LeafLevelList, LayoutEvent, Run, ImageManager, isObject, BoundsHelper, 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, Matrix, getMatrixData, MatrixHelper, MathHelper, AlignHelper, PointHelper, ImageEvent, 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, Group, TextConvert, Effect } from "@leafer-ui/draw";
7
+ import { PaintImage, Paint, ColorConvert, PaintGradient, Export, Effect, Group, TextConvert } from "@leafer-ui/draw";
8
8
 
9
9
  export * from "@leafer-ui/draw";
10
10
 
@@ -97,10 +97,22 @@ class LeaferCanvas extends LeaferCanvasBase {
97
97
  updateViewSize() {
98
98
  const {width: width, height: height, pixelRatio: pixelRatio} = this;
99
99
  const {style: style} = this.view;
100
- style.width = width + "px";
101
- style.height = height + "px";
102
- this.view.width = Math.ceil(width * pixelRatio);
103
- this.view.height = Math.ceil(height * pixelRatio);
100
+ if (this.unreal) {
101
+ const {config: config, autoWidthStr: autoWidthStr, autoHeightStr: autoHeightStr} = this;
102
+ if (config.width) {
103
+ if (isUndefined(autoWidthStr)) this.autoWidthStr = style.width || "";
104
+ style.width = config.width + "px";
105
+ } else if (!isUndefined(autoWidthStr)) style.width = autoWidthStr;
106
+ if (config.height) {
107
+ if (isUndefined(autoHeightStr)) this.autoHeightStr = style.height || "";
108
+ style.height = config.height + "px";
109
+ } else if (!isUndefined(autoHeightStr)) style.height = autoHeightStr;
110
+ } else {
111
+ style.width = width + "px";
112
+ style.height = height + "px";
113
+ this.view.width = Math.ceil(width * pixelRatio);
114
+ this.view.height = Math.ceil(height * pixelRatio);
115
+ }
104
116
  }
105
117
  updateClientBounds() {
106
118
  if (this.view.parentElement) this.clientBounds = this.view.getBoundingClientRect();
@@ -109,6 +121,7 @@ class LeaferCanvas extends LeaferCanvasBase {
109
121
  this.resizeListener = listener;
110
122
  if (autoBounds) {
111
123
  this.autoBounds = autoBounds;
124
+ if (this.resizeObserver) return;
112
125
  try {
113
126
  this.resizeObserver = new ResizeObserver(entries => {
114
127
  this.updateClientBounds();
@@ -125,18 +138,10 @@ class LeaferCanvas extends LeaferCanvasBase {
125
138
  } catch (_a) {
126
139
  this.imitateResizeObserver();
127
140
  }
141
+ this.stopListenPixelRatio();
128
142
  } else {
129
- window.addEventListener("resize", this.windowListener = () => {
130
- const pixelRatio = Platform.devicePixelRatio;
131
- if (!this.config.pixelRatio && this.pixelRatio !== pixelRatio) {
132
- const {width: width, height: height} = this;
133
- this.emitResize({
134
- width: width,
135
- height: height,
136
- pixelRatio: pixelRatio
137
- });
138
- }
139
- });
143
+ this.listenPixelRatio();
144
+ if (this.unreal) this.updateViewSize();
140
145
  }
141
146
  }
142
147
  imitateResizeObserver() {
@@ -145,6 +150,25 @@ class LeaferCanvas extends LeaferCanvasBase {
145
150
  Platform.requestRender(this.imitateResizeObserver.bind(this));
146
151
  }
147
152
  }
153
+ listenPixelRatio() {
154
+ if (!this.windowListener) window.addEventListener("resize", this.windowListener = () => {
155
+ const pixelRatio = Platform.devicePixelRatio;
156
+ if (!this.config.pixelRatio && this.pixelRatio !== pixelRatio) {
157
+ const {width: width, height: height} = this;
158
+ this.emitResize({
159
+ width: width,
160
+ height: height,
161
+ pixelRatio: pixelRatio
162
+ });
163
+ }
164
+ });
165
+ }
166
+ stopListenPixelRatio() {
167
+ if (this.windowListener) {
168
+ window.removeEventListener("resize", this.windowListener);
169
+ this.windowListener = null;
170
+ }
171
+ }
148
172
  checkAutoBounds(parentSize) {
149
173
  const view = this.view;
150
174
  const {x: x, y: y, width: width, height: height} = this.autoBounds.getBoundsFrom(parentSize);
@@ -182,10 +206,7 @@ class LeaferCanvas extends LeaferCanvasBase {
182
206
  destroy() {
183
207
  if (this.view) {
184
208
  this.stopAutoLayout();
185
- if (this.windowListener) {
186
- window.removeEventListener("resize", this.windowListener);
187
- this.windowListener = null;
188
- }
209
+ this.stopListenPixelRatio();
189
210
  if (!this.unreal) {
190
211
  const view = this.view;
191
212
  if (view.parentElement) view.remove();
@@ -614,7 +635,7 @@ class Renderer {
614
635
  this.times = 0;
615
636
  this.config = {
616
637
  usePartRender: true,
617
- maxFPS: 60
638
+ maxFPS: 120
618
639
  };
619
640
  this.target = target;
620
641
  this.canvas = canvas;
@@ -769,11 +790,15 @@ class Renderer {
769
790
  if (this.requestTime || !target) return;
770
791
  if (target.parentApp) return target.parentApp.requestRender(false);
771
792
  const requestTime = this.requestTime = Date.now();
772
- Platform.requestRender(() => {
773
- this.FPS = Math.min(60, Math.ceil(1e3 / (Date.now() - requestTime)));
793
+ const render = () => {
794
+ const nowFPS = 1e3 / (Date.now() - requestTime);
795
+ const {maxFPS: maxFPS} = this.config;
796
+ if (maxFPS && nowFPS > maxFPS - .5) return Platform.requestRender(render);
797
+ this.FPS = Math.min(120, Math.ceil(nowFPS));
774
798
  this.requestTime = 0;
775
799
  this.checkRender();
776
- });
800
+ };
801
+ Platform.requestRender(render);
777
802
  }
778
803
  __onResize(e) {
779
804
  if (this.canvas.unreal) return;
@@ -816,7 +841,8 @@ class Renderer {
816
841
  if (this.target) {
817
842
  this.stop();
818
843
  this.__removeListenEvents();
819
- this.target = this.canvas = this.config = null;
844
+ this.config = {};
845
+ this.target = this.canvas = null;
820
846
  }
821
847
  }
822
848
  }
@@ -1455,7 +1481,7 @@ function ignoreRender(ui, value) {
1455
1481
 
1456
1482
  const {get: get$1, scale: scale, copy: copy$1} = MatrixHelper;
1457
1483
 
1458
- const {floor: floor, max: max, abs: abs} = Math;
1484
+ const {floor: floor, ceil: ceil, max: max, abs: abs} = Math;
1459
1485
 
1460
1486
  function createPattern(ui, paint, pixelRatio) {
1461
1487
  let {scaleX: scaleX, scaleY: scaleY} = ui.getRenderScaleData(true, paint.scaleFixed);
@@ -1465,8 +1491,6 @@ function createPattern(ui, paint, pixelRatio) {
1465
1491
  let imageScale, imageMatrix, {width: width, height: height, scaleX: sx, scaleY: sy, transform: transform, repeat: repeat, gap: gap} = data;
1466
1492
  scaleX *= pixelRatio;
1467
1493
  scaleY *= pixelRatio;
1468
- const xGap = gap && gap.x * scaleX;
1469
- const yGap = gap && gap.y * scaleY;
1470
1494
  if (sx) {
1471
1495
  sx = abs(sx);
1472
1496
  sy = abs(sy);
@@ -1483,7 +1507,10 @@ function createPattern(ui, paint, pixelRatio) {
1483
1507
  if (size > Platform.image.maxCacheSize) return false;
1484
1508
  }
1485
1509
  let maxSize = Platform.image.maxPatternSize;
1486
- if (!image.isSVG) {
1510
+ if (image.isSVG) {
1511
+ const ws = width / image.width;
1512
+ if (ws > 1) imageScale = ws / ceil(ws);
1513
+ } else {
1487
1514
  const imageSize = image.width * image.height;
1488
1515
  if (maxSize > imageSize) maxSize = imageSize;
1489
1516
  }
@@ -1498,18 +1525,20 @@ function createPattern(ui, paint, pixelRatio) {
1498
1525
  scaleX /= sx;
1499
1526
  scaleY /= sy;
1500
1527
  }
1528
+ const xGap = gap && gap.x * scaleX;
1529
+ const yGap = gap && gap.y * scaleY;
1501
1530
  if (transform || scaleX !== 1 || scaleY !== 1) {
1531
+ const canvasWidth = width + (xGap || 0);
1532
+ const canvasHeight = height + (yGap || 0);
1533
+ scaleX /= canvasWidth / max(floor(canvasWidth), 1);
1534
+ scaleY /= canvasHeight / max(floor(canvasHeight), 1);
1502
1535
  if (!imageMatrix) {
1503
1536
  imageMatrix = get$1();
1504
1537
  if (transform) copy$1(imageMatrix, transform);
1505
1538
  }
1506
1539
  scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1507
1540
  }
1508
- if (imageMatrix) {
1509
- const canvasWidth = width + (xGap || 0), canvasHeight = height + (yGap || 0);
1510
- scale(imageMatrix, canvasWidth / max(floor(canvasWidth), 1), canvasHeight / max(floor(canvasHeight), 1));
1511
- }
1512
- const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap);
1541
+ const canvas = image.getCanvas(width, height, data.opacity, data.filters, xGap, yGap, ui.leafer && ui.leafer.config.smooth);
1513
1542
  const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || "no-repeat"), imageMatrix, paint);
1514
1543
  paint.style = pattern;
1515
1544
  paint.patternId = id;
@@ -1784,12 +1813,18 @@ function shadow(ui, current, shape) {
1784
1813
  }
1785
1814
  worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, "destination-out") : other.copyWorld(shape.canvas, shapeBounds, bounds, "destination-out");
1786
1815
  }
1787
- LeafHelper.copyCanvasByWorld(ui, current, other, copyBounds, item.blendMode);
1816
+ if (Effect.isTransformShadow(item)) Effect.renderTransformShadow(ui, current, other, copyBounds, item); else LeafHelper.copyCanvasByWorld(ui, current, other, copyBounds, item.blendMode);
1788
1817
  if (end && index < end) other.clearWorld(copyBounds);
1789
1818
  });
1790
1819
  other.recycle(copyBounds);
1791
1820
  }
1792
1821
 
1822
+ function getShadowSpread(_ui, shadow) {
1823
+ let width = 0;
1824
+ shadow.forEach(item => width = Math.max(width, Math.max(Math.abs(item.y), Math.abs(item.x)) + (item.spread > 0 ? item.spread : 0) + item.blur * 1.5));
1825
+ return width;
1826
+ }
1827
+
1793
1828
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1794
1829
  const {bounds: bounds, shapeBounds: shapeBounds} = shape;
1795
1830
  if (Platform.fullImageShadow) {
@@ -1867,7 +1902,11 @@ const EffectModule = {
1867
1902
  shadow: shadow,
1868
1903
  innerShadow: innerShadow,
1869
1904
  blur: blur,
1870
- backgroundBlur: backgroundBlur
1905
+ backgroundBlur: backgroundBlur,
1906
+ getShadowSpread: getShadowSpread,
1907
+ isTransformShadow(_shadow) {
1908
+ return undefined;
1909
+ }
1871
1910
  };
1872
1911
 
1873
1912
  const {excludeRenderBounds: excludeRenderBounds} = LeafBoundsHelper;
@@ -2375,16 +2414,17 @@ function toTextChar(row) {
2375
2414
  }
2376
2415
 
2377
2416
  function decorationText(drawData, style) {
2378
- let type;
2417
+ let type, offset = 0;
2379
2418
  const {fontSize: fontSize, textDecoration: textDecoration} = style;
2380
2419
  drawData.decorationHeight = fontSize / 11;
2381
2420
  if (isObject(textDecoration)) {
2382
2421
  type = textDecoration.type;
2383
2422
  if (textDecoration.color) drawData.decorationColor = ColorConvert.string(textDecoration.color);
2423
+ if (textDecoration.offset) offset = Math.min(fontSize * .3, Math.max(textDecoration.offset, -fontSize * .15));
2384
2424
  } else type = textDecoration;
2385
2425
  switch (type) {
2386
2426
  case "under":
2387
- drawData.decorationY = [ fontSize * .15 ];
2427
+ drawData.decorationY = [ fontSize * .15 + offset ];
2388
2428
  break;
2389
2429
 
2390
2430
  case "delete":
@@ -2392,7 +2432,7 @@ function decorationText(drawData, style) {
2392
2432
  break;
2393
2433
 
2394
2434
  case "under-delete":
2395
- drawData.decorationY = [ fontSize * .15, -fontSize * .35 ];
2435
+ drawData.decorationY = [ fontSize * .15 + offset, -fontSize * .35 ];
2396
2436
  }
2397
2437
  }
2398
2438