@leafer-ui/miniapp 1.0.0-rc.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,220 @@
1
- import { LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, Platform, AnimateEvent, ResizeEvent, BoundsHelper, Creator, LeaferCanvasBase, canvasPatch, canvasSizeAttrs, InteractionHelper, InteractionBase, LeaferImage, FileHelper, MatrixHelper, ImageEvent, PointHelper, Direction4, TaskProcessor } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, DataHelper, canvasSizeAttrs, ResizeEvent, Creator, LeaferImage, FileHelper, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, BoundsHelper, Answer, MatrixHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
- import { ColorConvert as ColorConvert$1, ImageManager as ImageManager$1, Paint, Effect, TextConvert as TextConvert$1, Export as Export$2, Platform as Platform$1 } from '@leafer-ui/core';
4
+ import { InteractionHelper, InteractionBase, HitCanvasManager, Platform as Platform$1 } from '@leafer-ui/core';
5
5
  export * from '@leafer-ui/core';
6
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
7
+
8
+ class LeaferCanvas extends LeaferCanvasBase {
9
+ get allowBackgroundColor() { return false; }
10
+ init() {
11
+ let { view } = this.config;
12
+ if (view) {
13
+ if (typeof view === 'string') {
14
+ if (view[0] !== '#')
15
+ view = '#' + view;
16
+ this.viewSelect = Platform.miniapp.select(view);
17
+ }
18
+ else if (view.fields) {
19
+ this.viewSelect = view;
20
+ }
21
+ else {
22
+ this.initView(view);
23
+ }
24
+ if (this.viewSelect)
25
+ Platform.miniapp.getSizeView(this.viewSelect).then(sizeView => {
26
+ this.initView(sizeView);
27
+ });
28
+ }
29
+ else {
30
+ this.initView();
31
+ }
32
+ }
33
+ initView(view) {
34
+ if (!view) {
35
+ view = {};
36
+ this.__createView();
37
+ }
38
+ else {
39
+ this.view = view.view || view;
40
+ }
41
+ this.__createContext();
42
+ const { width, height, pixelRatio } = this.config;
43
+ const size = { width: width || view.width, height: height || view.height, pixelRatio };
44
+ this.resize(size);
45
+ if (this.context.roundRect) {
46
+ this.roundRect = function (x, y, width, height, radius) {
47
+ this.context.roundRect(x, y, width, height, typeof radius === 'number' ? [radius] : radius);
48
+ };
49
+ }
50
+ canvasPatch(this.context.__proto__);
51
+ }
52
+ __createView() {
53
+ this.view = Platform.origin.createCanvas(1, 1);
54
+ }
55
+ updateViewSize() {
56
+ const { width, height, pixelRatio } = this;
57
+ this.view.width = Math.ceil(width * pixelRatio);
58
+ this.view.height = Math.ceil(height * pixelRatio);
59
+ }
60
+ updateClientBounds(callback) {
61
+ if (this.viewSelect)
62
+ Platform.miniapp.getBounds(this.viewSelect).then(bounds => {
63
+ this.clientBounds = bounds;
64
+ if (callback)
65
+ callback();
66
+ });
67
+ }
68
+ startAutoLayout(_autoBounds, listener) {
69
+ this.resizeListener = listener;
70
+ this.checkSize = this.checkSize.bind(this);
71
+ Platform.miniapp.onWindowResize(this.checkSize);
72
+ }
73
+ checkSize() {
74
+ if (this.viewSelect) {
75
+ setTimeout(() => {
76
+ this.updateClientBounds(() => {
77
+ const { width, height } = this.clientBounds;
78
+ const { pixelRatio } = this;
79
+ const size = { width, height, pixelRatio };
80
+ if (!this.isSameSize(size)) {
81
+ const oldSize = {};
82
+ DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
83
+ this.resize(size);
84
+ if (this.width !== undefined)
85
+ this.resizeListener(new ResizeEvent(size, oldSize));
86
+ }
87
+ });
88
+ }, 500);
89
+ }
90
+ }
91
+ stopAutoLayout() {
92
+ this.autoLayout = false;
93
+ this.resizeListener = null;
94
+ Platform.miniapp.offWindowResize(this.checkSize);
95
+ }
96
+ }
97
+
98
+ const { mineType, fileType } = FileHelper;
99
+ Object.assign(Creator, {
100
+ canvas: (options, manager) => new LeaferCanvas(options, manager),
101
+ image: (options) => new LeaferImage(options)
102
+ });
103
+ function useCanvas(_canvasType, app) {
104
+ if (!Platform.origin) {
105
+ Platform.origin = {
106
+ createCanvas: (width, height, _format) => app.createOffscreenCanvas({ type: '2d', width, height }),
107
+ canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
108
+ canvasToBolb: (canvas, type, quality) => canvas.toBuffer(type, { quality }),
109
+ canvasSaveAs: (canvas, filePath, quality) => {
110
+ let data = canvas.toDataURL(mineType(fileType(filePath)), quality);
111
+ data = data.substring(data.indexOf('64,') + 3);
112
+ return Platform.origin.download(data, filePath);
113
+ },
114
+ download(data, filePath) {
115
+ return new Promise((resolve, reject) => {
116
+ let toAlbum;
117
+ if (!filePath.includes('/')) {
118
+ filePath = `${app.env.USER_DATA_PATH}/` + filePath;
119
+ toAlbum = true;
120
+ }
121
+ const fs = app.getFileSystemManager();
122
+ fs.writeFile({
123
+ filePath,
124
+ data,
125
+ encoding: 'base64',
126
+ success() {
127
+ if (toAlbum) {
128
+ Platform.miniapp.saveToAlbum(filePath).then(() => {
129
+ fs.unlink({ filePath });
130
+ resolve();
131
+ });
132
+ }
133
+ else {
134
+ resolve();
135
+ }
136
+ },
137
+ fail(error) {
138
+ reject(error);
139
+ }
140
+ });
141
+ });
142
+ },
143
+ loadImage(src) {
144
+ return new Promise((resolve, reject) => {
145
+ const img = Platform.canvas.view.createImage();
146
+ img.onload = () => { resolve(img); };
147
+ img.onerror = (error) => { reject(error); };
148
+ img.src = Platform.image.getRealURL(src);
149
+ });
150
+ },
151
+ noRepeat: 'repeat-x'
152
+ };
153
+ Platform.miniapp = {
154
+ select(name) {
155
+ return app.createSelectorQuery().select(name);
156
+ },
157
+ getBounds(select) {
158
+ return new Promise((resolve) => {
159
+ select.boundingClientRect().exec((res) => {
160
+ const rect = res[1];
161
+ resolve({ x: rect.top, y: rect.left, width: rect.width, height: rect.height });
162
+ });
163
+ });
164
+ },
165
+ getSizeView(select) {
166
+ return new Promise((resolve) => {
167
+ select.fields({ node: true, size: true }).exec((res) => {
168
+ const data = res[0];
169
+ resolve({ view: data.node, width: data.width, height: data.height });
170
+ });
171
+ });
172
+ },
173
+ saveToAlbum(path) {
174
+ return new Promise((resolve) => {
175
+ app.getSetting({
176
+ success: (res) => {
177
+ if (res.authSetting['scope.writePhotosAlbum']) {
178
+ app.saveImageToPhotosAlbum({
179
+ filePath: path,
180
+ success() { resolve(true); }
181
+ });
182
+ }
183
+ else {
184
+ app.authorize({
185
+ scope: 'scope.writePhotosAlbum',
186
+ success: () => {
187
+ app.saveImageToPhotosAlbum({
188
+ filePath: path,
189
+ success() { resolve(true); }
190
+ });
191
+ },
192
+ fail: () => { }
193
+ });
194
+ }
195
+ }
196
+ });
197
+ });
198
+ },
199
+ onWindowResize(fun) {
200
+ app.onWindowResize(fun);
201
+ },
202
+ offWindowResize(fun) {
203
+ app.offWindowResize(fun);
204
+ }
205
+ };
206
+ Platform.event = {
207
+ stopDefault(_origin) { },
208
+ stopNow(_origin) { },
209
+ stop(_origin) { }
210
+ };
211
+ Platform.canvas = Creator.canvas();
212
+ Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
213
+ }
214
+ }
215
+ Platform.name = 'miniapp';
216
+ Platform.requestRender = function (render) { Platform.canvas.view.requestAnimationFrame(render); };
217
+ Platform.devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
6
218
 
