@leafer-ui/worker 1.0.0-rc.9 → 1.0.1

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,96 @@
1
- import { LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, Platform, AnimateEvent, ResizeEvent, BoundsHelper, Creator, LeaferCanvasBase, canvasPatch, LeaferImage, InteractionBase, FileHelper, MatrixHelper, ImageEvent, PointHelper, Direction4, TaskProcessor } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, Creator, LeaferImage, defineKey, FileHelper, LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, ResizeEvent, BoundsHelper, Answer, MatrixHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
- import { ColorConvert as ColorConvert$1, ImageManager as ImageManager$1, Paint, Effect, TextConvert as TextConvert$1, Export as Export$2 } 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
+ download(_url, _filename) { return undefined; },
52
+ loadImage(src) {
53
+ return new Promise((resolve, reject) => {
54
+ let req = new XMLHttpRequest();
55
+ req.open('GET', Platform.image.getRealURL(src), true);
56
+ req.responseType = "blob";
57
+ req.onload = () => {
58
+ createImageBitmap(req.response).then(img => {
59
+ resolve(img);
60
+ }).catch(e => {
61
+ reject(e);
62
+ });
63
+ };
64
+ req.onerror = (e) => reject(e);
65
+ req.send();
66
+ });
67
+ }
68
+ };
69
+ Platform.canvas = Creator.canvas();
70
+ Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
71
+ }
72
+ Platform.name = 'web';
73
+ Platform.isWorker = true;
74
+ Platform.requestRender = function (render) { requestAnimationFrame(render); };
75
+ defineKey(Platform, 'devicePixelRatio', { get() { return 1; } });
76
+ const { userAgent } = navigator;
77
+ if (userAgent.indexOf("Firefox") > -1) {
78
+ Platform.conicGradientRotate90 = true;
79
+ Platform.intWheelDeltaY = true;
80
+ }
81
+ else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") === -1) {
82
+ Platform.fullImageShadow = true;
83
+ }
84
+ if (userAgent.indexOf('Windows') > -1) {
85
+ Platform.os = 'Windows';
86
+ Platform.intWheelDeltaY = true;
87
+ }
88
+ else if (userAgent.indexOf('Mac') > -1) {
89
+ Platform.os = 'Mac';
90
+ }
91
+ else if (userAgent.indexOf('Linux') > -1) {
92
+ Platform.os = 'Linux';
93
+ }
6
94
 
