@leafer-ui/worker 1.0.0-beta.18 → 1.0.0-rc.10

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,97 @@
1
- import { LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, BoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, Platform, AnimateEvent, ResizeEvent, Creator, LeaferCanvasBase, canvasPatch, LeaferImage, InteractionBase, FileHelper, MatrixHelper, ImageEvent, PointHelper, MathHelper, TaskProcessor } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, Creator, LeaferImage, FileHelper, LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, ResizeEvent, BoundsHelper, Answer, MatrixHelper, ImageEvent, 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, Paint, Effect, TextConvert as TextConvert$1, Export as Export$1 } from '@leafer-ui/core';
4
+ import { InteractionBase, HitCanvasManager } from '@leafer-ui/core';
5
5
  export * from '@leafer-ui/core';
6
+ import { ColorConvert, Export, Group, TextConvert, Paint, PaintImage as PaintImage$1, PaintGradient as PaintGradient$1, Effect } from '@leafer-ui/draw';
7
+
8
+ class LeaferCanvas extends LeaferCanvasBase {
9
+ get allowBackgroundColor() { return true; }
10
+ init() {
11
+ this.__createView();
12
+ this.__createContext();
13
+ this.resize(this.config);
14
+ }
15
+ __createView() {
16
+ this.view = Platform.origin.createCanvas(1, 1);
17
+ }
18
+ updateViewSize() {
19
+ const { width, height, pixelRatio } = this;
20
+ this.view.width = Math.ceil(width * pixelRatio);
21
+ this.view.height = Math.ceil(height * pixelRatio);
22
+ this.clientBounds = this.bounds;
23
+ }
24
+ }
25
+
26
+ canvasPatch(OffscreenCanvasRenderingContext2D.prototype);
27
+ canvasPatch(Path2D.prototype);
28
+
29
+ const { mineType } = FileHelper;
30
+ Object.assign(Creator, {
31
+ canvas: (options, manager) => new LeaferCanvas(options, manager),
32
+ image: (options) => new LeaferImage(options)
33
+ });
34
+ function useCanvas(_canvasType, _power) {
35
+ Platform.origin = {
36
+ createCanvas: (width, height) => new OffscreenCanvas(width, height),
37
+ canvasToDataURL: (canvas, type, quality) => {
38
+ return new Promise((resolve, reject) => {
39
+ canvas.convertToBlob({ type: mineType(type), quality }).then((blob) => {
40
+ var reader = new FileReader();
41
+ reader.onload = (e) => resolve(e.target.result);
42
+ reader.onerror = (e) => reject(e);
43
+ reader.readAsDataURL(blob);
44
+ }).catch((e) => {
45
+ reject(e);
46
+ });
47
+ });
48
+ },
49
+ canvasToBolb: (canvas, type, quality) => canvas.convertToBlob({ type: mineType(type), quality }),
50
+ canvasSaveAs: (_canvas, _filename, _quality) => new Promise((resolve) => resolve()),
51
+ loadImage(src) {
52
+ return new Promise((resolve, reject) => {
53
+ if (!src.startsWith('data:') && Platform.image.suffix)
54
+ src += (src.includes("?") ? "&" : "?") + Platform.image.suffix;
55
+ let req = new XMLHttpRequest();
56
+ req.open('GET', src, true);
57
+ req.responseType = "blob";
58
+ req.onload = () => {
59
+ createImageBitmap(req.response).then(img => {
60
+ resolve(img);
61
+ }).catch(e => {
62
+ reject(e);
63
+ });
64
+ };
65
+ req.onerror = (e) => reject(e);
66
+ req.send();
67
+ });
68
+ }
69
+ };
70
+ Platform.canvas = Creator.canvas();
71
+ Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
72
+ }
73
+ Platform.name = 'web';
74
+ Platform.isWorker = true;
75
+ Platform.requestRender = function (render) { requestAnimationFrame(render); };
76
+ Platform.devicePixelRatio = 1;
77
+ const { userAgent } = navigator;
78
+ if (userAgent.indexOf("Firefox") > -1) {
79
+ Platform.conicGradientRotate90 = true;
80
+ Platform.intWheelDeltaY = true;
81
+ }
82
+ else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") === -1) {
83
+ Platform.fullImageShadow = true;
84
+ }
85
+ if (userAgent.indexOf('Windows') > -1) {
86
+ Platform.os = 'Windows';
87
+ Platform.intWheelDeltaY = true;
88
+ }
89
+ else if (userAgent.indexOf('Mac') > -1) {
90
+ Platform.os = 'Mac';
91
+ }
92
+ else if (userAgent.indexOf('Linux') > -1) {
93
+ Platform.os = 'Linux';
94
+ }
6
95
 
7
96
  class Watcher {
8
97
  get childrenChanged() { return this.hasAdd || this.hasRemove || this.hasVisible; }
@@ -10,7 +99,7 @@ class Watcher {
10
99
  if (this.hasRemove) {
11
100
  const updatedList = new LeafList();
12
101
  this.__updatedList.list.forEach(item => { if (item.leafer)
13
- updatedList.push(item); });
102
+ updatedList.add(item); });
14
103
  return updatedList;
15
104
  }
16
105
  else {
@@ -45,7 +134,7 @@ class Watcher {
45
134
  this.target.emit(RenderEvent.REQUEST);
46
135
  }
47
136
  __onAttrChange(event) {
48
- this.__updatedList.push(event.target);
137
+ this.__updatedList.add(event.target);
49
138
  this.update();
50
139
  }
51
140
  __onChildEvent(event) {
@@ -55,12 +144,12 @@ class Watcher {
55
144
  }
56
145
  else {
57
146
  this.hasRemove = true;
58
- this.__updatedList.push(event.parent);
147
+ this.__updatedList.add(event.parent);
59
148
  }
60
149
  this.update();
61
150
  }
62
151
  __pushChild(child) {
63
- this.__updatedList.push(child);
152
+ this.__updatedList.add(child);
64
153
  if (child.isBranch)
65
154
  this.__loopChildren(child);
66
155
  }
@@ -99,22 +188,22 @@ class Watcher {
99
188
  }
100
189
  }
101
190
 
102
- const { updateAllWorldMatrix: updateAllWorldMatrix$1, updateAllWorldOpacity } = LeafHelper;
191
+ const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateAllWorldOpacity } = LeafHelper;
103
192
  const { pushAllChildBranch, pushAllParent } = BranchHelper;