7
219
  class Watcher {
8
220
  get childrenChanged() { return this.hasAdd || this.hasRemove || this.hasVisible; }
@@ -185,7 +397,7 @@ class LayoutBlockData {
185
397
  }
186
398
 
187
399
  const { updateAllMatrix, updateAllChange } = LeafHelper;
188
- const debug$1 = Debug.get('Layouter');
400
+ const debug$2 = Debug.get('Layouter');
189
401
  class Layouter {
190
402
  constructor(target, userConfig) {
191
403
  this.totalTimes = 0;
@@ -220,7 +432,7 @@ class Layouter {
220
432
  target.emitEvent(new LayoutEvent(LayoutEvent.END, this.layoutedBlocks, this.times));
221
433
  }
222
434
  catch (e) {
223
- debug$1.error(e);
435
+ debug$2.error(e);
224
436
  }
225
437
  this.layoutedBlocks = null;
226
438
  }
@@ -234,9 +446,9 @@ class Layouter {
234
446
  }
235
447
  layoutOnce() {
236
448
  if (this.layouting)
237
- return debug$1.warn('layouting');
449
+ return debug$2.warn('layouting');
238
450
  if (this.times > 3)
239
- return debug$1.warn('layout max times');
451
+ return debug$2.warn('layout max times');
240
452
  this.times++;
241
453
  this.totalTimes++;
242
454
  this.layouting = true;
@@ -302,9 +514,11 @@ class Layouter {
302
514
  updateAllChange(target);
303
515
  }
304
516
  addExtra(leaf) {
305
- const block = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
306
- block.updatedList.add(leaf);
307
- block.beforeBounds.add(leaf.__world);
517
+ if (!this.__updatedList.has(leaf)) {
518
+ const { updatedList, beforeBounds } = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
519
+ updatedList.length ? beforeBounds.add(leaf.__world) : beforeBounds.set(leaf.__world);
520
+ updatedList.add(leaf);
521
+ }
308
522
  }
309
523
  createBlock(data) {
310
524
  return new LayoutBlockData(data);
@@ -338,7 +552,7 @@ class Layouter {
338
552
  }
339
553
  }
340
554
 
341
- const debug = Debug.get('Renderer');
555
+ const debug$1 = Debug.get('Renderer');
342
556
  class Renderer {
343
557
  get needFill() { return !!(!this.canvas.allowBackgroundColor && this.config.fill); }
344
558
  constructor(target, canvas, userConfig) {
@@ -376,7 +590,7 @@ class Renderer {
376
590
  const { target } = this;
377
591
  this.times = 0;
378
592
  this.totalBounds = new Bounds();
379
- debug.log(target.innerName, '--->');
593
+ debug$1.log(target.innerName, '--->');
380
594
  try {
381
595
  this.emitRender(RenderEvent.START);
382
596
  this.renderOnce(callback);
@@ -385,9 +599,9 @@ class Renderer {
385
599
  }
386
600
  catch (e) {
387
601
  this.rendering = false;
388
- debug.error(e);
602
+ debug$1.error(e);
389
603
  }
390
- debug.log('-------------|');
604
+ debug$1.log('-------------|');
391
605
  }
392
606
  renderAgain() {
393
607
  if (this.rendering) {
@@ -399,9 +613,9 @@ class Renderer {
399
613
  }
400
614
  renderOnce(callback) {
401
615
  if (this.rendering)
402
- return debug.warn('rendering');
616
+ return debug$1.warn('rendering');
403
617
  if (this.times > 3)
404
- return debug.warn('render max times');
618
+ return debug$1.warn('render max times');
405
619
  this.times++;
406
620
  this.totalTimes++;
407
621
  this.rendering = true;
@@ -414,6 +628,10 @@ class Renderer {
414
628
  }
415
629
  else {
416
630
  this.requestLayout();
631
+ if (this.ignore) {
632
+ this.ignore = this.rendering = false;
633
+ return;
634
+ }
417
635
  this.emitRender(RenderEvent.BEFORE);
418
636
  if (this.config.usePartRender && this.totalTimes > 1) {
419
637
  this.partRender();
@@ -434,7 +652,7 @@ class Renderer {
434
652
  partRender() {
435
653
  const { canvas, updateBlocks: list } = this;
436
654
  if (!list)
437
- return debug.warn('PartRender: need update attr');
655
+ return debug$1.warn('PartRender: need update attr');
438
656
  this.mergeBlocks();
439
657
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
440
658
  this.clipRender(block); });
@@ -450,7 +668,7 @@ class Renderer {
450
668
  canvas.clear();
451
669
  }
452
670
  else {
453
- bounds.spread(1 + 1 / this.canvas.pixelRatio).ceil();
671
+ bounds.spread(10 + 1 / this.canvas.pixelRatio).ceil();
454
672
  canvas.clearWorld(bounds, true);
455
673
  canvas.clipWorld(bounds, true);
456
674
  }
@@ -503,12 +721,12 @@ class Renderer {
503
721
  const startTime = Date.now();
504
722
  Platform.requestRender(() => {
505
723
  this.FPS = Math.min(60, Math.ceil(1000 / (Date.now() - startTime)));
506
- if (this.changed) {
507
- if (this.running && this.canvas.view)
724
+ if (this.running) {
725
+ this.target.emit(AnimateEvent.FRAME);
726
+ if (this.changed && this.canvas.view)
508
727
  this.render();
728
+ this.target.emit(RenderEvent.NEXT);
509
729
  }
510
- if (this.running)
511
- this.target.emit(AnimateEvent.FRAME);
512
730
  if (this.target)
513
731
  this.__requestRender();
514
732
  });
@@ -521,9 +739,12 @@ class Renderer {
521
739
  const bounds = new Bounds(0, 0, width, height);
522
740
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
523
741
  this.addBlock(this.canvas.bounds);
524
- this.target.forceUpdate('blendMode');
742
+ this.target.forceUpdate('surface');
743
+ return;
525
744
  }
526
745
  }
746
+ this.addBlock(new Bounds(0, 0, 1, 1));
747
+ this.changed = true;
527
748
  }
528
749
  __onLayoutEnd(event) {
529
750
  if (event.data)
@@ -534,7 +755,7 @@ class Renderer {
534
755
  empty = (!leaf.__world.width || !leaf.__world.height);
535
756
  if (empty) {
536
757
  if (!leaf.isLeafer)
537
- debug.tip(leaf.innerName, ': empty');
758
+ debug$1.tip(leaf.innerName, ': empty');
538
759
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
539
760
  }
540
761
  return empty;
@@ -561,23 +782,13 @@ class Renderer {
561
782
  if (this.target) {
562
783
  this.stop();
563
784
  this.__removeListenEvents();
564
- this.target = null;
565
- this.canvas = null;
566
- this.config = null;
785
+ this.target = this.canvas = this.config = null;
567
786
  }
568
787
  }
569
788
  }
570
789
 
571
- var AnswerType;
572
- (function (AnswerType) {
573
- AnswerType[AnswerType["No"] = 0] = "No";
574
- AnswerType[AnswerType["Yes"] = 1] = "Yes";
575
- AnswerType[AnswerType["NoAndSkip"] = 2] = "NoAndSkip";
576
- AnswerType[AnswerType["YesAndSkip"] = 3] = "YesAndSkip";
577
- })(AnswerType || (AnswerType = {}));
578
-
579
790
  const { hitRadiusPoint } = BoundsHelper;
580
- class Pather {
791
+ class Picker {
581
792
  constructor(target, selector) {
582
793
  this.target = target;
583
794
  this.selector = selector;
@@ -589,33 +800,41 @@ class Pather {
589
800
  options = {};
590
801
  const through = options.through || false;
591
802
  const ignoreHittable = options.ignoreHittable || false;
803
+ const target = options.target || this.target;
592
804
  this.exclude = options.exclude || null;
593
805
  this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius };
594
- this.findList = [];
595
- this.eachFind(this.target.children, this.target.__onlyHitMask);
596
- const list = this.findList;
597
- const leaf = this.getBestMatchLeaf();
806
+ this.findList = new LeafList(options.findList);
807
+ if (!options.findList)
808
+ this.hitBranch(target);
809
+ const { list } = this.findList;
810
+ const leaf = this.getBestMatchLeaf(list, options.bottomList, ignoreHittable);
598
811
  const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf);
599
812
  this.clear();
600
- return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf };
813
+ return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf };
601
814
  }
602
- getBestMatchLeaf() {
603
- const { findList: targets } = this;
604
- if (targets.length > 1) {
815
+ getBestMatchLeaf(list, bottomList, ignoreHittable) {
816
+ if (list.length) {
605
817
  let find;
606
- this.findList = [];
818
+ this.findList = new LeafList();
607
819
  const { x, y } = this.point;
608
820
  const point = { x, y, radiusX: 0, radiusY: 0 };
609
- for (let i = 0, len = targets.length; i < len; i++) {
610
- find = targets[i];
611
- if (LeafHelper.worldHittable(find)) {
821
+ for (let i = 0, len = list.length; i < len; i++) {
822
+ find = list[i];
823
+ if (ignoreHittable || LeafHelper.worldHittable(find)) {
612
824
  this.hitChild(find, point);
613
825
  if (this.findList.length)
614
- return this.findList[0];
826
+ return this.findList.list[0];
615
827
  }
616
828
  }
617
829
  }
618
- return targets[0];
830
+ if (bottomList) {
831
+ for (let i = 0, len = bottomList.length; i < len; i++) {
832
+ this.hitChild(bottomList[i].target, this.point, bottomList[i].proxy);
833
+ if (this.findList.length)
834
+ return this.findList.list[0];
835
+ }
836
+ }
837
+ return list[0];
619
838
  }
620
839
  getPath(leaf) {
621
840
  const path = new LeafList();
@@ -627,7 +846,7 @@ class Pather {
627
846
  return path;
628
847
  }
629
848
  getHitablePath(leaf) {
630
- const path = this.getPath(leaf);
849
+ const path = this.getPath(leaf && leaf.hittable ? leaf : null);
631
850
  let item, hittablePath = new LeafList();
632
851
  for (let i = path.list.length - 1; i > -1; i--) {
633
852
  item = path.list[i];
@@ -657,12 +876,15 @@ class Pather {
657
876
  }
658
877
  return throughPath;
659
878
  }
879
+ hitBranch(branch) {
880
+ this.eachFind(branch.children, branch.__onlyHitMask);
881
+ }
660
882
  eachFind(children, hitMask) {
661
883
  let child, hit;
662
884
  const { point } = this, len = children.length;
663
885
  for (let i = len - 1; i > -1; i--) {
664
886
  child = children[i];
665
- if (!child.__.visible || (hitMask && !child.__.isMask))
887
+ if (!child.__.visible || (hitMask && !child.__.mask))
666
888
  continue;
667
889
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
668
890
  if (child.isBranch) {
@@ -678,11 +900,15 @@ class Pather {
678
900
  }
679
901
  }
680
902
  }
681
- hitChild(child, point) {
903
+ hitChild(child, point, proxy) {
682
904
  if (this.exclude && this.exclude.has(child))
683
905
  return;
684
- if (child.__hitWorld(point))
685
- this.findList.push(child);
906
+ if (child.__hitWorld(point)) {
907
+ const { parent } = child;
908
+ if (parent && parent.__hasMask && !child.__.mask && !parent.children.some(item => item.__.mask && item.__hitWorld(point)))
909
+ return;
910
+ this.findList.add(proxy || child);
911
+ }
686
912
  }
687
913
  clear() {
688
914
  this.point = null;
@@ -694,7 +920,8 @@ class Pather {
694
920
  }
695
921
  }
696
922
 
697
- const { Yes, NoAndSkip, YesAndSkip } = AnswerType;
923
+ const { Yes, NoAndSkip, YesAndSkip } = Answer;
924
+ const idCondition = {}, classNameCondition = {}, tagCondition = {};
698
925
  class Selector {
699
926
  constructor(target, userConfig) {
700
927
  this.config = {};
@@ -704,12 +931,13 @@ class Selector {
704
931
  id: (leaf, name) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
705
932
  innerId: (leaf, innerId) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
706
933
  className: (leaf, name) => leaf.className === name ? 1 : 0,
707
- tag: (leaf, name) => leaf.__tag === name ? 1 : 0
934
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0,
935
+ tags: (leaf, nameMap) => nameMap[leaf.__tag] ? 1 : 0
708
936
  };
709
937
  this.target = target;
710
938
  if (userConfig)
711
939
  this.config = DataHelper.default(userConfig, this.config);
712
- this.pather = new Pather(target, this);
940
+ this.picker = new Picker(target, this);
713
941
  this.__listenEvents();
714
942
  }
715
943
  getBy(condition, branch, one, options) {
@@ -720,12 +948,25 @@ class Selector {
720
948
  case 'string':
721
949
  switch (condition[0]) {
722
950
  case '#':
723
- const leaf = this.getById(condition.substring(1), branch);
724
- return one ? leaf : (leaf ? [leaf] : []);
951
+ idCondition.id = condition.substring(1), condition = idCondition;
952
+ break;
725
953
  case '.':
726
- return this.getByMethod(this.methods.className, branch, one, condition.substring(1));
954
+ classNameCondition.className = condition.substring(1), condition = classNameCondition;
955
+ break;
727
956
  default:
728
- return this.getByMethod(this.methods.tag, branch, one, condition);
957
+ tagCondition.tag = condition, condition = tagCondition;
958
+ }
959
+ case 'object':
960
+ if (condition.id !== undefined) {
961
+ const leaf = this.getById(condition.id, branch);
962
+ return one ? leaf : (leaf ? [leaf] : []);
963
+ }
964
+ else if (condition.tag) {
965
+ const { tag } = condition, isArray = tag instanceof Array;
966
+ return this.getByMethod(isArray ? this.methods.tags : this.methods.tag, branch, one, isArray ? DataHelper.toMap(tag) : tag);
967
+ }
968
+ else {
969
+ return this.getByMethod(this.methods.className, branch, one, condition.className);
729
970
  }
730
971
  case 'function':
731
972
  return this.getByMethod(condition, branch, one, options);
@@ -734,7 +975,7 @@ class Selector {
734
975
  getByPoint(hitPoint, hitRadius, options) {
735
976
  if (Platform.name === 'node')
736
977
  this.target.emit(LayoutEvent.CHECK_UPDATE);
737
- return this.pather.getByPoint(hitPoint, hitRadius, options);
978
+ return this.picker.getByPoint(hitPoint, hitRadius, options);
738
979
  }
739
980
  getByInnerId(innerId, branch) {
740
981
  const cache = this.innerIdMap[innerId];
@@ -810,7 +1051,7 @@ class Selector {
810
1051
  destroy() {
811
1052
  if (this.__eventIds.length) {
812
1053
  this.__removeListenEvents();
813
- this.pather.destroy();
1054
+ this.picker.destroy();
814
1055
  this.findLeaf = null;
815
1056
  this.innerIdMap = {};
816
1057
  this.idMap = {};
@@ -826,104 +1067,14 @@ Object.assign(Creator, {
826
1067
  });
827
1068
  Platform.layout = Layouter.fullLayout;
828
1069
 
829
- class LeaferCanvas extends LeaferCanvasBase {
830
- get allowBackgroundColor() { return false; }
831
- init() {
832
- let { view } = this.config;
833
- if (view) {
834
- if (typeof view === 'string') {
835
- if (view[0] !== '#')
836
- view = '#' + view;
837
- this.viewSelect = Platform.miniapp.select(view);
838
- }
839
- else if (view.fields) {
840
- this.viewSelect = view;
841
- }
842
- else {
843
- this.initView(view);
844
- }
845
- if (this.viewSelect)
846
- Platform.miniapp.getSizeView(this.viewSelect).then(sizeView => {
847
- this.initView(sizeView);
848
- });
849
- }
850
- else {
851
- this.initView();
852
- }
853
- }
854
- initView(view) {
855
- if (!view) {
856
- view = {};
857
- this.__createView();
858
- }
859
- else {
860
- this.view = view.view || view;
861
- }
862
- this.__createContext();
863
- const { width, height, pixelRatio } = this.config;
864
- const size = { width: width || view.width, height: height || view.height, pixelRatio };
865
- this.resize(size);
866
- if (this.context.roundRect) {
867
- this.roundRect = function (x, y, width, height, radius) {
868
- this.context.roundRect(x, y, width, height, typeof radius === 'number' ? [radius] : radius);
869
- };
870
- }
871
- canvasPatch(this.context.__proto__);
872
- }
873
- __createView() {
874
- this.view = Platform.origin.createCanvas(1, 1);
875
- }
876
- updateViewSize() {
877
- const { width, height, pixelRatio } = this;
878
- this.view.width = width * pixelRatio;
879
- this.view.height = height * pixelRatio;
880
- }
881
- updateClientBounds(callback) {
882
- if (this.viewSelect)
883
- Platform.miniapp.getBounds(this.viewSelect).then(bounds => {
884
- this.clientBounds = bounds;
885
- if (callback)
886
- callback();
887
- });
888
- }
889
- startAutoLayout(_autoBounds, listener) {
890
- this.resizeListener = listener;
891
- this.checkSize = this.checkSize.bind(this);
892
- Platform.miniapp.onWindowResize(this.checkSize);
893
- }
894
- checkSize() {
895
- if (this.viewSelect) {
896
- setTimeout(() => {
897
- this.updateClientBounds(() => {
898
- const { width, height } = this.clientBounds;
899
- const { pixelRatio } = this;
900
- const size = { width, height, pixelRatio };
901
- if (!this.isSameSize(size)) {
902
- const oldSize = {};
903
- DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
904
- this.resize(size);
905
- if (this.width !== undefined)
906
- this.resizeListener(new ResizeEvent(size, oldSize));
907
- }
908
- });
909
- }, 500);
910
- }
911
- }
912
- stopAutoLayout() {
913
- this.autoLayout = false;
914
- this.resizeListener = null;
915
- Platform.miniapp.offWindowResize(this.checkSize);
916
- }
917
- }
918
-
919
- const PointerEventHelper = {
920
- convertTouch(e, local) {
921
- const touch = PointerEventHelper.getTouch(e);
922
- const base = InteractionHelper.getBase(e);
923
- return Object.assign(Object.assign({}, base), { x: local.x, y: local.y, width: 1, height: 1, pointerType: 'touch', pressure: touch.force || 1 });
924
- },
925
- getTouch(e) {
926
- return e.touches[0] || e.changedTouches[0];
1070
+ const PointerEventHelper = {
1071
+ convertTouch(e, local) {
1072
+ const touch = PointerEventHelper.getTouch(e);
1073
+ const base = InteractionHelper.getBase(e);
1074
+ return Object.assign(Object.assign({}, base), { x: local.x, y: local.y, width: 1, height: 1, pointerType: 'touch', pressure: touch.force || 1 });
1075
+ },
1076
+ getTouch(e) {
1077
+ return e.touches[0] || e.changedTouches[0];
927
1078
  }
928
1079
  };
929
1080
 
@@ -948,15 +1099,12 @@ class Interaction extends InteractionBase {
948
1099
  this.onTouchCancel();
949
1100
  }
950
1101
  }
951
- getLocal(p, updateClient) {
952
- if (updateClient)
953
- this.canvas.updateClientBounds();
954
- if (p.x !== undefined) {
955
- return { x: p.x, y: p.y };
1102
+ getLocal(clientPoint, updateClient) {
1103
+ if (clientPoint.x !== undefined) {
1104
+ return { x: clientPoint.x, y: clientPoint.y };
956
1105
  }
957
1106
  else {
958
- const { clientBounds } = this.canvas;
959
- return { x: p.clientX - clientBounds.x, y: p.clientY - clientBounds.y };
1107
+ return super.getLocal(clientPoint, updateClient);
960
1108
  }
961
1109
  }
962
1110
  getTouches(touches) {
@@ -1024,195 +1172,381 @@ class Interaction extends InteractionBase {
1024
1172
  }
1025
1173
  }
1026
1174
 
1027
- const { mineType, fileType } = FileHelper;
1028
- Object.assign(Creator, {
1029
- canvas: (options, manager) => new LeaferCanvas(options, manager),
1030
- image: (options) => new LeaferImage(options),
1031
- hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
1032
- interaction: (target, canvas, selector, options) => { return new Interaction(target, canvas, selector, options); }
1033
- });
1034
- function useCanvas(_canvasType, app) {
1035
- if (!Platform.origin) {
1036
- Platform.origin = {
1037
- createCanvas: (width, height, _format) => app.createOffscreenCanvas({ type: '2d', width, height }),
1038
- canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
1039
- canvasToBolb: (canvas, type, quality) => canvas.toBuffer(type, { quality }),
1040
- canvasSaveAs: (canvas, filePath, quality) => {
1041
- return new Promise((resolve, reject) => {
1042
- let data = canvas.toDataURL(mineType(fileType(filePath)), quality);
1043
- data = data.substring(data.indexOf('64,') + 3);
1044
- let toAlbum;
1045
- if (!filePath.includes('/')) {
1046
- filePath = `${app.env.USER_DATA_PATH}/` + filePath;
1047
- toAlbum = true;
1048
- }
1049
- const fs = app.getFileSystemManager();
1050
- fs.writeFile({
1051
- filePath,
1052
- data,
1053
- encoding: 'base64',
1054
- success() {
1055
- if (toAlbum) {
1056
- Platform.miniapp.saveToAlbum(filePath).then(() => {
1057
- fs.unlink({ filePath });
1058
- });
1059
- }
1060
- resolve();
1061
- },
1062
- fail(error) {
1063
- reject(error);
1064
- }
1065
- });
1066
- });
1067
- },
1068
- loadImage(url) {
1069
- return new Promise((resolve, reject) => {
1070
- const img = Platform.canvas.view.createImage();
1071
- img.onload = () => { resolve(img); };
1072
- img.onerror = (error) => { reject(error); };
1073
- img.src = url;
1074
- });
1075
- },
1076
- noRepeat: 'repeat-x'
1077
- };
1078
- Platform.miniapp = {
1079
- select(name) {
1080
- return app.createSelectorQuery().select(name);
1081
- },
1082
- getBounds(select) {
1083
- return new Promise((resolve) => {
1084
- select.boundingClientRect().exec((res) => {
1085
- const rect = res[1];
1086
- resolve({ x: rect.top, y: rect.left, width: rect.width, height: rect.height });
1087
- });
1088
- });
1089
- },
1090
- getSizeView(select) {
1091
- return new Promise((resolve) => {
1092
- select.fields({ node: true, size: true }).exec((res) => {
1093
- const data = res[0];
1094
- resolve({ view: data.node, width: data.width, height: data.height });
1095
- });
1096
- });
1097
- },
1098
- saveToAlbum(path) {
1099
- return new Promise((resolve) => {
1100
- app.getSetting({
1101
- success: (res) => {
1102
- if (res.authSetting['scope.writePhotosAlbum']) {
1103
- app.saveImageToPhotosAlbum({
1104
- filePath: path,
1105
- success() { resolve(true); }
1106
- });
1107
- }
1108
- else {
1109
- app.authorize({
1110
- scope: 'scope.writePhotosAlbum',
1111
- success: () => {
1112
- app.saveImageToPhotosAlbum({
1113
- filePath: path,
1114
- success() { resolve(true); }
1115
- });
1116
- },
1117
- fail: () => { }
1118
- });
1119
- }
1120
- }
1121
- });
1122
- });
1123
- },
1124
- onWindowResize(fun) {
1125
- app.onWindowResize(fun);
1126
- },
1127
- offWindowResize(fun) {
1128
- app.offWindowResize(fun);
1175
+ function fillText(ui, canvas) {
1176
+ let row;
1177
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1178
+ for (let i = 0, len = rows.length; i < len; i++) {
1179
+ row = rows[i];
1180
+ if (row.text) {
1181
+ canvas.fillText(row.text, row.x, row.y);
1182
+ }
1183
+ else if (row.data) {
1184
+ row.data.forEach(charData => {
1185
+ canvas.fillText(charData.char, charData.x, row.y);
1186
+ });
1187
+ }
1188
+ if (decorationY)
1189
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1190
+ }
1191
+ }
1192
+
1193
+ function fill(fill, ui, canvas) {
1194
+ canvas.fillStyle = fill;
1195
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1196
+ }
1197
+ function fills(fills, ui, canvas) {
1198
+ let item;
1199
+ const { windingRule, __font } = ui.__;
1200
+ for (let i = 0, len = fills.length; i < len; i++) {
1201
+ item = fills[i];
1202
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
1203
+ continue;
1204
+ if (item.style) {
1205
+ canvas.fillStyle = item.style;
1206
+ if (item.transform) {
1207
+ canvas.save();
1208
+ canvas.transform(item.transform);
1209
+ if (item.blendMode)
1210
+ canvas.blendMode = item.blendMode;
1211
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1212
+ canvas.restore();
1129
1213
  }
1130
- };
1131
- Platform.event = {
1132
- stopDefault(_origin) { },
1133
- stopNow(_origin) { },
1134
- stop(_origin) { }
1135
- };
1136
- Platform.canvas = Creator.canvas();
1137
- Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
1214
+ else {
1215
+ if (item.blendMode) {
1216
+ canvas.saveBlendMode(item.blendMode);
1217
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1218
+ canvas.restoreBlendMode();
1219
+ }
1220
+ else {
1221
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1222
+ }
1223
+ }
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ function strokeText(stroke, ui, canvas) {
1229
+ const { strokeAlign } = ui.__;
1230
+ const isStrokes = typeof stroke !== 'string';
1231
+ switch (strokeAlign) {
1232
+ case 'center':
1233
+ canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1234
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1235
+ break;
1236
+ case 'inside':
1237
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1238
+ break;
1239
+ case 'outside':
1240
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1241
+ break;
1242
+ }
1243
+ }
1244
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1245
+ const { __strokeWidth, __font } = ui.__;
1246
+ const out = canvas.getSameCanvas(true, true);
1247
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1248
+ out.font = __font;
1249
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1250
+ out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1251
+ fillText(ui, out);
1252
+ out.blendMode = 'normal';
1253
+ if (ui.__worldFlipped) {
1254
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1255
+ }
1256
+ else {
1257
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1258
+ }
1259
+ out.recycle(ui.__nowWorld);
1260
+ }
1261
+ function drawTextStroke(ui, canvas) {
1262
+ let row;
1263
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1264
+ for (let i = 0, len = rows.length; i < len; i++) {
1265
+ row = rows[i];
1266
+ if (row.text) {
1267
+ canvas.strokeText(row.text, row.x, row.y);
1268
+ }
1269
+ else if (row.data) {
1270
+ row.data.forEach(charData => {
1271
+ canvas.strokeText(charData.char, charData.x, row.y);
1272
+ });
1273
+ }
1274
+ if (decorationY)
1275
+ canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1276
+ }
1277
+ }
1278
+ function drawStrokesStyle(strokes, isText, ui, canvas) {
1279
+ let item;
1280
+ for (let i = 0, len = strokes.length; i < len; i++) {
1281
+ item = strokes[i];
1282
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1283
+ continue;
1284
+ if (item.style) {
1285
+ canvas.strokeStyle = item.style;
1286
+ if (item.blendMode) {
1287
+ canvas.saveBlendMode(item.blendMode);
1288
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1289
+ canvas.restoreBlendMode();
1290
+ }
1291
+ else {
1292
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1293
+ }
1294
+ }
1138
1295
  }
1139
1296
  }
1140
- Platform.name = 'miniapp';
1141
- Platform.requestRender = function (render) { Platform.canvas.view.requestAnimationFrame(render); };
1142
- Platform.devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
1297
+
1298
+ function stroke(stroke, ui, canvas) {
1299
+ const options = ui.__;
1300
+ const { __strokeWidth, strokeAlign, __font } = options;
1301
+ if (!__strokeWidth)
1302
+ return;
1303
+ if (__font) {
1304
+ strokeText(stroke, ui, canvas);
1305
+ }
1306
+ else {
1307
+ switch (strokeAlign) {
1308
+ case 'center':
1309
+ canvas.setStroke(stroke, __strokeWidth, options);
1310
+ canvas.stroke();
1311
+ break;
1312
+ case 'inside':
1313
+ canvas.save();
1314
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1315
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1316
+ canvas.stroke();
1317
+ canvas.restore();
1318
+ break;
1319
+ case 'outside':
1320
+ const out = canvas.getSameCanvas(true, true);
1321
+ out.setStroke(stroke, __strokeWidth * 2, options);
1322
+ ui.__drawRenderPath(out);
1323
+ out.stroke();
1324
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1325
+ out.clearWorld(ui.__layout.renderBounds);
1326
+ if (ui.__worldFlipped) {
1327
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1328
+ }
1329
+ else {
1330
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1331
+ }
1332
+ out.recycle(ui.__nowWorld);
1333
+ break;
1334
+ }
1335
+ }
1336
+ }
1337
+ function strokes(strokes, ui, canvas) {
1338
+ const options = ui.__;
1339
+ const { __strokeWidth, strokeAlign, __font } = options;
1340
+ if (!__strokeWidth)
1341
+ return;
1342
+ if (__font) {
1343
+ strokeText(strokes, ui, canvas);
1344
+ }
1345
+ else {
1346
+ switch (strokeAlign) {
1347
+ case 'center':
1348
+ canvas.setStroke(undefined, __strokeWidth, options);
1349
+ drawStrokesStyle(strokes, false, ui, canvas);
1350
+ break;
1351
+ case 'inside':
1352
+ canvas.save();
1353
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1354
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1355
+ drawStrokesStyle(strokes, false, ui, canvas);
1356
+ canvas.restore();
1357
+ break;
1358
+ case 'outside':
1359
+ const { renderBounds } = ui.__layout;
1360
+ const out = canvas.getSameCanvas(true, true);
1361
+ ui.__drawRenderPath(out);
1362
+ out.setStroke(undefined, __strokeWidth * 2, options);
1363
+ drawStrokesStyle(strokes, false, ui, out);
1364
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1365
+ out.clearWorld(renderBounds);
1366
+ if (ui.__worldFlipped) {
1367
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1368
+ }
1369
+ else {
1370
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1371
+ }
1372
+ out.recycle(ui.__nowWorld);
1373
+ break;
1374
+ }
1375
+ }
1376
+ }
1377
+
1378
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1379
+ function shape(ui, current, options) {
1380
+ const canvas = current.getSameCanvas();
1381
+ const nowWorld = ui.__nowWorld;
1382
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1383
+ let { scaleX, scaleY } = nowWorld;
1384
+ if (scaleX < 0)
1385
+ scaleX = -scaleX;
1386
+ if (scaleY < 0)
1387
+ scaleY = -scaleY;
1388
+ if (current.bounds.includes(nowWorld)) {
1389
+ worldCanvas = canvas;
1390
+ bounds = shapeBounds = nowWorld;
1391
+ }
1392
+ else {
1393
+ const { renderShapeSpread: spread } = ui.__layout;
1394
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, scaleX === scaleY ? spread * scaleX : [spread * scaleY, spread * scaleX]) : current.bounds, nowWorld);
1395
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1396
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1397
+ if (fitMatrix.a < 1) {
1398
+ worldCanvas = current.getSameCanvas();
1399
+ ui.__renderShape(worldCanvas, options);
1400
+ scaleX *= fitScaleX;
1401
+ scaleY *= fitScaleY;
1402
+ }
1403
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1404
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1405
+ if (options.matrix) {
1406
+ const { matrix } = options;
1407
+ fitMatrix.multiply(matrix);
1408
+ fitScaleX *= matrix.scaleX;
1409
+ fitScaleY *= matrix.scaleY;
1410
+ }
1411
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1412
+ }
1413
+ ui.__renderShape(canvas, options);
1414
+ return {
1415
+ canvas, matrix: fitMatrix, bounds,
1416
+ worldCanvas, shapeBounds, scaleX, scaleY
1417
+ };
1418
+ }
1419
+
1420
+ let recycleMap;
1421
+ function compute(attrName, ui) {
1422
+ const data = ui.__, leafPaints = [];
1423
+ let paints = data.__input[attrName], hasOpacityPixel;
1424
+ if (!(paints instanceof Array))
1425
+ paints = [paints];
1426
+ recycleMap = PaintImage.recycleImage(attrName, data);
1427
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1428
+ item = getLeafPaint(attrName, paints[i], ui);
1429
+ if (item)
1430
+ leafPaints.push(item);
1431
+ }
1432
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1433
+ if (leafPaints.length && leafPaints[0].image)
1434
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1435
+ if (attrName === 'fill') {
1436
+ data.__pixelFill = hasOpacityPixel;
1437
+ }
1438
+ else {
1439
+ data.__pixelStroke = hasOpacityPixel;
1440
+ }
1441
+ }
1442
+ function getLeafPaint(attrName, paint, ui) {
1443
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1444
+ return undefined;
1445
+ const { boxBounds } = ui.__layout;
1446
+ switch (paint.type) {
1447
+ case 'solid':
1448
+ let { type, blendMode, color, opacity } = paint;
1449
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1450
+ case 'image':
1451
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1452
+ case 'linear':
1453
+ return PaintGradient.linearGradient(paint, boxBounds);
1454
+ case 'radial':
1455
+ return PaintGradient.radialGradient(paint, boxBounds);
1456
+ case 'angular':
1457
+ return PaintGradient.conicGradient(paint, boxBounds);
1458
+ default:
1459
+ return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1460
+ }
1461
+ }
1462
+
1463
+ const PaintModule = {
1464
+ compute,
1465
+ fill,
1466
+ fills,
1467
+ fillText,
1468
+ stroke,
1469
+ strokes,
1470
+ strokeText,
1471
+ drawTextStroke,
1472
+ shape
1473
+ };
1143
1474
 
1144
1475
  let origin = {};
1145
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
1146
- function fillOrFitMode(data, mode, box, width, height, rotation) {
1147
- const transform = get$4();
1148
- const swap = rotation && rotation !== 180;
1149
- const sw = box.width / (swap ? height : width);
1150
- const sh = box.height / (swap ? width : height);
1151
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1152
- const x = box.x + (box.width - width * scale) / 2;
1153
- const y = box.y + (box.height - height * scale) / 2;
1154
- translate$1(transform, x, y);
1155
- scaleHelper(transform, scale);
1476
+ const { get: get$3, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, scale: scaleHelper, rotate } = MatrixHelper;
1477
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1478
+ const transform = get$3();
1479
+ translate$1(transform, box.x + x, box.y + y);
1480
+ scaleHelper(transform, scaleX, scaleY);
1156
1481
  if (rotation)
1157
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1158
- data.scaleX = data.scaleY = scale;
1482
+ rotateOfOuter$1(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1159
1483
  data.transform = transform;
1160
1484
  }
1161
1485
  function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
1162
- const transform = get$4();
1163
- translate$1(transform, box.x, box.y);
1164
- if (x || y)
1165
- translate$1(transform, x, y);
1166
- if (scaleX) {
1486
+ const transform = get$3();
1487
+ translate$1(transform, box.x + x, box.y + y);
1488
+ if (scaleX)
1167
1489
  scaleHelper(transform, scaleX, scaleY);
1168
- data.scaleX = transform.a;
1169
- data.scaleY = transform.d;
1170
- }
1171
1490
  if (rotation)
1172
1491
  rotate(transform, rotation);
1173
1492
  data.transform = transform;
1174
1493
  }
1175
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
1176
- const transform = get$4();
1494
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align) {
1495
+ const transform = get$3();
1177
1496
  if (rotation) {
1178
- rotate(transform, rotation);
1179
- switch (rotation) {
1180
- case 90:
1181
- translate$1(transform, height, 0);
1182
- break;
1183
- case 180:
1184
- translate$1(transform, width, height);
1185
- break;
1186
- case 270:
1187
- translate$1(transform, 0, width);
1188
- break;
1497
+ if (align === 'center') {
1498
+ rotateOfOuter$1(transform, { x: width / 2, y: height / 2 }, rotation);
1499
+ }
1500
+ else {
1501
+ rotate(transform, rotation);
1502
+ switch (rotation) {
1503
+ case 90:
1504
+ translate$1(transform, height, 0);
1505
+ break;
1506
+ case 180:
1507
+ translate$1(transform, width, height);
1508
+ break;
1509
+ case 270:
1510
+ translate$1(transform, 0, width);
1511
+ break;
1512
+ }
1189
1513
  }
1190
1514
  }
1191
- origin.x = box.x;
1192
- origin.y = box.y;
1193
- if (x || y)
1194
- origin.x += x, origin.y += y;
1515
+ origin.x = box.x + x;
1516
+ origin.y = box.y + y;
1195
1517
  translate$1(transform, origin.x, origin.y);
1196
- if (scaleX) {
1197
- scaleOfOuter$2(transform, origin, scaleX, scaleY);
1198
- data.scaleX = scaleX;
1199
- data.scaleY = scaleY;
1200
- }
1518
+ if (scaleX)
1519
+ scaleOfOuter$1(transform, origin, scaleX, scaleY);
1201
1520
  data.transform = transform;
1202
1521
  }
1203
1522
 
1204
- const { get: get$3, translate } = MatrixHelper;
1523
+ const { get: get$2, translate } = MatrixHelper;
1524
+ const tempBox = new Bounds();
1525
+ const tempPoint = {};
1205
1526
  function createData(leafPaint, image, paint, box) {
1206
- let { width, height } = image;
1207
- const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
1208
- const sameBox = box.width === width && box.height === height;
1527
+ const { blendMode } = paint;
1209
1528
  if (blendMode)
1210
1529
  leafPaint.blendMode = blendMode;
1211
- const data = leafPaint.data = { mode };
1212
- let x, y, scaleX, scaleY;
1213
- if (offset)
1214
- x = offset.x, y = offset.y;
1215
- if (size) {
1530
+ leafPaint.data = getPatternData(paint, box, image);
1531
+ }
1532
+ function getPatternData(paint, box, image) {
1533
+ let { width, height } = image;
1534
+ if (paint.padding)
1535
+ box = tempBox.set(box).shrink(paint.padding);
1536
+ const { opacity, mode, align, offset, scale, size, rotation, repeat } = paint;
1537
+ const sameBox = box.width === width && box.height === height;
1538
+ const data = { mode };
1539
+ const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1540
+ const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1541
+ let x = 0, y = 0, scaleX, scaleY;
1542
+ if (!mode || mode === 'cover' || mode === 'fit') {
1543
+ if (!sameBox || rotation) {
1544
+ const sw = box.width / swapWidth, sh = box.height / swapHeight;
1545
+ scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1546
+ x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1547
+ }
1548
+ }
1549
+ else if (size) {
1216
1550
  scaleX = (typeof size === 'number' ? size : size.width) / width;
1217
1551
  scaleY = (typeof size === 'number' ? size : size.height) / height;
1218
1552
  }
@@ -1220,30 +1554,46 @@ function createData(leafPaint, image, paint, box) {
1220
1554
  scaleX = typeof scale === 'number' ? scale : scale.x;
1221
1555
  scaleY = typeof scale === 'number' ? scale : scale.y;
1222
1556
  }
1557
+ if (align) {
1558
+ const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1559
+ if (scaleX)
1560
+ imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1561
+ AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1562
+ x += tempPoint.x, y += tempPoint.y;
1563
+ }
1564
+ if (offset)
1565
+ x += offset.x, y += offset.y;
1223
1566
  switch (mode) {
1224
1567
  case 'strench':
1225
1568
  if (!sameBox)
1226
1569
  width = box.width, height = box.height;
1227
- if (box.x || box.y) {
1228
- data.transform = get$3();
1229
- translate(data.transform, box.x, box.y);
1230
- }
1231
1570
  break;
1571
+ case 'normal':
1232
1572
  case 'clip':
1233
- if (offset || scaleX || rotation)
1573
+ if (x || y || scaleX || rotation)
1234
1574
  clipMode(data, box, x, y, scaleX, scaleY, rotation);
1235
1575
  break;
1236
1576
  case 'repeat':
1237
1577
  if (!sameBox || scaleX || rotation)
1238
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1578
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1239
1579
  if (!repeat)
1240
1580
  data.repeat = 'repeat';
1241
1581
  break;
1242
1582
  case 'fit':
1243
1583
  case 'cover':
1244
1584
  default:
1245
- if (!sameBox || rotation)
1246
- fillOrFitMode(data, mode, box, width, height, rotation);
1585
+ if (scaleX)
1586
+ fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1587
+ }
1588
+ if (!data.transform) {
1589
+ if (box.x || box.y) {
1590
+ data.transform = get$2();
1591
+ translate(data.transform, box.x, box.y);
1592
+ }
1593
+ }
1594
+ if (scaleX && mode !== 'strench') {
1595
+ data.scaleX = scaleX;
1596
+ data.scaleY = scaleY;
1247
1597
  }
1248
1598
  data.width = width;
1249
1599
  data.height = height;
@@ -1251,112 +1601,108 @@ function createData(leafPaint, image, paint, box) {
1251
1601
  data.opacity = opacity;
1252
1602
  if (repeat)
1253
1603
  data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1604
+ return data;
1254
1605
  }
1255
1606
 
1256
- function image(ui, attrName, attrValue, box, firstUse) {
1257
- const leafPaint = { type: attrValue.type };
1258
- const image = leafPaint.image = ImageManager.get(attrValue);
1259
- const event = (firstUse || image.loading) && { target: ui, image, attrName, attrValue };
1607
+ let cache, box = new Bounds();
1608
+ const { isSame } = BoundsHelper;
1609
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1610
+ let leafPaint, event;
1611
+ const image = ImageManager.get(paint);
1612
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1613
+ leafPaint = cache.leafPaint;
1614
+ }
1615
+ else {
1616
+ leafPaint = { type: paint.type, image };
1617
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1618
+ }
1619
+ if (firstUse || image.loading)
1620
+ event = { image, attrName, attrValue: paint };
1260
1621
  if (image.ready) {
1261
- if (hasNaturalSize(ui, attrName, image))
1262
- createData(leafPaint, image, attrValue, box);
1622
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1263
1623
  if (firstUse) {
1264
- emit(ImageEvent.LOAD, event);
1265
- emit(ImageEvent.LOADED, event);
1624
+ onLoad(ui, event);
1625
+ onLoadSuccess(ui, event);
1266
1626
  }
1267
1627
  }
1268
1628
  else if (image.error) {
1269
- if (firstUse) {
1270
- ui.forceUpdate('surface');
1271
- event.error = image.error;
1272
- emit(ImageEvent.ERROR, event);
1273
- }
1629
+ if (firstUse)
1630
+ onLoadError(ui, event, image.error);
1274
1631
  }
1275
1632
  else {
1633
+ ignoreRender(ui, true);
1276
1634
  if (firstUse)
1277
- emit(ImageEvent.LOAD, event);
1635
+ onLoad(ui, event);
1278
1636
  leafPaint.loadId = image.load(() => {
1637
+ ignoreRender(ui, false);
1279
1638
  if (!ui.destroyed) {
1280
- if (hasNaturalSize(ui, attrName, image)) {
1281
- createData(leafPaint, image, attrValue, box);
1639
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1640
+ if (image.hasOpacityPixel)
1641
+ ui.__layout.hitCanvasChanged = true;
1282
1642
  ui.forceUpdate('surface');
1283
1643
  }
1284
- emit(ImageEvent.LOADED, event);
1644
+ onLoadSuccess(ui, event);
1285
1645
  }
1646
+ leafPaint.loadId = null;
1286
1647
  }, (error) => {
1287
- ui.forceUpdate('surface');
1288
- event.error = error;
1289
- emit(ImageEvent.ERROR, event);
1648
+ ignoreRender(ui, false);
1649
+ onLoadError(ui, event, error);
1650
+ leafPaint.loadId = null;
1290
1651
  });
1291
1652
  }
1292
1653
  return leafPaint;
1293
1654
  }
1294
- function hasNaturalSize(ui, attrName, image) {
1655
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1295
1656
  if (attrName === 'fill' && !ui.__.__naturalWidth) {
1296
- const { __: d } = ui;
1297
- d.__naturalWidth = image.width;
1298
- d.__naturalHeight = image.height;
1299
- if (!d.__getInput('width') || !d.__getInput('height')) {
1657
+ const data = ui.__;
1658
+ data.__naturalWidth = image.width / data.pixelRatio;
1659
+ data.__naturalHeight = image.height / data.pixelRatio;
1660
+ if (data.__autoSide) {
1300
1661
  ui.forceUpdate('width');
1301
1662
  if (ui.__proxyData) {
1302
- ui.setProxyAttr('width', ui.__.width);
1303
- ui.setProxyAttr('height', ui.__.height);
1663
+ ui.setProxyAttr('width', data.width);
1664
+ ui.setProxyAttr('height', data.height);
1304
1665
  }
1305
1666
  return false;
1306
1667
  }
1307
1668
  }
1669
+ if (!leafPaint.data)
1670
+ createData(leafPaint, image, paint, boxBounds);
1308
1671
  return true;
1309
1672
  }
1310
- function emit(type, data) {
1311
- if (data.target.hasEvent(type))
1312
- data.target.emitEvent(new ImageEvent(type, data));
1673
+ function onLoad(ui, event) {
1674
+ emit(ui, ImageEvent.LOAD, event);
1675
+ }
1676
+ function onLoadSuccess(ui, event) {
1677
+ emit(ui, ImageEvent.LOADED, event);
1678
+ }
1679
+ function onLoadError(ui, event, error) {
1680
+ event.error = error;
1681
+ ui.forceUpdate('surface');
1682
+ emit(ui, ImageEvent.ERROR, event);
1683
+ }
1684
+ function emit(ui, type, data) {
1685
+ if (ui.hasEvent(type))
1686
+ ui.emitEvent(new ImageEvent(type, data));
1687
+ }
1688
+ function ignoreRender(ui, value) {
1689
+ const { leafer } = ui;
1690
+ if (leafer && leafer.viewReady)
1691
+ leafer.renderer.ignore = value;
1313
1692
  }
1314
1693
 
1315
- /******************************************************************************
1316
- Copyright (c) Microsoft Corporation.
1317
-
1318
- Permission to use, copy, modify, and/or distribute this software for any
1319
- purpose with or without fee is hereby granted.
1320
-
1321
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1322
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1323
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1324
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1325
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1326
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1327
- PERFORMANCE OF THIS SOFTWARE.
1328
- ***************************************************************************** */
1329
- /* global Reflect, Promise, SuppressedError, Symbol */
1330
-
1331
-
1332
- function __awaiter(thisArg, _arguments, P, generator) {
1333
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1334
- return new (P || (P = Promise))(function (resolve, reject) {
1335
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1336
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1337
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1338
- step((generator = generator.apply(thisArg, _arguments || [])).next());
1339
- });
1340
- }
1341
-
1342
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1343
- var e = new Error(message);
1344
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1345
- };
1346
-
1347
- const Export$1 = {};
1348
-
1349
- const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1694
+ const { get: get$1, scale, copy: copy$1 } = MatrixHelper;
1695
+ const { ceil, abs: abs$1 } = Math;
1350
1696
  function createPattern(ui, paint, pixelRatio) {
1351
- let { scaleX, scaleY } = ui.__world;
1697
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1352
1698
  const id = scaleX + '-' + scaleY;
1353
1699
  if (paint.patternId !== id && !ui.destroyed) {
1354
- scaleX = Math.abs(scaleX);
1355
- scaleY = Math.abs(scaleY);
1700
+ scaleX = abs$1(scaleX);
1701
+ scaleY = abs$1(scaleY);
1356
1702
  const { image, data } = paint;
1357
1703
  let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1358
1704
  if (sx) {
1359
- imageMatrix = get$2();
1705
+ imageMatrix = get$1();
1360
1706
  copy$1(imageMatrix, transform);
1361
1707
  scale(imageMatrix, 1 / sx, 1 / sy);
1362
1708
  scaleX *= sx;
@@ -1391,22 +1737,14 @@ function createPattern(ui, paint, pixelRatio) {
1391
1737
  }
1392
1738
  if (transform || scaleX !== 1 || scaleY !== 1) {
1393
1739
  if (!imageMatrix) {
1394
- imageMatrix = get$2();
1740
+ imageMatrix = get$1();
1395
1741
  if (transform)
1396
1742
  copy$1(imageMatrix, transform);
1397
1743
  }
1398
1744
  scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1399
1745
  }
1400
- const pattern = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), repeat || (Platform.origin.noRepeat || 'no-repeat'));
1401
- try {
1402
- if (paint.transform)
1403
- paint.transform = null;
1404
- if (imageMatrix)
1405
- pattern.setTransform ? pattern.setTransform(imageMatrix) : paint.transform = imageMatrix;
1406
- }
1407
- catch (_a) {
1408
- paint.transform = imageMatrix;
1409
- }
1746
+ const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, opacity);
1747
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1410
1748
  paint.style = pattern;
1411
1749
  paint.patternId = id;
1412
1750
  return true;
@@ -1416,9 +1754,41 @@ function createPattern(ui, paint, pixelRatio) {
1416
1754
  }
1417
1755
  }
1418
1756
 
1757
+ /******************************************************************************
1758
+ Copyright (c) Microsoft Corporation.
1759
+
1760
+ Permission to use, copy, modify, and/or distribute this software for any
1761
+ purpose with or without fee is hereby granted.
1762
+
1763
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1764
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1765
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1766
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1767
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1768
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1769
+ PERFORMANCE OF THIS SOFTWARE.
1770
+ ***************************************************************************** */
1771
+ /* global Reflect, Promise, SuppressedError, Symbol */
1772
+
1773
+
1774
+ function __awaiter(thisArg, _arguments, P, generator) {
1775
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1776
+ return new (P || (P = Promise))(function (resolve, reject) {
1777
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1778
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1779
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1780
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1781
+ });
1782
+ }
1783
+
1784
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1785
+ var e = new Error(message);
1786
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1787
+ };
1788
+
1419
1789
  const { abs } = Math;
1420
1790
  function checkImage(ui, canvas, paint, allowPaint) {
1421
- const { scaleX, scaleY } = ui.__world;
1791
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1422
1792
  if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1423
1793
  return false;
1424
1794
  }
@@ -1433,326 +1803,91 @@ function checkImage(ui, canvas, paint, allowPaint) {
1433
1803
  width *= data.scaleX;
1434
1804
  height *= data.scaleY;
1435
1805
  }
1436
- allowPaint = width * height > Platform.image.maxCacheSize;
1806
+ allowPaint = (width * height > Platform.image.maxCacheSize) || Export.running;
1437
1807
  }
1438
1808
  else {
1439
1809
  allowPaint = false;
1440
1810
  }
1441
1811
  }
1442
- if (allowPaint) {
1443
- canvas.save();
1444
- canvas.clip();
1445
- if (paint.blendMode)
1446
- canvas.blendMode = paint.blendMode;
1447
- if (data.opacity)
1448
- canvas.opacity *= data.opacity;
1449
- if (data.transform)
1450
- canvas.transform(data.transform);
1451
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1452
- canvas.restore();
1453
- return true;
1454
- }
1455
- else {
1456
- if (!paint.style || Export$1.running) {
1457
- createPattern(ui, paint, canvas.pixelRatio);
1458
- }
1459
- else {
1460
- if (!paint.patternTask) {
1461
- paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1462
- paint.patternTask = null;
1463
- if (canvas.bounds.hit(ui.__world))
1464
- createPattern(ui, paint, canvas.pixelRatio);
1465
- ui.forceUpdate('surface');
1466
- }), 300);
1467
- }
1468
- }
1469
- return false;
1470
- }
1471
- }
1472
- }
1473
-
1474
- function recycleImage(attrName, data) {
1475
- const paints = data['_' + attrName];
1476
- if (paints instanceof Array) {
1477
- let image, recycleMap, input, url;
1478
- for (let i = 0, len = paints.length; i < len; i++) {
1479
- image = paints[i].image;
1480
- url = image && image.url;
1481
- if (url) {
1482
- if (!recycleMap)
1483
- recycleMap = {};
1484
- recycleMap[url] = true;
1485
- ImageManager.recycle(image);
1486
- if (image.loading) {
1487
- if (!input) {
1488
- input = (data.__input && data.__input[attrName]) || [];
1489
- if (!(input instanceof Array))
1490
- input = [input];
1491
- }
1492
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1493
- }
1494
- }
1495
- }
1496
- return recycleMap;
1497
- }
1498
- return null;
1499
- }
1500
-
1501
- function fillText(ui, canvas) {
1502
- let row;
1503
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1504
- for (let i = 0, len = rows.length; i < len; i++) {
1505
- row = rows[i];
1506
- if (row.text) {
1507
- canvas.fillText(row.text, row.x, row.y);
1508
- }
1509
- else if (row.data) {
1510
- row.data.forEach(charData => {
1511
- canvas.fillText(charData.char, charData.x, row.y);
1512
- });
1513
- }
1514
- if (decorationY)
1515
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1516
- }
1517
- }
1518
-
1519
- function fill(fill, ui, canvas) {
1520
- canvas.fillStyle = fill;
1521
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1522
- }
1523
- function fills(fills, ui, canvas) {
1524
- let item;
1525
- const { windingRule, __font } = ui.__;
1526
- for (let i = 0, len = fills.length; i < len; i++) {
1527
- item = fills[i];
1528
- if (item.image && checkImage(ui, canvas, item, !__font))
1529
- continue;
1530
- if (item.style) {
1531
- canvas.fillStyle = item.style;
1532
- if (item.transform) {
1533
- canvas.save();
1534
- canvas.transform(item.transform);
1535
- if (item.blendMode)
1536
- canvas.blendMode = item.blendMode;
1537
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1538
- canvas.restore();
1539
- }
1540
- else {
1541
- if (item.blendMode) {
1542
- canvas.saveBlendMode(item.blendMode);
1543
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1544
- canvas.restoreBlendMode();
1545
- }
1546
- else {
1547
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1548
- }
1549
- }
1550
- }
1551
- }
1552
- }
1553
-
1554
- function strokeText(stroke, ui, canvas, renderOptions) {
1555
- const { strokeAlign } = ui.__;
1556
- const isStrokes = typeof stroke !== 'string';
1557
- switch (strokeAlign) {
1558
- case 'center':
1559
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1560
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1561
- break;
1562
- case 'inside':
1563
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas, renderOptions);
1564
- break;
1565
- case 'outside':
1566
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas, renderOptions);
1567
- break;
1568
- }
1569
- }
1570
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas, renderOptions) {
1571
- const { strokeWidth, __font } = ui.__;
1572
- const out = canvas.getSameCanvas(true);
1573
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1574
- out.font = __font;
1575
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1576
- out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1577
- fillText(ui, out);
1578
- out.blendMode = 'normal';
1579
- if (ui.__worldFlipped || renderOptions.matrix) {
1580
- canvas.copyWorldByReset(out);
1581
- }
1582
- else {
1583
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1584
- }
1585
- out.recycle();
1586
- }
1587
- function drawTextStroke(ui, canvas) {
1588
- let row;
1589
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1590
- for (let i = 0, len = rows.length; i < len; i++) {
1591
- row = rows[i];
1592
- if (row.text) {
1593
- canvas.strokeText(row.text, row.x, row.y);
1594
- }
1595
- else if (row.data) {
1596
- row.data.forEach(charData => {
1597
- canvas.strokeText(charData.char, charData.x, row.y);
1598
- });
1599
- }
1600
- if (decorationY)
1601
- canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1602
- }
1603
- }
1604
- function drawStrokesStyle(strokes, isText, ui, canvas) {
1605
- let item;
1606
- for (let i = 0, len = strokes.length; i < len; i++) {
1607
- item = strokes[i];
1608
- if (item.image && checkImage(ui, canvas, item, false))
1609
- continue;
1610
- if (item.style) {
1611
- canvas.strokeStyle = item.style;
1612
- if (item.blendMode) {
1613
- canvas.saveBlendMode(item.blendMode);
1614
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1615
- canvas.restoreBlendMode();
1812
+ if (allowPaint) {
1813
+ canvas.save();
1814
+ canvas.clip();
1815
+ if (paint.blendMode)
1816
+ canvas.blendMode = paint.blendMode;
1817
+ if (data.opacity)
1818
+ canvas.opacity *= data.opacity;
1819
+ if (data.transform)
1820
+ canvas.transform(data.transform);
1821
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1822
+ canvas.restore();
1823
+ return true;
1824
+ }
1825
+ else {
1826
+ if (!paint.style || Export.running) {
1827
+ createPattern(ui, paint, canvas.pixelRatio);
1616
1828
  }
1617
1829
  else {
1618
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1830
+ if (!paint.patternTask) {
1831
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1832
+ paint.patternTask = null;
1833
+ if (canvas.bounds.hit(ui.__nowWorld))
1834
+ createPattern(ui, paint, canvas.pixelRatio);
1835
+ ui.forceUpdate('surface');
1836
+ }), 300);
1837
+ }
1619
1838
  }
1839
+ return false;
1620
1840
  }
1621
1841
  }
1622
1842
  }
1623
1843
 
1624
- function stroke(stroke, ui, canvas, renderOptions) {
1625
- const options = ui.__;
1626
- const { strokeWidth, strokeAlign, __font } = options;
1627
- if (!strokeWidth)
1628
- return;
1629
- if (__font) {
1630
- strokeText(stroke, ui, canvas, renderOptions);
1631
- }
1632
- else {
1633
- switch (strokeAlign) {
1634
- case 'center':
1635
- canvas.setStroke(stroke, strokeWidth, options);
1636
- canvas.stroke();
1637
- break;
1638
- case 'inside':
1639
- canvas.save();
1640
- canvas.setStroke(stroke, strokeWidth * 2, options);
1641
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1642
- canvas.stroke();
1643
- canvas.restore();
1644
- break;
1645
- case 'outside':
1646
- const out = canvas.getSameCanvas(true);
1647
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1648
- ui.__drawRenderPath(out);
1649
- out.stroke();
1650
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1651
- out.clearWorld(ui.__layout.renderBounds);
1652
- if (ui.__worldFlipped || renderOptions.matrix) {
1653
- canvas.copyWorldByReset(out);
1654
- }
1655
- else {
1656
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1657
- }
1658
- out.recycle();
1659
- break;
1660
- }
1661
- }
1662
- }
1663
- function strokes(strokes, ui, canvas, renderOptions) {
1664
- const options = ui.__;
1665
- const { strokeWidth, strokeAlign, __font } = options;
1666
- if (!strokeWidth)
1667
- return;
1668
- if (__font) {
1669
- strokeText(strokes, ui, canvas, renderOptions);
1670
- }
1671
- else {
1672
- switch (strokeAlign) {
1673
- case 'center':
1674
- canvas.setStroke(undefined, strokeWidth, options);
1675
- drawStrokesStyle(strokes, false, ui, canvas);
1676
- break;
1677
- case 'inside':
1678
- canvas.save();
1679
- canvas.setStroke(undefined, strokeWidth * 2, options);
1680
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1681
- drawStrokesStyle(strokes, false, ui, canvas);
1682
- canvas.restore();
1683
- break;
1684
- case 'outside':
1685
- const { renderBounds } = ui.__layout;
1686
- const out = canvas.getSameCanvas(true);
1687
- ui.__drawRenderPath(out);
1688
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1689
- drawStrokesStyle(strokes, false, ui, out);
1690
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1691
- out.clearWorld(renderBounds);
1692
- if (ui.__worldFlipped || renderOptions.matrix) {
1693
- canvas.copyWorldByReset(out);
1694
- }
1695
- else {
1696
- canvas.copyWorldToInner(out, ui.__world, renderBounds);
1844
+ function recycleImage(attrName, data) {
1845
+ const paints = data['_' + attrName];
1846
+ if (paints instanceof Array) {
1847
+ let image, recycleMap, input, url;
1848
+ for (let i = 0, len = paints.length; i < len; i++) {
1849
+ image = paints[i].image;
1850
+ url = image && image.url;
1851
+ if (url) {
1852
+ if (!recycleMap)
1853
+ recycleMap = {};
1854
+ recycleMap[url] = true;
1855
+ ImageManager.recycle(image);
1856
+ if (image.loading) {
1857
+ if (!input) {
1858
+ input = (data.__input && data.__input[attrName]) || [];
1859
+ if (!(input instanceof Array))
1860
+ input = [input];
1861
+ }
1862
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1697
1863
  }
1698
- out.recycle();
1699
- break;
1864
+ }
1700
1865
  }
1866
+ return recycleMap;
1701
1867
  }
1868
+ return null;
1702
1869
  }
1703
1870
 
1704
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1705
- function shape(ui, current, options) {
1706
- const canvas = current.getSameCanvas();
1707
- let bounds, matrix, shapeBounds;
1708
- let worldCanvas;
1709
- const { __world } = ui;
1710
- let { scaleX, scaleY } = __world;
1711
- if (scaleX < 0)
1712
- scaleX = -scaleX;
1713
- if (scaleY < 0)
1714
- scaleY = -scaleY;
1715
- if (!current.bounds.includes(__world, options.matrix)) {
1716
- const { renderShapeSpread: spread } = ui.__layout;
1717
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1718
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1719
- if (matrix.a < 1) {
1720
- worldCanvas = current.getSameCanvas();
1721
- ui.__renderShape(worldCanvas, options);
1722
- scaleX *= matrix.a;
1723
- scaleY *= matrix.d;
1724
- }
1725
- shapeBounds = getOuterOf(__world, matrix);
1726
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1727
- if (options.matrix)
1728
- matrix.multiply(options.matrix);
1729
- options = Object.assign(Object.assign({}, options), { matrix });
1730
- }
1731
- else {
1732
- if (options.matrix) {
1733
- scaleX *= options.matrix.a;
1734
- scaleY *= options.matrix.d;
1735
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
1736
- }
1737
- else {
1738
- bounds = shapeBounds = __world;
1739
- }
1740
- worldCanvas = canvas;
1741
- }
1742
- ui.__renderShape(canvas, options);
1743
- return {
1744
- canvas, matrix, bounds,
1745
- worldCanvas, shapeBounds, scaleX, scaleY
1746
- };
1747
- }
1871
+ const PaintImageModule = {
1872
+ image,
1873
+ checkImage,
1874
+ createPattern,
1875
+ recycleImage,
1876
+ createData,
1877
+ getPatternData,
1878
+ fillOrFitMode,
1879
+ clipMode,
1880
+ repeatMode
1881
+ };
1748
1882
 
1749
- const defaultFrom$2 = { x: 0.5, y: 0 };
1750
- const defaultTo$2 = { x: 0.5, y: 1 };
1883
+ const { toPoint: toPoint$2 } = AroundHelper;
1884
+ const realFrom$2 = {};
1885
+ const realTo$2 = {};
1751
1886
  function linearGradient(paint, box) {
1752
1887
  let { from, to, type, blendMode, opacity } = paint;
1753
- from || (from = defaultFrom$2);
1754
- to || (to = defaultTo$2);
1755
- const style = Platform.canvas.createLinearGradient(box.x + from.x * box.width, box.y + from.y * box.height, box.x + to.x * box.width, box.y + to.y * box.height);
1888
+ toPoint$2(from || 'top', box, realFrom$2);
1889
+ toPoint$2(to || 'bottom', box, realTo$2);
1890
+ const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1756
1891
  applyStops(style, paint.stops, opacity);
1757
1892
  const data = { type, style };
1758
1893
  if (blendMode)
@@ -1763,137 +1898,84 @@ function applyStops(gradient, stops, opacity) {
1763
1898
  let stop;
1764
1899
  for (let i = 0, len = stops.length; i < len; i++) {
1765
1900
  stop = stops[i];
1766
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
1901
+ if (typeof stop === 'string') {
1902
+ gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1903
+ }
1904
+ else {
1905
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1906
+ }
1767
1907
  }
1768
1908
  }
1769
1909
 
1770
- const { set: set$1, getAngle: getAngle$1, getDistance: getDistance$1 } = PointHelper;
1771
- const { get: get$1, rotateOfOuter: rotateOfOuter$1, scaleOfOuter: scaleOfOuter$1 } = MatrixHelper;
1772
- const defaultFrom$1 = { x: 0.5, y: 0.5 };
1773
- const defaultTo$1 = { x: 0.5, y: 1 };
1910
+ const { getAngle, getDistance: getDistance$1 } = PointHelper;
1911
+ const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1912
+ const { toPoint: toPoint$1 } = AroundHelper;
1774
1913
  const realFrom$1 = {};
1775
1914
  const realTo$1 = {};
1776
1915
  function radialGradient(paint, box) {
1777
1916
  let { from, to, type, opacity, blendMode, stretch } = paint;
1778
- from || (from = defaultFrom$1);
1779
- to || (to = defaultTo$1);
1780
- const { x, y, width, height } = box;
1781
- set$1(realFrom$1, x + from.x * width, y + from.y * height);
1782
- set$1(realTo$1, x + to.x * width, y + to.y * height);
1783
- let transform;
1784
- if (width !== height || stretch) {
1785
- transform = get$1();
1786
- scaleOfOuter$1(transform, realFrom$1, width / height * (stretch || 1), 1);
1787
- rotateOfOuter$1(transform, realFrom$1, getAngle$1(realFrom$1, realTo$1) + 90);
1788
- }
1917
+ toPoint$1(from || 'center', box, realFrom$1);
1918
+ toPoint$1(to || 'bottom', box, realTo$1);
1789
1919
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1790
1920
  applyStops(style, paint.stops, opacity);
1791
- const data = { type, style, transform };
1921
+ const data = { type, style };
1922
+ const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1923
+ if (transform)
1924
+ data.transform = transform;
1792
1925
  if (blendMode)
1793
1926
  data.blendMode = blendMode;
1794
1927
  return data;
1795
1928
  }
1929
+ function getTransform(box, from, to, stretch, rotate90) {
1930
+ let transform;
1931
+ const { width, height } = box;
1932
+ if (width !== height || stretch) {
1933
+ const angle = getAngle(from, to);
1934
+ transform = get();
1935
+ if (rotate90) {
1936
+ scaleOfOuter(transform, from, width / height * (stretch || 1), 1);
1937
+ rotateOfOuter(transform, from, angle + 90);
1938
+ }
1939
+ else {
1940
+ scaleOfOuter(transform, from, 1, width / height * (stretch || 1));
1941
+ rotateOfOuter(transform, from, angle);
1942
+ }
1943
+ }
1944
+ return transform;
1945
+ }
1796
1946
 
1797
- const { set, getAngle, getDistance } = PointHelper;
1798
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1799
- const defaultFrom = { x: 0.5, y: 0.5 };
1800
- const defaultTo = { x: 0.5, y: 1 };
1947
+ const { getDistance } = PointHelper;
1948
+ const { toPoint } = AroundHelper;
1801
1949
  const realFrom = {};
1802
1950
  const realTo = {};
1803
1951
  function conicGradient(paint, box) {
1804
1952
  let { from, to, type, opacity, blendMode, stretch } = paint;
1805
- from || (from = defaultFrom);
1806
- to || (to = defaultTo);
1807
- const { x, y, width, height } = box;
1808
- set(realFrom, x + from.x * width, y + from.y * height);
1809
- set(realTo, x + to.x * width, y + to.y * height);
1810
- const transform = get();
1811
- const angle = getAngle(realFrom, realTo);
1812
- if (Platform.conicGradientRotate90) {
1813
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1);
1814
- rotateOfOuter(transform, realFrom, angle + 90);
1815
- }
1816
- else {
1817
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1));
1818
- rotateOfOuter(transform, realFrom, angle);
1819
- }
1953
+ toPoint(from || 'center', box, realFrom);
1954
+ toPoint(to || 'bottom', box, realTo);
1820
1955
  const style = Platform.conicGradientSupport ? Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo));
1821
1956
  applyStops(style, paint.stops, opacity);
1822
- const data = { type, style, transform };
1957
+ const data = { type, style };
1958
+ const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1959
+ if (transform)
1960
+ data.transform = transform;
1823
1961
  if (blendMode)
1824
1962
  data.blendMode = blendMode;
1825
1963
  return data;
1826
1964
  }
1827
1965
 
1828
- let recycleMap;
1829
- function compute(attrName, ui) {
1830
- const value = [];
1831
- const data = ui.__;
1832
- let item;
1833
- let paints = data.__input[attrName];
1834
- if (!(paints instanceof Array))
1835
- paints = [paints];
1836
- recycleMap = recycleImage(attrName, data);
1837
- for (let i = 0, len = paints.length; i < len; i++) {
1838
- item = getLeafPaint(attrName, paints[i], ui);
1839
- if (item)
1840
- value.push(item);
1841
- }
1842
- data['_' + attrName] = value.length ? value : undefined;
1843
- let isPixel;
1844
- if (paints.length === 1) {
1845
- const paint = paints[0];
1846
- if (paint.type === 'image')
1847
- isPixel = ImageManager$1.isPixel(paint);
1848
- }
1849
- if (attrName === 'fill') {
1850
- data.__pixelFill = isPixel;
1851
- }
1852
- else {
1853
- data.__pixelStroke = isPixel;
1854
- }
1855
- }
1856
- function getLeafPaint(attrName, paint, ui) {
1857
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1858
- return undefined;
1859
- const { boxBounds } = ui.__layout;
1860
- switch (paint.type) {
1861
- case 'solid':
1862
- let { type, blendMode, color, opacity } = paint;
1863
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
1864
- case 'image':
1865
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1866
- case 'linear':
1867
- return linearGradient(paint, boxBounds);
1868
- case 'radial':
1869
- return radialGradient(paint, boxBounds);
1870
- case 'angular':
1871
- return conicGradient(paint, boxBounds);
1872
- default:
1873
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
1874
- }
1875
- }
1876
-
1877
- var UIPaint = /*#__PURE__*/Object.freeze({
1878
- __proto__: null,
1879
- compute: compute,
1880
- drawTextStroke: drawTextStroke,
1881
- fill: fill,
1882
- fillText: fillText,
1883
- fills: fills,
1884
- recycleImage: recycleImage,
1885
- shape: shape,
1886
- stroke: stroke,
1887
- strokeText: strokeText,
1888
- strokes: strokes
1889
- });
1966
+ const PaintGradientModule = {
1967
+ linearGradient,
1968
+ radialGradient,
1969
+ conicGradient,
1970
+ getTransform
1971
+ };
1890
1972
 
1891
1973
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1892
1974
  const tempBounds = {};
1893
1975
  const offsetOutBounds$1 = {};
1894
- function shadow(ui, current, shape, renderOptions) {
1976
+ function shadow(ui, current, shape) {
1895
1977
  let copyBounds, spreadScale;
1896
- const { __world, __layout } = ui;
1978
+ const { __nowWorld: nowWorld, __layout } = ui;
1897
1979
  const { shadow } = ui.__;
1898
1980
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1899
1981
  const other = current.getSameCanvas();
@@ -1908,21 +1990,21 @@ function shadow(ui, current, shape, renderOptions) {
1908
1990
  other.restore();
1909
1991
  other.save();
1910
1992
  if (worldCanvas) {
1911
- other.copyWorld(other, bounds, __world, 'copy');
1912
- copyBounds = __world;
1993
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1994
+ copyBounds = nowWorld;
1913
1995
  }
1914
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1996
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1915
1997
  }
1916
- if (ui.__worldFlipped || renderOptions.matrix) {
1917
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1998
+ if (ui.__worldFlipped) {
1999
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1918
2000
  }
1919
2001
  else {
1920
2002
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1921
2003
  }
1922
2004
  if (end && index < end)
1923
- other.clear();
2005
+ other.clearWorld(copyBounds, true);
1924
2006
  });
1925
- other.recycle();
2007
+ other.recycle(copyBounds);
1926
2008
  }
1927
2009
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1928
2010
  const { bounds, shapeBounds } = shape;
@@ -1953,9 +2035,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1953
2035
 
1954
2036
  const { toOffsetOutBounds } = BoundsHelper;
1955
2037
  const offsetOutBounds = {};
1956
- function innerShadow(ui, current, shape, renderOptions) {
2038
+ function innerShadow(ui, current, shape) {
1957
2039
  let copyBounds, spreadScale;
1958
- const { __world, __layout: __layout } = ui;
2040
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1959
2041
  const { innerShadow } = ui.__;
1960
2042
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1961
2043
  const other = current.getSameCanvas();
@@ -1968,40 +2050,115 @@ function innerShadow(ui, current, shape, renderOptions) {
1968
2050
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1969
2051
  other.restore();
1970
2052
  if (worldCanvas) {
1971
- other.copyWorld(other, bounds, __world, 'copy');
1972
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1973
- copyBounds = __world;
2053
+ other.copyWorld(other, bounds, nowWorld, 'copy');
2054
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
2055
+ copyBounds = nowWorld;
1974
2056
  }
1975
2057
  else {
1976
2058
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1977
2059
  copyBounds = bounds;
1978
2060
  }
1979
2061
  other.fillWorld(copyBounds, item.color, 'source-in');
1980
- if (ui.__worldFlipped || renderOptions.matrix) {
1981
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
2062
+ if (ui.__worldFlipped) {
2063
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1982
2064
  }
1983
2065
  else {
1984
2066
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1985
2067
  }
1986
2068
  if (end && index < end)
1987
- other.clear();
2069
+ other.clearWorld(copyBounds, true);
1988
2070
  });
1989
- other.recycle();
2071
+ other.recycle(copyBounds);
1990
2072
  }
1991
2073
 
1992
2074
  function blur(ui, current, origin) {
1993
2075
  const { blur } = ui.__;
1994
- origin.setWorldBlur(blur * ui.__world.a);
1995
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
2076
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
2077
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
1996
2078
  origin.filter = 'none';
1997
2079
  }
1998
2080
 
1999
- var UIEffect = /*#__PURE__*/Object.freeze({
2000
- __proto__: null,
2001
- blur: blur,
2002
- innerShadow: innerShadow,
2003
- shadow: shadow
2004
- });
2081
+ function backgroundBlur(_ui, _current, _shape) {
2082
+ }
2083
+
2084
+ const EffectModule = {
2085
+ shadow,
2086
+ innerShadow,
2087
+ blur,
2088
+ backgroundBlur
2089
+ };
2090
+
2091
+ const { excludeRenderBounds } = LeafBoundsHelper;
2092
+ Group.prototype.__renderMask = function (canvas, options) {
2093
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
2094
+ const { children } = this;
2095
+ for (let i = 0, len = children.length; i < len; i++) {
2096
+ child = children[i];
2097
+ if (child.__.mask) {
2098
+ if (currentMask) {
2099
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
2100
+ maskCanvas = contentCanvas = null;
2101
+ }
2102
+ if (child.__.mask === 'path') {
2103
+ if (child.opacity < 1) {
2104
+ currentMask = 'opacity-path';
2105
+ maskOpacity = child.opacity;
2106
+ if (!contentCanvas)
2107
+ contentCanvas = getCanvas(canvas);
2108
+ }
2109
+ else {
2110
+ currentMask = 'path';
2111
+ canvas.save();
2112
+ }
2113
+ child.__clip(contentCanvas || canvas, options);
2114
+ }
2115
+ else {
2116
+ currentMask = 'alpha';
2117
+ if (!maskCanvas)
2118
+ maskCanvas = getCanvas(canvas);
2119
+ if (!contentCanvas)
2120
+ contentCanvas = getCanvas(canvas);
2121
+ child.__render(maskCanvas, options);
2122
+ }
2123
+ if (child.__.mask !== 'clipping')
2124
+ continue;
2125
+ }
2126
+ if (excludeRenderBounds(child, options))
2127
+ continue;
2128
+ child.__render(contentCanvas || canvas, options);
2129
+ }
2130
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
2131
+ };
2132
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
2133
+ switch (maskMode) {
2134
+ case 'alpha':
2135
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
2136
+ break;
2137
+ case 'opacity-path':
2138
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
2139
+ break;
2140
+ case 'path':
2141
+ canvas.restore();
2142
+ }
2143
+ }
2144
+ function getCanvas(canvas) {
2145
+ return canvas.getSameCanvas(false, true);
2146
+ }
2147
+ function usePixelMask(leaf, canvas, content, mask) {
2148
+ const realBounds = leaf.__nowWorld;
2149
+ content.resetTransform();
2150
+ content.opacity = 1;
2151
+ content.useMask(mask, realBounds);
2152
+ mask.recycle(realBounds);
2153
+ copyContent(leaf, canvas, content, 1);
2154
+ }
2155
+ function copyContent(leaf, canvas, content, maskOpacity) {
2156
+ const realBounds = leaf.__nowWorld;
2157
+ canvas.resetTransform();
2158
+ canvas.opacity = maskOpacity;
2159
+ canvas.copyWorld(content, realBounds);
2160
+ content.recycle(realBounds);
2161
+ }
2005
2162
 
2006
2163
  const money = '¥¥$€££¢¢';
2007
2164
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -2158,7 +2315,8 @@ function createRows(drawData, content, style) {
2158
2315
  if (breakAll) {
2159
2316
  if (wordWidth)
2160
2317
  addWord();
2161
- addRow();
2318
+ if (rowWidth)
2319
+ addRow();
2162
2320
  }
2163
2321
  else {
2164
2322
  if (!afterBreak)
@@ -2166,10 +2324,12 @@ function createRows(drawData, content, style) {
2166
2324
  if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2167
2325
  if (wordWidth)
2168
2326
  addWord();
2169
- addRow();
2327
+ if (rowWidth)
2328
+ addRow();
2170
2329
  }
2171
2330
  else {
2172
- addRow();
2331
+ if (rowWidth)
2332
+ addRow();
2173
2333
  }
2174
2334
  }
2175
2335
  }
@@ -2264,11 +2424,11 @@ function layoutChar(drawData, style, width, _height) {
2264
2424
  if (mode === WordMode) {
2265
2425
  wordChar = { char: '', x: charX };
2266
2426
  charX = toWordChar(word.data, charX, wordChar);
2267
- if (wordChar.char !== ' ')
2427
+ if (row.isOverflow || wordChar.char !== ' ')
2268
2428
  row.data.push(wordChar);
2269
2429
  }
2270
2430
  else {
2271
- charX = toChar(word.data, charX, row.data);
2431
+ charX = toChar(word.data, charX, row.data, row.isOverflow);
2272
2432
  }
2273
2433
  if (!row.paraEnd && addWordWidth) {
2274
2434
  charX += addWordWidth;
@@ -2295,9 +2455,9 @@ function toWordChar(data, charX, wordChar) {
2295
2455
  });
2296
2456
  return charX;
2297
2457
  }
2298
- function toChar(data, charX, rowData) {
2458
+ function toChar(data, charX, rowData, isOverflow) {
2299
2459
  data.forEach(char => {
2300
- if (char.char !== ' ') {
2460
+ if (isOverflow || char.char !== ' ') {
2301
2461
  char.x = charX;
2302
2462
  rowData.push(char);
2303
2463
  }
@@ -2329,12 +2489,14 @@ function layoutText(drawData, style) {
2329
2489
  for (let i = 0, len = rows.length; i < len; i++) {
2330
2490
  row = rows[i];
2331
2491
  row.x = x;
2332
- switch (textAlign) {
2333
- case 'center':
2334
- row.x += (width - row.width) / 2;
2335
- break;
2336
- case 'right':
2337
- row.x += width - row.width;
2492
+ if (row.width < width || (row.width > width && !__clipText)) {
2493
+ switch (textAlign) {
2494
+ case 'center':
2495
+ row.x += (width - row.width) / 2;
2496
+ break;
2497
+ case 'right':
2498
+ row.x += width - row.width;
2499
+ }
2338
2500
  }
2339
2501
  if (row.paraStart && paraSpacing && i > 0)
2340
2502
  starY += paraSpacing;
@@ -2370,16 +2532,20 @@ function layoutText(drawData, style) {
2370
2532
  bounds.height = realHeight;
2371
2533
  }
2372
2534
 
2373
- function clipText(drawData, style) {
2535
+ function clipText(drawData, style, x, width) {
2536
+ if (!width)
2537
+ return;
2374
2538
  const { rows, overflow } = drawData;
2375
2539
  let { textOverflow } = style;
2376
2540
  rows.splice(overflow);
2377
- if (textOverflow !== 'hide') {
2378
- if (textOverflow === 'ellipsis')
2541
+ if (textOverflow && textOverflow !== 'show') {
2542
+ if (textOverflow === 'hide')
2543
+ textOverflow = '';
2544
+ else if (textOverflow === 'ellipsis')
2379
2545
  textOverflow = '...';
2380
2546
  let char, charRight;
2381
- const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2382
- const right = style.x + style.width - ellipsisWidth;
2547
+ const ellipsisWidth = textOverflow ? Platform.canvas.measureText(textOverflow).width : 0;
2548
+ const right = x + width - ellipsisWidth;
2383
2549
  const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2384
2550
  list.forEach(row => {
2385
2551
  if (row.isOverflow && row.data) {
@@ -2426,42 +2592,40 @@ function decorationText(drawData, style) {
2426
2592
  }
2427
2593
 
2428
2594
  const { top, right, bottom, left } = Direction4;
2429
- const TextConvert = {
2430
- getDrawData(content, style) {
2431
- if (typeof content !== 'string')
2432
- content = String(content);
2433
- let x = 0, y = 0;
2434
- let width = style.__getInput('width') || 0;
2435
- let height = style.__getInput('height') || 0;
2436
- const { textDecoration, __font, __padding: padding } = style;
2437
- if (padding) {
2438
- if (width) {
2439
- x = padding[left];
2440
- width -= (padding[right] + padding[left]);
2441
- }
2442
- if (height) {
2443
- y = padding[top];
2444
- height -= (padding[top] + padding[bottom]);
2445
- }
2446
- }
2447
- const drawData = {
2448
- bounds: { x, y, width, height },
2449
- rows: [],
2450
- paraNumber: 0,
2451
- font: Platform.canvas.font = __font
2452
- };
2453
- createRows(drawData, content, style);
2454
- if (padding)
2455
- padAutoText(padding, drawData, style, width, height);
2456
- layoutText(drawData, style);
2457
- layoutChar(drawData, style, width);
2458
- if (drawData.overflow)
2459
- clipText(drawData, style);
2460
- if (textDecoration !== 'none')
2461
- decorationText(drawData, style);
2462
- return drawData;
2463
- }
2464
- };
2595
+ function getDrawData(content, style) {
2596
+ if (typeof content !== 'string')
2597
+ content = String(content);
2598
+ let x = 0, y = 0;
2599
+ let width = style.__getInput('width') || 0;
2600
+ let height = style.__getInput('height') || 0;
2601
+ const { textDecoration, __font, __padding: padding } = style;
2602
+ if (padding) {
2603
+ if (width) {
2604
+ x = padding[left];
2605
+ width -= (padding[right] + padding[left]);
2606
+ }
2607
+ if (height) {
2608
+ y = padding[top];
2609
+ height -= (padding[top] + padding[bottom]);
2610
+ }
2611
+ }
2612
+ const drawData = {
2613
+ bounds: { x, y, width, height },
2614
+ rows: [],
2615
+ paraNumber: 0,
2616
+ font: Platform.canvas.font = __font
2617
+ };
2618
+ createRows(drawData, content, style);
2619
+ if (padding)
2620
+ padAutoText(padding, drawData, style, width, height);
2621
+ layoutText(drawData, style);
2622
+ layoutChar(drawData, style, width);
2623
+ if (drawData.overflow)
2624
+ clipText(drawData, style, x, width);
2625
+ if (textDecoration !== 'none')
2626
+ decorationText(drawData, style);
2627
+ return drawData;
2628
+ }
2465
2629
  function padAutoText(padding, drawData, style, width, height) {
2466
2630
  if (!width) {
2467
2631
  switch (style.textAlign) {
@@ -2489,67 +2653,152 @@ function offsetText(drawData, attrName, value) {
2489
2653
  rows[i][attrName] += value;
2490
2654
  }
2491
2655
 
2492
- const ColorConvert = {
2493
- string(color, opacity) {
2494
- if (typeof color === 'string')
2495
- return color;
2496
- let a = color.a === undefined ? 1 : color.a;
2497
- if (opacity)
2498
- a *= opacity;
2499
- const rgb = color.r + ',' + color.g + ',' + color.b;
2500
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2501
- }
2656
+ const TextConvertModule = {
2657
+ getDrawData
2502
2658
  };
2503
2659
 
2504
- const Export = {
2660
+ function string(color, opacity) {
2661
+ if (typeof color === 'string')
2662
+ return color;
2663
+ let a = color.a === undefined ? 1 : color.a;
2664
+ if (opacity)
2665
+ a *= opacity;
2666
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2667
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2668
+ }
2669
+
2670
+ const ColorConvertModule = {
2671
+ string
2672
+ };
2673
+
2674
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2675
+ function getTrimBounds(canvas) {
2676
+ const { width, height } = canvas.view;
2677
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2678
+ let x, y, pointBounds, index = 0;
2679
+ for (let i = 0; i < data.length; i += 4) {
2680
+ if (data[i + 3] !== 0) {
2681
+ x = index % width;
2682
+ y = (index - x) / width;
2683
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2684
+ }
2685
+ index++;
2686
+ }
2687
+ const bounds = new Bounds();
2688
+ toBounds(pointBounds, bounds);
2689
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2690
+ }
2691
+
2692
+ const ExportModule = {
2505
2693
  export(leaf, filename, options) {
2506
- Export.running = true;
2694
+ this.running = true;
2695
+ const fileType = FileHelper.fileType(filename);
2696
+ options = FileHelper.getExportOptions(options);
2507
2697
  return addTask((success) => new Promise((resolve) => {
2698
+ const over = (result) => {
2699
+ success(result);
2700
+ resolve();
2701
+ this.running = false;
2702
+ };
2703
+ const { toURL } = Platform;
2704
+ const { download } = Platform.origin;
2705
+ if (filename === 'json') {
2706
+ return over({ data: leaf.toJSON(options.json) });
2707
+ }
2708
+ else if (fileType === 'json') {
2709
+ download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename);
2710
+ return over({ data: true });
2711
+ }
2712
+ if (filename === 'svg') {
2713
+ return over({ data: leaf.toSVG() });
2714
+ }
2715
+ else if (fileType === 'svg') {
2716
+ download(toURL(leaf.toSVG(), 'svg'), filename);
2717
+ return over({ data: true });
2718
+ }
2508
2719
  const { leafer } = leaf;
2509
2720
  if (leafer) {
2721
+ checkLazy(leaf);
2510
2722
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2511
- let quality, blob;
2512
- let { canvas } = leafer;
2513
- let { unreal } = canvas;
2514
- if (unreal) {
2515
- canvas = canvas.getSameCanvas();
2516
- canvas.backgroundColor = leafer.config.fill;
2517
- leafer.__render(canvas, {});
2723
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2724
+ const { worldTransform, isLeafer, isFrame } = leaf;
2725
+ const { slice, trim, onCanvas } = options;
2726
+ let scale = options.scale || 1;
2727
+ let pixelRatio = options.pixelRatio || 1;
2728
+ const smooth = options.smooth === undefined ? leafer.config.smooth : options.smooth;
2729
+ const contextSettings = options.contextSettings || leafer.config.contextSettings;
2730
+ if (leaf.isApp) {
2731
+ scale *= pixelRatio;
2732
+ pixelRatio = leaf.app.pixelRatio;
2518
2733
  }
2519
- switch (typeof options) {
2520
- case 'object':
2521
- if (options.quality)
2522
- quality = options.quality;
2523
- if (options.blob)
2524
- blob = true;
2525
- break;
2526
- case 'number':
2527
- quality = options;
2528
- break;
2529
- case 'boolean':
2530
- blob = options;
2734
+ const screenshot = options.screenshot || leaf.isApp;
2735
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2736
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2737
+ if (screenshot) {
2738
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2739
+ }
2740
+ else {
2741
+ let relative = options.relative || (isLeafer ? 'inner' : 'local');
2742
+ scaleX = worldTransform.scaleX;
2743
+ scaleY = worldTransform.scaleY;
2744
+ switch (relative) {
2745
+ case 'inner':
2746
+ matrix.set(worldTransform);
2747
+ break;
2748
+ case 'local':
2749
+ matrix.set(worldTransform).divide(leaf.localTransform);
2750
+ scaleX /= leaf.scaleX;
2751
+ scaleY /= leaf.scaleY;
2752
+ break;
2753
+ case 'world':
2754
+ scaleX = 1;
2755
+ scaleY = 1;
2756
+ break;
2757
+ case 'page':
2758
+ relative = leaf.leafer;
2759
+ default:
2760
+ matrix.set(worldTransform).divide(leaf.getTransform(relative));
2761
+ const l = relative.worldTransform;
2762
+ scaleX /= scaleX / l.scaleX;
2763
+ scaleY /= scaleY / l.scaleY;
2764
+ }
2765
+ renderBounds = leaf.getBounds('render', relative);
2531
2766
  }
2532
- let data;
2533
- if (filename.includes('.')) {
2534
- data = yield canvas.saveAs(filename, quality);
2767
+ const { x, y, width, height } = new Bounds(renderBounds).scale(scale);
2768
+ let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio, smooth, contextSettings });
2769
+ const renderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) };
2770
+ if (slice) {
2771
+ leaf = leafer;
2772
+ renderOptions.bounds = canvas.bounds;
2535
2773
  }
2536
- else if (blob) {
2537
- data = yield canvas.toBlob(filename, quality);
2774
+ canvas.save();
2775
+ if (isFrame && fill !== undefined) {
2776
+ const oldFill = leaf.get('fill');
2777
+ leaf.fill = '';
2778
+ leaf.__render(canvas, renderOptions);
2779
+ leaf.fill = oldFill;
2538
2780
  }
2539
2781
  else {
2540
- data = yield canvas.toDataURL(filename, quality);
2782
+ leaf.__render(canvas, renderOptions);
2783
+ }
2784
+ canvas.restore();
2785
+ if (trim) {
2786
+ trimBounds = getTrimBounds(canvas);
2787
+ const old = canvas, { width, height } = trimBounds;
2788
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2789
+ canvas = Creator.canvas(config);
2790
+ canvas.copyWorld(old, trimBounds, config);
2541
2791
  }
2542
- success({ data });
2543
- resolve();
2544
- Export.running = false;
2545
- if (unreal)
2546
- canvas.recycle();
2792
+ if (needFill)
2793
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2794
+ if (onCanvas)
2795
+ onCanvas(canvas);
2796
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2797
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2547
2798
  }));
2548
2799
  }
2549
2800
  else {
2550
- success({ data: false });
2551
- resolve();
2552
- Export.running = false;
2801
+ over({ data: false });
2553
2802
  }
2554
2803
  }));
2555
2804
  }
@@ -2562,13 +2811,64 @@ function addTask(task) {
2562
2811
  tasker.add(() => __awaiter(this, void 0, void 0, function* () { return yield task(resolve); }), { parallel: false });
2563
2812
  });
2564
2813
  }
2814
+ function checkLazy(leaf) {
2815
+ if (leaf.__.__needComputePaint)
2816
+ leaf.__.__computePaint();
2817
+ if (leaf.isBranch)
2818
+ leaf.children.forEach(child => checkLazy(child));
2819
+ }
2820
+
2821
+ const canvas = LeaferCanvasBase.prototype;
2822
+ const debug = Debug.get('@leafer-ui/export');
2823
+ canvas.export = function (filename, options) {
2824
+ const { quality, blob } = FileHelper.getExportOptions(options);
2825
+ if (filename.includes('.')) {
2826
+ return this.saveAs(filename, quality);
2827
+ }
2828
+ else if (blob) {
2829
+ return this.toBlob(filename, quality);
2830
+ }
2831
+ else {
2832
+ return this.toDataURL(filename, quality);
2833
+ }
2834
+ };
2835
+ canvas.toBlob = function (type, quality) {
2836
+ return new Promise((resolve) => {
2837
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2838
+ resolve(blob);
2839
+ }).catch((e) => {
2840
+ debug.error(e);
2841
+ resolve(null);
2842
+ });
2843
+ });
2844
+ };
2845
+ canvas.toDataURL = function (type, quality) {
2846
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
2847
+ };
2848
+ canvas.saveAs = function (filename, quality) {
2849
+ return new Promise((resolve) => {
2850
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2851
+ resolve(true);
2852
+ }).catch((e) => {
2853
+ debug.error(e);
2854
+ resolve(false);
2855
+ });
2856
+ });
2857
+ };
2565
2858
 
2566
- Object.assign(Paint, UIPaint);
2567
- Object.assign(Effect, UIEffect);
2568
- Object.assign(TextConvert$1, TextConvert);
2569
- Object.assign(ColorConvert$1, ColorConvert);
2570
- Object.assign(Export$2, Export);
2859
+ Object.assign(TextConvert, TextConvertModule);
2860
+ Object.assign(ColorConvert, ColorConvertModule);
2861
+ Object.assign(Paint, PaintModule);
2862
+ Object.assign(PaintImage, PaintImageModule);
2863
+ Object.assign(PaintGradient, PaintGradientModule);
2864
+ Object.assign(Effect, EffectModule);
2865
+ Object.assign(Export, ExportModule);
2571
2866
 
2867
+ Object.assign(Creator, {
2868
+ interaction: (target, canvas, selector, options) => new Interaction(target, canvas, selector, options),
2869
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2870
+ hitCanvasManager: () => new HitCanvasManager()
2871
+ });
2572
2872
  try {
2573
2873
  useCanvas('wx', wx);
2574
2874
  }