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

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 { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, 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,330 @@ 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);
839
-
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();
912
+ function fillText(ui, canvas) {
913
+ let row;
914
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
915
+ for (let i = 0, len = rows.length; i < len; i++) {
916
+ row = rows[i];
917
+ if (row.text) {
918
+ canvas.fillText(row.text, row.x, row.y);
919
+ }
920
+ else if (row.data) {
921
+ row.data.forEach(charData => {
922
+ canvas.fillText(charData.char, charData.x, row.y);
880
923
  });
881
924
  }
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;
925
+ if (decorationY)
926
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
927
+ }
902
928
  }
903
- else if (userAgent.indexOf('Mac') > -1) {
904
- Platform.os = 'Mac';
929
+
930
+ function fill(fill, ui, canvas) {
931
+ canvas.fillStyle = fill;
932
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
905
933
  }
906
- else if (userAgent.indexOf('Linux') > -1) {
907
- Platform.os = 'Linux';
934
+ function fills(fills, ui, canvas) {
935
+ let item;
936
+ const { windingRule, __font } = ui.__;
937
+ for (let i = 0, len = fills.length; i < len; i++) {
938
+ item = fills[i];
939
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
940
+ continue;
941
+ if (item.style) {
942
+ canvas.fillStyle = item.style;
943
+ if (item.transform) {
944
+ canvas.save();
945
+ canvas.transform(item.transform);
946
+ if (item.blendMode)
947
+ canvas.blendMode = item.blendMode;
948
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
949
+ canvas.restore();
950
+ }
951
+ else {
952
+ if (item.blendMode) {
953
+ canvas.saveBlendMode(item.blendMode);
954
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
955
+ canvas.restoreBlendMode();
956
+ }
957
+ else {
958
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
959
+ }
960
+ }
961
+ }
962
+ }
908
963
  }
909
964
 
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);
965
+ function strokeText(stroke, ui, canvas) {
966
+ const { strokeAlign } = ui.__;
967
+ const isStrokes = typeof stroke !== 'string';
968
+ switch (strokeAlign) {
969
+ case 'center':
970
+ canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
971
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
972
+ break;
973
+ case 'inside':
974
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
975
+ break;
976
+ case 'outside':
977
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
978
+ break;
979
+ }
980
+ }
981
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
982
+ const { __strokeWidth, __font } = ui.__;
983
+ const out = canvas.getSameCanvas(true, true);
984
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
985
+ out.font = __font;
986
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
987
+ out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
988
+ fillText(ui, out);
989
+ out.blendMode = 'normal';
990
+ if (ui.__worldFlipped) {
991
+ canvas.copyWorldByReset(out, ui.__nowWorld);
992
+ }
993
+ else {
994
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
995
+ }
996
+ out.recycle(ui.__nowWorld);
997
+ }
998
+ function drawTextStroke(ui, canvas) {
999
+ let row;
1000
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1001
+ for (let i = 0, len = rows.length; i < len; i++) {
1002
+ row = rows[i];
1003
+ if (row.text) {
1004
+ canvas.strokeText(row.text, row.x, row.y);
1005
+ }
1006
+ else if (row.data) {
1007
+ row.data.forEach(charData => {
1008
+ canvas.strokeText(charData.char, charData.x, row.y);
1009
+ });
1010
+ }
1011
+ if (decorationY)
1012
+ canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1013
+ }
1014
+ }
1015
+ function drawStrokesStyle(strokes, isText, ui, canvas) {
1016
+ let item;
1017
+ for (let i = 0, len = strokes.length; i < len; i++) {
1018
+ item = strokes[i];
1019
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1020
+ continue;
1021
+ if (item.style) {
1022
+ canvas.strokeStyle = item.style;
1023
+ if (item.blendMode) {
1024
+ canvas.saveBlendMode(item.blendMode);
1025
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1026
+ canvas.restoreBlendMode();
1027
+ }
1028
+ else {
1029
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1030
+ }
1031
+ }
1032
+ }
1033
+ }
1034
+
1035
+ function stroke(stroke, ui, canvas) {
1036
+ const options = ui.__;
1037
+ const { __strokeWidth, strokeAlign, __font } = options;
1038
+ if (!__strokeWidth)
1039
+ return;
1040
+ if (__font) {
1041
+ strokeText(stroke, ui, canvas);
1042
+ }
1043
+ else {
1044
+ switch (strokeAlign) {
1045
+ case 'center':
1046
+ canvas.setStroke(stroke, __strokeWidth, options);
1047
+ canvas.stroke();
1048
+ break;
1049
+ case 'inside':
1050
+ canvas.save();
1051
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1052
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1053
+ canvas.stroke();
1054
+ canvas.restore();
1055
+ break;
1056
+ case 'outside':
1057
+ const out = canvas.getSameCanvas(true, true);
1058
+ out.setStroke(stroke, __strokeWidth * 2, options);
1059
+ ui.__drawRenderPath(out);
1060
+ out.stroke();
1061
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1062
+ out.clearWorld(ui.__layout.renderBounds);
1063
+ if (ui.__worldFlipped) {
1064
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1065
+ }
1066
+ else {
1067
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1068
+ }
1069
+ out.recycle(ui.__nowWorld);
1070
+ break;
1071
+ }
1072
+ }
1073
+ }
1074
+ function strokes(strokes, ui, canvas) {
1075
+ const options = ui.__;
1076
+ const { __strokeWidth, strokeAlign, __font } = options;
1077
+ if (!__strokeWidth)
1078
+ return;
1079
+ if (__font) {
1080
+ strokeText(strokes, ui, canvas);
1081
+ }
1082
+ else {
1083
+ switch (strokeAlign) {
1084
+ case 'center':
1085
+ canvas.setStroke(undefined, __strokeWidth, options);
1086
+ drawStrokesStyle(strokes, false, ui, canvas);
1087
+ break;
1088
+ case 'inside':
1089
+ canvas.save();
1090
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1091
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1092
+ drawStrokesStyle(strokes, false, ui, canvas);
1093
+ canvas.restore();
1094
+ break;
1095
+ case 'outside':
1096
+ const { renderBounds } = ui.__layout;
1097
+ const out = canvas.getSameCanvas(true, true);
1098
+ ui.__drawRenderPath(out);
1099
+ out.setStroke(undefined, __strokeWidth * 2, options);
1100
+ drawStrokesStyle(strokes, false, ui, out);
1101
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1102
+ out.clearWorld(renderBounds);
1103
+ if (ui.__worldFlipped) {
1104
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1105
+ }
1106
+ else {
1107
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1108
+ }
1109
+ out.recycle(ui.__nowWorld);
1110
+ break;
1111
+ }
1112
+ }
1113
+ }
1114
+
1115
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1116
+ function shape(ui, current, options) {
1117
+ const canvas = current.getSameCanvas();
1118
+ const nowWorld = ui.__nowWorld;
1119
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1120
+ let { scaleX, scaleY } = nowWorld;
1121
+ if (scaleX < 0)
1122
+ scaleX = -scaleX;
1123
+ if (scaleY < 0)
1124
+ scaleY = -scaleY;
1125
+ if (current.bounds.includes(nowWorld)) {
1126
+ worldCanvas = canvas;
1127
+ bounds = shapeBounds = nowWorld;
1128
+ }
1129
+ else {
1130
+ const { renderShapeSpread: spread } = ui.__layout;
1131
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, nowWorld);
1132
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1133
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1134
+ if (fitMatrix.a < 1) {
1135
+ worldCanvas = current.getSameCanvas();
1136
+ ui.__renderShape(worldCanvas, options);
1137
+ scaleX *= fitScaleX;
1138
+ scaleY *= fitScaleY;
1139
+ }
1140
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1141
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1142
+ if (options.matrix) {
1143
+ const { matrix } = options;
1144
+ fitMatrix.multiply(matrix);
1145
+ fitScaleX *= matrix.scaleX;
1146
+ fitScaleY *= matrix.scaleY;
1147
+ }
1148
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1149
+ }
1150
+ ui.__renderShape(canvas, options);
1151
+ return {
1152
+ canvas, matrix: fitMatrix, bounds,
1153
+ worldCanvas, shapeBounds, scaleX, scaleY
1154
+ };
1155
+ }
1156
+
1157
+ let recycleMap;
1158
+ function compute(attrName, ui) {
1159
+ const data = ui.__, leafPaints = [];
1160
+ let paints = data.__input[attrName], hasOpacityPixel;
1161
+ if (!(paints instanceof Array))
1162
+ paints = [paints];
1163
+ recycleMap = PaintImage.recycleImage(attrName, data);
1164
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1165
+ item = getLeafPaint(attrName, paints[i], ui);
1166
+ if (item)
1167
+ leafPaints.push(item);
1168
+ }
1169
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1170
+ if (leafPaints.length && leafPaints[0].image)
1171
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1172
+ if (attrName === 'fill') {
1173
+ data.__pixelFill = hasOpacityPixel;
1174
+ }
1175
+ else {
1176
+ data.__pixelStroke = hasOpacityPixel;
1177
+ }
1178
+ }
1179
+ function getLeafPaint(attrName, paint, ui) {
1180
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1181
+ return undefined;
1182
+ const { boxBounds } = ui.__layout;
1183
+ switch (paint.type) {
1184
+ case 'solid':
1185
+ let { type, blendMode, color, opacity } = paint;
1186
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1187
+ case 'image':
1188
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1189
+ case 'linear':
1190
+ return PaintGradient.linearGradient(paint, boxBounds);
1191
+ case 'radial':
1192
+ return PaintGradient.radialGradient(paint, boxBounds);
1193
+ case 'angular':
1194
+ return PaintGradient.conicGradient(paint, boxBounds);
1195
+ default:
1196
+ return paint.r ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1197
+ }
1198
+ }
1199
+
1200
+ const PaintModule = {
1201
+ compute,
1202
+ fill,
1203
+ fills,
1204
+ fillText,
1205
+ stroke,
1206
+ strokes,
1207
+ strokeText,
1208
+ drawTextStroke,
1209
+ shape
1210
+ };
1211
+
1212
+ let origin = {};
1213
+ const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
1214
+ function fillOrFitMode(data, mode, box, width, height, rotation) {
1215
+ const transform = get$4();
1216
+ const swap = rotation && rotation !== 180;
1217
+ const sw = box.width / (swap ? height : width);
1218
+ const sh = box.height / (swap ? width : height);
916
1219
  const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
917
1220
  const x = box.x + (box.width - width * scale) / 2;
918
1221
  const y = box.y + (box.height - height * scale) / 2;
919
1222
  translate$1(transform, x, y);
920
- scaleHelper$1(transform, scale);
1223
+ scaleHelper(transform, scale);
921
1224
  if (rotation)
922
1225
  rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
923
1226
  data.scaleX = data.scaleY = scale;
924
1227
  data.transform = transform;
925
1228
  }