104
193
  function updateMatrix(updateList, levelList) {
105
194
  let layout;
106
195
  updateList.list.forEach(leaf => {
107
196
  layout = leaf.__layout;
108
- if (levelList.without(leaf) && !layout.useZoomProxy) {
197
+ if (levelList.without(leaf) && !layout.proxyZoom) {
109
198
  if (layout.matrixChanged) {
110
- updateAllWorldMatrix$1(leaf);
111
- levelList.push(leaf);
199
+ updateAllMatrix$1(leaf, true);
200
+ levelList.add(leaf);
112
201
  if (leaf.isBranch)
113
202
  pushAllChildBranch(leaf, levelList);
114
203
  pushAllParent(leaf, levelList);
115
204
  }
116
205
  else if (layout.boundsChanged) {
117
- levelList.push(leaf);
206
+ levelList.add(leaf);
118
207
  if (leaf.isBranch)
119
208
  leaf.__tempNumber = 0;
120
209
  pushAllParent(leaf, levelList);
@@ -123,20 +212,21 @@ function updateMatrix(updateList, levelList) {
123
212
  });
124
213
  }
125
214
  function updateBounds(boundsList) {
126
- let itemList, branch;
215
+ let list, branch, children;
127
216
  boundsList.sort(true);
128
217
  boundsList.levels.forEach(level => {
129
- itemList = boundsList.levelMap[level];
130
- for (let i = 0, len = itemList.length; i < len; i++) {
131
- branch = itemList[i];
218
+ list = boundsList.levelMap[level];
219
+ for (let i = 0, len = list.length; i < len; i++) {
220
+ branch = list[i];
132
221
  if (branch.isBranch && branch.__tempNumber) {
133
- for (let j = 0, jLen = branch.children.length; j < jLen; j++) {
134
- if (!branch.children[j].isBranch) {
135
- branch.children[j].__updateWorldBounds();
222
+ children = branch.children;
223
+ for (let j = 0, jLen = children.length; j < jLen; j++) {
224
+ if (!children[j].isBranch) {
225
+ updateOneBounds(children[j]);
136
226
  }
137
227
  }
138
228
  }
139
- branch.__updateWorldBounds();
229
+ updateOneBounds(branch);
140
230
  }
141
231
  });
142
232
  }
@@ -149,7 +239,7 @@ function updateChange(updateList) {
149
239
  }
150
240
 
151
241
  const { worldBounds } = LeafBoundsHelper;
152
- const { setByListWithHandle } = BoundsHelper;
242
+ const bigBounds = { x: 0, y: 0, width: 100000, height: 100000 };
153
243
  class LayoutBlockData {
154
244
  constructor(list) {
155
245
  this.updatedBounds = new Bounds();
@@ -160,14 +250,20 @@ class LayoutBlockData {
160
250
  this.updatedList = list;
161
251
  }
162
252
  setBefore() {
163
- setByListWithHandle(this.beforeBounds, this.updatedList.list, worldBounds);
253
+ this.beforeBounds.setListWithFn(this.updatedList.list, worldBounds);
164
254
  }
165
255
  setAfter() {
166
- setByListWithHandle(this.afterBounds, this.updatedList.list, worldBounds);
167
- this.updatedBounds.setByList([this.beforeBounds, this.afterBounds]);
256
+ const { list } = this.updatedList;
257
+ if (list.some(leaf => leaf.noBounds)) {
258
+ this.afterBounds.set(bigBounds);
259
+ }
260
+ else {
261
+ this.afterBounds.setListWithFn(list, worldBounds);
262
+ }
263
+ this.updatedBounds.setList([this.beforeBounds, this.afterBounds]);
168
264
  }
169
265
  merge(data) {
170
- this.updatedList.pushList(data.updatedList.list);
266
+ this.updatedList.addList(data.updatedList.list);
171
267
  this.beforeBounds.add(data.beforeBounds);
172
268
  this.afterBounds.add(data.afterBounds);
173
269
  this.updatedBounds.add(data.updatedBounds);
@@ -177,8 +273,7 @@ class LayoutBlockData {
177
273
  }
178
274
  }
179
275
 
180
- const { updateAllWorldMatrix, updateAllChange } = LeafHelper;
181
- const { pushAllBranchStack, updateWorldBoundsByBranchStack } = BranchHelper;
276
+ const { updateAllMatrix, updateAllChange } = LeafHelper;
182
277
  const debug$1 = Debug.get('Layouter');
183
278
  class Layouter {
184
279
  constructor(target, userConfig) {
@@ -255,12 +350,15 @@ class Layouter {
255
350
  const { target, __updatedList: updateList } = this;
256
351
  const { BEFORE, LAYOUT, AFTER } = LayoutEvent;
257
352
  const blocks = this.getBlocks(updateList);
258
- blocks.forEach(item => { item.setBefore(); });
353
+ blocks.forEach(item => item.setBefore());
259
354
  target.emitEvent(new LayoutEvent(BEFORE, blocks, this.times));
355
+ this.extraBlock = null;
260
356
  updateList.sort();
261
357
  updateMatrix(updateList, this.__levelList);
262
358
  updateBounds(this.__levelList);
263
359
  updateChange(updateList);
360
+ if (this.extraBlock)
361
+ blocks.push(this.extraBlock);
264
362
  blocks.forEach(item => item.setAfter());
265
363
  target.emitEvent(new LayoutEvent(LAYOUT, blocks, this.times));
266
364
  target.emitEvent(new LayoutEvent(AFTER, blocks, this.times));
@@ -283,17 +381,20 @@ class Layouter {
283
381
  Run.end(t);
284
382
  }
285
383
  static fullLayout(target) {
286
- updateAllWorldMatrix(target);
384
+ updateAllMatrix(target, true);
287
385
  if (target.isBranch) {
288
- const branchStack = [target];
289
- pushAllBranchStack(target, branchStack);
290
- updateWorldBoundsByBranchStack(branchStack);
386
+ BranchHelper.updateBounds(target);
291
387
  }
292
388
  else {
293
- target.__updateWorldBounds();
389
+ LeafHelper.updateBounds(target);
294
390
  }
295
391
  updateAllChange(target);
296
392
  }
393
+ addExtra(leaf) {
394
+ const block = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
395
+ block.updatedList.add(leaf);
396
+ block.beforeBounds.add(leaf.__world);
397
+ }
297
398
  createBlock(data) {
298
399
  return new LayoutBlockData(data);
299
400
  }
@@ -321,8 +422,7 @@ class Layouter {
321
422
  if (this.target) {
322
423
  this.stop();
323
424
  this.__removeListenEvents();
324
- this.target = null;
325
- this.config = null;
425
+ this.target = this.config = null;
326
426
  }
327
427
  }
328
428
  }
@@ -424,8 +524,7 @@ class Renderer {
424
524
  const { canvas, updateBlocks: list } = this;
425
525
  if (!list)
426
526
  return debug.warn('PartRender: need update attr');
427
- if (list.some(block => block.includes(this.target.__world)))
428
- this.mergeBlocks();
527
+ this.mergeBlocks();
429
528
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
430
529
  this.clipRender(block); });
431
530
  }
@@ -434,7 +533,7 @@ class Renderer {
434
533
  const { canvas } = this;
435
534
  const bounds = block.getIntersect(canvas.bounds);
436
535
  const includes = block.includes(this.target.__world);
437
- const realBounds = new Bounds().copy(bounds);
536
+ const realBounds = new Bounds(bounds);
438
537
  canvas.save();
439
538
  if (includes && !Debug.showRepaint) {
440
539
  canvas.clear();
@@ -444,7 +543,7 @@ class Renderer {
444
543
  canvas.clearWorld(bounds, true);
445
544
  canvas.clipWorld(bounds, true);
446
545
  }
447
- this.__render(bounds, realBounds);
546
+ this.__render(bounds, includes, realBounds);
448
547
  canvas.restore();
449
548
  Run.end(t);
450
549
  }
@@ -453,12 +552,12 @@ class Renderer {
453
552
  const { canvas } = this;
454
553
  canvas.save();
455
554
  canvas.clear();
456
- this.__render(canvas.bounds);
555
+ this.__render(canvas.bounds, true);
457
556
  canvas.restore();
458
557
  Run.end(t);
459
558
  }
460
- __render(bounds, realBounds) {
461
- const options = (bounds === null || bounds === void 0 ? void 0 : bounds.includes(this.target.__world)) ? {} : { bounds };
559
+ __render(bounds, includes, realBounds) {
560
+ const options = bounds.includes(this.target.__world) ? { includes } : { bounds, includes };
462
561
  if (this.needFill)
463
562
  this.canvas.fillWorld(bounds, this.config.fill);
464
563
  if (Debug.showRepaint)
@@ -484,7 +583,7 @@ class Renderer {
484
583
  const { updateBlocks: list } = this;
485
584
  if (list) {
486
585
  const bounds = new Bounds();
487
- bounds.setByList(list);
586
+ bounds.setList(list);
488
587
  list.length = 0;
489
588
  list.push(bounds);
490
589
  }
@@ -493,12 +592,12 @@ class Renderer {
493
592
  const startTime = Date.now();
494
593
  Platform.requestRender(() => {
495
594
  this.FPS = Math.min(60, Math.ceil(1000 / (Date.now() - startTime)));
496
- if (this.changed) {
497
- if (this.running && this.canvas.view)
595
+ if (this.running) {
596
+ this.target.emit(AnimateEvent.FRAME);
597
+ if (this.changed && this.canvas.view)
498
598
  this.render();
599
+ this.target.emit(RenderEvent.NEXT);
499
600
  }
500
- if (this.running)
501
- this.target.emit(AnimateEvent.FRAME);
502
601
  if (this.target)
503
602
  this.__requestRender();
504
603
  });
@@ -511,7 +610,7 @@ class Renderer {
511
610
  const bounds = new Bounds(0, 0, width, height);
512
611
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
513
612
  this.addBlock(this.canvas.bounds);
514
- this.target.forceUpdate('blendMode');
613
+ this.target.forceUpdate('surface');
515
614
  }
516
615
  }
517
616
  }
@@ -524,7 +623,7 @@ class Renderer {
524
623
  empty = (!leaf.__world.width || !leaf.__world.height);
525
624
  if (empty) {
526
625
  if (!leaf.isLeafer)
527
- debug.warn(leaf.innerName, ': empty');
626
+ debug.tip(leaf.innerName, ': empty');
528
627
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
529
628
  }
530
629
  return empty;
@@ -559,7 +658,7 @@ class Renderer {
559
658
  }
560
659
 
561
660
  const { hitRadiusPoint } = BoundsHelper;
562
- class FindPath {
661
+ class Picker {
563
662
  constructor(target, selector) {
564
663
  this.target = target;
565
664
  this.selector = selector;
@@ -571,15 +670,17 @@ class FindPath {
571
670
  options = {};
572
671
  const through = options.through || false;
573
672
  const ignoreHittable = options.ignoreHittable || false;
673
+ const target = options.target || this.target;
574
674
  this.exclude = options.exclude || null;
575
675
  this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius };
576
- this.findList = [];
577
- this.eachFind(this.target.children, this.target.__onlyHitMask);
676
+ this.findList = options.findList || [];
677
+ if (!options.findList)
678
+ this.eachFind(target.children, target.__onlyHitMask);
578
679
  const list = this.findList;
579
680
  const leaf = this.getBestMatchLeaf();
580
681
  const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf);
581
682
  this.clear();
582
- return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf };
683
+ return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf };
583
684
  }
584
685
  getBestMatchLeaf() {
585
686
  const { findList: targets } = this;
@@ -602,10 +703,10 @@ class FindPath {
602
703
  getPath(leaf) {
603
704
  const path = new LeafList();
604
705
  while (leaf) {
605
- path.push(leaf);
706
+ path.add(leaf);
606
707
  leaf = leaf.parent;
607
708
  }
608
- path.push(this.target);
709
+ path.add(this.target);
609
710
  return path;
610
711
  }
611
712
  getHitablePath(leaf) {
@@ -615,7 +716,7 @@ class FindPath {
615
716
  item = path.list[i];
616
717
  if (!item.__.hittable)
617
718
  break;
618
- hittablePath.unshift(item);
719
+ hittablePath.addAt(item, 0);
619
720
  if (!item.__.hitChildren)
620
721
  break;
621
722
  }
@@ -634,7 +735,7 @@ class FindPath {
634
735
  leaf = path.list[j];
635
736
  if (nextPath && nextPath.has(leaf))
636
737
  break;
637
- throughPath.push(leaf);
738
+ throughPath.add(leaf);
638
739
  }
639
740
  }
640
741
  return throughPath;
@@ -644,7 +745,7 @@ class FindPath {
644
745
  const { point } = this, len = children.length;
645
746
  for (let i = len - 1; i > -1; i--) {
646
747
  child = children[i];
647
- if (!child.__.visible || (hitMask && !child.__.isMask))
748
+ if (!child.__.visible || (hitMask && !child.__.mask))
648
749
  continue;
649
750
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
650
751
  if (child.isBranch) {
@@ -676,120 +777,113 @@ class FindPath {
676
777
  }
677
778
  }
678
779
 
780
+ const { Yes, NoAndSkip, YesAndSkip } = Answer;
679
781
  class Selector {
680
782
  constructor(target, userConfig) {
681
783
  this.config = {};
682
- this.innerIdList = {};
683
- this.idList = {};
684
- this.classNameList = {};
685
- this.tagNameList = {};
784
+ this.innerIdMap = {};
785
+ this.idMap = {};
786
+ this.methods = {
787
+ id: (leaf, name) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
788
+ innerId: (leaf, innerId) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
789
+ className: (leaf, name) => leaf.className === name ? 1 : 0,
790
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0
791
+ };
686
792
  this.target = target;
687
793
  if (userConfig)
688
794
  this.config = DataHelper.default(userConfig, this.config);
689
- this.findPath = new FindPath(target, this);
795
+ this.picker = new Picker(target, this);
690
796
  this.__listenEvents();
691
797
  }
798
+ getBy(condition, branch, one, options) {
799
+ switch (typeof condition) {
800
+ case 'number':
801
+ const leaf = this.getByInnerId(condition, branch);
802
+ return one ? leaf : (leaf ? [leaf] : []);
803
+ case 'string':
804
+ switch (condition[0]) {
805
+ case '#':
806
+ const leaf = this.getById(condition.substring(1), branch);
807
+ return one ? leaf : (leaf ? [leaf] : []);
808
+ case '.':
809
+ return this.getByMethod(this.methods.className, branch, one, condition.substring(1));
810
+ default:
811
+ return this.getByMethod(this.methods.tag, branch, one, condition);
812
+ }
813
+ case 'function':
814
+ return this.getByMethod(condition, branch, one, options);
815
+ }
816
+ }
692
817
  getByPoint(hitPoint, hitRadius, options) {
693
818
  if (Platform.name === 'node')
694
819
  this.target.emit(LayoutEvent.CHECK_UPDATE);
695
- return this.findPath.getByPoint(hitPoint, hitRadius, options);
696
- }
697
- find(name, branch) {
698
- if (typeof name === 'number') {
699
- return this.getByInnerId(name, branch);
700
- }
701
- else if (name.startsWith('#')) {
702
- return this.getById(name.substring(1), branch);
703
- }
704
- else if (name.startsWith('.')) {
705
- return this.getByClassName(name.substring(1), branch);
706
- }
707
- else {
708
- return this.getByTagName(name, branch);
709
- }
820
+ return this.picker.getByPoint(hitPoint, hitRadius, options);
710
821
  }
711
- getByInnerId(name, branch) {
712
- let cache = this.innerIdList[name];
822
+ getByInnerId(innerId, branch) {
823
+ const cache = this.innerIdMap[innerId];
713
824
  if (cache)
714
825
  return cache;
715
- if (!branch)
716
- branch = this.target;
717
- let find;
718
- this.loopFind(branch, (leaf) => {
719
- if (leaf.innerId === name) {
720
- find = leaf;
721
- this.innerIdList[name] = find;
722
- return true;
723
- }
724
- else {
725
- return false;
726
- }
727
- });
728
- return find;
826
+ this.eachFind(this.toChildren(branch), this.methods.innerId, null, innerId);
827
+ return this.findLeaf;
729
828
  }
730
- getById(name, branch) {
731
- let cache = this.idList[name];
732
- if (cache)
829
+ getById(id, branch) {
830
+ const cache = this.idMap[id];
831
+ if (cache && LeafHelper.hasParent(cache, branch || this.target))
733
832
  return cache;
734
- if (!branch)
735
- branch = this.target;
736
- let find;
737
- this.loopFind(branch, (leaf) => {
738
- if (leaf.id === name) {
739
- find = leaf;
740
- this.idList[name] = find;
741
- return true;
742
- }
743
- else {
744
- return false;
745
- }
746
- });
747
- return find;
748
- }
749
- getByClassName(name, branch) {
750
- if (!branch)
751
- branch = this.target;
752
- let find = [];
753
- this.loopFind(branch, (leaf) => {
754
- if (leaf.className === name)
755
- find.push(leaf);
756
- return false;
757
- });
758
- return find;
759
- }
760
- getByTagName(name, branch) {
761
- if (!branch)
762
- branch = this.target;
763
- let find = [];
764
- this.loopFind(branch, (leaf) => {
765
- if (leaf.__tag === name)
766
- find.push(leaf);
767
- return false;
768
- });
769
- return find;
833
+ this.eachFind(this.toChildren(branch), this.methods.id, null, id);
834
+ return this.findLeaf;
770
835
  }
771
- loopFind(branch, find) {
772
- if (find(branch))
773
- return;
774
- const { children } = branch;
836
+ getByClassName(className, branch) {
837
+ return this.getByMethod(this.methods.className, branch, false, className);
838
+ }
839
+ getByTag(tag, branch) {
840
+ return this.getByMethod(this.methods.tag, branch, false, tag);
841
+ }
842
+ getByMethod(method, branch, one, options) {
843
+ const list = one ? null : [];
844
+ this.eachFind(this.toChildren(branch), method, list, options);
845
+ return list || this.findLeaf;
846
+ }
847
+ eachFind(children, method, list, options) {
848
+ let child, result;
775
849
  for (let i = 0, len = children.length; i < len; i++) {
776
- branch = children[i];
777
- if (find(branch))
778
- return;
779
- if (branch.isBranch)
780
- this.loopFind(branch, find);
850
+ child = children[i];
851
+ result = method(child, options);
852
+ if (result === Yes || result === YesAndSkip) {
853
+ if (list) {
854
+ list.push(child);
855
+ }
856
+ else {
857
+ this.findLeaf = child;
858
+ return;
859
+ }
860
+ }
861
+ if (child.isBranch && result < NoAndSkip)
862
+ this.eachFind(child.children, method, list, options);
781
863
  }
782
864
  }
865
+ toChildren(branch) {
866
+ this.findLeaf = null;
867
+ return [branch || this.target];
868
+ }
783
869
  __onRemoveChild(event) {
784
- const target = event.target;
785
- if (this.idList[target.id])
786
- this.idList[target.id] = null;
787
- if (this.innerIdList[target.id])
788
- this.innerIdList[target.innerId] = null;
870
+ const { id, innerId } = event.child;
871
+ if (this.idMap[id])
872
+ delete this.idMap[id];
873
+ if (this.innerIdMap[innerId])
874
+ delete this.innerIdMap[innerId];
875
+ }
876
+ __checkIdChange(event) {
877
+ if (event.attrName === 'id') {
878
+ const id = event.oldValue;
879
+ if (this.idMap[id])
880
+ delete this.idMap[id];
881
+ }
789
882
  }
790
883
  __listenEvents() {
791
884
  this.__eventIds = [
792
- this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this)
885
+ this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this),
886
+ this.target.on_(PropertyEvent.CHANGE, this.__checkIdChange, this)
793
887
  ];
794
888
  }
795
889
  __removeListenEvents() {
@@ -799,11 +893,10 @@ class Selector {
799
893
  destroy() {
800
894
  if (this.__eventIds.length) {
801
895
  this.__removeListenEvents();
802
- this.findPath.destroy();
803
- this.innerIdList = {};
804
- this.idList = {};
805
- this.classNameList = {};
806
- this.tagNameList = {};
896
+ this.picker.destroy();
897
+ this.findLeaf = null;
898
+ this.innerIdMap = {};
899
+ this.idMap = {};
807
900
  }
808
901
  }
809
902
  }
@@ -816,120 +909,333 @@ Object.assign(Creator, {
816
909
  });
817
910
  Platform.layout = Layouter.fullLayout;
818
911
 
819
- class LeaferCanvas extends LeaferCanvasBase {
820
- get allowBackgroundColor() { return true; }
821
- init() {
822
- this.__createView();
823
- this.__createContext();
824
- this.resize(this.config);
825
- }
826
- __createView() {
827
- this.view = Platform.origin.createCanvas(1, 1);
828
- }
829
- updateViewSize() {
830
- const { width, height, pixelRatio } = this;
831
- this.view.width = width * pixelRatio;
832
- this.view.height = height * pixelRatio;
833
- this.clientBounds = this.bounds;
834
- }
835
- }
836
-
837
- canvasPatch(OffscreenCanvasRenderingContext2D.prototype);
838
- canvasPatch(Path2D.prototype);
912
+ const PaintImage = {};
913
+ const PaintGradient = {};
839
914
 
840
- const { mineType } = FileHelper;
841
- Object.assign(Creator, {
842
- canvas: (options, manager) => new LeaferCanvas(options, manager),
843
- image: (options) => new LeaferImage(options),
844
- hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
845
- interaction: (target, canvas, selector, options) => new InteractionBase(target, canvas, selector, options),
846
- });
847
- function useCanvas(_canvasType, _power) {
848
- Platform.origin = {
849
- createCanvas: (width, height) => new OffscreenCanvas(width, height),
850
- canvasToDataURL: (canvas, type, quality) => {
851
- return new Promise((resolve, reject) => {
852
- canvas.convertToBlob({ type: mineType(type), quality }).then((blob) => {
853
- var reader = new FileReader();
854
- reader.onload = (e) => resolve(e.target.result);
855
- reader.onerror = (e) => reject(e);
856
- reader.readAsDataURL(blob);
857
- }).catch((e) => {
858
- reject(e);
859
- });
860
- });
861
- },
862
- canvasToBolb: (canvas, type, quality) => canvas.convertToBlob({ type: mineType(type), quality }),
863
- canvasSaveAs: (_canvas, _filename, _quality) => new Promise((resolve) => resolve()),
864
- loadImage(src) {
865
- return new Promise((resolve, reject) => {
866
- if (!src.startsWith('data:') && Platform.imageSuffix)
867
- src += (src.includes("?") ? "&" : "?") + Platform.imageSuffix;
868
- let req = new XMLHttpRequest();
869
- req.open('GET', src, true);
870
- req.responseType = "blob";
871
- req.onload = () => {
872
- createImageBitmap(req.response).then(img => {
873
- resolve(img);
874
- }).catch(e => {
875
- reject(e);
876
- });
877
- };
878
- req.onerror = (e) => reject(e);
879
- req.send();
915
+ function fillText(ui, canvas) {
916
+ let row;
917
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
918
+ for (let i = 0, len = rows.length; i < len; i++) {
919
+ row = rows[i];
920
+ if (row.text) {
921
+ canvas.fillText(row.text, row.x, row.y);
922
+ }
923
+ else if (row.data) {
924
+ row.data.forEach(charData => {
925
+ canvas.fillText(charData.char, charData.x, row.y);
880
926
  });
881
927
  }
882
- };
883
- Platform.canvas = Creator.canvas();
884
- Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
885
- }
886
- Platform.name = 'web';
887
- Platform.isWorker = true;
888
- Platform.requestRender = function (render) { requestAnimationFrame(render); };
889
- Platform.devicePixelRatio = 1;
890
- Platform.realtimeLayout = true;
891
- const { userAgent } = navigator;
892
- if (userAgent.indexOf("Firefox") > -1) {
893
- Platform.conicGradientRotate90 = true;
894
- Platform.intWheelDeltaY = true;
895
- }
896
- else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") === -1) {
897
- Platform.fullImageShadow = true;
898
- }
899
- if (userAgent.indexOf('Windows') > -1) {
900
- Platform.os = 'Windows';
901
- Platform.intWheelDeltaY = true;
928
+ if (decorationY)
929
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
930
+ }
902
931
  }
903
- else if (userAgent.indexOf('Mac') > -1) {
904
- Platform.os = 'Mac';
932
+
933
+ function fill(fill, ui, canvas) {
934
+ canvas.fillStyle = fill;
935
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
905
936
  }
906
- else if (userAgent.indexOf('Linux') > -1) {
907
- Platform.os = 'Linux';
937
+ function fills(fills, ui, canvas) {
938
+ let item;
939
+ const { windingRule, __font } = ui.__;
940
+ for (let i = 0, len = fills.length; i < len; i++) {
941
+ item = fills[i];
942
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
943
+ continue;
944
+ if (item.style) {
945
+ canvas.fillStyle = item.style;
946
+ if (item.transform) {
947
+ canvas.save();
948
+ canvas.transform(item.transform);
949
+ if (item.blendMode)
950
+ canvas.blendMode = item.blendMode;
951
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
952
+ canvas.restore();
953
+ }
954
+ else {
955
+ if (item.blendMode) {
956
+ canvas.saveBlendMode(item.blendMode);
957
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
958
+ canvas.restoreBlendMode();
959
+ }
960
+ else {
961
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
962
+ }
963
+ }
964
+ }
965
+ }
908
966
  }
909
967
 
910
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper$1, rotate } = MatrixHelper;
911
- function fillOrFitMode(data, mode, box, width, height, rotation) {
912
- const transform = get$4();
913
- const swap = rotation && rotation !== 180;
914
- const sw = box.width / (swap ? height : width);
915
- const sh = box.height / (swap ? width : height);
916
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
968
+ function strokeText(stroke, ui, canvas) {
969
+ const { strokeAlign } = ui.__;
970
+ const isStrokes = typeof stroke !== 'string';
971
+ switch (strokeAlign) {
972
+ case 'center':
973
+ canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
974
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
975
+ break;
976
+ case 'inside':
977
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
978
+ break;
979
+ case 'outside':
980
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
981
+ break;
982
+ }
983
+ }
984
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
985
+ const { __strokeWidth, __font } = ui.__;
986
+ const out = canvas.getSameCanvas(true, true);
987
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
988
+ out.font = __font;
989
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
990
+ out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
991
+ fillText(ui, out);
992
+ out.blendMode = 'normal';
993
+ if (ui.__worldFlipped) {
994
+ canvas.copyWorldByReset(out, ui.__nowWorld);
995
+ }
996
+ else {
997
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
998
+ }
999
+ out.recycle(ui.__nowWorld);
1000
+ }
1001
+ function drawTextStroke(ui, canvas) {
1002
+ let row;
1003
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1004
+ for (let i = 0, len = rows.length; i < len; i++) {
1005
+ row = rows[i];
1006
+ if (row.text) {
1007
+ canvas.strokeText(row.text, row.x, row.y);
1008
+ }
1009
+ else if (row.data) {
1010
+ row.data.forEach(charData => {
1011
+ canvas.strokeText(charData.char, charData.x, row.y);
1012
+ });
1013
+ }
1014
+ if (decorationY)
1015
+ canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1016
+ }
1017
+ }
1018
+ function drawStrokesStyle(strokes, isText, ui, canvas) {
1019
+ let item;
1020
+ for (let i = 0, len = strokes.length; i < len; i++) {
1021
+ item = strokes[i];
1022
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1023
+ continue;
1024
+ if (item.style) {
1025
+ canvas.strokeStyle = item.style;
1026
+ if (item.blendMode) {
1027
+ canvas.saveBlendMode(item.blendMode);
1028
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1029
+ canvas.restoreBlendMode();
1030
+ }
1031
+ else {
1032
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1033
+ }
1034
+ }
1035
+ }
1036
+ }
1037
+
1038
+ function stroke(stroke, ui, canvas) {
1039
+ const options = ui.__;
1040
+ const { __strokeWidth, strokeAlign, __font } = options;
1041
+ if (!__strokeWidth)
1042
+ return;
1043
+ if (__font) {
1044
+ strokeText(stroke, ui, canvas);
1045
+ }
1046
+ else {
1047
+ switch (strokeAlign) {
1048
+ case 'center':
1049
+ canvas.setStroke(stroke, __strokeWidth, options);
1050
+ canvas.stroke();
1051
+ break;
1052
+ case 'inside':
1053
+ canvas.save();
1054
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1055
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1056
+ canvas.stroke();
1057
+ canvas.restore();
1058
+ break;
1059
+ case 'outside':
1060
+ const out = canvas.getSameCanvas(true, true);
1061
+ out.setStroke(stroke, __strokeWidth * 2, options);
1062
+ ui.__drawRenderPath(out);
1063
+ out.stroke();
1064
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1065
+ out.clearWorld(ui.__layout.renderBounds);
1066
+ if (ui.__worldFlipped) {
1067
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1068
+ }
1069
+ else {
1070
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1071
+ }
1072
+ out.recycle(ui.__nowWorld);
1073
+ break;
1074
+ }
1075
+ }
1076
+ }
1077
+ function strokes(strokes, ui, canvas) {
1078
+ const options = ui.__;
1079
+ const { __strokeWidth, strokeAlign, __font } = options;
1080
+ if (!__strokeWidth)
1081
+ return;
1082
+ if (__font) {
1083
+ strokeText(strokes, ui, canvas);
1084
+ }
1085
+ else {
1086
+ switch (strokeAlign) {
1087
+ case 'center':
1088
+ canvas.setStroke(undefined, __strokeWidth, options);
1089
+ drawStrokesStyle(strokes, false, ui, canvas);
1090
+ break;
1091
+ case 'inside':
1092
+ canvas.save();
1093
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1094
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1095
+ drawStrokesStyle(strokes, false, ui, canvas);
1096
+ canvas.restore();
1097
+ break;
1098
+ case 'outside':
1099
+ const { renderBounds } = ui.__layout;
1100
+ const out = canvas.getSameCanvas(true, true);
1101
+ ui.__drawRenderPath(out);
1102
+ out.setStroke(undefined, __strokeWidth * 2, options);
1103
+ drawStrokesStyle(strokes, false, ui, out);
1104
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1105
+ out.clearWorld(renderBounds);
1106
+ if (ui.__worldFlipped) {
1107
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1108
+ }
1109
+ else {
1110
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1111
+ }
1112
+ out.recycle(ui.__nowWorld);
1113
+ break;
1114
+ }
1115
+ }
1116
+ }
1117
+
1118
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1119
+ function shape(ui, current, options) {
1120
+ const canvas = current.getSameCanvas();
1121
+ const nowWorld = ui.__nowWorld;
1122
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1123
+ let { scaleX, scaleY } = nowWorld;
1124
+ if (scaleX < 0)
1125
+ scaleX = -scaleX;
1126
+ if (scaleY < 0)
1127
+ scaleY = -scaleY;
1128
+ if (current.bounds.includes(nowWorld)) {
1129
+ worldCanvas = canvas;
1130
+ bounds = shapeBounds = nowWorld;
1131
+ }
1132
+ else {
1133
+ const { renderShapeSpread: spread } = ui.__layout;
1134
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, nowWorld);
1135
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1136
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1137
+ if (fitMatrix.a < 1) {
1138
+ worldCanvas = current.getSameCanvas();
1139
+ ui.__renderShape(worldCanvas, options);
1140
+ scaleX *= fitScaleX;
1141
+ scaleY *= fitScaleY;
1142
+ }
1143
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1144
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1145
+ if (options.matrix) {
1146
+ const { matrix } = options;
1147
+ fitMatrix.multiply(matrix);
1148
+ fitScaleX *= matrix.scaleX;
1149
+ fitScaleY *= matrix.scaleY;
1150
+ }
1151
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1152
+ }
1153
+ ui.__renderShape(canvas, options);
1154
+ return {
1155
+ canvas, matrix: fitMatrix, bounds,
1156
+ worldCanvas, shapeBounds, scaleX, scaleY
1157
+ };
1158
+ }
1159
+
1160
+ let recycleMap;
1161
+ function compute(attrName, ui) {
1162
+ const data = ui.__, leafPaints = [];
1163
+ let paints = data.__input[attrName], hasOpacityPixel;
1164
+ if (!(paints instanceof Array))
1165
+ paints = [paints];
1166
+ recycleMap = PaintImage.recycleImage(attrName, data);
1167
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1168
+ item = getLeafPaint(attrName, paints[i], ui);
1169
+ if (item)
1170
+ leafPaints.push(item);
1171
+ }
1172
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1173
+ if (leafPaints.length && leafPaints[0].image)
1174
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1175
+ if (attrName === 'fill') {
1176
+ data.__pixelFill = hasOpacityPixel;
1177
+ }
1178
+ else {
1179
+ data.__pixelStroke = hasOpacityPixel;
1180
+ }
1181
+ }
1182
+ function getLeafPaint(attrName, paint, ui) {
1183
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1184
+ return undefined;
1185
+ const { boxBounds } = ui.__layout;
1186
+ switch (paint.type) {
1187
+ case 'solid':
1188
+ let { type, blendMode, color, opacity } = paint;
1189
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1190
+ case 'image':
1191
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1192
+ case 'linear':
1193
+ return PaintGradient.linearGradient(paint, boxBounds);
1194
+ case 'radial':
1195
+ return PaintGradient.radialGradient(paint, boxBounds);
1196
+ case 'angular':
1197
+ return PaintGradient.conicGradient(paint, boxBounds);
1198
+ default:
1199
+ return paint.r ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1200
+ }
1201
+ }
1202
+
1203
+ const PaintModule = {
1204
+ compute,
1205
+ fill,
1206
+ fills,
1207
+ fillText,
1208
+ stroke,
1209
+ strokes,
1210
+ strokeText,
1211
+ drawTextStroke,
1212
+ shape
1213
+ };
1214
+
1215
+ let origin = {};
1216
+ const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
1217
+ function fillOrFitMode(data, mode, box, width, height, rotation) {
1218
+ const transform = get$4();
1219
+ const swap = rotation && rotation !== 180;
1220
+ const sw = box.width / (swap ? height : width);
1221
+ const sh = box.height / (swap ? width : height);
1222
+ const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
917
1223
  const x = box.x + (box.width - width * scale) / 2;
918
1224
  const y = box.y + (box.height - height * scale) / 2;
919
1225
  translate$1(transform, x, y);
920
- scaleHelper$1(transform, scale);
1226
+ scaleHelper(transform, scale);
921
1227
  if (rotation)
922
1228
  rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
923
1229
  data.scaleX = data.scaleY = scale;
924
1230
  data.transform = transform;
925
1231
  }
926
- function clipMode(data, box, offset, scale, rotation) {
1232
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
927
1233
  const transform = get$4();
928
1234
  translate$1(transform, box.x, box.y);
929
- if (offset)
930
- translate$1(transform, offset.x, offset.y);
931
- if (scale) {
932
- typeof scale === 'number' ? scaleHelper$1(transform, scale) : scaleHelper$1(transform, scale.x, scale.y);
1235
+ if (x || y)
1236
+ translate$1(transform, x, y);
1237
+ if (scaleX) {
1238
+ scaleHelper(transform, scaleX, scaleY);
933
1239
  data.scaleX = transform.a;
934
1240
  data.scaleY = transform.d;
935
1241
  }
@@ -937,7 +1243,7 @@ function clipMode(data, box, offset, scale, rotation) {
937
1243
  rotate(transform, rotation);
938
1244
  data.transform = transform;
939
1245
  }
940
- function repeatMode(data, box, width, height, scale, rotation) {
1246
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
941
1247
  const transform = get$4();
942
1248
  if (rotation) {
943
1249
  rotate(transform, rotation);
@@ -953,10 +1259,15 @@ function repeatMode(data, box, width, height, scale, rotation) {
953
1259
  break;
954
1260
  }
955
1261
  }
956
- translate$1(transform, box.x, box.y);
957
- if (scale) {
958
- scaleOfOuter$2(transform, box, scale);
959
- data.scaleX = data.scaleY = scale;
1262
+ origin.x = box.x;
1263
+ origin.y = box.y;
1264
+ if (x || y)
1265
+ origin.x += x, origin.y += y;
1266
+ translate$1(transform, origin.x, origin.y);
1267
+ if (scaleX) {
1268
+ scaleOfOuter$2(transform, origin, scaleX, scaleY);
1269
+ data.scaleX = scaleX;
1270
+ data.scaleY = scaleY;
960
1271
  }
961
1272
  data.transform = transform;
962
1273
  }
@@ -964,11 +1275,22 @@ function repeatMode(data, box, width, height, scale, rotation) {
964
1275
  const { get: get$3, translate } = MatrixHelper;
965
1276
  function createData(leafPaint, image, paint, box) {
966
1277
  let { width, height } = image;
967
- const { opacity, mode, offset, scale, rotation, blendMode } = paint;
1278
+ const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
968
1279
  const sameBox = box.width === width && box.height === height;
969
1280
  if (blendMode)
970
1281
  leafPaint.blendMode = blendMode;
971
1282
  const data = leafPaint.data = { mode };
1283
+ let x, y, scaleX, scaleY;
1284
+ if (offset)
1285
+ x = offset.x, y = offset.y;
1286
+ if (size) {
1287
+ scaleX = (typeof size === 'number' ? size : size.width) / width;
1288
+ scaleY = (typeof size === 'number' ? size : size.height) / height;
1289
+ }
1290
+ else if (scale) {
1291
+ scaleX = typeof scale === 'number' ? scale : scale.x;
1292
+ scaleY = typeof scale === 'number' ? scale : scale.y;
1293
+ }
972
1294
  switch (mode) {
973
1295
  case 'strench':
974
1296
  if (!sameBox)
@@ -979,12 +1301,14 @@ function createData(leafPaint, image, paint, box) {
979
1301
  }
980
1302
  break;
981
1303
  case 'clip':
982
- if (offset || scale || rotation)
983
- clipMode(data, box, offset, scale, rotation);
1304
+ if (offset || scaleX || rotation)
1305
+ clipMode(data, box, x, y, scaleX, scaleY, rotation);
984
1306
  break;
985
1307
  case 'repeat':
986
- if (!sameBox || scale || rotation)
987
- repeatMode(data, box, width, height, scale, rotation);
1308
+ if (!sameBox || scaleX || rotation)
1309
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1310
+ if (!repeat)
1311
+ data.repeat = 'repeat';
988
1312
  break;
989
1313
  case 'fit':
990
1314
  case 'cover':
@@ -996,111 +1320,101 @@ function createData(leafPaint, image, paint, box) {
996
1320
  data.height = height;
997
1321
  if (opacity)
998
1322
  data.opacity = opacity;
1323
+ if (repeat)
1324
+ data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
999
1325
  }
1000
1326
 
1001
- function image(ui, attrName, attrValue, box, firstUse) {
1002
- const leafPaint = { type: attrValue.type };
1003
- const image = leafPaint.image = ImageManager.get(attrValue);
1004
- const event = (firstUse || image.loading) && { target: ui, image, attrName, attrValue };
1327
+ let cache, box = new Bounds();
1328
+ const { isSame } = BoundsHelper;
1329
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1330
+ let leafPaint, event;
1331
+ const image = ImageManager.get(paint);
1332
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1333
+ leafPaint = cache.leafPaint;
1334
+ }
1335
+ else {
1336
+ leafPaint = { type: paint.type };
1337
+ leafPaint.image = image;
1338
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1339
+ }
1340
+ if (firstUse || image.loading)
1341
+ event = { image, attrName, attrValue: paint };
1005
1342
  if (image.ready) {
1006
- if (hasNaturalSize(ui, attrName, image))
1007
- createData(leafPaint, image, attrValue, box);
1343
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1008
1344
  if (firstUse) {
1009
- emit(ImageEvent.LOAD, event);
1010
- emit(ImageEvent.LOADED, event);
1345
+ onLoad(ui, event);
1346
+ onLoadSuccess(ui, event);
1011
1347
  }
1012
1348
  }
1013
1349
  else if (image.error) {
1014
- if (firstUse) {
1015
- ui.forceUpdate('surface');
1016
- event.error = image.error;
1017
- emit(ImageEvent.ERROR, event);
1018
- }
1350
+ if (firstUse)
1351
+ onLoadError(ui, event, image.error);
1019
1352
  }
1020
1353
  else {
1021
1354
  if (firstUse)
1022
- emit(ImageEvent.LOAD, event);
1355
+ onLoad(ui, event);
1023
1356
  leafPaint.loadId = image.load(() => {
1024
1357
  if (!ui.destroyed) {
1025
- if (hasNaturalSize(ui, attrName, image)) {
1026
- createData(leafPaint, image, attrValue, box);
1358
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds))
1027
1359
  ui.forceUpdate('surface');
1028
- }
1029
- emit(ImageEvent.LOADED, event);
1360
+ onLoadSuccess(ui, event);
1030
1361
  }
1362
+ leafPaint.loadId = null;
1031
1363
  }, (error) => {
1032
- ui.forceUpdate('surface');
1033
- event.error = error;
1034
- emit(ImageEvent.ERROR, event);
1364
+ onLoadError(ui, event, error);
1365
+ leafPaint.loadId = null;
1035
1366
  });
1036
1367
  }
1037
1368
  return leafPaint;
1038
1369
  }
1039
- function hasNaturalSize(ui, attrName, image) {
1370
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1040
1371
  if (attrName === 'fill' && !ui.__.__naturalWidth) {
1041
- const { __: d } = ui;
1042
- d.__naturalWidth = image.width;
1043
- d.__naturalHeight = image.height;
1044
- if (!d.__getInput('width') || !d.__getInput('height')) {
1372
+ const data = ui.__;
1373
+ data.__naturalWidth = image.width;
1374
+ data.__naturalHeight = image.height;
1375
+ if (data.__autoWidth || data.__autoHeight) {
1045
1376
  ui.forceUpdate('width');
1377
+ if (ui.__proxyData) {
1378
+ ui.setProxyAttr('width', data.width);
1379
+ ui.setProxyAttr('height', data.height);
1380
+ }
1046
1381
  return false;
1047
1382
  }
1048
1383
  }
1384
+ if (!leafPaint.data)
1385
+ createData(leafPaint, image, paint, boxBounds);
1049
1386
  return true;
1050
1387
  }
1051
- function emit(type, data) {
1052
- if (data.target.hasEvent(type))
1053
- data.target.emitEvent(new ImageEvent(type, data));
1388
+ function onLoad(ui, event) {
1389
+ emit(ui, ImageEvent.LOAD, event);
1390
+ }
1391
+ function onLoadSuccess(ui, event) {
1392
+ emit(ui, ImageEvent.LOADED, event);
1393
+ }
1394
+ function onLoadError(ui, event, error) {
1395
+ event.error = error;
1396
+ ui.forceUpdate('surface');
1397
+ emit(ui, ImageEvent.ERROR, event);
1398
+ }
1399
+ function emit(ui, type, data) {
1400
+ if (ui.hasEvent(type))
1401
+ ui.emitEvent(new ImageEvent(type, data));
1054
1402
  }
1055
1403
 
1056
- /******************************************************************************
1057
- Copyright (c) Microsoft Corporation.
1058
-
1059
- Permission to use, copy, modify, and/or distribute this software for any
1060
- purpose with or without fee is hereby granted.
1061
-
1062
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1063
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1064
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1065
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1066
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1067
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1068
- PERFORMANCE OF THIS SOFTWARE.
1069
- ***************************************************************************** */
1070
- /* global Reflect, Promise, SuppressedError, Symbol */
1071
-
1072
-
1073
- function __awaiter(thisArg, _arguments, P, generator) {
1074
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1075
- return new (P || (P = Promise))(function (resolve, reject) {
1076
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1077
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1078
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1079
- step((generator = generator.apply(thisArg, _arguments || [])).next());
1080
- });
1081
- }
1082
-
1083
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1084
- var e = new Error(message);
1085
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1086
- };
1087
-
1088
- const { get: get$2, scale: scaleHelper, copy: copy$1 } = MatrixHelper;
1404
+ const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1405
+ const { round, abs: abs$1 } = Math;
1089
1406
  function createPattern(ui, paint, pixelRatio) {
1090
1407
  let { scaleX, scaleY } = ui.__world;
1091
1408
  const id = scaleX + '-' + scaleY;
1092
1409
  if (paint.patternId !== id && !ui.destroyed) {
1093
- paint.patternId = id;
1094
- scaleX = Math.abs(scaleX);
1095
- scaleY = Math.abs(scaleY);
1410
+ scaleX = abs$1(scaleX);
1411
+ scaleY = abs$1(scaleY);
1096
1412
  const { image, data } = paint;
1097
- const maxWidth = image.isSVG ? 4096 : Math.min(image.width, 4096);
1098
- const maxHeight = image.isSVG ? 4096 : Math.min(image.height, 4096);
1099
- let scale, matrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, mode } = data;
1413
+ let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1100
1414
  if (sx) {
1101
- matrix = get$2();
1102
- copy$1(matrix, transform);
1103
- scaleHelper(matrix, 1 / sx, 1 / sy);
1415
+ imageMatrix = get$2();
1416
+ copy$1(imageMatrix, transform);
1417
+ scale(imageMatrix, 1 / sx, 1 / sy);
1104
1418
  scaleX *= sx;
1105
1419
  scaleY *= sy;
1106
1420
  }
@@ -1108,38 +1422,41 @@ function createPattern(ui, paint, pixelRatio) {
1108
1422
  scaleY *= pixelRatio;
1109
1423
  width *= scaleX;
1110
1424
  height *= scaleY;
1111
- if (width > maxWidth || height > maxHeight) {
1112
- scale = Math.max(width / maxWidth, height / maxHeight);
1425
+ const size = width * height;
1426
+ if (!repeat) {
1427
+ if (size > Platform.image.maxCacheSize)
1428
+ return false;
1429
+ }
1430
+ let maxSize = Platform.image.maxPatternSize;
1431
+ if (!image.isSVG) {
1432
+ const imageSize = image.width * image.height;
1433
+ if (maxSize > imageSize)
1434
+ maxSize = imageSize;
1113
1435
  }
1114
- if (scale) {
1115
- scaleX /= scale;
1116
- scaleY /= scale;
1117
- width /= scale;
1118
- height /= scale;
1436
+ if (size > maxSize)
1437
+ imageScale = Math.sqrt(size / maxSize);
1438
+ if (imageScale) {
1439
+ scaleX /= imageScale;
1440
+ scaleY /= imageScale;
1441
+ width /= imageScale;
1442
+ height /= imageScale;
1119
1443
  }
1120
1444
  if (sx) {
1121
1445
  scaleX /= sx;
1122
1446
  scaleY /= sy;
1123
1447
  }
1124
1448
  if (transform || scaleX !== 1 || scaleY !== 1) {
1125
- if (!matrix) {
1126
- matrix = get$2();
1449
+ if (!imageMatrix) {
1450
+ imageMatrix = get$2();
1127
1451
  if (transform)
1128
- copy$1(matrix, transform);
1452
+ copy$1(imageMatrix, transform);
1129
1453
  }
1130
- scaleHelper(matrix, 1 / scaleX, 1 / scaleY);
1454
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1131
1455
  }
1132
- const style = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), mode === 'repeat' ? 'repeat' : (Platform.origin.noRepeat || 'no-repeat'));
1133
- try {
1134
- if (paint.transform)
1135
- paint.transform = null;
1136
- if (matrix)
1137
- style.setTransform ? style.setTransform(matrix) : paint.transform = matrix;
1138
- }
1139
- catch (_a) {
1140
- paint.transform = matrix;
1141
- }
1142
- paint.style = style;
1456
+ const canvas = image.getCanvas(width < 1 ? 1 : round(width), height < 1 ? 1 : round(height), opacity);
1457
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1458
+ paint.style = pattern;
1459
+ paint.patternId = id;
1143
1460
  return true;
1144
1461
  }
1145
1462
  else {
@@ -1147,311 +1464,130 @@ function createPattern(ui, paint, pixelRatio) {
1147
1464
  }
1148
1465
  }
1149
1466
 
1150
- function checkImage(ui, canvas, paint, allowPaint) {
1151
- const { scaleX, scaleY } = ui.__world;
1152
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1153
- return false;
1154
- }
1155
- else {
1156
- if (allowPaint) {
1157
- if (paint.image.isSVG && paint.data.mode !== 'repeat') {
1158
- let { width, height } = paint.data;
1159
- width *= scaleX * canvas.pixelRatio;
1160
- height *= scaleY * canvas.pixelRatio;
1161
- allowPaint = width > 4096 || height > 4096;
1162
- }
1163
- else {
1164
- allowPaint = false;
1165
- }
1166
- }
1167
- if (allowPaint) {
1168
- canvas.save();
1169
- canvas.clip();
1170
- const { data } = paint;
1171
- if (paint.blendMode)
1172
- canvas.blendMode = paint.blendMode;
1173
- if (data.opacity)
1174
- canvas.opacity *= data.opacity;
1175
- if (data.transform)
1176
- canvas.transform(data.transform);
1177
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1178
- canvas.restore();
1179
- return true;
1180
- }
1181
- else {
1182
- if (!paint.style) {
1183
- createPattern(ui, paint, canvas.pixelRatio);
1184
- }
1185
- else {
1186
- ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1187
- if (canvas.bounds.hit(ui.__world) && createPattern(ui, paint, canvas.pixelRatio))
1188
- ui.forceUpdate('surface');
1189
- }), 300);
1190
- }
1191
- return false;
1192
- }
1193
- }
1194
- }
1195
-
1196
- function recycleImage(data, attrName) {
1197
- const paints = (attrName === 'fill' ? data._fill : data._stroke);
1198
- if (paints instanceof Array) {
1199
- let image, recycleMap, input, url;
1200
- for (let i = 0, len = paints.length; i < len; i++) {
1201
- image = paints[i].image;
1202
- url = image && image.url;
1203
- if (url) {
1204
- if (!recycleMap)
1205
- recycleMap = {};
1206
- recycleMap[url] = true;
1207
- ImageManager.recycle(image);
1208
- if (image.loading) {
1209
- if (!input) {
1210
- input = (data.__input && data.__input[attrName]) || [];
1211
- if (!(input instanceof Array))
1212
- input = [input];
1213
- }
1214
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1215
- }
1216
- }
1217
- }
1218
- return recycleMap;
1219
- }
1220
- return null;
1221
- }
1222
-
1223
- function fillText(ui, canvas) {
1224
- let row;
1225
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1226
- for (let i = 0, len = rows.length; i < len; i++) {
1227
- row = rows[i];
1228
- if (row.text) {
1229
- canvas.fillText(row.text, row.x, row.y);
1230
- }
1231
- else if (row.data) {
1232
- row.data.forEach(charData => {
1233
- canvas.fillText(charData.char, charData.x, row.y);
1234
- });
1235
- }
1236
- if (decorationY)
1237
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1238
- }
1239
- }
1240
-
1241
- function fill(ui, canvas, fill) {
1242
- canvas.fillStyle = fill;
1243
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1244
- }
1245
- function fills(ui, canvas, fills) {
1246
- let item;
1247
- const { windingRule, __font } = ui.__;
1248
- for (let i = 0, len = fills.length; i < len; i++) {
1249
- item = fills[i];
1250
- if (item.image && checkImage(ui, canvas, item, !__font))
1251
- continue;
1252
- if (item.style) {
1253
- canvas.fillStyle = item.style;
1254
- if (item.transform) {
1255
- canvas.save();
1256
- canvas.transform(item.transform);
1257
- if (item.blendMode)
1258
- canvas.blendMode = item.blendMode;
1259
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1260
- canvas.restore();
1261
- }
1262
- else {
1263
- if (item.blendMode) {
1264
- canvas.saveBlendMode(item.blendMode);
1265
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1266
- canvas.restoreBlendMode();
1267
- }
1268
- else {
1269
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1270
- }
1271
- }
1272
- }
1273
- }
1274
- }
1275
-
1276
- function strokeText(ui, canvas, stroke) {
1277
- const { strokeAlign } = ui.__;
1278
- const isStrokes = typeof stroke !== 'string';
1279
- switch (strokeAlign) {
1280
- case 'center':
1281
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1282
- isStrokes ? drawStrokesStyle(ui, stroke, canvas, true) : drawTextStroke(ui, canvas);
1283
- break;
1284
- case 'inside':
1285
- drawAlignStroke(ui, canvas, stroke, 'inside', isStrokes);
1286
- break;
1287
- case 'outside':
1288
- drawAlignStroke(ui, canvas, stroke, 'outside', isStrokes);
1289
- break;
1467
+ /******************************************************************************
1468
+ Copyright (c) Microsoft Corporation.
1469
+
1470
+ Permission to use, copy, modify, and/or distribute this software for any
1471
+ purpose with or without fee is hereby granted.
1472
+
1473
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1474
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1475
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1476
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1477
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1478
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1479
+ PERFORMANCE OF THIS SOFTWARE.
1480
+ ***************************************************************************** */
1481
+ /* global Reflect, Promise, SuppressedError, Symbol */
1482
+
1483
+
1484
+ function __awaiter(thisArg, _arguments, P, generator) {
1485
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1486
+ return new (P || (P = Promise))(function (resolve, reject) {
1487
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1488
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1489
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1490
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1491
+ });
1492
+ }
1493
+
1494
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1495
+ var e = new Error(message);
1496
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1497
+ };
1498
+
1499
+ const { abs } = Math;
1500
+ function checkImage(ui, canvas, paint, allowPaint) {
1501
+ const { scaleX, scaleY } = ui.__world;
1502
+ if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1503
+ return false;
1290
1504
  }
1291
- }
1292
- function drawAlignStroke(ui, canvas, stroke, align, isStrokes) {
1293
- const { strokeWidth, __font } = ui.__;
1294
- const out = canvas.getSameCanvas(true);
1295
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1296
- out.font = __font;
1297
- isStrokes ? drawStrokesStyle(ui, stroke, out, true) : drawTextStroke(ui, out);
1298
- out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1299
- fillText(ui, out);
1300
- out.blendMode = 'normal';
1301
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1302
- out.recycle();
1303
- }
1304
- function drawTextStroke(ui, canvas) {
1305
- let row;
1306
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1307
- for (let i = 0, len = rows.length; i < len; i++) {
1308
- row = rows[i];
1309
- if (row.text) {
1310
- canvas.strokeText(row.text, row.x, row.y);
1505
+ else {
1506
+ const { data } = paint;
1507
+ if (allowPaint) {
1508
+ if (!data.repeat) {
1509
+ let { width, height } = data;
1510
+ width *= abs(scaleX) * canvas.pixelRatio;
1511
+ height *= abs(scaleY) * canvas.pixelRatio;
1512
+ if (data.scaleX) {
1513
+ width *= data.scaleX;
1514
+ height *= data.scaleY;
1515
+ }
1516
+ allowPaint = width * height > Platform.image.maxCacheSize;
1517
+ }
1518
+ else {
1519
+ allowPaint = false;
1520
+ }
1311
1521
  }
1312
- else if (row.data) {
1313
- row.data.forEach(charData => {
1314
- canvas.strokeText(charData.char, charData.x, row.y);
1315
- });
1522
+ if (allowPaint) {
1523
+ canvas.save();
1524
+ canvas.clip();
1525
+ if (paint.blendMode)
1526
+ canvas.blendMode = paint.blendMode;
1527
+ if (data.opacity)
1528
+ canvas.opacity *= data.opacity;
1529
+ if (data.transform)
1530
+ canvas.transform(data.transform);
1531
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1532
+ canvas.restore();
1533
+ return true;
1316
1534
  }
1317
- if (decorationY)
1318
- canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1319
- }
1320
- }
1321
- function drawStrokesStyle(ui, strokes, canvas, isText) {
1322
- let item;
1323
- for (let i = 0, len = strokes.length; i < len; i++) {
1324
- item = strokes[i];
1325
- if (item.image && checkImage(ui, canvas, item, false))
1326
- continue;
1327
- if (item.style) {
1328
- canvas.strokeStyle = item.style;
1329
- if (item.blendMode) {
1330
- canvas.saveBlendMode(item.blendMode);
1331
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1332
- canvas.restoreBlendMode();
1535
+ else {
1536
+ if (!paint.style || Export.running) {
1537
+ createPattern(ui, paint, canvas.pixelRatio);
1333
1538
  }
1334
1539
  else {
1335
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1540
+ if (!paint.patternTask) {
1541
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1542
+ paint.patternTask = null;
1543
+ if (canvas.bounds.hit(ui.__world))
1544
+ createPattern(ui, paint, canvas.pixelRatio);
1545
+ ui.forceUpdate('surface');
1546
+ }), 300);
1547
+ }
1336
1548
  }
1549
+ return false;
1337
1550
  }
1338
1551
  }
1339
1552
  }
1340
1553
 
1341
- function stroke(ui, canvas, stroke) {
1342
- const options = ui.__;
1343
- const { strokeWidth, strokeAlign, __font } = options;
1344
- if (!strokeWidth)
1345
- return;
1346
- if (__font) {
1347
- strokeText(ui, canvas, stroke);
1348
- }
1349
- else {
1350
- switch (strokeAlign) {
1351
- case 'center':
1352
- canvas.setStroke(stroke, strokeWidth, options);
1353
- canvas.stroke();
1354
- break;
1355
- case 'inside':
1356
- canvas.save();
1357
- canvas.setStroke(stroke, strokeWidth * 2, options);
1358
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1359
- canvas.stroke();
1360
- canvas.restore();
1361
- break;
1362
- case 'outside':
1363
- const out = canvas.getSameCanvas(true);
1364
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1365
- ui.__drawRenderPath(out);
1366
- out.stroke();
1367
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1368
- out.clearWorld(ui.__layout.renderBounds);
1369
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1370
- out.recycle();
1371
- break;
1372
- }
1373
- }
1374
- }
1375
- function strokes(ui, canvas, strokes) {
1376
- const options = ui.__;
1377
- const { strokeWidth, strokeAlign, __font } = options;
1378
- if (!strokeWidth)
1379
- return;
1380
- if (__font) {
1381
- strokeText(ui, canvas, strokes);
1382
- }
1383
- else {
1384
- switch (strokeAlign) {
1385
- case 'center':
1386
- canvas.setStroke(undefined, strokeWidth, options);
1387
- drawStrokesStyle(ui, strokes, canvas);
1388
- break;
1389
- case 'inside':
1390
- canvas.save();
1391
- canvas.setStroke(undefined, strokeWidth * 2, options);
1392
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1393
- drawStrokesStyle(ui, strokes, canvas);
1394
- canvas.restore();
1395
- break;
1396
- case 'outside':
1397
- const { renderBounds } = ui.__layout;
1398
- const out = canvas.getSameCanvas(true);
1399
- ui.__drawRenderPath(out);
1400
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1401
- drawStrokesStyle(ui, strokes, out);
1402
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1403
- out.clearWorld(renderBounds);
1404
- canvas.copyWorldToInner(out, ui.__world, renderBounds);
1405
- out.recycle();
1406
- break;
1554
+ function recycleImage(attrName, data) {
1555
+ const paints = data['_' + attrName];
1556
+ if (paints instanceof Array) {
1557
+ let image, recycleMap, input, url;
1558
+ for (let i = 0, len = paints.length; i < len; i++) {
1559
+ image = paints[i].image;
1560
+ url = image && image.url;
1561
+ if (url) {
1562
+ if (!recycleMap)
1563
+ recycleMap = {};
1564
+ recycleMap[url] = true;
1565
+ ImageManager.recycle(image);
1566
+ if (image.loading) {
1567
+ if (!input) {
1568
+ input = (data.__input && data.__input[attrName]) || [];
1569
+ if (!(input instanceof Array))
1570
+ input = [input];
1571
+ }
1572
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1573
+ }
1574
+ }
1407
1575
  }
1576
+ return recycleMap;
1408
1577
  }
1578
+ return null;
1409
1579
  }
1410
1580
 
1411
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1412
- function shape(ui, current, options) {
1413
- const canvas = current.getSameCanvas();
1414
- let bounds, matrix, shapeBounds;
1415
- let worldCanvas;
1416
- const { __world } = ui;
1417
- let { scaleX, scaleY } = __world;
1418
- if (scaleX < 0)
1419
- scaleX = -scaleX;
1420
- if (scaleY < 0)
1421
- scaleY = -scaleY;
1422
- if (!current.bounds.includes(__world, options.matrix)) {
1423
- const { renderShapeSpread: spread } = ui.__layout;
1424
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1425
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1426
- if (matrix.a < 1) {
1427
- worldCanvas = current.getSameCanvas();
1428
- ui.__renderShape(worldCanvas, options);
1429
- scaleX *= matrix.a;
1430
- scaleY *= matrix.d;
1431
- }
1432
- shapeBounds = getOuterOf(__world, matrix);
1433
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1434
- if (options.matrix)
1435
- matrix.multiply(options.matrix);
1436
- options = Object.assign(Object.assign({}, options), { matrix });
1437
- }
1438
- else {
1439
- if (options.matrix) {
1440
- scaleX *= options.matrix.a;
1441
- scaleY *= options.matrix.d;
1442
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
1443
- }
1444
- else {
1445
- bounds = shapeBounds = __world;
1446
- }
1447
- worldCanvas = canvas;
1448
- }
1449
- ui.__renderShape(canvas, options);
1450
- return {
1451
- canvas, matrix, bounds,
1452
- worldCanvas, shapeBounds, scaleX, scaleY
1453
- };
1454
- }
1581
+ const PaintImageModule = {
1582
+ image,
1583
+ createData,
1584
+ fillOrFitMode,
1585
+ clipMode,
1586
+ repeatMode,
1587
+ createPattern,
1588
+ checkImage,
1589
+ recycleImage
1590
+ };
1455
1591
 
1456
1592
  const defaultFrom$2 = { x: 0.5, y: 0 };
1457
1593
  const defaultTo$2 = { x: 0.5, y: 1 };
@@ -1470,7 +1606,7 @@ function applyStops(gradient, stops, opacity) {
1470
1606
  let stop;
1471
1607
  for (let i = 0, len = stops.length; i < len; i++) {
1472
1608
  stop = stops[i];
1473
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
1609
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1474
1610
  }
1475
1611
  }
1476
1612
 
@@ -1532,62 +1668,18 @@ function conicGradient(paint, box) {
1532
1668
  return data;
1533
1669
  }
1534
1670
 
1535
- let recycleMap;
1536
- function compute(ui, attrName) {
1537
- const value = [];
1538
- let item;
1539
- let paints = ui.__.__input[attrName];
1540
- if (!(paints instanceof Array))
1541
- paints = [paints];
1542
- recycleMap = recycleImage(ui.__, attrName);
1543
- for (let i = 0, len = paints.length; i < len; i++) {
1544
- item = getLeafPaint(ui, paints[i], attrName);
1545
- if (item)
1546
- value.push(item);
1547
- }
1548
- ui.__['_' + attrName] = value.length ? value : undefined;
1549
- }
1550
- function getLeafPaint(ui, paint, attrName) {
1551
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1552
- return undefined;
1553
- const { boxBounds } = ui.__layout;
1554
- switch (paint.type) {
1555
- case 'solid':
1556
- let { type, blendMode, color, opacity } = paint;
1557
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
1558
- case 'image':
1559
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1560
- case 'linear':
1561
- return linearGradient(paint, boxBounds);
1562
- case 'radial':
1563
- return radialGradient(paint, boxBounds);
1564
- case 'angular':
1565
- return conicGradient(paint, boxBounds);
1566
- default:
1567
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
1568
- }
1569
- }
1570
-
1571
- var UIPaint = /*#__PURE__*/Object.freeze({
1572
- __proto__: null,
1573
- compute: compute,
1574
- drawTextStroke: drawTextStroke,
1575
- fill: fill,
1576
- fillText: fillText,
1577
- fills: fills,
1578
- recycleImage: recycleImage,
1579
- shape: shape,
1580
- stroke: stroke,
1581
- strokeText: strokeText,
1582
- strokes: strokes
1583
- });
1671
+ const PaintGradientModule = {
1672
+ linearGradient,
1673
+ radialGradient,
1674
+ conicGradient
1675
+ };
1584
1676
 
1585
1677
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1586
1678
  const tempBounds = {};
1587
1679
  const offsetOutBounds$1 = {};
1588
- function shadow(ui, current, shape, _options) {
1680
+ function shadow(ui, current, shape) {
1589
1681
  let copyBounds, spreadScale;
1590
- const { __world, __layout } = ui;
1682
+ const { __nowWorld: nowWorld, __layout } = ui;
1591
1683
  const { shadow } = ui.__;
1592
1684
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1593
1685
  const other = current.getSameCanvas();
@@ -1602,21 +1694,21 @@ function shadow(ui, current, shape, _options) {
1602
1694
  other.restore();
1603
1695
  other.save();
1604
1696
  if (worldCanvas) {
1605
- other.copyWorld(other, bounds, __world, 'copy');
1606
- copyBounds = __world;
1697
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1698
+ copyBounds = nowWorld;
1607
1699
  }
1608
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1700
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1609
1701
  }
1610
- if (ui.__hasMirror) {
1611
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1702
+ if (ui.__worldFlipped) {
1703
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1612
1704
  }
1613
1705
  else {
1614
1706
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1615
1707
  }
1616
1708
  if (end && index < end)
1617
- other.clear();
1709
+ other.clearWorld(copyBounds, true);
1618
1710
  });
1619
- other.recycle();
1711
+ other.recycle(copyBounds);
1620
1712
  }
1621
1713
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1622
1714
  const { bounds, shapeBounds } = shape;
@@ -1647,9 +1739,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1647
1739
 
1648
1740
  const { toOffsetOutBounds } = BoundsHelper;
1649
1741
  const offsetOutBounds = {};
1650
- function innerShadow(ui, current, shape, _options) {
1742
+ function innerShadow(ui, current, shape) {
1651
1743
  let copyBounds, spreadScale;
1652
- const { __world, __layout: __layout } = ui;
1744
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1653
1745
  const { innerShadow } = ui.__;
1654
1746
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1655
1747
  const other = current.getSameCanvas();
@@ -1662,25 +1754,25 @@ function innerShadow(ui, current, shape, _options) {
1662
1754
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1663
1755
  other.restore();
1664
1756
  if (worldCanvas) {
1665
- other.copyWorld(other, bounds, __world, 'copy');
1666
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1667
- copyBounds = __world;
1757
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1758
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
1759
+ copyBounds = nowWorld;
1668
1760
  }
1669
1761
  else {
1670
1762
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1671
1763
  copyBounds = bounds;
1672
1764
  }
1673
1765
  other.fillWorld(copyBounds, item.color, 'source-in');
1674
- if (ui.__hasMirror) {
1675
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1766
+ if (ui.__worldFlipped) {
1767
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1676
1768
  }
1677
1769
  else {
1678
1770
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1679
1771
  }
1680
1772
  if (end && index < end)
1681
- other.clear();
1773
+ other.clearWorld(copyBounds, true);
1682
1774
  });
1683
- other.recycle();
1775
+ other.recycle(copyBounds);
1684
1776
  }
1685
1777
 
1686
1778
  function blur(ui, current, origin) {
@@ -1690,12 +1782,87 @@ function blur(ui, current, origin) {
1690
1782
  origin.filter = 'none';
1691
1783
  }
1692
1784
 
1693
- var UIEffect = /*#__PURE__*/Object.freeze({
1694
- __proto__: null,
1695
- blur: blur,
1696
- innerShadow: innerShadow,
1697
- shadow: shadow
1698
- });
1785
+ function backgroundBlur(_ui, _current, _shape) {
1786
+ }
1787
+
1788
+ const EffectModule = {
1789
+ shadow,
1790
+ innerShadow,
1791
+ blur,
1792
+ backgroundBlur
1793
+ };
1794
+
1795
+ const { excludeRenderBounds } = LeafBoundsHelper;
1796
+ Group.prototype.__renderMask = function (canvas, options) {
1797
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
1798
+ const { children } = this;
1799
+ for (let i = 0, len = children.length; i < len; i++) {
1800
+ child = children[i];
1801
+ if (child.__.mask) {
1802
+ if (currentMask) {
1803
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1804
+ maskCanvas = contentCanvas = null;
1805
+ }
1806
+ if (child.__.maskType === 'path') {
1807
+ if (child.opacity < 1) {
1808
+ currentMask = 'opacity-path';
1809
+ maskOpacity = child.opacity;
1810
+ if (!contentCanvas)
1811
+ contentCanvas = getCanvas(canvas);
1812
+ }
1813
+ else {
1814
+ currentMask = 'path';
1815
+ canvas.save();
1816
+ }
1817
+ child.__clip(contentCanvas || canvas, options);
1818
+ }
1819
+ else {
1820
+ currentMask = 'alpha';
1821
+ if (!maskCanvas)
1822
+ maskCanvas = getCanvas(canvas);
1823
+ if (!contentCanvas)
1824
+ contentCanvas = getCanvas(canvas);
1825
+ child.__render(maskCanvas, options);
1826
+ }
1827
+ if (child.__.maskType !== 'clipping')
1828
+ continue;
1829
+ }
1830
+ if (excludeRenderBounds(child, options))
1831
+ continue;
1832
+ child.__render(contentCanvas || canvas, options);
1833
+ }
1834
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1835
+ };
1836
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
1837
+ switch (maskMode) {
1838
+ case 'alpha':
1839
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
1840
+ break;
1841
+ case 'opacity-path':
1842
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
1843
+ break;
1844
+ case 'path':
1845
+ canvas.restore();
1846
+ }
1847
+ }
1848
+ function getCanvas(canvas) {
1849
+ return canvas.getSameCanvas(false, true);
1850
+ }
1851
+ function usePixelMask(leaf, canvas, content, mask) {
1852
+ const realBounds = leaf.__nowWorld;
1853
+ content.resetTransform();
1854
+ content.opacity = 1;
1855
+ content.useMask(mask, realBounds);
1856
+ mask.recycle(realBounds);
1857
+ copyContent(leaf, canvas, content, 1);
1858
+ }
1859
+ function copyContent(leaf, canvas, content, maskOpacity) {
1860
+ const realBounds = leaf.__nowWorld;
1861
+ canvas.resetTransform();
1862
+ canvas.opacity = maskOpacity;
1863
+ canvas.copyWorld(content, realBounds);
1864
+ content.recycle(realBounds);
1865
+ }
1699
1866
 
1700
1867
  const money = '¥¥$€££¢¢';
1701
1868
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -1809,7 +1976,7 @@ function getTextCase(char, textCase, firstChar) {
1809
1976
  const { trimRight } = TextRowHelper;
1810
1977
  const { Letter, Single, Before, After, Symbol, Break } = CharType;
1811
1978
  let word, row, wordWidth, rowWidth, realWidth;
1812
- let char, charWidth, charType, lastCharType, langBreak, afterBreak, paraStart;
1979
+ let char, charWidth, startCharSize, charSize, charType, lastCharType, langBreak, afterBreak, paraStart;
1813
1980
  let textDrawData, rows = [], bounds;
1814
1981
  function createRows(drawData, content, style) {
1815
1982
  textDrawData = drawData;
@@ -1820,9 +1987,11 @@ function createRows(drawData, content, style) {
1820
1987
  const { width, height } = bounds;
1821
1988
  const charMode = width || height || __letterSpacing || (textCase !== 'none');
1822
1989
  if (charMode) {
1990
+ const wrap = style.textWrap !== 'none';
1991
+ const breakAll = style.textWrap === 'break';
1823
1992
  paraStart = true;
1824
1993
  lastCharType = null;
1825
- wordWidth = rowWidth = 0;
1994
+ startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1826
1995
  word = { data: [] }, row = { words: [] };
1827
1996
  for (let i = 0, len = content.length; i < len; i++) {
1828
1997
  char = content[i];
@@ -1838,21 +2007,31 @@ function createRows(drawData, content, style) {
1838
2007
  if (charType === Letter && textCase !== 'none')
1839
2008
  char = getTextCase(char, textCase, !wordWidth);
1840
2009
  charWidth = canvas.measureText(char).width;
1841
- if (__letterSpacing)
2010
+ if (__letterSpacing) {
2011
+ if (__letterSpacing < 0)
2012
+ charSize = charWidth;
1842
2013
  charWidth += __letterSpacing;
2014
+ }
1843
2015
  langBreak = (charType === Single && (lastCharType === Single || lastCharType === Letter)) || (lastCharType === Single && charType !== After);
1844
2016
  afterBreak = ((charType === Before || charType === Single) && (lastCharType === Symbol || lastCharType === After));
1845
2017
  realWidth = paraStart && paraIndent ? width - paraIndent : width;
1846
- if (width && rowWidth + wordWidth + charWidth > realWidth) {
1847
- if (!afterBreak)
1848
- afterBreak = charType === Letter && lastCharType == After;
1849
- if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2018
+ if (wrap && (width && rowWidth + wordWidth + charWidth > realWidth)) {
2019
+ if (breakAll) {
1850
2020
  if (wordWidth)
1851
2021
  addWord();
1852
2022
  addRow();
1853
2023
  }
1854
2024
  else {
1855
- addRow();
2025
+ if (!afterBreak)
2026
+ afterBreak = charType === Letter && lastCharType == After;
2027
+ if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2028
+ if (wordWidth)
2029
+ addWord();
2030
+ addRow();
2031
+ }
2032
+ else {
2033
+ addRow();
2034
+ }
1856
2035
  }
1857
2036
  }
1858
2037
  if (char === ' ' && paraStart !== true && (rowWidth + wordWidth) === 0) ;
@@ -1889,6 +2068,8 @@ function createRows(drawData, content, style) {
1889
2068
  }
1890
2069
  }
1891
2070
  function addChar(char, width) {
2071
+ if (charSize && !startCharSize)
2072
+ startCharSize = charSize;
1892
2073
  word.data.push({ char, width });
1893
2074
  wordWidth += width;
1894
2075
  }
@@ -1905,6 +2086,11 @@ function addRow() {
1905
2086
  row.paraStart = true;
1906
2087
  paraStart = false;
1907
2088
  }
2089
+ if (charSize) {
2090
+ row.startCharSize = startCharSize;
2091
+ row.endCharSize = charSize;
2092
+ startCharSize = 0;
2093
+ }
1908
2094
  row.width = rowWidth;
1909
2095
  if (bounds.width)
1910
2096
  trimRight(row);
@@ -1915,7 +2101,7 @@ function addRow() {
1915
2101
 
1916
2102
  const CharMode = 0;
1917
2103
  const WordMode = 1;
1918
- const RowMode = 2;
2104
+ const TextMode = 2;
1919
2105
  function layoutChar(drawData, style, width, _height) {
1920
2106
  const { rows } = drawData;
1921
2107
  const { textAlign, paraIndent, letterSpacing } = style;
@@ -1924,15 +2110,12 @@ function layoutChar(drawData, style, width, _height) {
1924
2110
  if (row.words) {
1925
2111
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0;
1926
2112
  addWordWidth = (width && textAlign === 'justify' && row.words.length > 1) ? (width - row.width - indentWidth) / (row.words.length - 1) : 0;
1927
- mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : RowMode);
1928
- if (mode === RowMode) {
1929
- row.text = '';
2113
+ mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : TextMode);
2114
+ if (row.isOverflow && !letterSpacing)
2115
+ row.textMode = true;
2116
+ if (mode === TextMode) {
1930
2117
  row.x += indentWidth;
1931
- row.words.forEach(word => {
1932
- word.data.forEach(char => {
1933
- row.text += char.char;
1934
- });
1935
- });
2118
+ toTextChar$1(row);
1936
2119
  }
1937
2120
  else {
1938
2121
  row.x += indentWidth;
@@ -1958,6 +2141,14 @@ function layoutChar(drawData, style, width, _height) {
1958
2141
  }
1959
2142
  });
1960
2143
  }
2144
+ function toTextChar$1(row) {
2145
+ row.text = '';
2146
+ row.words.forEach(word => {
2147
+ word.data.forEach(char => {
2148
+ row.text += char.char;
2149
+ });
2150
+ });
2151
+ }
1961
2152
  function toWordChar(data, charX, wordChar) {
1962
2153
  data.forEach(char => {
1963
2154
  wordChar.char += char.char;
@@ -1978,10 +2169,10 @@ function toChar(data, charX, rowData) {
1978
2169
 
1979
2170
  function layoutText(drawData, style) {
1980
2171
  const { rows, bounds } = drawData;
1981
- const { __lineHeight, __baseLine, textAlign, verticalAlign, paraSpacing, textOverflow } = style;
2172
+ const { __lineHeight, __baseLine, __letterSpacing, __clipText, textAlign, verticalAlign, paraSpacing } = style;
1982
2173
  let { x, y, width, height } = bounds, realHeight = __lineHeight * rows.length + (paraSpacing ? paraSpacing * (drawData.paraNumber - 1) : 0);
1983
2174
  let starY = __baseLine;
1984
- if (textOverflow !== 'show' && realHeight > height) {
2175
+ if (__clipText && realHeight > height) {
1985
2176
  realHeight = Math.max(height, __lineHeight);
1986
2177
  drawData.overflow = rows.length;
1987
2178
  }
@@ -1995,7 +2186,7 @@ function layoutText(drawData, style) {
1995
2186
  }
1996
2187
  }
1997
2188
  starY += y;
1998
- let row;
2189
+ let row, rowX, rowWidth;
1999
2190
  for (let i = 0, len = rows.length; i < len; i++) {
2000
2191
  row = rows[i];
2001
2192
  row.x = x;
@@ -2014,53 +2205,74 @@ function layoutText(drawData, style) {
2014
2205
  row.isOverflow = true;
2015
2206
  drawData.overflow = i + 1;
2016
2207
  }
2017
- if (row.width < 0) {
2018
- const charWidth = row.words[0].data[0].width;
2019
- const rowX = row.x + row.width;
2020
- if (rowX < bounds.x)
2021
- bounds.x = rowX - charWidth;
2022
- if (-row.width > bounds.width)
2023
- bounds.width = -row.width + style.fontSize + charWidth;
2208
+ rowX = row.x;
2209
+ rowWidth = row.width;
2210
+ if (__letterSpacing < 0) {
2211
+ if (row.width < 0) {
2212
+ rowWidth = -row.width + style.fontSize + __letterSpacing;
2213
+ rowX -= rowWidth;
2214
+ rowWidth += style.fontSize;
2215
+ }
2216
+ else {
2217
+ rowWidth -= __letterSpacing;
2218
+ }
2024
2219
  }
2025
- else {
2026
- if (row.x < bounds.x)
2027
- bounds.x = row.x;
2028
- if (row.width > bounds.width)
2029
- bounds.width = row.width;
2220
+ if (rowX < bounds.x)
2221
+ bounds.x = rowX;
2222
+ if (rowWidth > bounds.width)
2223
+ bounds.width = rowWidth;
2224
+ if (__clipText && width && width < rowWidth) {
2225
+ row.isOverflow = true;
2226
+ if (!drawData.overflow)
2227
+ drawData.overflow = rows.length;
2030
2228
  }
2031
2229
  }
2032
2230
  bounds.y = y;
2033
2231
  bounds.height = realHeight;
2034
2232
  }
2035
2233
 
2036
- function clipText(drawData, textOverflow) {
2234
+ function clipText(drawData, style) {
2037
2235
  const { rows, overflow } = drawData;
2236
+ let { textOverflow } = style;
2038
2237
  rows.splice(overflow);
2039
2238
  if (textOverflow !== 'hide') {
2040
2239
  if (textOverflow === 'ellipsis')
2041
2240
  textOverflow = '...';
2241
+ let char, charRight;
2042
2242
  const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2043
- const row = rows[overflow - 1];
2044
- let char, end = row.data.length - 1, charRight;
2045
- const { x, width } = drawData.bounds;
2046
- const right = x + width - ellipsisWidth;
2047
- for (let i = end; i > -1; i--) {
2048
- char = row.data[i];
2049
- charRight = char.x + char.width;
2050
- if (i === end && charRight < right) {
2051
- break;
2052
- }
2053
- else if (charRight < right && char.char !== ' ') {
2054
- row.data.splice(i + 1);
2055
- row.width -= char.width;
2056
- break;
2243
+ const right = style.x + style.width - ellipsisWidth;
2244
+ const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2245
+ list.forEach(row => {
2246
+ if (row.isOverflow && row.data) {
2247
+ let end = row.data.length - 1;
2248
+ for (let i = end; i > -1; i--) {
2249
+ char = row.data[i];
2250
+ charRight = char.x + char.width;
2251
+ if (i === end && charRight < right) {
2252
+ break;
2253
+ }
2254
+ else if (charRight < right && char.char !== ' ') {
2255
+ row.data.splice(i + 1);
2256
+ row.width -= char.width;
2257
+ break;
2258
+ }
2259
+ row.width -= char.width;
2260
+ }
2261
+ row.width += ellipsisWidth;
2262
+ row.data.push({ char: textOverflow, x: charRight });
2263
+ if (row.textMode)
2264
+ toTextChar(row);
2057
2265
  }
2058
- row.width -= char.width;
2059
- }
2060
- row.width += ellipsisWidth;
2061
- row.data.push({ char: textOverflow, x: charRight });
2266
+ });
2062
2267
  }
2063
2268
  }
2269
+ function toTextChar(row) {
2270
+ row.text = '';
2271
+ row.data.forEach(char => {
2272
+ row.text += char.char;
2273
+ });
2274
+ row.data = null;
2275
+ }
2064
2276
 
2065
2277
  function decorationText(drawData, style) {
2066
2278
  const { fontSize } = style;
@@ -2074,101 +2286,162 @@ function decorationText(drawData, style) {
2074
2286
  }
2075
2287
  }
2076
2288
 
2077
- const TextConvert = {
2078
- getDrawData(content, style) {
2079
- if (typeof content !== 'string')
2080
- content = String(content);
2081
- let x = 0, y = 0;
2082
- let { width, height, padding } = style;
2083
- const { textDecoration, textOverflow, __font } = style;
2084
- if (!width)
2085
- width = 0;
2086
- if (padding) {
2087
- const [top, right, bottom, left] = MathHelper.fourNumber(padding);
2088
- if (width) {
2089
- x = left;
2090
- width -= (right + left);
2091
- }
2092
- if (height) {
2093
- y = top;
2094
- height -= (top + bottom);
2095
- }
2289
+ const { top, right, bottom, left } = Direction4;
2290
+ function getDrawData(content, style) {
2291
+ if (typeof content !== 'string')
2292
+ content = String(content);
2293
+ let x = 0, y = 0;
2294
+ let width = style.__getInput('width') || 0;
2295
+ let height = style.__getInput('height') || 0;
2296
+ const { textDecoration, __font, __padding: padding } = style;
2297
+ if (padding) {
2298
+ if (width) {
2299
+ x = padding[left];
2300
+ width -= (padding[right] + padding[left]);
2301
+ }
2302
+ if (height) {
2303
+ y = padding[top];
2304
+ height -= (padding[top] + padding[bottom]);
2305
+ }
2306
+ }
2307
+ const drawData = {
2308
+ bounds: { x, y, width, height },
2309
+ rows: [],
2310
+ paraNumber: 0,
2311
+ font: Platform.canvas.font = __font
2312
+ };
2313
+ createRows(drawData, content, style);
2314
+ if (padding)
2315
+ padAutoText(padding, drawData, style, width, height);
2316
+ layoutText(drawData, style);
2317
+ layoutChar(drawData, style, width);
2318
+ if (drawData.overflow)
2319
+ clipText(drawData, style);
2320
+ if (textDecoration !== 'none')
2321
+ decorationText(drawData, style);
2322
+ return drawData;
2323
+ }
2324
+ function padAutoText(padding, drawData, style, width, height) {
2325
+ if (!width) {
2326
+ switch (style.textAlign) {
2327
+ case 'left':
2328
+ offsetText(drawData, 'x', padding[left]);
2329
+ break;
2330
+ case 'right':
2331
+ offsetText(drawData, 'x', -padding[right]);
2332
+ }
2333
+ }
2334
+ if (!height) {
2335
+ switch (style.verticalAlign) {
2336
+ case 'top':
2337
+ offsetText(drawData, 'y', padding[top]);
2338
+ break;
2339
+ case 'bottom':
2340
+ offsetText(drawData, 'y', -padding[bottom]);
2096
2341
  }
2097
- const drawData = {
2098
- bounds: { x, y, width, height },
2099
- rows: [],
2100
- paraNumber: 0,
2101
- font: Platform.canvas.font = __font
2102
- };
2103
- createRows(drawData, content, style);
2104
- layoutText(drawData, style);
2105
- layoutChar(drawData, style, width);
2106
- if (drawData.overflow)
2107
- clipText(drawData, textOverflow);
2108
- if (textDecoration !== 'none')
2109
- decorationText(drawData, style);
2110
- return drawData;
2111
2342
  }
2343
+ }
2344
+ function offsetText(drawData, attrName, value) {
2345
+ const { bounds, rows } = drawData;
2346
+ bounds[attrName] += value;
2347
+ for (let i = 0; i < rows.length; i++)
2348
+ rows[i][attrName] += value;
2349
+ }
2350
+
2351
+ const TextConvertModule = {
2352
+ getDrawData
2112
2353
  };
2113
2354
 
2114
- const ColorConvert = {
2115
- string(color, opacity) {
2116
- if (typeof color === 'string')
2117
- return color;
2118
- let a = color.a === undefined ? 1 : color.a;
2119
- if (opacity)
2120
- a *= opacity;
2121
- const rgb = color.r + ',' + color.g + ',' + color.b;
2122
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2123
- }
2355
+ function string(color, opacity) {
2356
+ if (typeof color === 'string')
2357
+ return color;
2358
+ let a = color.a === undefined ? 1 : color.a;
2359
+ if (opacity)
2360
+ a *= opacity;
2361
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2362
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2363
+ }
2364
+
2365
+ const ColorConvertModule = {
2366
+ string
2124
2367
  };
2125
2368
 
2126
- const Export = {
2369
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2370
+ function getTrimBounds(canvas) {
2371
+ const { width, height } = canvas.view;
2372
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2373
+ let x, y, pointBounds, index = 0;
2374
+ for (let i = 0; i < data.length; i += 4) {
2375
+ if (data[i + 3] !== 0) {
2376
+ x = index % width;
2377
+ y = (index - x) / width;
2378
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2379
+ }
2380
+ index++;
2381
+ }
2382
+ const bounds = new Bounds();
2383
+ toBounds(pointBounds, bounds);
2384
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2385
+ }
2386
+
2387
+ const ExportModule = {
2127
2388
  export(leaf, filename, options) {
2389
+ this.running = true;
2128
2390
  return addTask((success) => new Promise((resolve) => {
2391
+ const over = (result) => {
2392
+ success(result);
2393
+ resolve();
2394
+ this.running = false;
2395
+ };
2129
2396
  const { leafer } = leaf;
2130
2397
  if (leafer) {
2131
2398
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2132
- let quality, blob;
2133
- let { canvas } = leafer;
2134
- let { unreal } = canvas;
2135
- if (unreal) {
2136
- canvas = canvas.getSameCanvas();
2137
- canvas.backgroundColor = leafer.config.fill;
2138
- leafer.__render(canvas, {});
2399
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2400
+ options = FileHelper.getExportOptions(options);
2401
+ const { scale, pixelRatio, slice, trim } = options;
2402
+ const screenshot = options.screenshot || leaf.isApp;
2403
+ const fill = options.fill === undefined ? ((leaf.isLeafer && screenshot) ? leaf.fill : '') : options.fill;
2404
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2405
+ if (screenshot) {
2406
+ renderBounds = screenshot === true ? (leaf.isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2139
2407
  }
2140
- switch (typeof options) {
2141
- case 'object':
2142
- if (options.quality)
2143
- quality = options.quality;
2144
- if (options.blob)
2145
- blob = true;
2146
- break;
2147
- case 'number':
2148
- quality = options;
2149
- break;
2150
- case 'boolean':
2151
- blob = options;
2408
+ else {
2409
+ const { localTransform, __world: world } = leaf;
2410
+ matrix.set(world).divide(localTransform).invert();
2411
+ scaleX = 1 / (world.scaleX / leaf.scaleX);
2412
+ scaleY = 1 / (world.scaleY / leaf.scaleY);
2413
+ renderBounds = leaf.getBounds('render', 'local');
2152
2414
  }
2153
- let data;
2154
- if (filename.includes('.')) {
2155
- data = yield canvas.saveAs(filename, quality);
2415
+ let { x, y, width, height } = renderBounds;
2416
+ if (scale) {
2417
+ matrix.scale(scale);
2418
+ width *= scale, height *= scale;
2419
+ scaleX *= scale, scaleY *= scale;
2156
2420
  }
2157
- else if (blob) {
2158
- data = yield canvas.toBlob(filename, quality);
2421
+ let canvas = Creator.canvas({ width, height, pixelRatio });
2422
+ const renderOptions = { matrix: matrix.translate(-x, -y).withScale(scaleX, scaleY) };
2423
+ if (slice) {
2424
+ leaf = leafer;
2425
+ renderOptions.bounds = canvas.bounds;
2159
2426
  }
2160
- else {
2161
- data = yield canvas.toDataURL(filename, quality);
2427
+ canvas.save();
2428
+ leaf.__render(canvas, renderOptions);
2429
+ canvas.restore();
2430
+ if (trim) {
2431
+ trimBounds = getTrimBounds(canvas);
2432
+ const old = canvas, { width, height } = trimBounds;
2433
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2434
+ canvas = Creator.canvas(config);
2435
+ canvas.copyWorld(old, trimBounds, config);
2162
2436
  }
2163
- success({ data });
2164
- resolve();
2165
- if (unreal)
2166
- canvas.recycle();
2437
+ if (needFill)
2438
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2439
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2440
+ over({ data, renderBounds, trimBounds });
2167
2441
  }));
2168
2442
  }
2169
2443
  else {
2170
- success({ data: false });
2171
- resolve();
2444
+ over({ data: false });
2172
2445
  }
2173
2446
  }));
2174
2447
  }
@@ -2182,12 +2455,19 @@ function addTask(task) {
2182
2455
  });
2183
2456
  }
2184
2457
 
2185
- Object.assign(Paint, UIPaint);
2186
- Object.assign(Effect, UIEffect);
2187
- Object.assign(TextConvert$1, TextConvert);
2188
- Object.assign(ColorConvert$1, ColorConvert);
2189
- Object.assign(Export$1, Export);
2458
+ Object.assign(TextConvert, TextConvertModule);
2459
+ Object.assign(ColorConvert, ColorConvertModule);
2460
+ Object.assign(Paint, PaintModule);
2461
+ Object.assign(PaintImage$1, PaintImageModule);
2462
+ Object.assign(PaintGradient$1, PaintGradientModule);
2463
+ Object.assign(Effect, EffectModule);
2464
+ Object.assign(Export, ExportModule);
2190
2465
 
2466
+ Object.assign(Creator, {
2467
+ interaction: (target, canvas, selector, options) => new InteractionBase(target, canvas, selector, options),
2468
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2469
+ hitCanvasManager: () => new HitCanvasManager()
2470
+ });
2191
2471
  useCanvas();
2192
2472
 
2193
2473
  export { Layouter, LeaferCanvas, Renderer, Selector, Watcher, useCanvas };