7
95
  class Watcher {
8
96
  get childrenChanged() { return this.hasAdd || this.hasRemove || this.hasVisible; }
@@ -185,7 +273,7 @@ class LayoutBlockData {
185
273
  }
186
274
 
187
275
  const { updateAllMatrix, updateAllChange } = LeafHelper;
188
- const debug$1 = Debug.get('Layouter');
276
+ const debug$2 = Debug.get('Layouter');
189
277
  class Layouter {
190
278
  constructor(target, userConfig) {
191
279
  this.totalTimes = 0;
@@ -220,7 +308,7 @@ class Layouter {
220
308
  target.emitEvent(new LayoutEvent(LayoutEvent.END, this.layoutedBlocks, this.times));
221
309
  }
222
310
  catch (e) {
223
- debug$1.error(e);
311
+ debug$2.error(e);
224
312
  }
225
313
  this.layoutedBlocks = null;
226
314
  }
@@ -234,9 +322,9 @@ class Layouter {
234
322
  }
235
323
  layoutOnce() {
236
324
  if (this.layouting)
237
- return debug$1.warn('layouting');
325
+ return debug$2.warn('layouting');
238
326
  if (this.times > 3)
239
- return debug$1.warn('layout max times');
327
+ return debug$2.warn('layout max times');
240
328
  this.times++;
241
329
  this.totalTimes++;
242
330
  this.layouting = true;
@@ -302,9 +390,11 @@ class Layouter {
302
390
  updateAllChange(target);
303
391
  }
304
392
  addExtra(leaf) {
305
- const block = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
306
- block.updatedList.add(leaf);
307
- block.beforeBounds.add(leaf.__world);
393
+ if (!this.__updatedList.has(leaf)) {
394
+ const { updatedList, beforeBounds } = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
395
+ updatedList.length ? beforeBounds.add(leaf.__world) : beforeBounds.set(leaf.__world);
396
+ updatedList.add(leaf);
397
+ }
308
398
  }
309
399
  createBlock(data) {
310
400
  return new LayoutBlockData(data);
@@ -338,7 +428,7 @@ class Layouter {
338
428
  }
339
429
  }
340
430
 
341
- const debug = Debug.get('Renderer');
431
+ const debug$1 = Debug.get('Renderer');
342
432
  class Renderer {
343
433
  get needFill() { return !!(!this.canvas.allowBackgroundColor && this.config.fill); }
344
434
  constructor(target, canvas, userConfig) {
@@ -376,7 +466,7 @@ class Renderer {
376
466
  const { target } = this;
377
467
  this.times = 0;
378
468
  this.totalBounds = new Bounds();
379
- debug.log(target.innerName, '--->');
469
+ debug$1.log(target.innerName, '--->');
380
470
  try {
381
471
  this.emitRender(RenderEvent.START);
382
472
  this.renderOnce(callback);
@@ -385,9 +475,9 @@ class Renderer {
385
475
  }
386
476
  catch (e) {
387
477
  this.rendering = false;
388
- debug.error(e);
478
+ debug$1.error(e);
389
479
  }
390
- debug.log('-------------|');
480
+ debug$1.log('-------------|');
391
481
  }
392
482
  renderAgain() {
393
483
  if (this.rendering) {
@@ -399,9 +489,9 @@ class Renderer {
399
489
  }
400
490
  renderOnce(callback) {
401
491
  if (this.rendering)
402
- return debug.warn('rendering');
492
+ return debug$1.warn('rendering');
403
493
  if (this.times > 3)
404
- return debug.warn('render max times');
494
+ return debug$1.warn('render max times');
405
495
  this.times++;
406
496
  this.totalTimes++;
407
497
  this.rendering = true;
@@ -414,6 +504,10 @@ class Renderer {
414
504
  }
415
505
  else {
416
506
  this.requestLayout();
507
+ if (this.ignore) {
508
+ this.ignore = this.rendering = false;
509
+ return;
510
+ }
417
511
  this.emitRender(RenderEvent.BEFORE);
418
512
  if (this.config.usePartRender && this.totalTimes > 1) {
419
513
  this.partRender();
@@ -434,7 +528,7 @@ class Renderer {
434
528
  partRender() {
435
529
  const { canvas, updateBlocks: list } = this;
436
530
  if (!list)
437
- return debug.warn('PartRender: need update attr');
531
+ return debug$1.warn('PartRender: need update attr');
438
532
  this.mergeBlocks();
439
533
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
440
534
  this.clipRender(block); });
@@ -450,7 +544,7 @@ class Renderer {
450
544
  canvas.clear();
451
545
  }
452
546
  else {
453
- bounds.spread(1 + 1 / this.canvas.pixelRatio).ceil();
547
+ bounds.spread(10 + 1 / this.canvas.pixelRatio).ceil();
454
548
  canvas.clearWorld(bounds, true);
455
549
  canvas.clipWorld(bounds, true);
456
550
  }
@@ -474,14 +568,14 @@ class Renderer {
474
568
  if (Debug.showRepaint)
475
569
  this.canvas.strokeWorld(bounds, 'red');
476
570
  this.target.__render(this.canvas, options);
477
- this.renderBounds = realBounds || bounds;
571
+ this.renderBounds = realBounds = realBounds || bounds;
478
572
  this.renderOptions = options;
479
- this.totalBounds.isEmpty() ? this.totalBounds = this.renderBounds : this.totalBounds.add(this.renderBounds);
573
+ this.totalBounds.isEmpty() ? this.totalBounds = realBounds : this.totalBounds.add(realBounds);
480
574
  if (Debug.showHitView)
481
575
  this.renderHitView(options);
482
576
  if (Debug.showBoundsView)
483
577
  this.renderBoundsView(options);
484
- this.canvas.updateRender();
578
+ this.canvas.updateRender(realBounds);
485
579
  }
486
580
  renderHitView(_options) { }
487
581
  renderBoundsView(_options) { }
@@ -503,12 +597,12 @@ class Renderer {
503
597
  const startTime = Date.now();
504
598
  Platform.requestRender(() => {
505
599
  this.FPS = Math.min(60, Math.ceil(1000 / (Date.now() - startTime)));
506
- if (this.changed) {
507
- if (this.running && this.canvas.view)
600
+ if (this.running) {
601
+ this.target.emit(AnimateEvent.FRAME);
602
+ if (this.changed && this.canvas.view)
508
603
  this.render();
604
+ this.target.emit(RenderEvent.NEXT);
509
605
  }
510
- if (this.running)
511
- this.target.emit(AnimateEvent.FRAME);
512
606
  if (this.target)
513
607
  this.__requestRender();
514
608
  });
@@ -521,9 +615,12 @@ class Renderer {
521
615
  const bounds = new Bounds(0, 0, width, height);
522
616
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
523
617
  this.addBlock(this.canvas.bounds);
524
- this.target.forceUpdate('blendMode');
618
+ this.target.forceUpdate('surface');
619
+ return;
525
620
  }
526
621
  }
622
+ this.addBlock(new Bounds(0, 0, 1, 1));
623
+ this.changed = true;
527
624
  }
528
625
  __onLayoutEnd(event) {
529
626
  if (event.data)
@@ -534,7 +631,7 @@ class Renderer {
534
631
  empty = (!leaf.__world.width || !leaf.__world.height);
535
632
  if (empty) {
536
633
  if (!leaf.isLeafer)
537
- debug.tip(leaf.innerName, ': empty');
634
+ debug$1.tip(leaf.innerName, ': empty');
538
635
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
539
636
  }
540
637
  return empty;
@@ -561,23 +658,13 @@ class Renderer {
561
658
  if (this.target) {
562
659
  this.stop();
563
660
  this.__removeListenEvents();
564
- this.target = null;
565
- this.canvas = null;
566
- this.config = null;
661
+ this.target = this.canvas = this.config = null;
567
662
  }
568
663
  }
569
664
  }
570
665
 
571
- var AnswerType;
572
- (function (AnswerType) {
573
- AnswerType[AnswerType["No"] = 0] = "No";
574
- AnswerType[AnswerType["Yes"] = 1] = "Yes";
575
- AnswerType[AnswerType["NoAndSkip"] = 2] = "NoAndSkip";
576
- AnswerType[AnswerType["YesAndSkip"] = 3] = "YesAndSkip";
577
- })(AnswerType || (AnswerType = {}));
578
-
579
666
  const { hitRadiusPoint } = BoundsHelper;
580
- class Pather {
667
+ class Picker {
581
668
  constructor(target, selector) {
582
669
  this.target = target;
583
670
  this.selector = selector;
@@ -589,33 +676,41 @@ class Pather {
589
676
  options = {};
590
677
  const through = options.through || false;
591
678
  const ignoreHittable = options.ignoreHittable || false;
679
+ const target = options.target || this.target;
592
680
  this.exclude = options.exclude || null;
593
681
  this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius };
594
- this.findList = [];
595
- this.eachFind(this.target.children, this.target.__onlyHitMask);
596
- const list = this.findList;
597
- const leaf = this.getBestMatchLeaf();
682
+ this.findList = new LeafList(options.findList);
683
+ if (!options.findList)
684
+ this.hitBranch(target);
685
+ const { list } = this.findList;
686
+ const leaf = this.getBestMatchLeaf(list, options.bottomList, ignoreHittable);
598
687
  const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf);
599
688
  this.clear();
600
- return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf };
689
+ return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf };
601
690
  }
602
- getBestMatchLeaf() {
603
- const { findList: targets } = this;
604
- if (targets.length > 1) {
691
+ getBestMatchLeaf(list, bottomList, ignoreHittable) {
692
+ if (list.length) {
605
693
  let find;
606
- this.findList = [];
694
+ this.findList = new LeafList();
607
695
  const { x, y } = this.point;
608
696
  const point = { x, y, radiusX: 0, radiusY: 0 };
609
- for (let i = 0, len = targets.length; i < len; i++) {
610
- find = targets[i];
611
- if (LeafHelper.worldHittable(find)) {
697
+ for (let i = 0, len = list.length; i < len; i++) {
698
+ find = list[i];
699
+ if (ignoreHittable || LeafHelper.worldHittable(find)) {
612
700
  this.hitChild(find, point);
613
701
  if (this.findList.length)
614
- return this.findList[0];
702
+ return this.findList.list[0];
615
703
  }
616
704
  }
617
705
  }
618
- return targets[0];
706
+ if (bottomList) {
707
+ for (let i = 0, len = bottomList.length; i < len; i++) {
708
+ this.hitChild(bottomList[i].target, this.point, bottomList[i].proxy);
709
+ if (this.findList.length)
710
+ return this.findList.list[0];
711
+ }
712
+ }
713
+ return list[0];
619
714
  }
620
715
  getPath(leaf) {
621
716
  const path = new LeafList();
@@ -627,7 +722,7 @@ class Pather {
627
722
  return path;
628
723
  }
629
724
  getHitablePath(leaf) {
630
- const path = this.getPath(leaf);
725
+ const path = this.getPath(leaf && leaf.hittable ? leaf : null);
631
726
  let item, hittablePath = new LeafList();
632
727
  for (let i = path.list.length - 1; i > -1; i--) {
633
728
  item = path.list[i];
@@ -657,12 +752,15 @@ class Pather {
657
752
  }
658
753
  return throughPath;
659
754
  }
755
+ hitBranch(branch) {
756
+ this.eachFind(branch.children, branch.__onlyHitMask);
757
+ }
660
758
  eachFind(children, hitMask) {
661
759
  let child, hit;
662
760
  const { point } = this, len = children.length;
663
761
  for (let i = len - 1; i > -1; i--) {
664
762
  child = children[i];
665
- if (!child.__.visible || (hitMask && !child.__.isMask))
763
+ if (!child.__.visible || (hitMask && !child.__.mask))
666
764
  continue;
667
765
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
668
766
  if (child.isBranch) {
@@ -678,11 +776,15 @@ class Pather {
678
776
  }
679
777
  }
680
778
  }
681
- hitChild(child, point) {
779
+ hitChild(child, point, proxy) {
682
780
  if (this.exclude && this.exclude.has(child))
683
781
  return;
684
- if (child.__hitWorld(point))
685
- this.findList.push(child);
782
+ if (child.__hitWorld(point)) {
783
+ const { parent } = child;
784
+ if (parent && parent.__hasMask && !child.__.mask && !parent.children.some(item => item.__.mask && item.__hitWorld(point)))
785
+ return;
786
+ this.findList.add(proxy || child);
787
+ }
686
788
  }
687
789
  clear() {
688
790
  this.point = null;
@@ -694,7 +796,8 @@ class Pather {
694
796
  }
695
797
  }
696
798
 
697
- const { Yes, NoAndSkip, YesAndSkip } = AnswerType;
799
+ const { Yes, NoAndSkip, YesAndSkip } = Answer;
800
+ const idCondition = {}, classNameCondition = {}, tagCondition = {};
698
801
  class Selector {
699
802
  constructor(target, userConfig) {
700
803
  this.config = {};
@@ -704,12 +807,13 @@ class Selector {
704
807
  id: (leaf, name) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
705
808
  innerId: (leaf, innerId) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
706
809
  className: (leaf, name) => leaf.className === name ? 1 : 0,
707
- tag: (leaf, name) => leaf.__tag === name ? 1 : 0
810
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0,
811
+ tags: (leaf, nameMap) => nameMap[leaf.__tag] ? 1 : 0
708
812
  };
709
813
  this.target = target;
710
814
  if (userConfig)
711
815
  this.config = DataHelper.default(userConfig, this.config);
712
- this.pather = new Pather(target, this);
816
+ this.picker = new Picker(target, this);
713
817
  this.__listenEvents();
714
818
  }
715
819
  getBy(condition, branch, one, options) {
@@ -720,12 +824,25 @@ class Selector {
720
824
  case 'string':
721
825
  switch (condition[0]) {
722
826
  case '#':
723
- const leaf = this.getById(condition.substring(1), branch);
724
- return one ? leaf : (leaf ? [leaf] : []);
827
+ idCondition.id = condition.substring(1), condition = idCondition;
828
+ break;
725
829
  case '.':
726
- return this.getByMethod(this.methods.className, branch, one, condition.substring(1));
830
+ classNameCondition.className = condition.substring(1), condition = classNameCondition;
831
+ break;
727
832
  default:
728
- return this.getByMethod(this.methods.tag, branch, one, condition);
833
+ tagCondition.tag = condition, condition = tagCondition;
834
+ }
835
+ case 'object':
836
+ if (condition.id !== undefined) {
837
+ const leaf = this.getById(condition.id, branch);
838
+ return one ? leaf : (leaf ? [leaf] : []);
839
+ }
840
+ else if (condition.tag) {
841
+ const { tag } = condition, isArray = tag instanceof Array;
842
+ return this.getByMethod(isArray ? this.methods.tags : this.methods.tag, branch, one, isArray ? DataHelper.toMap(tag) : tag);
843
+ }
844
+ else {
845
+ return this.getByMethod(this.methods.className, branch, one, condition.className);
729
846
  }
730
847
  case 'function':
731
848
  return this.getByMethod(condition, branch, one, options);
@@ -734,7 +851,7 @@ class Selector {
734
851
  getByPoint(hitPoint, hitRadius, options) {
735
852
  if (Platform.name === 'node')
736
853
  this.target.emit(LayoutEvent.CHECK_UPDATE);
737
- return this.pather.getByPoint(hitPoint, hitRadius, options);
854
+ return this.picker.getByPoint(hitPoint, hitRadius, options);
738
855
  }
739
856
  getByInnerId(innerId, branch) {
740
857
  const cache = this.innerIdMap[innerId];
@@ -810,7 +927,7 @@ class Selector {
810
927
  destroy() {
811
928
  if (this.__eventIds.length) {
812
929
  this.__removeListenEvents();
813
- this.pather.destroy();
930
+ this.picker.destroy();
814
931
  this.findLeaf = null;
815
932
  this.innerIdMap = {};
816
933
  this.idMap = {};
@@ -826,199 +943,428 @@ Object.assign(Creator, {
826
943
  });
827
944
  Platform.layout = Layouter.fullLayout;
828
945
 
829
- class LeaferCanvas extends LeaferCanvasBase {
830
- get allowBackgroundColor() { return true; }
831
- init() {
832
- this.__createView();
833
- this.__createContext();
834
- this.resize(this.config);
835
- }
836
- __createView() {
837
- this.view = Platform.origin.createCanvas(1, 1);
838
- }
839
- updateViewSize() {
840
- const { width, height, pixelRatio } = this;
841
- this.view.width = width * pixelRatio;
842
- this.view.height = height * pixelRatio;
843
- this.clientBounds = this.bounds;
844
- }
845
- }
846
-
847
- canvasPatch(OffscreenCanvasRenderingContext2D.prototype);
848
- canvasPatch(Path2D.prototype);
849
-
850
- const { mineType } = FileHelper;
851
- Object.assign(Creator, {
852
- canvas: (options, manager) => new LeaferCanvas(options, manager),
853
- image: (options) => new LeaferImage(options),
854
- hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
855
- interaction: (target, canvas, selector, options) => new InteractionBase(target, canvas, selector, options),
856
- });
857
- function useCanvas(_canvasType, _power) {
858
- Platform.origin = {
859
- createCanvas: (width, height) => new OffscreenCanvas(width, height),
860
- canvasToDataURL: (canvas, type, quality) => {
861
- return new Promise((resolve, reject) => {
862
- canvas.convertToBlob({ type: mineType(type), quality }).then((blob) => {
863
- var reader = new FileReader();
864
- reader.onload = (e) => resolve(e.target.result);
865
- reader.onerror = (e) => reject(e);
866
- reader.readAsDataURL(blob);
867
- }).catch((e) => {
868
- reject(e);
869
- });
870
- });
871
- },
872
- canvasToBolb: (canvas, type, quality) => canvas.convertToBlob({ type: mineType(type), quality }),
873
- canvasSaveAs: (_canvas, _filename, _quality) => new Promise((resolve) => resolve()),
874
- loadImage(src) {
875
- return new Promise((resolve, reject) => {
876
- if (!src.startsWith('data:') && Platform.image.suffix)
877
- src += (src.includes("?") ? "&" : "?") + Platform.image.suffix;
878
- let req = new XMLHttpRequest();
879
- req.open('GET', src, true);
880
- req.responseType = "blob";
881
- req.onload = () => {
882
- createImageBitmap(req.response).then(img => {
883
- resolve(img);
884
- }).catch(e => {
885
- reject(e);
886
- });
887
- };
888
- req.onerror = (e) => reject(e);
889
- req.send();
946
+ function fillText(ui, canvas) {
947
+ let row;
948
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
949
+ for (let i = 0, len = rows.length; i < len; i++) {
950
+ row = rows[i];
951
+ if (row.text) {
952
+ canvas.fillText(row.text, row.x, row.y);
953
+ }
954
+ else if (row.data) {
955
+ row.data.forEach(charData => {
956
+ canvas.fillText(charData.char, charData.x, row.y);
890
957
  });
891
958
  }
892
- };
893
- Platform.canvas = Creator.canvas();
894
- Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
895
- }
896
- Platform.name = 'web';
897
- Platform.isWorker = true;
898
- Platform.requestRender = function (render) { requestAnimationFrame(render); };
899
- Platform.devicePixelRatio = 1;
900
- const { userAgent } = navigator;
901
- if (userAgent.indexOf("Firefox") > -1) {
902
- Platform.conicGradientRotate90 = true;
903
- Platform.intWheelDeltaY = true;
904
- }
905
- else if (userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") === -1) {
906
- Platform.fullImageShadow = true;
907
- }
908
- if (userAgent.indexOf('Windows') > -1) {
909
- Platform.os = 'Windows';
910
- Platform.intWheelDeltaY = true;
911
- }
912
- else if (userAgent.indexOf('Mac') > -1) {
913
- Platform.os = 'Mac';
914
- }
915
- else if (userAgent.indexOf('Linux') > -1) {
916
- Platform.os = 'Linux';
959
+ if (decorationY)
960
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
961
+ }
917
962
  }
918
963
 
919
- let origin = {};
920
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
921
- function fillOrFitMode(data, mode, box, width, height, rotation) {
922
- const transform = get$4();
923
- const swap = rotation && rotation !== 180;
924
- const sw = box.width / (swap ? height : width);
925
- const sh = box.height / (swap ? width : height);
926
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
927
- const x = box.x + (box.width - width * scale) / 2;
928
- const y = box.y + (box.height - height * scale) / 2;
929
- translate$1(transform, x, y);
930
- scaleHelper(transform, scale);
931
- if (rotation)
932
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
933
- data.scaleX = data.scaleY = scale;
934
- data.transform = transform;
935
- }
936
- function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
937
- const transform = get$4();
938
- translate$1(transform, box.x, box.y);
939
- if (x || y)
940
- translate$1(transform, x, y);
941
- if (scaleX) {
942
- scaleHelper(transform, scaleX, scaleY);
943
- data.scaleX = transform.a;
944
- data.scaleY = transform.d;
945
- }
946
- if (rotation)
947
- rotate(transform, rotation);
948
- data.transform = transform;
964
+ function fill(fill, ui, canvas) {
965
+ canvas.fillStyle = fill;
966
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
949
967
  }
950
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
951
- const transform = get$4();
952
- if (rotation) {
953
- rotate(transform, rotation);
954
- switch (rotation) {
955
- case 90:
956
- translate$1(transform, height, 0);
957
- break;
958
- case 180:
959
- translate$1(transform, width, height);
960
- break;
961
- case 270:
962
- translate$1(transform, 0, width);
963
- break;
968
+ function fills(fills, ui, canvas) {
969
+ let item;
970
+ const { windingRule, __font } = ui.__;
971
+ for (let i = 0, len = fills.length; i < len; i++) {
972
+ item = fills[i];
973
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
974
+ continue;
975
+ if (item.style) {
976
+ canvas.fillStyle = item.style;
977
+ if (item.transform) {
978
+ canvas.save();
979
+ canvas.transform(item.transform);
980
+ if (item.blendMode)
981
+ canvas.blendMode = item.blendMode;
982
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
983
+ canvas.restore();
984
+ }
985
+ else {
986
+ if (item.blendMode) {
987
+ canvas.saveBlendMode(item.blendMode);
988
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
989
+ canvas.restoreBlendMode();
990
+ }
991
+ else {
992
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
993
+ }
994
+ }
964
995
  }
965
996
  }
966
- origin.x = box.x;
967
- origin.y = box.y;
968
- if (x || y)
969
- origin.x += x, origin.y += y;
970
- translate$1(transform, origin.x, origin.y);
971
- if (scaleX) {
972
- scaleOfOuter$2(transform, origin, scaleX, scaleY);
973
- data.scaleX = scaleX;
974
- data.scaleY = scaleY;
975
- }
976
- data.transform = transform;
977
997
  }
978
998
 
979
- const { get: get$3, translate } = MatrixHelper;
980
- function createData(leafPaint, image, paint, box) {
981
- let { width, height } = image;
982
- const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
983
- const sameBox = box.width === width && box.height === height;
984
- if (blendMode)
985
- leafPaint.blendMode = blendMode;
986
- const data = leafPaint.data = { mode };
987
- let x, y, scaleX, scaleY;
988
- if (offset)
989
- x = offset.x, y = offset.y;
990
- if (size) {
991
- scaleX = (typeof size === 'number' ? size : size.width) / width;
992
- scaleY = (typeof size === 'number' ? size : size.height) / height;
993
- }
994
- else if (scale) {
995
- scaleX = typeof scale === 'number' ? scale : scale.x;
996
- scaleY = typeof scale === 'number' ? scale : scale.y;
997
- }
999
+ function strokeText(stroke, ui, canvas) {
1000
+ const { strokeAlign } = ui.__;
1001
+ const isStrokes = typeof stroke !== 'string';
1002
+ switch (strokeAlign) {
1003
+ case 'center':
1004
+ canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1005
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1006
+ break;
1007
+ case 'inside':
1008
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1009
+ break;
1010
+ case 'outside':
1011
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1012
+ break;
1013
+ }
1014
+ }
1015
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1016
+ const { __strokeWidth, __font } = ui.__;
1017
+ const out = canvas.getSameCanvas(true, true);
1018
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1019
+ out.font = __font;
1020
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1021
+ out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1022
+ fillText(ui, out);
1023
+ out.blendMode = 'normal';
1024
+ if (ui.__worldFlipped) {
1025
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1026
+ }
1027
+ else {
1028
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1029
+ }
1030
+ out.recycle(ui.__nowWorld);
1031
+ }
1032
+ function drawTextStroke(ui, canvas) {
1033
+ let row;
1034
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1035
+ for (let i = 0, len = rows.length; i < len; i++) {
1036
+ row = rows[i];
1037
+ if (row.text) {
1038
+ canvas.strokeText(row.text, row.x, row.y);
1039
+ }
1040
+ else if (row.data) {
1041
+ row.data.forEach(charData => {
1042
+ canvas.strokeText(charData.char, charData.x, row.y);
1043
+ });
1044
+ }
1045
+ if (decorationY)
1046
+ canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1047
+ }
1048
+ }
1049
+ function drawStrokesStyle(strokes, isText, ui, canvas) {
1050
+ let item;
1051
+ for (let i = 0, len = strokes.length; i < len; i++) {
1052
+ item = strokes[i];
1053
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1054
+ continue;
1055
+ if (item.style) {
1056
+ canvas.strokeStyle = item.style;
1057
+ if (item.blendMode) {
1058
+ canvas.saveBlendMode(item.blendMode);
1059
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1060
+ canvas.restoreBlendMode();
1061
+ }
1062
+ else {
1063
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1064
+ }
1065
+ }
1066
+ }
1067
+ }
1068
+
1069
+ function stroke(stroke, ui, canvas) {
1070
+ const options = ui.__;
1071
+ const { __strokeWidth, strokeAlign, __font } = options;
1072
+ if (!__strokeWidth)
1073
+ return;
1074
+ if (__font) {
1075
+ strokeText(stroke, ui, canvas);
1076
+ }
1077
+ else {
1078
+ switch (strokeAlign) {
1079
+ case 'center':
1080
+ canvas.setStroke(stroke, __strokeWidth, options);
1081
+ canvas.stroke();
1082
+ break;
1083
+ case 'inside':
1084
+ canvas.save();
1085
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1086
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1087
+ canvas.stroke();
1088
+ canvas.restore();
1089
+ break;
1090
+ case 'outside':
1091
+ const out = canvas.getSameCanvas(true, true);
1092
+ out.setStroke(stroke, __strokeWidth * 2, options);
1093
+ ui.__drawRenderPath(out);
1094
+ out.stroke();
1095
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1096
+ out.clearWorld(ui.__layout.renderBounds);
1097
+ if (ui.__worldFlipped) {
1098
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1099
+ }
1100
+ else {
1101
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1102
+ }
1103
+ out.recycle(ui.__nowWorld);
1104
+ break;
1105
+ }
1106
+ }
1107
+ }
1108
+ function strokes(strokes, ui, canvas) {
1109
+ const options = ui.__;
1110
+ const { __strokeWidth, strokeAlign, __font } = options;
1111
+ if (!__strokeWidth)
1112
+ return;
1113
+ if (__font) {
1114
+ strokeText(strokes, ui, canvas);
1115
+ }
1116
+ else {
1117
+ switch (strokeAlign) {
1118
+ case 'center':
1119
+ canvas.setStroke(undefined, __strokeWidth, options);
1120
+ drawStrokesStyle(strokes, false, ui, canvas);
1121
+ break;
1122
+ case 'inside':
1123
+ canvas.save();
1124
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1125
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1126
+ drawStrokesStyle(strokes, false, ui, canvas);
1127
+ canvas.restore();
1128
+ break;
1129
+ case 'outside':
1130
+ const { renderBounds } = ui.__layout;
1131
+ const out = canvas.getSameCanvas(true, true);
1132
+ ui.__drawRenderPath(out);
1133
+ out.setStroke(undefined, __strokeWidth * 2, options);
1134
+ drawStrokesStyle(strokes, false, ui, out);
1135
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1136
+ out.clearWorld(renderBounds);
1137
+ if (ui.__worldFlipped) {
1138
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1139
+ }
1140
+ else {
1141
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1142
+ }
1143
+ out.recycle(ui.__nowWorld);
1144
+ break;
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1150
+ function shape(ui, current, options) {
1151
+ const canvas = current.getSameCanvas();
1152
+ const nowWorld = ui.__nowWorld;
1153
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1154
+ let { scaleX, scaleY } = nowWorld;
1155
+ if (scaleX < 0)
1156
+ scaleX = -scaleX;
1157
+ if (scaleY < 0)
1158
+ scaleY = -scaleY;
1159
+ if (current.bounds.includes(nowWorld)) {
1160
+ worldCanvas = canvas;
1161
+ bounds = shapeBounds = nowWorld;
1162
+ }
1163
+ else {
1164
+ const { renderShapeSpread: spread } = ui.__layout;
1165
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, scaleX === scaleY ? spread * scaleX : [spread * scaleY, spread * scaleX]) : current.bounds, nowWorld);
1166
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1167
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1168
+ if (fitMatrix.a < 1) {
1169
+ worldCanvas = current.getSameCanvas();
1170
+ ui.__renderShape(worldCanvas, options);
1171
+ scaleX *= fitScaleX;
1172
+ scaleY *= fitScaleY;
1173
+ }
1174
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1175
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1176
+ if (options.matrix) {
1177
+ const { matrix } = options;
1178
+ fitMatrix.multiply(matrix);
1179
+ fitScaleX *= matrix.scaleX;
1180
+ fitScaleY *= matrix.scaleY;
1181
+ }
1182
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1183
+ }
1184
+ ui.__renderShape(canvas, options);
1185
+ return {
1186
+ canvas, matrix: fitMatrix, bounds,
1187
+ worldCanvas, shapeBounds, scaleX, scaleY
1188
+ };
1189
+ }
1190
+
1191
+ let recycleMap;
1192
+ function compute(attrName, ui) {
1193
+ const data = ui.__, leafPaints = [];
1194
+ let paints = data.__input[attrName], hasOpacityPixel;
1195
+ if (!(paints instanceof Array))
1196
+ paints = [paints];
1197
+ recycleMap = PaintImage.recycleImage(attrName, data);
1198
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1199
+ item = getLeafPaint(attrName, paints[i], ui);
1200
+ if (item)
1201
+ leafPaints.push(item);
1202
+ }
1203
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1204
+ if (leafPaints.length && leafPaints[0].image)
1205
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1206
+ if (attrName === 'fill') {
1207
+ data.__pixelFill = hasOpacityPixel;
1208
+ }
1209
+ else {
1210
+ data.__pixelStroke = hasOpacityPixel;
1211
+ }
1212
+ }
1213
+ function getLeafPaint(attrName, paint, ui) {
1214
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1215
+ return undefined;
1216
+ const { boxBounds } = ui.__layout;
1217
+ switch (paint.type) {
1218
+ case 'solid':
1219
+ let { type, blendMode, color, opacity } = paint;
1220
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1221
+ case 'image':
1222
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1223
+ case 'linear':
1224
+ return PaintGradient.linearGradient(paint, boxBounds);
1225
+ case 'radial':
1226
+ return PaintGradient.radialGradient(paint, boxBounds);
1227
+ case 'angular':
1228
+ return PaintGradient.conicGradient(paint, boxBounds);
1229
+ default:
1230
+ return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1231
+ }
1232
+ }
1233
+
1234
+ const PaintModule = {
1235
+ compute,
1236
+ fill,
1237
+ fills,
1238
+ fillText,
1239
+ stroke,
1240
+ strokes,
1241
+ strokeText,
1242
+ drawTextStroke,
1243
+ shape
1244
+ };
1245
+
1246
+ let origin = {};
1247
+ const { get: get$3, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, scale: scaleHelper, rotate } = MatrixHelper;
1248
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1249
+ const transform = get$3();
1250
+ translate$1(transform, box.x + x, box.y + y);
1251
+ scaleHelper(transform, scaleX, scaleY);
1252
+ if (rotation)
1253
+ rotateOfOuter$1(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1254
+ data.transform = transform;
1255
+ }
1256
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
1257
+ const transform = get$3();
1258
+ translate$1(transform, box.x + x, box.y + y);
1259
+ if (scaleX)
1260
+ scaleHelper(transform, scaleX, scaleY);
1261
+ if (rotation)
1262
+ rotate(transform, rotation);
1263
+ data.transform = transform;
1264
+ }
1265
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align) {
1266
+ const transform = get$3();
1267
+ if (rotation) {
1268
+ if (align === 'center') {
1269
+ rotateOfOuter$1(transform, { x: width / 2, y: height / 2 }, rotation);
1270
+ }
1271
+ else {
1272
+ rotate(transform, rotation);
1273
+ switch (rotation) {
1274
+ case 90:
1275
+ translate$1(transform, height, 0);
1276
+ break;
1277
+ case 180:
1278
+ translate$1(transform, width, height);
1279
+ break;
1280
+ case 270:
1281
+ translate$1(transform, 0, width);
1282
+ break;
1283
+ }
1284
+ }
1285
+ }
1286
+ origin.x = box.x + x;
1287
+ origin.y = box.y + y;
1288
+ translate$1(transform, origin.x, origin.y);
1289
+ if (scaleX)
1290
+ scaleOfOuter$1(transform, origin, scaleX, scaleY);
1291
+ data.transform = transform;
1292
+ }
1293
+
1294
+ const { get: get$2, translate } = MatrixHelper;
1295
+ const tempBox = new Bounds();
1296
+ const tempPoint = {};
1297
+ function createData(leafPaint, image, paint, box) {
1298
+ const { blendMode } = paint;
1299
+ if (blendMode)
1300
+ leafPaint.blendMode = blendMode;
1301
+ leafPaint.data = getPatternData(paint, box, image);
1302
+ }
1303
+ function getPatternData(paint, box, image) {
1304
+ let { width, height } = image;
1305
+ if (paint.padding)
1306
+ box = tempBox.set(box).shrink(paint.padding);
1307
+ const { opacity, mode, align, offset, scale, size, rotation, repeat } = paint;
1308
+ const sameBox = box.width === width && box.height === height;
1309
+ const data = { mode };
1310
+ const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1311
+ const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1312
+ let x = 0, y = 0, scaleX, scaleY;
1313
+ if (!mode || mode === 'cover' || mode === 'fit') {
1314
+ if (!sameBox || rotation) {
1315
+ const sw = box.width / swapWidth, sh = box.height / swapHeight;
1316
+ scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1317
+ x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1318
+ }
1319
+ }
1320
+ else if (size) {
1321
+ scaleX = (typeof size === 'number' ? size : size.width) / width;
1322
+ scaleY = (typeof size === 'number' ? size : size.height) / height;
1323
+ }
1324
+ else if (scale) {
1325
+ scaleX = typeof scale === 'number' ? scale : scale.x;
1326
+ scaleY = typeof scale === 'number' ? scale : scale.y;
1327
+ }
1328
+ if (align) {
1329
+ const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1330
+ if (scaleX)
1331
+ imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1332
+ AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1333
+ x += tempPoint.x, y += tempPoint.y;
1334
+ }
1335
+ if (offset)
1336
+ x += offset.x, y += offset.y;
998
1337
  switch (mode) {
999
1338
  case 'strench':
1000
1339
  if (!sameBox)
1001
1340
  width = box.width, height = box.height;
1002
- if (box.x || box.y) {
1003
- data.transform = get$3();
1004
- translate(data.transform, box.x, box.y);
1005
- }
1006
1341
  break;
1342
+ case 'normal':
1007
1343
  case 'clip':
1008
- if (offset || scaleX || rotation)
1344
+ if (x || y || scaleX || rotation)
1009
1345
  clipMode(data, box, x, y, scaleX, scaleY, rotation);
1010
1346
  break;
1011
1347
  case 'repeat':
1012
1348
  if (!sameBox || scaleX || rotation)
1013
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1349
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1014
1350
  if (!repeat)
1015
1351
  data.repeat = 'repeat';
1016
1352
  break;
1017
1353
  case 'fit':
1018
1354
  case 'cover':
1019
1355
  default:
1020
- if (!sameBox || rotation)
1021
- fillOrFitMode(data, mode, box, width, height, rotation);
1356
+ if (scaleX)
1357
+ fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1358
+ }
1359
+ if (!data.transform) {
1360
+ if (box.x || box.y) {
1361
+ data.transform = get$2();
1362
+ translate(data.transform, box.x, box.y);
1363
+ }
1364
+ }
1365
+ if (scaleX && mode !== 'strench') {
1366
+ data.scaleX = scaleX;
1367
+ data.scaleY = scaleY;
1022
1368
  }
1023
1369
  data.width = width;
1024
1370
  data.height = height;
@@ -1026,112 +1372,108 @@ function createData(leafPaint, image, paint, box) {
1026
1372
  data.opacity = opacity;
1027
1373
  if (repeat)
1028
1374
  data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1375
+ return data;
1029
1376
  }
1030
1377
 
1031
- function image(ui, attrName, attrValue, box, firstUse) {
1032
- const leafPaint = { type: attrValue.type };
1033
- const image = leafPaint.image = ImageManager.get(attrValue);
1034
- const event = (firstUse || image.loading) && { target: ui, image, attrName, attrValue };
1378
+ let cache, box = new Bounds();
1379
+ const { isSame } = BoundsHelper;
1380
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1381
+ let leafPaint, event;
1382
+ const image = ImageManager.get(paint);
1383
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1384
+ leafPaint = cache.leafPaint;
1385
+ }
1386
+ else {
1387
+ leafPaint = { type: paint.type, image };
1388
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1389
+ }
1390
+ if (firstUse || image.loading)
1391
+ event = { image, attrName, attrValue: paint };
1035
1392
  if (image.ready) {
1036
- if (hasNaturalSize(ui, attrName, image))
1037
- createData(leafPaint, image, attrValue, box);
1393
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1038
1394
  if (firstUse) {
1039
- emit(ImageEvent.LOAD, event);
1040
- emit(ImageEvent.LOADED, event);
1395
+ onLoad(ui, event);
1396
+ onLoadSuccess(ui, event);
1041
1397
  }
1042
1398
  }
1043
1399
  else if (image.error) {
1044
- if (firstUse) {
1045
- ui.forceUpdate('surface');
1046
- event.error = image.error;
1047
- emit(ImageEvent.ERROR, event);
1048
- }
1400
+ if (firstUse)
1401
+ onLoadError(ui, event, image.error);
1049
1402
  }
1050
1403
  else {
1404
+ ignoreRender(ui, true);
1051
1405
  if (firstUse)
1052
- emit(ImageEvent.LOAD, event);
1406
+ onLoad(ui, event);
1053
1407
  leafPaint.loadId = image.load(() => {
1408
+ ignoreRender(ui, false);
1054
1409
  if (!ui.destroyed) {
1055
- if (hasNaturalSize(ui, attrName, image)) {
1056
- createData(leafPaint, image, attrValue, box);
1410
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1411
+ if (image.hasOpacityPixel)
1412
+ ui.__layout.hitCanvasChanged = true;
1057
1413
  ui.forceUpdate('surface');
1058
1414
  }
1059
- emit(ImageEvent.LOADED, event);
1415
+ onLoadSuccess(ui, event);
1060
1416
  }
1417
+ leafPaint.loadId = null;
1061
1418
  }, (error) => {
1062
- ui.forceUpdate('surface');
1063
- event.error = error;
1064
- emit(ImageEvent.ERROR, event);
1419
+ ignoreRender(ui, false);
1420
+ onLoadError(ui, event, error);
1421
+ leafPaint.loadId = null;
1065
1422
  });
1066
1423
  }
1067
1424
  return leafPaint;
1068
1425
  }
1069
- function hasNaturalSize(ui, attrName, image) {
1426
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1070
1427
  if (attrName === 'fill' && !ui.__.__naturalWidth) {
1071
- const { __: d } = ui;
1072
- d.__naturalWidth = image.width;
1073
- d.__naturalHeight = image.height;
1074
- if (!d.__getInput('width') || !d.__getInput('height')) {
1428
+ const data = ui.__;
1429
+ data.__naturalWidth = image.width / data.pixelRatio;
1430
+ data.__naturalHeight = image.height / data.pixelRatio;
1431
+ if (data.__autoSide) {
1075
1432
  ui.forceUpdate('width');
1076
1433
  if (ui.__proxyData) {
1077
- ui.setProxyAttr('width', ui.__.width);
1078
- ui.setProxyAttr('height', ui.__.height);
1434
+ ui.setProxyAttr('width', data.width);
1435
+ ui.setProxyAttr('height', data.height);
1079
1436
  }
1080
1437
  return false;
1081
1438
  }
1082
1439
  }
1440
+ if (!leafPaint.data)
1441
+ createData(leafPaint, image, paint, boxBounds);
1083
1442
  return true;
1084
1443
  }
1085
- function emit(type, data) {
1086
- if (data.target.hasEvent(type))
1087
- data.target.emitEvent(new ImageEvent(type, data));
1444
+ function onLoad(ui, event) {
1445
+ emit(ui, ImageEvent.LOAD, event);
1446
+ }
1447
+ function onLoadSuccess(ui, event) {
1448
+ emit(ui, ImageEvent.LOADED, event);
1449
+ }
1450
+ function onLoadError(ui, event, error) {
1451
+ event.error = error;
1452
+ ui.forceUpdate('surface');
1453
+ emit(ui, ImageEvent.ERROR, event);
1454
+ }
1455
+ function emit(ui, type, data) {
1456
+ if (ui.hasEvent(type))
1457
+ ui.emitEvent(new ImageEvent(type, data));
1458
+ }
1459
+ function ignoreRender(ui, value) {
1460
+ const { leafer } = ui;
1461
+ if (leafer && leafer.viewReady)
1462
+ leafer.renderer.ignore = value;
1088
1463
  }
1089
1464
 
1090
- /******************************************************************************
1091
- Copyright (c) Microsoft Corporation.
1092
-
1093
- Permission to use, copy, modify, and/or distribute this software for any
1094
- purpose with or without fee is hereby granted.
1095
-
1096
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1097
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1098
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1099
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1100
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1101
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1102
- PERFORMANCE OF THIS SOFTWARE.
1103
- ***************************************************************************** */
1104
- /* global Reflect, Promise, SuppressedError, Symbol */
1105
-
1106
-
1107
- function __awaiter(thisArg, _arguments, P, generator) {
1108
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1109
- return new (P || (P = Promise))(function (resolve, reject) {
1110
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1111
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1112
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1113
- step((generator = generator.apply(thisArg, _arguments || [])).next());
1114
- });
1115
- }
1116
-
1117
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1118
- var e = new Error(message);
1119
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1120
- };
1121
-
1122
- const Export$1 = {};
1123
-
1124
- const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1465
+ const { get: get$1, scale, copy: copy$1 } = MatrixHelper;
1466
+ const { ceil, abs: abs$1 } = Math;
1125
1467
  function createPattern(ui, paint, pixelRatio) {
1126
- let { scaleX, scaleY } = ui.__world;
1468
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1127
1469
  const id = scaleX + '-' + scaleY;
1128
1470
  if (paint.patternId !== id && !ui.destroyed) {
1129
- scaleX = Math.abs(scaleX);
1130
- scaleY = Math.abs(scaleY);
1471
+ scaleX = abs$1(scaleX);
1472
+ scaleY = abs$1(scaleY);
1131
1473
  const { image, data } = paint;
1132
1474
  let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1133
1475
  if (sx) {
1134
- imageMatrix = get$2();
1476
+ imageMatrix = get$1();
1135
1477
  copy$1(imageMatrix, transform);
1136
1478
  scale(imageMatrix, 1 / sx, 1 / sy);
1137
1479
  scaleX *= sx;
@@ -1166,22 +1508,14 @@ function createPattern(ui, paint, pixelRatio) {
1166
1508
  }
1167
1509
  if (transform || scaleX !== 1 || scaleY !== 1) {
1168
1510
  if (!imageMatrix) {
1169
- imageMatrix = get$2();
1511
+ imageMatrix = get$1();
1170
1512
  if (transform)
1171
1513
  copy$1(imageMatrix, transform);
1172
1514
  }
1173
1515
  scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1174
1516
  }
1175
- const pattern = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), repeat || (Platform.origin.noRepeat || 'no-repeat'));
1176
- try {
1177
- if (paint.transform)
1178
- paint.transform = null;
1179
- if (imageMatrix)
1180
- pattern.setTransform ? pattern.setTransform(imageMatrix) : paint.transform = imageMatrix;
1181
- }
1182
- catch (_a) {
1183
- paint.transform = imageMatrix;
1184
- }
1517
+ const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, opacity);
1518
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1185
1519
  paint.style = pattern;
1186
1520
  paint.patternId = id;
1187
1521
  return true;
@@ -1191,10 +1525,42 @@ function createPattern(ui, paint, pixelRatio) {
1191
1525
  }
1192
1526
  }
1193
1527
 
1528
+ /******************************************************************************
1529
+ Copyright (c) Microsoft Corporation.
1530
+
1531
+ Permission to use, copy, modify, and/or distribute this software for any
1532
+ purpose with or without fee is hereby granted.
1533
+
1534
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1535
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1536
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1537
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1538
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1539
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1540
+ PERFORMANCE OF THIS SOFTWARE.
1541
+ ***************************************************************************** */
1542
+ /* global Reflect, Promise, SuppressedError, Symbol */
1543
+
1544
+
1545
+ function __awaiter(thisArg, _arguments, P, generator) {
1546
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1547
+ return new (P || (P = Promise))(function (resolve, reject) {
1548
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1549
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1550
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1551
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1552
+ });
1553
+ }
1554
+
1555
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1556
+ var e = new Error(message);
1557
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1558
+ };
1559
+
1194
1560
  const { abs } = Math;
1195
1561
  function checkImage(ui, canvas, paint, allowPaint) {
1196
- const { scaleX, scaleY } = ui.__world;
1197
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1562
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1563
+ if (!paint.data || (paint.patternId === scaleX + '-' + scaleY && !Export.running)) {
1198
1564
  return false;
1199
1565
  }
1200
1566
  else {
@@ -1208,326 +1574,91 @@ function checkImage(ui, canvas, paint, allowPaint) {
1208
1574
  width *= data.scaleX;
1209
1575
  height *= data.scaleY;
1210
1576
  }
1211
- allowPaint = width * height > Platform.image.maxCacheSize;
1577
+ allowPaint = (width * height > Platform.image.maxCacheSize) || Export.running;
1212
1578
  }
1213
1579
  else {
1214
1580
  allowPaint = false;
1215
1581
  }
1216
1582
  }
1217
- if (allowPaint) {
1218
- canvas.save();
1219
- canvas.clip();
1220
- if (paint.blendMode)
1221
- canvas.blendMode = paint.blendMode;
1222
- if (data.opacity)
1223
- canvas.opacity *= data.opacity;
1224
- if (data.transform)
1225
- canvas.transform(data.transform);
1226
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1227
- canvas.restore();
1228
- return true;
1229
- }
1230
- else {
1231
- if (!paint.style || Export$1.running) {
1232
- createPattern(ui, paint, canvas.pixelRatio);
1233
- }
1234
- else {
1235
- if (!paint.patternTask) {
1236
- paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1237
- paint.patternTask = null;
1238
- if (canvas.bounds.hit(ui.__world))
1239
- createPattern(ui, paint, canvas.pixelRatio);
1240
- ui.forceUpdate('surface');
1241
- }), 300);
1242
- }
1243
- }
1244
- return false;
1245
- }
1246
- }
1247
- }
1248
-
1249
- function recycleImage(attrName, data) {
1250
- const paints = data['_' + attrName];
1251
- if (paints instanceof Array) {
1252
- let image, recycleMap, input, url;
1253
- for (let i = 0, len = paints.length; i < len; i++) {
1254
- image = paints[i].image;
1255
- url = image && image.url;
1256
- if (url) {
1257
- if (!recycleMap)
1258
- recycleMap = {};
1259
- recycleMap[url] = true;
1260
- ImageManager.recycle(image);
1261
- if (image.loading) {
1262
- if (!input) {
1263
- input = (data.__input && data.__input[attrName]) || [];
1264
- if (!(input instanceof Array))
1265
- input = [input];
1266
- }
1267
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1268
- }
1269
- }
1270
- }
1271
- return recycleMap;
1272
- }
1273
- return null;
1274
- }
1275
-
1276
- function fillText(ui, canvas) {
1277
- let row;
1278
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1279
- for (let i = 0, len = rows.length; i < len; i++) {
1280
- row = rows[i];
1281
- if (row.text) {
1282
- canvas.fillText(row.text, row.x, row.y);
1283
- }
1284
- else if (row.data) {
1285
- row.data.forEach(charData => {
1286
- canvas.fillText(charData.char, charData.x, row.y);
1287
- });
1288
- }
1289
- if (decorationY)
1290
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1291
- }
1292
- }
1293
-
1294
- function fill(fill, ui, canvas) {
1295
- canvas.fillStyle = fill;
1296
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1297
- }
1298
- function fills(fills, ui, canvas) {
1299
- let item;
1300
- const { windingRule, __font } = ui.__;
1301
- for (let i = 0, len = fills.length; i < len; i++) {
1302
- item = fills[i];
1303
- if (item.image && checkImage(ui, canvas, item, !__font))
1304
- continue;
1305
- if (item.style) {
1306
- canvas.fillStyle = item.style;
1307
- if (item.transform) {
1308
- canvas.save();
1309
- canvas.transform(item.transform);
1310
- if (item.blendMode)
1311
- canvas.blendMode = item.blendMode;
1312
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1313
- canvas.restore();
1314
- }
1315
- else {
1316
- if (item.blendMode) {
1317
- canvas.saveBlendMode(item.blendMode);
1318
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1319
- canvas.restoreBlendMode();
1320
- }
1321
- else {
1322
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1323
- }
1324
- }
1325
- }
1326
- }
1327
- }
1328
-
1329
- function strokeText(stroke, ui, canvas, renderOptions) {
1330
- const { strokeAlign } = ui.__;
1331
- const isStrokes = typeof stroke !== 'string';
1332
- switch (strokeAlign) {
1333
- case 'center':
1334
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1335
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1336
- break;
1337
- case 'inside':
1338
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas, renderOptions);
1339
- break;
1340
- case 'outside':
1341
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas, renderOptions);
1342
- break;
1343
- }
1344
- }
1345
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas, renderOptions) {
1346
- const { strokeWidth, __font } = ui.__;
1347
- const out = canvas.getSameCanvas(true);
1348
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1349
- out.font = __font;
1350
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1351
- out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1352
- fillText(ui, out);
1353
- out.blendMode = 'normal';
1354
- if (ui.__worldFlipped || renderOptions.matrix) {
1355
- canvas.copyWorldByReset(out);
1356
- }
1357
- else {
1358
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1359
- }
1360
- out.recycle();
1361
- }
1362
- function drawTextStroke(ui, canvas) {
1363
- let row;
1364
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1365
- for (let i = 0, len = rows.length; i < len; i++) {
1366
- row = rows[i];
1367
- if (row.text) {
1368
- canvas.strokeText(row.text, row.x, row.y);
1369
- }
1370
- else if (row.data) {
1371
- row.data.forEach(charData => {
1372
- canvas.strokeText(charData.char, charData.x, row.y);
1373
- });
1374
- }
1375
- if (decorationY)
1376
- canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1377
- }
1378
- }
1379
- function drawStrokesStyle(strokes, isText, ui, canvas) {
1380
- let item;
1381
- for (let i = 0, len = strokes.length; i < len; i++) {
1382
- item = strokes[i];
1383
- if (item.image && checkImage(ui, canvas, item, false))
1384
- continue;
1385
- if (item.style) {
1386
- canvas.strokeStyle = item.style;
1387
- if (item.blendMode) {
1388
- canvas.saveBlendMode(item.blendMode);
1389
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1390
- canvas.restoreBlendMode();
1583
+ if (allowPaint) {
1584
+ canvas.save();
1585
+ canvas.clip();
1586
+ if (paint.blendMode)
1587
+ canvas.blendMode = paint.blendMode;
1588
+ if (data.opacity)
1589
+ canvas.opacity *= data.opacity;
1590
+ if (data.transform)
1591
+ canvas.transform(data.transform);
1592
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1593
+ canvas.restore();
1594
+ return true;
1595
+ }
1596
+ else {
1597
+ if (!paint.style || Export.running) {
1598
+ createPattern(ui, paint, canvas.pixelRatio);
1391
1599
  }
1392
1600
  else {
1393
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1601
+ if (!paint.patternTask) {
1602
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1603
+ paint.patternTask = null;
1604
+ if (canvas.bounds.hit(ui.__nowWorld))
1605
+ createPattern(ui, paint, canvas.pixelRatio);
1606
+ ui.forceUpdate('surface');
1607
+ }), 300);
1608
+ }
1394
1609
  }
1610
+ return false;
1395
1611
  }
1396
1612
  }
1397
1613
  }
1398
1614
 
1399
- function stroke(stroke, ui, canvas, renderOptions) {
1400
- const options = ui.__;
1401
- const { strokeWidth, strokeAlign, __font } = options;
1402
- if (!strokeWidth)
1403
- return;
1404
- if (__font) {
1405
- strokeText(stroke, ui, canvas, renderOptions);
1406
- }
1407
- else {
1408
- switch (strokeAlign) {
1409
- case 'center':
1410
- canvas.setStroke(stroke, strokeWidth, options);
1411
- canvas.stroke();
1412
- break;
1413
- case 'inside':
1414
- canvas.save();
1415
- canvas.setStroke(stroke, strokeWidth * 2, options);
1416
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1417
- canvas.stroke();
1418
- canvas.restore();
1419
- break;
1420
- case 'outside':
1421
- const out = canvas.getSameCanvas(true);
1422
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1423
- ui.__drawRenderPath(out);
1424
- out.stroke();
1425
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1426
- out.clearWorld(ui.__layout.renderBounds);
1427
- if (ui.__worldFlipped || renderOptions.matrix) {
1428
- canvas.copyWorldByReset(out);
1429
- }
1430
- else {
1431
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1432
- }
1433
- out.recycle();
1434
- break;
1435
- }
1436
- }
1437
- }
1438
- function strokes(strokes, ui, canvas, renderOptions) {
1439
- const options = ui.__;
1440
- const { strokeWidth, strokeAlign, __font } = options;
1441
- if (!strokeWidth)
1442
- return;
1443
- if (__font) {
1444
- strokeText(strokes, ui, canvas, renderOptions);
1445
- }
1446
- else {
1447
- switch (strokeAlign) {
1448
- case 'center':
1449
- canvas.setStroke(undefined, strokeWidth, options);
1450
- drawStrokesStyle(strokes, false, ui, canvas);
1451
- break;
1452
- case 'inside':
1453
- canvas.save();
1454
- canvas.setStroke(undefined, strokeWidth * 2, options);
1455
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1456
- drawStrokesStyle(strokes, false, ui, canvas);
1457
- canvas.restore();
1458
- break;
1459
- case 'outside':
1460
- const { renderBounds } = ui.__layout;
1461
- const out = canvas.getSameCanvas(true);
1462
- ui.__drawRenderPath(out);
1463
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1464
- drawStrokesStyle(strokes, false, ui, out);
1465
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1466
- out.clearWorld(renderBounds);
1467
- if (ui.__worldFlipped || renderOptions.matrix) {
1468
- canvas.copyWorldByReset(out);
1469
- }
1470
- else {
1471
- canvas.copyWorldToInner(out, ui.__world, renderBounds);
1615
+ function recycleImage(attrName, data) {
1616
+ const paints = data['_' + attrName];
1617
+ if (paints instanceof Array) {
1618
+ let image, recycleMap, input, url;
1619
+ for (let i = 0, len = paints.length; i < len; i++) {
1620
+ image = paints[i].image;
1621
+ url = image && image.url;
1622
+ if (url) {
1623
+ if (!recycleMap)
1624
+ recycleMap = {};
1625
+ recycleMap[url] = true;
1626
+ ImageManager.recycle(image);
1627
+ if (image.loading) {
1628
+ if (!input) {
1629
+ input = (data.__input && data.__input[attrName]) || [];
1630
+ if (!(input instanceof Array))
1631
+ input = [input];
1632
+ }
1633
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1472
1634
  }
1473
- out.recycle();
1474
- break;
1635
+ }
1475
1636
  }
1637
+ return recycleMap;
1476
1638
  }
1639
+ return null;
1477
1640
  }
1478
1641
 
1479
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1480
- function shape(ui, current, options) {
1481
- const canvas = current.getSameCanvas();
1482
- let bounds, matrix, shapeBounds;
1483
- let worldCanvas;
1484
- const { __world } = ui;
1485
- let { scaleX, scaleY } = __world;
1486
- if (scaleX < 0)
1487
- scaleX = -scaleX;
1488
- if (scaleY < 0)
1489
- scaleY = -scaleY;
1490
- if (!current.bounds.includes(__world, options.matrix)) {
1491
- const { renderShapeSpread: spread } = ui.__layout;
1492
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1493
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1494
- if (matrix.a < 1) {
1495
- worldCanvas = current.getSameCanvas();
1496
- ui.__renderShape(worldCanvas, options);
1497
- scaleX *= matrix.a;
1498
- scaleY *= matrix.d;
1499
- }
1500
- shapeBounds = getOuterOf(__world, matrix);
1501
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1502
- if (options.matrix)
1503
- matrix.multiply(options.matrix);
1504
- options = Object.assign(Object.assign({}, options), { matrix });
1505
- }
1506
- else {
1507
- if (options.matrix) {
1508
- scaleX *= options.matrix.a;
1509
- scaleY *= options.matrix.d;
1510
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
1511
- }
1512
- else {
1513
- bounds = shapeBounds = __world;
1514
- }
1515
- worldCanvas = canvas;
1516
- }
1517
- ui.__renderShape(canvas, options);
1518
- return {
1519
- canvas, matrix, bounds,
1520
- worldCanvas, shapeBounds, scaleX, scaleY
1521
- };
1522
- }
1642
+ const PaintImageModule = {
1643
+ image,
1644
+ checkImage,
1645
+ createPattern,
1646
+ recycleImage,
1647
+ createData,
1648
+ getPatternData,
1649
+ fillOrFitMode,
1650
+ clipMode,
1651
+ repeatMode
1652
+ };
1523
1653
 
1524
- const defaultFrom$2 = { x: 0.5, y: 0 };
1525
- const defaultTo$2 = { x: 0.5, y: 1 };
1654
+ const { toPoint: toPoint$2 } = AroundHelper;
1655
+ const realFrom$2 = {};
1656
+ const realTo$2 = {};
1526
1657
  function linearGradient(paint, box) {
1527
1658
  let { from, to, type, blendMode, opacity } = paint;
1528
- from || (from = defaultFrom$2);
1529
- to || (to = defaultTo$2);
1530
- const style = Platform.canvas.createLinearGradient(box.x + from.x * box.width, box.y + from.y * box.height, box.x + to.x * box.width, box.y + to.y * box.height);
1659
+ toPoint$2(from || 'top', box, realFrom$2);
1660
+ toPoint$2(to || 'bottom', box, realTo$2);
1661
+ const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1531
1662
  applyStops(style, paint.stops, opacity);
1532
1663
  const data = { type, style };
1533
1664
  if (blendMode)
@@ -1538,137 +1669,84 @@ function applyStops(gradient, stops, opacity) {
1538
1669
  let stop;
1539
1670
  for (let i = 0, len = stops.length; i < len; i++) {
1540
1671
  stop = stops[i];
1541
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
1672
+ if (typeof stop === 'string') {
1673
+ gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1674
+ }
1675
+ else {
1676
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1677
+ }
1542
1678
  }
1543
1679
  }
1544
1680
 
1545
- const { set: set$1, getAngle: getAngle$1, getDistance: getDistance$1 } = PointHelper;
1546
- const { get: get$1, rotateOfOuter: rotateOfOuter$1, scaleOfOuter: scaleOfOuter$1 } = MatrixHelper;
1547
- const defaultFrom$1 = { x: 0.5, y: 0.5 };
1548
- const defaultTo$1 = { x: 0.5, y: 1 };
1681
+ const { getAngle, getDistance: getDistance$1 } = PointHelper;
1682
+ const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1683
+ const { toPoint: toPoint$1 } = AroundHelper;
1549
1684
  const realFrom$1 = {};
1550
1685
  const realTo$1 = {};
1551
1686
  function radialGradient(paint, box) {
1552
1687
  let { from, to, type, opacity, blendMode, stretch } = paint;
1553
- from || (from = defaultFrom$1);
1554
- to || (to = defaultTo$1);
1555
- const { x, y, width, height } = box;
1556
- set$1(realFrom$1, x + from.x * width, y + from.y * height);
1557
- set$1(realTo$1, x + to.x * width, y + to.y * height);
1558
- let transform;
1559
- if (width !== height || stretch) {
1560
- transform = get$1();
1561
- scaleOfOuter$1(transform, realFrom$1, width / height * (stretch || 1), 1);
1562
- rotateOfOuter$1(transform, realFrom$1, getAngle$1(realFrom$1, realTo$1) + 90);
1563
- }
1688
+ toPoint$1(from || 'center', box, realFrom$1);
1689
+ toPoint$1(to || 'bottom', box, realTo$1);
1564
1690
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1565
1691
  applyStops(style, paint.stops, opacity);
1566
- const data = { type, style, transform };
1692
+ const data = { type, style };
1693
+ const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1694
+ if (transform)
1695
+ data.transform = transform;
1567
1696
  if (blendMode)
1568
1697
  data.blendMode = blendMode;
1569
1698
  return data;
1570
1699
  }
1700
+ function getTransform(box, from, to, stretch, rotate90) {
1701
+ let transform;
1702
+ const { width, height } = box;
1703
+ if (width !== height || stretch) {
1704
+ const angle = getAngle(from, to);
1705
+ transform = get();
1706
+ if (rotate90) {
1707
+ scaleOfOuter(transform, from, width / height * (stretch || 1), 1);
1708
+ rotateOfOuter(transform, from, angle + 90);
1709
+ }
1710
+ else {
1711
+ scaleOfOuter(transform, from, 1, width / height * (stretch || 1));
1712
+ rotateOfOuter(transform, from, angle);
1713
+ }
1714
+ }
1715
+ return transform;
1716
+ }
1571
1717
 
1572
- const { set, getAngle, getDistance } = PointHelper;
1573
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1574
- const defaultFrom = { x: 0.5, y: 0.5 };
1575
- const defaultTo = { x: 0.5, y: 1 };
1718
+ const { getDistance } = PointHelper;
1719
+ const { toPoint } = AroundHelper;
1576
1720
  const realFrom = {};
1577
1721
  const realTo = {};
1578
1722
  function conicGradient(paint, box) {
1579
1723
  let { from, to, type, opacity, blendMode, stretch } = paint;
1580
- from || (from = defaultFrom);
1581
- to || (to = defaultTo);
1582
- const { x, y, width, height } = box;
1583
- set(realFrom, x + from.x * width, y + from.y * height);
1584
- set(realTo, x + to.x * width, y + to.y * height);
1585
- const transform = get();
1586
- const angle = getAngle(realFrom, realTo);
1587
- if (Platform.conicGradientRotate90) {
1588
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1);
1589
- rotateOfOuter(transform, realFrom, angle + 90);
1590
- }
1591
- else {
1592
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1));
1593
- rotateOfOuter(transform, realFrom, angle);
1594
- }
1724
+ toPoint(from || 'center', box, realFrom);
1725
+ toPoint(to || 'bottom', box, realTo);
1595
1726
  const style = Platform.conicGradientSupport ? Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo));
1596
1727
  applyStops(style, paint.stops, opacity);
1597
- const data = { type, style, transform };
1728
+ const data = { type, style };
1729
+ const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1730
+ if (transform)
1731
+ data.transform = transform;
1598
1732
  if (blendMode)
1599
1733
  data.blendMode = blendMode;
1600
1734
  return data;
1601
1735
  }
1602
1736
 
1603
- let recycleMap;
1604
- function compute(attrName, ui) {
1605
- const value = [];
1606
- const data = ui.__;
1607
- let item;
1608
- let paints = data.__input[attrName];
1609
- if (!(paints instanceof Array))
1610
- paints = [paints];
1611
- recycleMap = recycleImage(attrName, data);
1612
- for (let i = 0, len = paints.length; i < len; i++) {
1613
- item = getLeafPaint(attrName, paints[i], ui);
1614
- if (item)
1615
- value.push(item);
1616
- }
1617
- data['_' + attrName] = value.length ? value : undefined;
1618
- let isPixel;
1619
- if (paints.length === 1) {
1620
- const paint = paints[0];
1621
- if (paint.type === 'image')
1622
- isPixel = ImageManager$1.isPixel(paint);
1623
- }
1624
- if (attrName === 'fill') {
1625
- data.__pixelFill = isPixel;
1626
- }
1627
- else {
1628
- data.__pixelStroke = isPixel;
1629
- }
1630
- }
1631
- function getLeafPaint(attrName, paint, ui) {
1632
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1633
- return undefined;
1634
- const { boxBounds } = ui.__layout;
1635
- switch (paint.type) {
1636
- case 'solid':
1637
- let { type, blendMode, color, opacity } = paint;
1638
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
1639
- case 'image':
1640
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1641
- case 'linear':
1642
- return linearGradient(paint, boxBounds);
1643
- case 'radial':
1644
- return radialGradient(paint, boxBounds);
1645
- case 'angular':
1646
- return conicGradient(paint, boxBounds);
1647
- default:
1648
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
1649
- }
1650
- }
1651
-
1652
- var UIPaint = /*#__PURE__*/Object.freeze({
1653
- __proto__: null,
1654
- compute: compute,
1655
- drawTextStroke: drawTextStroke,
1656
- fill: fill,
1657
- fillText: fillText,
1658
- fills: fills,
1659
- recycleImage: recycleImage,
1660
- shape: shape,
1661
- stroke: stroke,
1662
- strokeText: strokeText,
1663
- strokes: strokes
1664
- });
1737
+ const PaintGradientModule = {
1738
+ linearGradient,
1739
+ radialGradient,
1740
+ conicGradient,
1741
+ getTransform
1742
+ };
1665
1743
 
1666
1744
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1667
1745
  const tempBounds = {};
1668
1746
  const offsetOutBounds$1 = {};
1669
- function shadow(ui, current, shape, renderOptions) {
1747
+ function shadow(ui, current, shape) {
1670
1748
  let copyBounds, spreadScale;
1671
- const { __world, __layout } = ui;
1749
+ const { __nowWorld: nowWorld, __layout } = ui;
1672
1750
  const { shadow } = ui.__;
1673
1751
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1674
1752
  const other = current.getSameCanvas();
@@ -1683,21 +1761,21 @@ function shadow(ui, current, shape, renderOptions) {
1683
1761
  other.restore();
1684
1762
  other.save();
1685
1763
  if (worldCanvas) {
1686
- other.copyWorld(other, bounds, __world, 'copy');
1687
- copyBounds = __world;
1764
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1765
+ copyBounds = nowWorld;
1688
1766
  }
1689
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1767
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1690
1768
  }
1691
- if (ui.__worldFlipped || renderOptions.matrix) {
1692
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1769
+ if (ui.__worldFlipped) {
1770
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1693
1771
  }
1694
1772
  else {
1695
1773
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1696
1774
  }
1697
1775
  if (end && index < end)
1698
- other.clear();
1776
+ other.clearWorld(copyBounds, true);
1699
1777
  });
1700
- other.recycle();
1778
+ other.recycle(copyBounds);
1701
1779
  }
1702
1780
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1703
1781
  const { bounds, shapeBounds } = shape;
@@ -1728,9 +1806,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1728
1806
 
1729
1807
  const { toOffsetOutBounds } = BoundsHelper;
1730
1808
  const offsetOutBounds = {};
1731
- function innerShadow(ui, current, shape, renderOptions) {
1809
+ function innerShadow(ui, current, shape) {
1732
1810
  let copyBounds, spreadScale;
1733
- const { __world, __layout: __layout } = ui;
1811
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1734
1812
  const { innerShadow } = ui.__;
1735
1813
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1736
1814
  const other = current.getSameCanvas();
@@ -1743,40 +1821,115 @@ function innerShadow(ui, current, shape, renderOptions) {
1743
1821
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1744
1822
  other.restore();
1745
1823
  if (worldCanvas) {
1746
- other.copyWorld(other, bounds, __world, 'copy');
1747
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1748
- copyBounds = __world;
1824
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1825
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
1826
+ copyBounds = nowWorld;
1749
1827
  }
1750
1828
  else {
1751
1829
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1752
1830
  copyBounds = bounds;
1753
1831
  }
1754
1832
  other.fillWorld(copyBounds, item.color, 'source-in');
1755
- if (ui.__worldFlipped || renderOptions.matrix) {
1756
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1833
+ if (ui.__worldFlipped) {
1834
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1757
1835
  }
1758
1836
  else {
1759
1837
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1760
1838
  }
1761
1839
  if (end && index < end)
1762
- other.clear();
1840
+ other.clearWorld(copyBounds, true);
1763
1841
  });
1764
- other.recycle();
1842
+ other.recycle(copyBounds);
1765
1843
  }
1766
1844
 
1767
1845
  function blur(ui, current, origin) {
1768
1846
  const { blur } = ui.__;
1769
- origin.setWorldBlur(blur * ui.__world.a);
1770
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
1847
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
1848
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
1771
1849
  origin.filter = 'none';
1772
1850
  }
1773
1851
 
1774
- var UIEffect = /*#__PURE__*/Object.freeze({
1775
- __proto__: null,
1776
- blur: blur,
1777
- innerShadow: innerShadow,
1778
- shadow: shadow
1779
- });
1852
+ function backgroundBlur(_ui, _current, _shape) {
1853
+ }
1854
+
1855
+ const EffectModule = {
1856
+ shadow,
1857
+ innerShadow,
1858
+ blur,
1859
+ backgroundBlur
1860
+ };
1861
+
1862
+ const { excludeRenderBounds } = LeafBoundsHelper;
1863
+ Group.prototype.__renderMask = function (canvas, options) {
1864
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
1865
+ const { children } = this;
1866
+ for (let i = 0, len = children.length; i < len; i++) {
1867
+ child = children[i];
1868
+ if (child.__.mask) {
1869
+ if (currentMask) {
1870
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1871
+ maskCanvas = contentCanvas = null;
1872
+ }
1873
+ if (child.__.mask === 'path') {
1874
+ if (child.opacity < 1) {
1875
+ currentMask = 'opacity-path';
1876
+ maskOpacity = child.opacity;
1877
+ if (!contentCanvas)
1878
+ contentCanvas = getCanvas(canvas);
1879
+ }
1880
+ else {
1881
+ currentMask = 'path';
1882
+ canvas.save();
1883
+ }
1884
+ child.__clip(contentCanvas || canvas, options);
1885
+ }
1886
+ else {
1887
+ currentMask = 'alpha';
1888
+ if (!maskCanvas)
1889
+ maskCanvas = getCanvas(canvas);
1890
+ if (!contentCanvas)
1891
+ contentCanvas = getCanvas(canvas);
1892
+ child.__render(maskCanvas, options);
1893
+ }
1894
+ if (child.__.mask !== 'clipping')
1895
+ continue;
1896
+ }
1897
+ if (excludeRenderBounds(child, options))
1898
+ continue;
1899
+ child.__render(contentCanvas || canvas, options);
1900
+ }
1901
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1902
+ };
1903
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
1904
+ switch (maskMode) {
1905
+ case 'alpha':
1906
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
1907
+ break;
1908
+ case 'opacity-path':
1909
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
1910
+ break;
1911
+ case 'path':
1912
+ canvas.restore();
1913
+ }
1914
+ }
1915
+ function getCanvas(canvas) {
1916
+ return canvas.getSameCanvas(false, true);
1917
+ }
1918
+ function usePixelMask(leaf, canvas, content, mask) {
1919
+ const realBounds = leaf.__nowWorld;
1920
+ content.resetTransform();
1921
+ content.opacity = 1;
1922
+ content.useMask(mask, realBounds);
1923
+ mask.recycle(realBounds);
1924
+ copyContent(leaf, canvas, content, 1);
1925
+ }
1926
+ function copyContent(leaf, canvas, content, maskOpacity) {
1927
+ const realBounds = leaf.__nowWorld;
1928
+ canvas.resetTransform();
1929
+ canvas.opacity = maskOpacity;
1930
+ canvas.copyWorld(content, realBounds);
1931
+ content.recycle(realBounds);
1932
+ }
1780
1933
 
1781
1934
  const money = '¥¥$€££¢¢';
1782
1935
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -1933,7 +2086,8 @@ function createRows(drawData, content, style) {
1933
2086
  if (breakAll) {
1934
2087
  if (wordWidth)
1935
2088
  addWord();
1936
- addRow();
2089
+ if (rowWidth)
2090
+ addRow();
1937
2091
  }
1938
2092
  else {
1939
2093
  if (!afterBreak)
@@ -1941,10 +2095,12 @@ function createRows(drawData, content, style) {
1941
2095
  if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
1942
2096
  if (wordWidth)
1943
2097
  addWord();
1944
- addRow();
2098
+ if (rowWidth)
2099
+ addRow();
1945
2100
  }
1946
2101
  else {
1947
- addRow();
2102
+ if (rowWidth)
2103
+ addRow();
1948
2104
  }
1949
2105
  }
1950
2106
  }
@@ -2039,11 +2195,11 @@ function layoutChar(drawData, style, width, _height) {
2039
2195
  if (mode === WordMode) {
2040
2196
  wordChar = { char: '', x: charX };
2041
2197
  charX = toWordChar(word.data, charX, wordChar);
2042
- if (wordChar.char !== ' ')
2198
+ if (row.isOverflow || wordChar.char !== ' ')
2043
2199
  row.data.push(wordChar);
2044
2200
  }
2045
2201
  else {
2046
- charX = toChar(word.data, charX, row.data);
2202
+ charX = toChar(word.data, charX, row.data, row.isOverflow);
2047
2203
  }
2048
2204
  if (!row.paraEnd && addWordWidth) {
2049
2205
  charX += addWordWidth;
@@ -2070,9 +2226,9 @@ function toWordChar(data, charX, wordChar) {
2070
2226
  });
2071
2227
  return charX;
2072
2228
  }
2073
- function toChar(data, charX, rowData) {
2229
+ function toChar(data, charX, rowData, isOverflow) {
2074
2230
  data.forEach(char => {
2075
- if (char.char !== ' ') {
2231
+ if (isOverflow || char.char !== ' ') {
2076
2232
  char.x = charX;
2077
2233
  rowData.push(char);
2078
2234
  }
@@ -2104,12 +2260,14 @@ function layoutText(drawData, style) {
2104
2260
  for (let i = 0, len = rows.length; i < len; i++) {
2105
2261
  row = rows[i];
2106
2262
  row.x = x;
2107
- switch (textAlign) {
2108
- case 'center':
2109
- row.x += (width - row.width) / 2;
2110
- break;
2111
- case 'right':
2112
- row.x += width - row.width;
2263
+ if (row.width < width || (row.width > width && !__clipText)) {
2264
+ switch (textAlign) {
2265
+ case 'center':
2266
+ row.x += (width - row.width) / 2;
2267
+ break;
2268
+ case 'right':
2269
+ row.x += width - row.width;
2270
+ }
2113
2271
  }
2114
2272
  if (row.paraStart && paraSpacing && i > 0)
2115
2273
  starY += paraSpacing;
@@ -2145,16 +2303,20 @@ function layoutText(drawData, style) {
2145
2303
  bounds.height = realHeight;
2146
2304
  }
2147
2305
 
2148
- function clipText(drawData, style) {
2306
+ function clipText(drawData, style, x, width) {
2307
+ if (!width)
2308
+ return;
2149
2309
  const { rows, overflow } = drawData;
2150
2310
  let { textOverflow } = style;
2151
2311
  rows.splice(overflow);
2152
- if (textOverflow !== 'hide') {
2153
- if (textOverflow === 'ellipsis')
2312
+ if (textOverflow && textOverflow !== 'show') {
2313
+ if (textOverflow === 'hide')
2314
+ textOverflow = '';
2315
+ else if (textOverflow === 'ellipsis')
2154
2316
  textOverflow = '...';
2155
2317
  let char, charRight;
2156
- const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2157
- const right = style.x + style.width - ellipsisWidth;
2318
+ const ellipsisWidth = textOverflow ? Platform.canvas.measureText(textOverflow).width : 0;
2319
+ const right = x + width - ellipsisWidth;
2158
2320
  const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2159
2321
  list.forEach(row => {
2160
2322
  if (row.isOverflow && row.data) {
@@ -2201,42 +2363,40 @@ function decorationText(drawData, style) {
2201
2363
  }
2202
2364
 
2203
2365
  const { top, right, bottom, left } = Direction4;
2204
- const TextConvert = {
2205
- getDrawData(content, style) {
2206
- if (typeof content !== 'string')
2207
- content = String(content);
2208
- let x = 0, y = 0;
2209
- let width = style.__getInput('width') || 0;
2210
- let height = style.__getInput('height') || 0;
2211
- const { textDecoration, __font, __padding: padding } = style;
2212
- if (padding) {
2213
- if (width) {
2214
- x = padding[left];
2215
- width -= (padding[right] + padding[left]);
2216
- }
2217
- if (height) {
2218
- y = padding[top];
2219
- height -= (padding[top] + padding[bottom]);
2220
- }
2221
- }
2222
- const drawData = {
2223
- bounds: { x, y, width, height },
2224
- rows: [],
2225
- paraNumber: 0,
2226
- font: Platform.canvas.font = __font
2227
- };
2228
- createRows(drawData, content, style);
2229
- if (padding)
2230
- padAutoText(padding, drawData, style, width, height);
2231
- layoutText(drawData, style);
2232
- layoutChar(drawData, style, width);
2233
- if (drawData.overflow)
2234
- clipText(drawData, style);
2235
- if (textDecoration !== 'none')
2236
- decorationText(drawData, style);
2237
- return drawData;
2238
- }
2239
- };
2366
+ function getDrawData(content, style) {
2367
+ if (typeof content !== 'string')
2368
+ content = String(content);
2369
+ let x = 0, y = 0;
2370
+ let width = style.__getInput('width') || 0;
2371
+ let height = style.__getInput('height') || 0;
2372
+ const { textDecoration, __font, __padding: padding } = style;
2373
+ if (padding) {
2374
+ if (width) {
2375
+ x = padding[left];
2376
+ width -= (padding[right] + padding[left]);
2377
+ }
2378
+ if (height) {
2379
+ y = padding[top];
2380
+ height -= (padding[top] + padding[bottom]);
2381
+ }
2382
+ }
2383
+ const drawData = {
2384
+ bounds: { x, y, width, height },
2385
+ rows: [],
2386
+ paraNumber: 0,
2387
+ font: Platform.canvas.font = __font
2388
+ };
2389
+ createRows(drawData, content, style);
2390
+ if (padding)
2391
+ padAutoText(padding, drawData, style, width, height);
2392
+ layoutText(drawData, style);
2393
+ layoutChar(drawData, style, width);
2394
+ if (drawData.overflow)
2395
+ clipText(drawData, style, x, width);
2396
+ if (textDecoration !== 'none')
2397
+ decorationText(drawData, style);
2398
+ return drawData;
2399
+ }
2240
2400
  function padAutoText(padding, drawData, style, width, height) {
2241
2401
  if (!width) {
2242
2402
  switch (style.textAlign) {
@@ -2264,67 +2424,157 @@ function offsetText(drawData, attrName, value) {
2264
2424
  rows[i][attrName] += value;
2265
2425
  }
2266
2426
 
2267
- const ColorConvert = {
2268
- string(color, opacity) {
2269
- if (typeof color === 'string')
2270
- return color;
2271
- let a = color.a === undefined ? 1 : color.a;
2272
- if (opacity)
2273
- a *= opacity;
2274
- const rgb = color.r + ',' + color.g + ',' + color.b;
2275
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2276
- }
2427
+ const TextConvertModule = {
2428
+ getDrawData
2277
2429
  };
2278
2430
 
2279
- const Export = {
2431
+ function string(color, opacity) {
2432
+ if (typeof color === 'string')
2433
+ return color;
2434
+ let a = color.a === undefined ? 1 : color.a;
2435
+ if (opacity)
2436
+ a *= opacity;
2437
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2438
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2439
+ }
2440
+
2441
+ const ColorConvertModule = {
2442
+ string
2443
+ };
2444
+
2445
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2446
+ function getTrimBounds(canvas) {
2447
+ const { width, height } = canvas.view;
2448
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2449
+ let x, y, pointBounds, index = 0;
2450
+ for (let i = 0; i < data.length; i += 4) {
2451
+ if (data[i + 3] !== 0) {
2452
+ x = index % width;
2453
+ y = (index - x) / width;
2454
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2455
+ }
2456
+ index++;
2457
+ }
2458
+ const bounds = new Bounds();
2459
+ toBounds(pointBounds, bounds);
2460
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2461
+ }
2462
+
2463
+ const ExportModule = {
2280
2464
  export(leaf, filename, options) {
2281
- Export.running = true;
2465
+ this.running = true;
2466
+ const fileType = FileHelper.fileType(filename);
2467
+ options = FileHelper.getExportOptions(options);
2282
2468
  return addTask((success) => new Promise((resolve) => {
2469
+ const over = (result) => {
2470
+ success(result);
2471
+ resolve();
2472
+ this.running = false;
2473
+ };
2474
+ const { toURL } = Platform;
2475
+ const { download } = Platform.origin;
2476
+ if (filename === 'json') {
2477
+ return over({ data: leaf.toJSON(options.json) });
2478
+ }
2479
+ else if (fileType === 'json') {
2480
+ download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename);
2481
+ return over({ data: true });
2482
+ }
2483
+ if (filename === 'svg') {
2484
+ return over({ data: leaf.toSVG() });
2485
+ }
2486
+ else if (fileType === 'svg') {
2487
+ download(toURL(leaf.toSVG(), 'svg'), filename);
2488
+ return over({ data: true });
2489
+ }
2283
2490
  const { leafer } = leaf;
2284
2491
  if (leafer) {
2492
+ checkLazy(leaf);
2285
2493
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2286
- let quality, blob;
2287
- let { canvas } = leafer;
2288
- let { unreal } = canvas;
2289
- if (unreal) {
2290
- canvas = canvas.getSameCanvas();
2291
- canvas.backgroundColor = leafer.config.fill;
2292
- leafer.__render(canvas, {});
2494
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2495
+ const { worldTransform, isLeafer, isFrame } = leaf;
2496
+ const { slice, trim, onCanvas } = options;
2497
+ let scale = options.scale || 1;
2498
+ let pixelRatio = options.pixelRatio || 1;
2499
+ const smooth = options.smooth === undefined ? leafer.config.smooth : options.smooth;
2500
+ const contextSettings = options.contextSettings || leafer.config.contextSettings;
2501
+ if (leaf.isApp) {
2502
+ scale *= pixelRatio;
2503
+ pixelRatio = leaf.app.pixelRatio;
2504
+ }
2505
+ const screenshot = options.screenshot || leaf.isApp;
2506
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2507
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2508
+ if (screenshot) {
2509
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2293
2510
  }
2294
- switch (typeof options) {
2295
- case 'object':
2296
- if (options.quality)
2297
- quality = options.quality;
2298
- if (options.blob)
2299
- blob = true;
2300
- break;
2301
- case 'number':
2302
- quality = options;
2303
- break;
2304
- case 'boolean':
2305
- blob = options;
2511
+ else {
2512
+ let relative = options.relative || (isLeafer ? 'inner' : 'local');
2513
+ scaleX = worldTransform.scaleX;
2514
+ scaleY = worldTransform.scaleY;
2515
+ switch (relative) {
2516
+ case 'inner':
2517
+ matrix.set(worldTransform);
2518
+ break;
2519
+ case 'local':
2520
+ matrix.set(worldTransform).divide(leaf.localTransform);
2521
+ scaleX /= leaf.scaleX;
2522
+ scaleY /= leaf.scaleY;
2523
+ break;
2524
+ case 'world':
2525
+ scaleX = 1;
2526
+ scaleY = 1;
2527
+ break;
2528
+ case 'page':
2529
+ relative = leaf.leafer;
2530
+ default:
2531
+ matrix.set(worldTransform).divide(leaf.getTransform(relative));
2532
+ const l = relative.worldTransform;
2533
+ scaleX /= scaleX / l.scaleX;
2534
+ scaleY /= scaleY / l.scaleY;
2535
+ }
2536
+ renderBounds = leaf.getBounds('render', relative);
2306
2537
  }
2307
- let data;
2308
- if (filename.includes('.')) {
2309
- data = yield canvas.saveAs(filename, quality);
2538
+ const { x, y, width, height } = new Bounds(renderBounds).scale(scale);
2539
+ let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio, smooth, contextSettings });
2540
+ const renderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) };
2541
+ let sliceLeaf;
2542
+ if (slice) {
2543
+ sliceLeaf = leaf;
2544
+ sliceLeaf.__worldOpacity = 0;
2545
+ leaf = leafer;
2546
+ renderOptions.bounds = canvas.bounds;
2310
2547
  }
2311
- else if (blob) {
2312
- data = yield canvas.toBlob(filename, quality);
2548
+ canvas.save();
2549
+ if (isFrame && fill !== undefined) {
2550
+ const oldFill = leaf.get('fill');
2551
+ leaf.fill = '';
2552
+ leaf.__render(canvas, renderOptions);
2553
+ leaf.fill = oldFill;
2313
2554
  }
2314
2555
  else {
2315
- data = yield canvas.toDataURL(filename, quality);
2556
+ leaf.__render(canvas, renderOptions);
2316
2557
  }
2317
- success({ data });
2318
- resolve();
2319
- Export.running = false;
2320
- if (unreal)
2321
- canvas.recycle();
2558
+ canvas.restore();
2559
+ if (sliceLeaf)
2560
+ sliceLeaf.__updateWorldOpacity();
2561
+ if (trim) {
2562
+ trimBounds = getTrimBounds(canvas);
2563
+ const old = canvas, { width, height } = trimBounds;
2564
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2565
+ canvas = Creator.canvas(config);
2566
+ canvas.copyWorld(old, trimBounds, config);
2567
+ }
2568
+ if (needFill)
2569
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2570
+ if (onCanvas)
2571
+ onCanvas(canvas);
2572
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2573
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2322
2574
  }));
2323
2575
  }
2324
2576
  else {
2325
- success({ data: false });
2326
- resolve();
2327
- Export.running = false;
2577
+ over({ data: false });
2328
2578
  }
2329
2579
  }));
2330
2580
  }
@@ -2337,13 +2587,64 @@ function addTask(task) {
2337
2587
  tasker.add(() => __awaiter(this, void 0, void 0, function* () { return yield task(resolve); }), { parallel: false });
2338
2588
  });
2339
2589
  }
2590
+ function checkLazy(leaf) {
2591
+ if (leaf.__.__needComputePaint)
2592
+ leaf.__.__computePaint();
2593
+ if (leaf.isBranch)
2594
+ leaf.children.forEach(child => checkLazy(child));
2595
+ }
2596
+
2597
+ const canvas = LeaferCanvasBase.prototype;
2598
+ const debug = Debug.get('@leafer-ui/export');
2599
+ canvas.export = function (filename, options) {
2600
+ const { quality, blob } = FileHelper.getExportOptions(options);
2601
+ if (filename.includes('.')) {
2602
+ return this.saveAs(filename, quality);
2603
+ }
2604
+ else if (blob) {
2605
+ return this.toBlob(filename, quality);
2606
+ }
2607
+ else {
2608
+ return this.toDataURL(filename, quality);
2609
+ }
2610
+ };
2611
+ canvas.toBlob = function (type, quality) {
2612
+ return new Promise((resolve) => {
2613
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2614
+ resolve(blob);
2615
+ }).catch((e) => {
2616
+ debug.error(e);
2617
+ resolve(null);
2618
+ });
2619
+ });
2620
+ };
2621
+ canvas.toDataURL = function (type, quality) {
2622
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
2623
+ };
2624
+ canvas.saveAs = function (filename, quality) {
2625
+ return new Promise((resolve) => {
2626
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2627
+ resolve(true);
2628
+ }).catch((e) => {
2629
+ debug.error(e);
2630
+ resolve(false);
2631
+ });
2632
+ });
2633
+ };
2340
2634
 
2341
- Object.assign(Paint, UIPaint);
2342
- Object.assign(Effect, UIEffect);
2343
- Object.assign(TextConvert$1, TextConvert);
2344
- Object.assign(ColorConvert$1, ColorConvert);
2345
- Object.assign(Export$2, Export);
2635
+ Object.assign(TextConvert, TextConvertModule);
2636
+ Object.assign(ColorConvert, ColorConvertModule);
2637
+ Object.assign(Paint, PaintModule);
2638
+ Object.assign(PaintImage, PaintImageModule);
2639
+ Object.assign(PaintGradient, PaintGradientModule);
2640
+ Object.assign(Effect, EffectModule);
2641
+ Object.assign(Export, ExportModule);
2346
2642
 
2643
+ Object.assign(Creator, {
2644
+ interaction: (target, canvas, selector, options) => new InteractionBase(target, canvas, selector, options),
2645
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2646
+ hitCanvasManager: () => new HitCanvasManager()
2647
+ });
2347
2648
  useCanvas();
2348
2649
 
2349
2650
  export { Layouter, LeaferCanvas, Renderer, Selector, Watcher, useCanvas };