926
- function clipMode(data, box, offset, scale, rotation) {
1229
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
927
1230
  const transform = get$4();
928
1231
  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);
1232
+ if (x || y)
1233
+ translate$1(transform, x, y);
1234
+ if (scaleX) {
1235
+ scaleHelper(transform, scaleX, scaleY);
933
1236
  data.scaleX = transform.a;
934
1237
  data.scaleY = transform.d;
935
1238
  }
@@ -937,7 +1240,7 @@ function clipMode(data, box, offset, scale, rotation) {
937
1240
  rotate(transform, rotation);
938
1241
  data.transform = transform;
939
1242
  }
940
- function repeatMode(data, box, width, height, scale, rotation) {
1243
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
941
1244
  const transform = get$4();
942
1245
  if (rotation) {
943
1246
  rotate(transform, rotation);
@@ -953,10 +1256,15 @@ function repeatMode(data, box, width, height, scale, rotation) {
953
1256
  break;
954
1257
  }
955
1258
  }
956
- translate$1(transform, box.x, box.y);
957
- if (scale) {
958
- scaleOfOuter$2(transform, box, scale);
959
- data.scaleX = data.scaleY = scale;
1259
+ origin.x = box.x;
1260
+ origin.y = box.y;
1261
+ if (x || y)
1262
+ origin.x += x, origin.y += y;
1263
+ translate$1(transform, origin.x, origin.y);
1264
+ if (scaleX) {
1265
+ scaleOfOuter$2(transform, origin, scaleX, scaleY);
1266
+ data.scaleX = scaleX;
1267
+ data.scaleY = scaleY;
960
1268
  }
961
1269
  data.transform = transform;
962
1270
  }
@@ -964,11 +1272,22 @@ function repeatMode(data, box, width, height, scale, rotation) {
964
1272
  const { get: get$3, translate } = MatrixHelper;
965
1273
  function createData(leafPaint, image, paint, box) {
966
1274
  let { width, height } = image;
967
- const { opacity, mode, offset, scale, rotation, blendMode } = paint;
1275
+ const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
968
1276
  const sameBox = box.width === width && box.height === height;
969
1277
  if (blendMode)
970
1278
  leafPaint.blendMode = blendMode;
971
1279
  const data = leafPaint.data = { mode };
1280
+ let x, y, scaleX, scaleY;
1281
+ if (offset)
1282
+ x = offset.x, y = offset.y;
1283
+ if (size) {
1284
+ scaleX = (typeof size === 'number' ? size : size.width) / width;
1285
+ scaleY = (typeof size === 'number' ? size : size.height) / height;
1286
+ }
1287
+ else if (scale) {
1288
+ scaleX = typeof scale === 'number' ? scale : scale.x;
1289
+ scaleY = typeof scale === 'number' ? scale : scale.y;
1290
+ }
972
1291
  switch (mode) {
973
1292
  case 'strench':
974
1293
  if (!sameBox)
@@ -979,12 +1298,14 @@ function createData(leafPaint, image, paint, box) {
979
1298
  }
980
1299
  break;
981
1300
  case 'clip':
982
- if (offset || scale || rotation)
983
- clipMode(data, box, offset, scale, rotation);
1301
+ if (offset || scaleX || rotation)
1302
+ clipMode(data, box, x, y, scaleX, scaleY, rotation);
984
1303
  break;
985
1304
  case 'repeat':
986
- if (!sameBox || scale || rotation)
987
- repeatMode(data, box, width, height, scale, rotation);
1305
+ if (!sameBox || scaleX || rotation)
1306
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1307
+ if (!repeat)
1308
+ data.repeat = 'repeat';
988
1309
  break;
989
1310
  case 'fit':
990
1311
  case 'cover':
@@ -996,111 +1317,101 @@ function createData(leafPaint, image, paint, box) {
996
1317
  data.height = height;
997
1318
  if (opacity)
998
1319
  data.opacity = opacity;
1320
+ if (repeat)
1321
+ data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
999
1322
  }
1000
1323
 
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 };
1324
+ let cache, box = new Bounds();
1325
+ const { isSame } = BoundsHelper;
1326
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1327
+ let leafPaint, event;
1328
+ const image = ImageManager.get(paint);
1329
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1330
+ leafPaint = cache.leafPaint;
1331
+ }
1332
+ else {
1333
+ leafPaint = { type: paint.type };
1334
+ leafPaint.image = image;
1335
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1336
+ }
1337
+ if (firstUse || image.loading)
1338
+ event = { image, attrName, attrValue: paint };
1005
1339
  if (image.ready) {
1006
- if (hasNaturalSize(ui, attrName, image))
1007
- createData(leafPaint, image, attrValue, box);
1340
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1008
1341
  if (firstUse) {
1009
- emit(ImageEvent.LOAD, event);
1010
- emit(ImageEvent.LOADED, event);
1342
+ onLoad(ui, event);
1343
+ onLoadSuccess(ui, event);
1011
1344
  }
1012
1345
  }
1013
1346
  else if (image.error) {
1014
- if (firstUse) {
1015
- ui.forceUpdate('surface');
1016
- event.error = image.error;
1017
- emit(ImageEvent.ERROR, event);
1018
- }
1347
+ if (firstUse)
1348
+ onLoadError(ui, event, image.error);
1019
1349
  }
1020
1350
  else {
1021
1351
  if (firstUse)
1022
- emit(ImageEvent.LOAD, event);
1352
+ onLoad(ui, event);
1023
1353
  leafPaint.loadId = image.load(() => {
1024
1354
  if (!ui.destroyed) {
1025
- if (hasNaturalSize(ui, attrName, image)) {
1026
- createData(leafPaint, image, attrValue, box);
1355
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds))
1027
1356
  ui.forceUpdate('surface');
1028
- }
1029
- emit(ImageEvent.LOADED, event);
1357
+ onLoadSuccess(ui, event);
1030
1358
  }
1359
+ leafPaint.loadId = null;
1031
1360
  }, (error) => {
1032
- ui.forceUpdate('surface');
1033
- event.error = error;
1034
- emit(ImageEvent.ERROR, event);
1361
+ onLoadError(ui, event, error);
1362
+ leafPaint.loadId = null;
1035
1363
  });
1036
1364
  }
1037
1365
  return leafPaint;
1038
1366
  }
1039
- function hasNaturalSize(ui, attrName, image) {
1367
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1040
1368
  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')) {
1369
+ const data = ui.__;
1370
+ data.__naturalWidth = image.width;
1371
+ data.__naturalHeight = image.height;
1372
+ if (data.__autoWidth || data.__autoHeight) {
1045
1373
  ui.forceUpdate('width');
1374
+ if (ui.__proxyData) {
1375
+ ui.setProxyAttr('width', data.width);
1376
+ ui.setProxyAttr('height', data.height);
1377
+ }
1046
1378
  return false;
1047
1379
  }
1048
1380
  }
1381
+ if (!leafPaint.data)
1382
+ createData(leafPaint, image, paint, boxBounds);
1049
1383
  return true;
1050
1384
  }
1051
- function emit(type, data) {
1052
- if (data.target.hasEvent(type))
1053
- data.target.emitEvent(new ImageEvent(type, data));
1385
+ function onLoad(ui, event) {
1386
+ emit(ui, ImageEvent.LOAD, event);
1387
+ }
1388
+ function onLoadSuccess(ui, event) {
1389
+ emit(ui, ImageEvent.LOADED, event);
1390
+ }
1391
+ function onLoadError(ui, event, error) {
1392
+ event.error = error;
1393
+ ui.forceUpdate('surface');
1394
+ emit(ui, ImageEvent.ERROR, event);
1395
+ }
1396
+ function emit(ui, type, data) {
1397
+ if (ui.hasEvent(type))
1398
+ ui.emitEvent(new ImageEvent(type, data));
1054
1399
  }
1055
1400
 
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;
1401
+ const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1402
+ const { round, abs: abs$1 } = Math;
1089
1403
  function createPattern(ui, paint, pixelRatio) {
1090
1404
  let { scaleX, scaleY } = ui.__world;
1091
1405
  const id = scaleX + '-' + scaleY;
1092
1406
  if (paint.patternId !== id && !ui.destroyed) {
1093
- paint.patternId = id;
1094
- scaleX = Math.abs(scaleX);
1095
- scaleY = Math.abs(scaleY);
1407
+ scaleX = abs$1(scaleX);
1408
+ scaleY = abs$1(scaleY);
1096
1409
  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;
1410
+ let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1100
1411
  if (sx) {
1101
- matrix = get$2();
1102
- copy$1(matrix, transform);
1103
- scaleHelper(matrix, 1 / sx, 1 / sy);
1412
+ imageMatrix = get$2();
1413
+ copy$1(imageMatrix, transform);
1414
+ scale(imageMatrix, 1 / sx, 1 / sy);
1104
1415
  scaleX *= sx;
1105
1416
  scaleY *= sy;
1106
1417
  }
@@ -1108,38 +1419,41 @@ function createPattern(ui, paint, pixelRatio) {
1108
1419
  scaleY *= pixelRatio;
1109
1420
  width *= scaleX;
1110
1421
  height *= scaleY;
1111
- if (width > maxWidth || height > maxHeight) {
1112
- scale = Math.max(width / maxWidth, height / maxHeight);
1422
+ const size = width * height;
1423
+ if (!repeat) {
1424
+ if (size > Platform.image.maxCacheSize)
1425
+ return false;
1426
+ }
1427
+ let maxSize = Platform.image.maxPatternSize;
1428
+ if (!image.isSVG) {
1429
+ const imageSize = image.width * image.height;
1430
+ if (maxSize > imageSize)
1431
+ maxSize = imageSize;
1113
1432
  }
1114
- if (scale) {
1115
- scaleX /= scale;
1116
- scaleY /= scale;
1117
- width /= scale;
1118
- height /= scale;
1433
+ if (size > maxSize)
1434
+ imageScale = Math.sqrt(size / maxSize);
1435
+ if (imageScale) {
1436
+ scaleX /= imageScale;
1437
+ scaleY /= imageScale;
1438
+ width /= imageScale;
1439
+ height /= imageScale;
1119
1440
  }
1120
1441
  if (sx) {
1121
1442
  scaleX /= sx;
1122
1443
  scaleY /= sy;
1123
1444
  }
1124
1445
  if (transform || scaleX !== 1 || scaleY !== 1) {
1125
- if (!matrix) {
1126
- matrix = get$2();
1446
+ if (!imageMatrix) {
1447
+ imageMatrix = get$2();
1127
1448
  if (transform)
1128
- copy$1(matrix, transform);
1449
+ copy$1(imageMatrix, transform);
1129
1450
  }
1130
- scaleHelper(matrix, 1 / scaleX, 1 / scaleY);
1131
- }
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;
1451
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1141
1452
  }
1142
- paint.style = style;
1453
+ const canvas = image.getCanvas(width < 1 ? 1 : round(width), height < 1 ? 1 : round(height), opacity);
1454
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1455
+ paint.style = pattern;
1456
+ paint.patternId = id;
1143
1457
  return true;
1144
1458
  }
1145
1459
  else {
@@ -1147,311 +1461,130 @@ function createPattern(ui, paint, pixelRatio) {
1147
1461
  }
1148
1462
  }
1149
1463
 
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;
1464
+ /******************************************************************************
1465
+ Copyright (c) Microsoft Corporation.
1466
+
1467
+ Permission to use, copy, modify, and/or distribute this software for any
1468
+ purpose with or without fee is hereby granted.
1469
+
1470
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1471
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1472
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1473
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1474
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1475
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1476
+ PERFORMANCE OF THIS SOFTWARE.
1477
+ ***************************************************************************** */
1478
+ /* global Reflect, Promise, SuppressedError, Symbol */
1479
+
1480
+
1481
+ function __awaiter(thisArg, _arguments, P, generator) {
1482
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1483
+ return new (P || (P = Promise))(function (resolve, reject) {
1484
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1485
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1486
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1487
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1488
+ });
1489
+ }
1490
+
1491
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1492
+ var e = new Error(message);
1493
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1494
+ };
1495
+
1496
+ const { abs } = Math;
1497
+ function checkImage(ui, canvas, paint, allowPaint) {
1498
+ const { scaleX, scaleY } = ui.__world;
1499
+ if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1500
+ return false;
1290
1501
  }
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);
1502
+ else {
1503
+ const { data } = paint;
1504
+ if (allowPaint) {
1505
+ if (!data.repeat) {
1506
+ let { width, height } = data;
1507
+ width *= abs(scaleX) * canvas.pixelRatio;
1508
+ height *= abs(scaleY) * canvas.pixelRatio;
1509
+ if (data.scaleX) {
1510
+ width *= data.scaleX;
1511
+ height *= data.scaleY;
1512
+ }
1513
+ allowPaint = width * height > Platform.image.maxCacheSize;
1514
+ }
1515
+ else {
1516
+ allowPaint = false;
1517
+ }
1311
1518
  }
1312
- else if (row.data) {
1313
- row.data.forEach(charData => {
1314
- canvas.strokeText(charData.char, charData.x, row.y);
1315
- });
1519
+ if (allowPaint) {
1520
+ canvas.save();
1521
+ canvas.clip();
1522
+ if (paint.blendMode)
1523
+ canvas.blendMode = paint.blendMode;
1524
+ if (data.opacity)
1525
+ canvas.opacity *= data.opacity;
1526
+ if (data.transform)
1527
+ canvas.transform(data.transform);
1528
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1529
+ canvas.restore();
1530
+ return true;
1316
1531
  }
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();
1532
+ else {
1533
+ if (!paint.style || Export.running) {
1534
+ createPattern(ui, paint, canvas.pixelRatio);
1333
1535
  }
1334
1536
  else {
1335
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1537
+ if (!paint.patternTask) {
1538
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1539
+ paint.patternTask = null;
1540
+ if (canvas.bounds.hit(ui.__world))
1541
+ createPattern(ui, paint, canvas.pixelRatio);
1542
+ ui.forceUpdate('surface');
1543
+ }), 300);
1544
+ }
1336
1545
  }
1546
+ return false;
1337
1547
  }
1338
1548
  }
1339
1549
  }
1340
1550
 
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;
1551
+ function recycleImage(attrName, data) {
1552
+ const paints = data['_' + attrName];
1553
+ if (paints instanceof Array) {
1554
+ let image, recycleMap, input, url;
1555
+ for (let i = 0, len = paints.length; i < len; i++) {
1556
+ image = paints[i].image;
1557
+ url = image && image.url;
1558
+ if (url) {
1559
+ if (!recycleMap)
1560
+ recycleMap = {};
1561
+ recycleMap[url] = true;
1562
+ ImageManager.recycle(image);
1563
+ if (image.loading) {
1564
+ if (!input) {
1565
+ input = (data.__input && data.__input[attrName]) || [];
1566
+ if (!(input instanceof Array))
1567
+ input = [input];
1568
+ }
1569
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1570
+ }
1571
+ }
1407
1572
  }
1573
+ return recycleMap;
1408
1574
  }
1575
+ return null;
1409
1576
  }
1410
1577
 
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
- }
1578
+ const PaintImageModule = {
1579
+ image,
1580
+ createData,
1581
+ fillOrFitMode,
1582
+ clipMode,
1583
+ repeatMode,
1584
+ createPattern,
1585
+ checkImage,
1586
+ recycleImage
1587
+ };
1455
1588
 
1456
1589
  const defaultFrom$2 = { x: 0.5, y: 0 };
1457
1590
  const defaultTo$2 = { x: 0.5, y: 1 };
@@ -1470,7 +1603,7 @@ function applyStops(gradient, stops, opacity) {
1470
1603
  let stop;
1471
1604
  for (let i = 0, len = stops.length; i < len; i++) {
1472
1605
  stop = stops[i];
1473
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
1606
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1474
1607
  }
1475
1608
  }
1476
1609
 
@@ -1532,62 +1665,18 @@ function conicGradient(paint, box) {
1532
1665
  return data;
1533
1666
  }
1534
1667
 
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
- });
1668
+ const PaintGradientModule = {
1669
+ linearGradient,
1670
+ radialGradient,
1671
+ conicGradient
1672
+ };
1584
1673
 
1585
1674
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1586
1675
  const tempBounds = {};
1587
1676
  const offsetOutBounds$1 = {};
1588
- function shadow(ui, current, shape, _options) {
1677
+ function shadow(ui, current, shape) {
1589
1678
  let copyBounds, spreadScale;
1590
- const { __world, __layout } = ui;
1679
+ const { __nowWorld: nowWorld, __layout } = ui;
1591
1680
  const { shadow } = ui.__;
1592
1681
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1593
1682
  const other = current.getSameCanvas();
@@ -1602,21 +1691,21 @@ function shadow(ui, current, shape, _options) {
1602
1691
  other.restore();
1603
1692
  other.save();
1604
1693
  if (worldCanvas) {
1605
- other.copyWorld(other, bounds, __world, 'copy');
1606
- copyBounds = __world;
1694
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1695
+ copyBounds = nowWorld;
1607
1696
  }
1608
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1697
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1609
1698
  }
1610
- if (ui.__hasMirror) {
1611
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1699
+ if (ui.__worldFlipped) {
1700
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1612
1701
  }
1613
1702
  else {
1614
1703
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1615
1704
  }
1616
1705
  if (end && index < end)
1617
- other.clear();
1706
+ other.clearWorld(copyBounds, true);
1618
1707
  });
1619
- other.recycle();
1708
+ other.recycle(copyBounds);
1620
1709
  }
1621
1710
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1622
1711
  const { bounds, shapeBounds } = shape;
@@ -1647,9 +1736,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1647
1736
 
1648
1737
  const { toOffsetOutBounds } = BoundsHelper;
1649
1738
  const offsetOutBounds = {};
1650
- function innerShadow(ui, current, shape, _options) {
1739
+ function innerShadow(ui, current, shape) {
1651
1740
  let copyBounds, spreadScale;
1652
- const { __world, __layout: __layout } = ui;
1741
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1653
1742
  const { innerShadow } = ui.__;
1654
1743
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1655
1744
  const other = current.getSameCanvas();
@@ -1662,25 +1751,25 @@ function innerShadow(ui, current, shape, _options) {
1662
1751
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1663
1752
  other.restore();
1664
1753
  if (worldCanvas) {
1665
- other.copyWorld(other, bounds, __world, 'copy');
1666
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1667
- copyBounds = __world;
1754
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1755
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
1756
+ copyBounds = nowWorld;
1668
1757
  }
1669
1758
  else {
1670
1759
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1671
1760
  copyBounds = bounds;
1672
1761
  }
1673
1762
  other.fillWorld(copyBounds, item.color, 'source-in');
1674
- if (ui.__hasMirror) {
1675
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1763
+ if (ui.__worldFlipped) {
1764
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1676
1765
  }
1677
1766
  else {
1678
1767
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1679
1768
  }
1680
1769
  if (end && index < end)
1681
- other.clear();
1770
+ other.clearWorld(copyBounds, true);
1682
1771
  });
1683
- other.recycle();
1772
+ other.recycle(copyBounds);
1684
1773
  }
1685
1774
 
1686
1775
  function blur(ui, current, origin) {
@@ -1690,12 +1779,87 @@ function blur(ui, current, origin) {
1690
1779
  origin.filter = 'none';
1691
1780
  }
1692
1781
 
1693
- var UIEffect = /*#__PURE__*/Object.freeze({
1694
- __proto__: null,
1695
- blur: blur,
1696
- innerShadow: innerShadow,
1697
- shadow: shadow
1698
- });
1782
+ function backgroundBlur(_ui, _current, _shape) {
1783
+ }
1784
+
1785
+ const EffectModule = {
1786
+ shadow,
1787
+ innerShadow,
1788
+ blur,
1789
+ backgroundBlur
1790
+ };
1791
+
1792
+ const { excludeRenderBounds } = LeafBoundsHelper;
1793
+ Group.prototype.__renderMask = function (canvas, options) {
1794
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
1795
+ const { children } = this;
1796
+ for (let i = 0, len = children.length; i < len; i++) {
1797
+ child = children[i];
1798
+ if (child.__.mask) {
1799
+ if (currentMask) {
1800
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1801
+ maskCanvas = contentCanvas = null;
1802
+ }
1803
+ if (child.__.maskType === 'path') {
1804
+ if (child.opacity < 1) {
1805
+ currentMask = 'opacity-path';
1806
+ maskOpacity = child.opacity;
1807
+ if (!contentCanvas)
1808
+ contentCanvas = getCanvas(canvas);
1809
+ }
1810
+ else {
1811
+ currentMask = 'path';
1812
+ canvas.save();
1813
+ }
1814
+ child.__clip(contentCanvas || canvas, options);
1815
+ }
1816
+ else {
1817
+ currentMask = 'alpha';
1818
+ if (!maskCanvas)
1819
+ maskCanvas = getCanvas(canvas);
1820
+ if (!contentCanvas)
1821
+ contentCanvas = getCanvas(canvas);
1822
+ child.__render(maskCanvas, options);
1823
+ }
1824
+ if (child.__.maskType !== 'clipping')
1825
+ continue;
1826
+ }
1827
+ if (excludeRenderBounds(child, options))
1828
+ continue;
1829
+ child.__render(contentCanvas || canvas, options);
1830
+ }
1831
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1832
+ };
1833
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
1834
+ switch (maskMode) {
1835
+ case 'alpha':
1836
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
1837
+ break;
1838
+ case 'opacity-path':
1839
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
1840
+ break;
1841
+ case 'path':
1842
+ canvas.restore();
1843
+ }
1844
+ }
1845
+ function getCanvas(canvas) {
1846
+ return canvas.getSameCanvas(false, true);
1847
+ }
1848
+ function usePixelMask(leaf, canvas, content, mask) {
1849
+ const realBounds = leaf.__nowWorld;
1850
+ content.resetTransform();
1851
+ content.opacity = 1;
1852
+ content.useMask(mask, realBounds);
1853
+ mask.recycle(realBounds);
1854
+ copyContent(leaf, canvas, content, 1);
1855
+ }
1856
+ function copyContent(leaf, canvas, content, maskOpacity) {
1857
+ const realBounds = leaf.__nowWorld;
1858
+ canvas.resetTransform();
1859
+ canvas.opacity = maskOpacity;
1860
+ canvas.copyWorld(content, realBounds);
1861
+ content.recycle(realBounds);
1862
+ }
1699
1863
 
1700
1864
  const money = '¥¥$€££¢¢';
1701
1865
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -1809,7 +1973,7 @@ function getTextCase(char, textCase, firstChar) {
1809
1973
  const { trimRight } = TextRowHelper;
1810
1974
  const { Letter, Single, Before, After, Symbol, Break } = CharType;
1811
1975
  let word, row, wordWidth, rowWidth, realWidth;
1812
- let char, charWidth, charType, lastCharType, langBreak, afterBreak, paraStart;
1976
+ let char, charWidth, startCharSize, charSize, charType, lastCharType, langBreak, afterBreak, paraStart;
1813
1977
  let textDrawData, rows = [], bounds;
1814
1978
  function createRows(drawData, content, style) {
1815
1979
  textDrawData = drawData;
@@ -1820,9 +1984,11 @@ function createRows(drawData, content, style) {
1820
1984
  const { width, height } = bounds;
1821
1985
  const charMode = width || height || __letterSpacing || (textCase !== 'none');
1822
1986
  if (charMode) {
1987
+ const wrap = style.textWrap !== 'none';
1988
+ const breakAll = style.textWrap === 'break';
1823
1989
  paraStart = true;
1824
1990
  lastCharType = null;
1825
- wordWidth = rowWidth = 0;
1991
+ startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
1826
1992
  word = { data: [] }, row = { words: [] };
1827
1993
  for (let i = 0, len = content.length; i < len; i++) {
1828
1994
  char = content[i];
@@ -1838,21 +2004,31 @@ function createRows(drawData, content, style) {
1838
2004
  if (charType === Letter && textCase !== 'none')
1839
2005
  char = getTextCase(char, textCase, !wordWidth);
1840
2006
  charWidth = canvas.measureText(char).width;
1841
- if (__letterSpacing)
2007
+ if (__letterSpacing) {
2008
+ if (__letterSpacing < 0)
2009
+ charSize = charWidth;
1842
2010
  charWidth += __letterSpacing;
2011
+ }
1843
2012
  langBreak = (charType === Single && (lastCharType === Single || lastCharType === Letter)) || (lastCharType === Single && charType !== After);
1844
2013
  afterBreak = ((charType === Before || charType === Single) && (lastCharType === Symbol || lastCharType === After));
1845
2014
  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)) {
2015
+ if (wrap && (width && rowWidth + wordWidth + charWidth > realWidth)) {
2016
+ if (breakAll) {
1850
2017
  if (wordWidth)
1851
2018
  addWord();
1852
2019
  addRow();
1853
2020
  }
1854
2021
  else {
1855
- addRow();
2022
+ if (!afterBreak)
2023
+ afterBreak = charType === Letter && lastCharType == After;
2024
+ if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2025
+ if (wordWidth)
2026
+ addWord();
2027
+ addRow();
2028
+ }
2029
+ else {
2030
+ addRow();
2031
+ }
1856
2032
  }
1857
2033
  }
1858
2034
  if (char === ' ' && paraStart !== true && (rowWidth + wordWidth) === 0) ;
@@ -1889,6 +2065,8 @@ function createRows(drawData, content, style) {
1889
2065
  }
1890
2066
  }
1891
2067
  function addChar(char, width) {
2068
+ if (charSize && !startCharSize)
2069
+ startCharSize = charSize;
1892
2070
  word.data.push({ char, width });
1893
2071
  wordWidth += width;
1894
2072
  }
@@ -1905,6 +2083,11 @@ function addRow() {
1905
2083
  row.paraStart = true;
1906
2084
  paraStart = false;
1907
2085
  }
2086
+ if (charSize) {
2087
+ row.startCharSize = startCharSize;
2088
+ row.endCharSize = charSize;
2089
+ startCharSize = 0;
2090
+ }
1908
2091
  row.width = rowWidth;
1909
2092
  if (bounds.width)
1910
2093
  trimRight(row);
@@ -1915,7 +2098,7 @@ function addRow() {
1915
2098
 
1916
2099
  const CharMode = 0;
1917
2100
  const WordMode = 1;
1918
- const RowMode = 2;
2101
+ const TextMode = 2;
1919
2102
  function layoutChar(drawData, style, width, _height) {
1920
2103
  const { rows } = drawData;
1921
2104
  const { textAlign, paraIndent, letterSpacing } = style;
@@ -1924,15 +2107,12 @@ function layoutChar(drawData, style, width, _height) {
1924
2107
  if (row.words) {
1925
2108
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0;
1926
2109
  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 = '';
2110
+ mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : TextMode);
2111
+ if (row.isOverflow && !letterSpacing)
2112
+ row.textMode = true;
2113
+ if (mode === TextMode) {
1930
2114
  row.x += indentWidth;
1931
- row.words.forEach(word => {
1932
- word.data.forEach(char => {
1933
- row.text += char.char;
1934
- });
1935
- });
2115
+ toTextChar$1(row);
1936
2116
  }
1937
2117
  else {
1938
2118
  row.x += indentWidth;
@@ -1958,6 +2138,14 @@ function layoutChar(drawData, style, width, _height) {
1958
2138
  }
1959
2139
  });
1960
2140
  }
2141
+ function toTextChar$1(row) {
2142
+ row.text = '';
2143
+ row.words.forEach(word => {
2144
+ word.data.forEach(char => {
2145
+ row.text += char.char;
2146
+ });
2147
+ });
2148
+ }
1961
2149
  function toWordChar(data, charX, wordChar) {
1962
2150
  data.forEach(char => {
1963
2151
  wordChar.char += char.char;
@@ -1978,10 +2166,10 @@ function toChar(data, charX, rowData) {
1978
2166
 
1979
2167
  function layoutText(drawData, style) {
1980
2168
  const { rows, bounds } = drawData;
1981
- const { __lineHeight, __baseLine, textAlign, verticalAlign, paraSpacing, textOverflow } = style;
2169
+ const { __lineHeight, __baseLine, __letterSpacing, __clipText, textAlign, verticalAlign, paraSpacing } = style;
1982
2170
  let { x, y, width, height } = bounds, realHeight = __lineHeight * rows.length + (paraSpacing ? paraSpacing * (drawData.paraNumber - 1) : 0);
1983
2171
  let starY = __baseLine;
1984
- if (textOverflow !== 'show' && realHeight > height) {
2172
+ if (__clipText && realHeight > height) {
1985
2173
  realHeight = Math.max(height, __lineHeight);
1986
2174
  drawData.overflow = rows.length;
1987
2175
  }
@@ -1995,7 +2183,7 @@ function layoutText(drawData, style) {
1995
2183
  }
1996
2184
  }
1997
2185
  starY += y;
1998
- let row;
2186
+ let row, rowX, rowWidth;
1999
2187
  for (let i = 0, len = rows.length; i < len; i++) {
2000
2188
  row = rows[i];
2001
2189
  row.x = x;
@@ -2014,53 +2202,74 @@ function layoutText(drawData, style) {
2014
2202
  row.isOverflow = true;
2015
2203
  drawData.overflow = i + 1;
2016
2204
  }
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;
2205
+ rowX = row.x;
2206
+ rowWidth = row.width;
2207
+ if (__letterSpacing < 0) {
2208
+ if (row.width < 0) {
2209
+ rowWidth = -row.width + style.fontSize + __letterSpacing;
2210
+ rowX -= rowWidth;
2211
+ rowWidth += style.fontSize;
2212
+ }
2213
+ else {
2214
+ rowWidth -= __letterSpacing;
2215
+ }
2024
2216
  }
2025
- else {
2026
- if (row.x < bounds.x)
2027
- bounds.x = row.x;
2028
- if (row.width > bounds.width)
2029
- bounds.width = row.width;
2217
+ if (rowX < bounds.x)
2218
+ bounds.x = rowX;
2219
+ if (rowWidth > bounds.width)
2220
+ bounds.width = rowWidth;
2221
+ if (__clipText && width && width < rowWidth) {
2222
+ row.isOverflow = true;
2223
+ if (!drawData.overflow)
2224
+ drawData.overflow = rows.length;
2030
2225
  }
2031
2226
  }
2032
2227
  bounds.y = y;
2033
2228
  bounds.height = realHeight;
2034
2229
  }
2035
2230
 
2036
- function clipText(drawData, textOverflow) {
2231
+ function clipText(drawData, style) {
2037
2232
  const { rows, overflow } = drawData;
2233
+ let { textOverflow } = style;
2038
2234
  rows.splice(overflow);
2039
2235
  if (textOverflow !== 'hide') {
2040
2236
  if (textOverflow === 'ellipsis')
2041
2237
  textOverflow = '...';
2238
+ let char, charRight;
2042
2239
  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;
2240
+ const right = style.x + style.width - ellipsisWidth;
2241
+ const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2242
+ list.forEach(row => {
2243
+ if (row.isOverflow && row.data) {
2244
+ let end = row.data.length - 1;
2245
+ for (let i = end; i > -1; i--) {
2246
+ char = row.data[i];
2247
+ charRight = char.x + char.width;
2248
+ if (i === end && charRight < right) {
2249
+ break;
2250
+ }
2251
+ else if (charRight < right && char.char !== ' ') {
2252
+ row.data.splice(i + 1);
2253
+ row.width -= char.width;
2254
+ break;
2255
+ }
2256
+ row.width -= char.width;
2257
+ }
2258
+ row.width += ellipsisWidth;
2259
+ row.data.push({ char: textOverflow, x: charRight });
2260
+ if (row.textMode)
2261
+ toTextChar(row);
2057
2262
  }
2058
- row.width -= char.width;
2059
- }
2060
- row.width += ellipsisWidth;
2061
- row.data.push({ char: textOverflow, x: charRight });
2263
+ });
2062
2264
  }
2063
2265
  }
2266
+ function toTextChar(row) {
2267
+ row.text = '';
2268
+ row.data.forEach(char => {
2269
+ row.text += char.char;
2270
+ });
2271
+ row.data = null;
2272
+ }
2064
2273
 
2065
2274
  function decorationText(drawData, style) {
2066
2275
  const { fontSize } = style;
@@ -2074,101 +2283,163 @@ function decorationText(drawData, style) {
2074
2283
  }
2075
2284
  }
2076
2285
 
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
- }
2286
+ const { top, right, bottom, left } = Direction4;
2287
+ function getDrawData(content, style) {
2288
+ if (typeof content !== 'string')
2289
+ content = String(content);
2290
+ let x = 0, y = 0;
2291
+ let width = style.__getInput('width') || 0;
2292
+ let height = style.__getInput('height') || 0;
2293
+ const { textDecoration, __font, __padding: padding } = style;
2294
+ if (padding) {
2295
+ if (width) {
2296
+ x = padding[left];
2297
+ width -= (padding[right] + padding[left]);
2298
+ }
2299
+ if (height) {
2300
+ y = padding[top];
2301
+ height -= (padding[top] + padding[bottom]);
2302
+ }
2303
+ }
2304
+ const drawData = {
2305
+ bounds: { x, y, width, height },
2306
+ rows: [],
2307
+ paraNumber: 0,
2308
+ font: Platform.canvas.font = __font
2309
+ };
2310
+ createRows(drawData, content, style);
2311
+ if (padding)
2312
+ padAutoText(padding, drawData, style, width, height);
2313
+ layoutText(drawData, style);
2314
+ layoutChar(drawData, style, width);
2315
+ if (drawData.overflow)
2316
+ clipText(drawData, style);
2317
+ if (textDecoration !== 'none')
2318
+ decorationText(drawData, style);
2319
+ return drawData;
2320
+ }
2321
+ function padAutoText(padding, drawData, style, width, height) {
2322
+ if (!width) {
2323
+ switch (style.textAlign) {
2324
+ case 'left':
2325
+ offsetText(drawData, 'x', padding[left]);
2326
+ break;
2327
+ case 'right':
2328
+ offsetText(drawData, 'x', -padding[right]);
2329
+ }
2330
+ }
2331
+ if (!height) {
2332
+ switch (style.verticalAlign) {
2333
+ case 'top':
2334
+ offsetText(drawData, 'y', padding[top]);
2335
+ break;
2336
+ case 'bottom':
2337
+ offsetText(drawData, 'y', -padding[bottom]);
2096
2338
  }
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
2339
  }
2340
+ }
2341
+ function offsetText(drawData, attrName, value) {
2342
+ const { bounds, rows } = drawData;
2343
+ bounds[attrName] += value;
2344
+ for (let i = 0; i < rows.length; i++)
2345
+ rows[i][attrName] += value;
2346
+ }
2347
+
2348
+ const TextConvertModule = {
2349
+ getDrawData
2112
2350
  };
2113
2351
 
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
- }
2352
+ function string(color, opacity) {
2353
+ if (typeof color === 'string')
2354
+ return color;
2355
+ let a = color.a === undefined ? 1 : color.a;
2356
+ if (opacity)
2357
+ a *= opacity;
2358
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2359
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2360
+ }
2361
+
2362
+ const ColorConvertModule = {
2363
+ string
2124
2364
  };
2125
2365
 
2126
- const Export = {
2366
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2367
+ function getTrimBounds(canvas) {
2368
+ const { width, height } = canvas.view;
2369
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2370
+ let x, y, pointBounds, index = 0;
2371
+ for (let i = 0; i < data.length; i += 4) {
2372
+ if (data[i + 3] !== 0) {
2373
+ x = index % width;
2374
+ y = (index - x) / width;
2375
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2376
+ }
2377
+ index++;
2378
+ }
2379
+ const bounds = new Bounds();
2380
+ toBounds(pointBounds, bounds);
2381
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2382
+ }
2383
+
2384
+ const ExportModule = {
2127
2385
  export(leaf, filename, options) {
2386
+ this.running = true;
2128
2387
  return addTask((success) => new Promise((resolve) => {
2388
+ const over = (result) => {
2389
+ success(result);
2390
+ resolve();
2391
+ this.running = false;
2392
+ };
2129
2393
  const { leafer } = leaf;
2130
2394
  if (leafer) {
2131
2395
  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, {});
2396
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2397
+ options = FileHelper.getExportOptions(options);
2398
+ const { scale, slice, trim } = options;
2399
+ const pixelRatio = options.pixelRatio || 1;
2400
+ const screenshot = options.screenshot || leaf.isApp;
2401
+ const fill = options.fill === undefined ? ((leaf.isLeafer && screenshot) ? leaf.fill : '') : options.fill;
2402
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2403
+ if (screenshot) {
2404
+ renderBounds = screenshot === true ? (leaf.isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2139
2405
  }
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;
2406
+ else {
2407
+ const { localTransform, __world: world } = leaf;
2408
+ matrix.set(world).divide(localTransform).invert();
2409
+ scaleX = 1 / (world.scaleX / leaf.scaleX);
2410
+ scaleY = 1 / (world.scaleY / leaf.scaleY);
2411
+ renderBounds = leaf.getBounds('render', 'local');
2152
2412
  }
2153
- let data;
2154
- if (filename.includes('.')) {
2155
- data = yield canvas.saveAs(filename, quality);
2413
+ let { x, y, width, height } = renderBounds;
2414
+ if (scale) {
2415
+ matrix.scale(scale);
2416
+ width *= scale, height *= scale;
2417
+ scaleX *= scale, scaleY *= scale;
2156
2418
  }
2157
- else if (blob) {
2158
- data = yield canvas.toBlob(filename, quality);
2419
+ let canvas = Creator.canvas({ width: Math.ceil(width), height: Math.ceil(width), pixelRatio });
2420
+ const renderOptions = { matrix: matrix.translate(-x, -y).withScale(scaleX, scaleY) };
2421
+ if (slice) {
2422
+ leaf = leafer;
2423
+ renderOptions.bounds = canvas.bounds;
2159
2424
  }
2160
- else {
2161
- data = yield canvas.toDataURL(filename, quality);
2425
+ canvas.save();
2426
+ leaf.__render(canvas, renderOptions);
2427
+ canvas.restore();
2428
+ if (trim) {
2429
+ trimBounds = getTrimBounds(canvas);
2430
+ const old = canvas, { width, height } = trimBounds;
2431
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2432
+ canvas = Creator.canvas(config);
2433
+ canvas.copyWorld(old, trimBounds, config);
2162
2434
  }
2163
- success({ data });
2164
- resolve();
2165
- if (unreal)
2166
- canvas.recycle();
2435
+ if (needFill)
2436
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2437
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2438
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2167
2439
  }));
2168
2440
  }
2169
2441
  else {
2170
- success({ data: false });
2171
- resolve();
2442
+ over({ data: false });
2172
2443
  }
2173
2444
  }));
2174
2445
  }
@@ -2182,12 +2453,19 @@ function addTask(task) {
2182
2453
  });
2183
2454
  }
2184
2455
 
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);
2456
+ Object.assign(TextConvert, TextConvertModule);
2457
+ Object.assign(ColorConvert, ColorConvertModule);
2458
+ Object.assign(Paint, PaintModule);
2459
+ Object.assign(PaintImage, PaintImageModule);
2460
+ Object.assign(PaintGradient, PaintGradientModule);
2461
+ Object.assign(Effect, EffectModule);
2462
+ Object.assign(Export, ExportModule);
2190
2463
 
2464
+ Object.assign(Creator, {
2465
+ interaction: (target, canvas, selector, options) => new InteractionBase(target, canvas, selector, options),
2466
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2467
+ hitCanvasManager: () => new HitCanvasManager()
2468
+ });
2191
2469
  useCanvas();
2192
2470
 
2193
2471
  export { Layouter, LeaferCanvas, Renderer, Selector, Watcher, useCanvas };