@leafer-ui/worker 1.0.0-rc.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,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, 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
+ Platform.devicePixelRatio = 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
  }
@@ -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,182 +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
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
920
- function fillOrFitMode(data, mode, box, width, height, rotation) {
921
- const transform = get$4();
922
- const swap = rotation && rotation !== 180;
923
- const sw = box.width / (swap ? height : width);
924
- const sh = box.height / (swap ? width : height);
925
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
926
- const x = box.x + (box.width - width * scale) / 2;
927
- const y = box.y + (box.height - height * scale) / 2;
928
- translate$1(transform, x, y);
929
- scaleHelper(transform, scale);
930
- if (rotation)
931
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
932
- data.scaleX = data.scaleY = scale;
933
- data.transform = transform;
934
- }
935
- function clipMode(data, box, offset, scale, rotation) {
936
- const transform = get$4();
937
- translate$1(transform, box.x, box.y);
938
- if (offset)
939
- translate$1(transform, offset.x, offset.y);
940
- if (scale) {
941
- typeof scale === 'number' ? scaleHelper(transform, scale) : scaleHelper(transform, scale.x, scale.y);
942
- data.scaleX = transform.a;
943
- data.scaleY = transform.d;
944
- }
945
- if (rotation)
946
- rotate(transform, rotation);
947
- 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());
948
967
  }
949
- function repeatMode(data, box, width, height, scale, rotation) {
950
- const transform = get$4();
951
- if (rotation) {
952
- rotate(transform, rotation);
953
- switch (rotation) {
954
- case 90:
955
- translate$1(transform, height, 0);
956
- break;
957
- case 180:
958
- translate$1(transform, width, height);
959
- break;
960
- case 270:
961
- translate$1(transform, 0, width);
962
- 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
+ }
963
995
  }
964
996
  }
965
- translate$1(transform, box.x, box.y);
966
- if (scale) {
967
- scaleOfOuter$2(transform, box, scale);
968
- data.scaleX = data.scaleY = scale;
969
- }
970
- data.transform = transform;
971
997
  }
972
998
 
973
- const { get: get$3, translate } = MatrixHelper;
974
- function createData(leafPaint, image, paint, box) {
975
- let { width, height } = image;
976
- const { opacity, mode, offset, scale, rotation, blendMode, repeat } = paint;
977
- const sameBox = box.width === width && box.height === height;
978
- if (blendMode)
979
- leafPaint.blendMode = blendMode;
980
- const data = leafPaint.data = { mode };
981
- switch (mode) {
982
- case 'strench':
983
- if (!sameBox)
984
- width = box.width, height = box.height;
985
- if (box.x || box.y) {
986
- data.transform = get$3();
987
- translate(data.transform, box.x, box.y);
988
- }
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);
989
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;
1337
+ switch (mode) {
1338
+ case 'strench':
1339
+ if (!sameBox)
1340
+ width = box.width, height = box.height;
1341
+ break;
1342
+ case 'normal':
990
1343
  case 'clip':
991
- if (offset || scale || rotation)
992
- clipMode(data, box, offset, scale, rotation);
1344
+ if (x || y || scaleX || rotation)
1345
+ clipMode(data, box, x, y, scaleX, scaleY, rotation);
993
1346
  break;
994
1347
  case 'repeat':
995
- if (!sameBox || scale || rotation)
996
- repeatMode(data, box, width, height, scale, rotation);
1348
+ if (!sameBox || scaleX || rotation)
1349
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
997
1350
  if (!repeat)
998
1351
  data.repeat = 'repeat';
999
1352
  break;
1000
1353
  case 'fit':
1001
1354
  case 'cover':
1002
1355
  default:
1003
- if (!sameBox || rotation)
1004
- 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;
1005
1368
  }
1006
1369
  data.width = width;
1007
1370
  data.height = height;
@@ -1009,112 +1372,108 @@ function createData(leafPaint, image, paint, box) {
1009
1372
  data.opacity = opacity;
1010
1373
  if (repeat)
1011
1374
  data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1375
+ return data;
1012
1376
  }
1013
1377
 
1014
- function image(ui, attrName, attrValue, box, firstUse) {
1015
- const leafPaint = { type: attrValue.type };
1016
- const image = leafPaint.image = ImageManager.get(attrValue);
1017
- 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 };
1018
1392
  if (image.ready) {
1019
- if (hasNaturalSize(ui, attrName, image))
1020
- createData(leafPaint, image, attrValue, box);
1393
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1021
1394
  if (firstUse) {
1022
- emit(ImageEvent.LOAD, event);
1023
- emit(ImageEvent.LOADED, event);
1395
+ onLoad(ui, event);
1396
+ onLoadSuccess(ui, event);
1024
1397
  }
1025
1398
  }
1026
1399
  else if (image.error) {
1027
- if (firstUse) {
1028
- ui.forceUpdate('surface');
1029
- event.error = image.error;
1030
- emit(ImageEvent.ERROR, event);
1031
- }
1400
+ if (firstUse)
1401
+ onLoadError(ui, event, image.error);
1032
1402
  }
1033
1403
  else {
1404
+ ignoreRender(ui, true);
1034
1405
  if (firstUse)
1035
- emit(ImageEvent.LOAD, event);
1406
+ onLoad(ui, event);
1036
1407
  leafPaint.loadId = image.load(() => {
1408
+ ignoreRender(ui, false);
1037
1409
  if (!ui.destroyed) {
1038
- if (hasNaturalSize(ui, attrName, image)) {
1039
- createData(leafPaint, image, attrValue, box);
1410
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1411
+ if (image.hasOpacityPixel)
1412
+ ui.__layout.hitCanvasChanged = true;
1040
1413
  ui.forceUpdate('surface');
1041
1414
  }
1042
- emit(ImageEvent.LOADED, event);
1415
+ onLoadSuccess(ui, event);
1043
1416
  }
1417
+ leafPaint.loadId = null;
1044
1418
  }, (error) => {
1045
- ui.forceUpdate('surface');
1046
- event.error = error;
1047
- emit(ImageEvent.ERROR, event);
1419
+ ignoreRender(ui, false);
1420
+ onLoadError(ui, event, error);
1421
+ leafPaint.loadId = null;
1048
1422
  });
1049
1423
  }
1050
1424
  return leafPaint;
1051
1425
  }
1052
- function hasNaturalSize(ui, attrName, image) {
1426
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1053
1427
  if (attrName === 'fill' && !ui.__.__naturalWidth) {
1054
- const { __: d } = ui;
1055
- d.__naturalWidth = image.width;
1056
- d.__naturalHeight = image.height;
1057
- 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) {
1058
1432
  ui.forceUpdate('width');
1059
1433
  if (ui.__proxyData) {
1060
- ui.setProxyAttr('width', ui.__.width);
1061
- ui.setProxyAttr('height', ui.__.height);
1434
+ ui.setProxyAttr('width', data.width);
1435
+ ui.setProxyAttr('height', data.height);
1062
1436
  }
1063
1437
  return false;
1064
1438
  }
1065
1439
  }
1440
+ if (!leafPaint.data)
1441
+ createData(leafPaint, image, paint, boxBounds);
1066
1442
  return true;
1067
1443
  }
1068
- function emit(type, data) {
1069
- if (data.target.hasEvent(type))
1070
- 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;
1071
1463
  }
1072
1464
 
1073
- /******************************************************************************
1074
- Copyright (c) Microsoft Corporation.
1075
-
1076
- Permission to use, copy, modify, and/or distribute this software for any
1077
- purpose with or without fee is hereby granted.
1078
-
1079
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1080
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1081
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1082
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1083
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1084
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1085
- PERFORMANCE OF THIS SOFTWARE.
1086
- ***************************************************************************** */
1087
- /* global Reflect, Promise, SuppressedError, Symbol */
1088
-
1089
-
1090
- function __awaiter(thisArg, _arguments, P, generator) {
1091
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1092
- return new (P || (P = Promise))(function (resolve, reject) {
1093
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1094
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1095
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1096
- step((generator = generator.apply(thisArg, _arguments || [])).next());
1097
- });
1098
- }
1099
-
1100
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1101
- var e = new Error(message);
1102
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1103
- };
1104
-
1105
- const Export$1 = {};
1106
-
1107
- 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;
1108
1467
  function createPattern(ui, paint, pixelRatio) {
1109
- let { scaleX, scaleY } = ui.__world;
1468
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1110
1469
  const id = scaleX + '-' + scaleY;
1111
1470
  if (paint.patternId !== id && !ui.destroyed) {
1112
- scaleX = Math.abs(scaleX);
1113
- scaleY = Math.abs(scaleY);
1471
+ scaleX = abs$1(scaleX);
1472
+ scaleY = abs$1(scaleY);
1114
1473
  const { image, data } = paint;
1115
1474
  let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1116
1475
  if (sx) {
1117
- imageMatrix = get$2();
1476
+ imageMatrix = get$1();
1118
1477
  copy$1(imageMatrix, transform);
1119
1478
  scale(imageMatrix, 1 / sx, 1 / sy);
1120
1479
  scaleX *= sx;
@@ -1149,22 +1508,14 @@ function createPattern(ui, paint, pixelRatio) {
1149
1508
  }
1150
1509
  if (transform || scaleX !== 1 || scaleY !== 1) {
1151
1510
  if (!imageMatrix) {
1152
- imageMatrix = get$2();
1511
+ imageMatrix = get$1();
1153
1512
  if (transform)
1154
1513
  copy$1(imageMatrix, transform);
1155
1514
  }
1156
1515
  scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1157
1516
  }
1158
- const pattern = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), repeat || (Platform.origin.noRepeat || 'no-repeat'));
1159
- try {
1160
- if (paint.transform)
1161
- paint.transform = null;
1162
- if (imageMatrix)
1163
- pattern.setTransform ? pattern.setTransform(imageMatrix) : paint.transform = imageMatrix;
1164
- }
1165
- catch (_a) {
1166
- paint.transform = imageMatrix;
1167
- }
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);
1168
1519
  paint.style = pattern;
1169
1520
  paint.patternId = id;
1170
1521
  return true;
@@ -1174,9 +1525,41 @@ function createPattern(ui, paint, pixelRatio) {
1174
1525
  }
1175
1526
  }
1176
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
+
1177
1560
  const { abs } = Math;
1178
1561
  function checkImage(ui, canvas, paint, allowPaint) {
1179
- const { scaleX, scaleY } = ui.__world;
1562
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1180
1563
  if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1181
1564
  return false;
1182
1565
  }
@@ -1191,326 +1574,91 @@ function checkImage(ui, canvas, paint, allowPaint) {
1191
1574
  width *= data.scaleX;
1192
1575
  height *= data.scaleY;
1193
1576
  }
1194
- allowPaint = width * height > Platform.image.maxCacheSize;
1577
+ allowPaint = (width * height > Platform.image.maxCacheSize) || Export.running;
1195
1578
  }
1196
1579
  else {
1197
1580
  allowPaint = false;
1198
1581
  }
1199
1582
  }
1200
- if (allowPaint) {
1201
- canvas.save();
1202
- canvas.clip();
1203
- if (paint.blendMode)
1204
- canvas.blendMode = paint.blendMode;
1205
- if (data.opacity)
1206
- canvas.opacity *= data.opacity;
1207
- if (data.transform)
1208
- canvas.transform(data.transform);
1209
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1210
- canvas.restore();
1211
- return true;
1212
- }
1213
- else {
1214
- if (!paint.style || Export$1.running) {
1215
- createPattern(ui, paint, canvas.pixelRatio);
1216
- }
1217
- else {
1218
- if (!paint.patternTask) {
1219
- paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1220
- paint.patternTask = null;
1221
- if (canvas.bounds.hit(ui.__world))
1222
- createPattern(ui, paint, canvas.pixelRatio);
1223
- ui.forceUpdate('surface');
1224
- }), 300);
1225
- }
1226
- }
1227
- return false;
1228
- }
1229
- }
1230
- }
1231
-
1232
- function recycleImage(attrName, data) {
1233
- const paints = data['_' + attrName];
1234
- if (paints instanceof Array) {
1235
- let image, recycleMap, input, url;
1236
- for (let i = 0, len = paints.length; i < len; i++) {
1237
- image = paints[i].image;
1238
- url = image && image.url;
1239
- if (url) {
1240
- if (!recycleMap)
1241
- recycleMap = {};
1242
- recycleMap[url] = true;
1243
- ImageManager.recycle(image);
1244
- if (image.loading) {
1245
- if (!input) {
1246
- input = (data.__input && data.__input[attrName]) || [];
1247
- if (!(input instanceof Array))
1248
- input = [input];
1249
- }
1250
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1251
- }
1252
- }
1253
- }
1254
- return recycleMap;
1255
- }
1256
- return null;
1257
- }
1258
-
1259
- function fillText(ui, canvas) {
1260
- let row;
1261
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1262
- for (let i = 0, len = rows.length; i < len; i++) {
1263
- row = rows[i];
1264
- if (row.text) {
1265
- canvas.fillText(row.text, row.x, row.y);
1266
- }
1267
- else if (row.data) {
1268
- row.data.forEach(charData => {
1269
- canvas.fillText(charData.char, charData.x, row.y);
1270
- });
1271
- }
1272
- if (decorationY)
1273
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1274
- }
1275
- }
1276
-
1277
- function fill(fill, ui, canvas) {
1278
- canvas.fillStyle = fill;
1279
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1280
- }
1281
- function fills(fills, ui, canvas) {
1282
- let item;
1283
- const { windingRule, __font } = ui.__;
1284
- for (let i = 0, len = fills.length; i < len; i++) {
1285
- item = fills[i];
1286
- if (item.image && checkImage(ui, canvas, item, !__font))
1287
- continue;
1288
- if (item.style) {
1289
- canvas.fillStyle = item.style;
1290
- if (item.transform) {
1291
- canvas.save();
1292
- canvas.transform(item.transform);
1293
- if (item.blendMode)
1294
- canvas.blendMode = item.blendMode;
1295
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1296
- canvas.restore();
1297
- }
1298
- else {
1299
- if (item.blendMode) {
1300
- canvas.saveBlendMode(item.blendMode);
1301
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1302
- canvas.restoreBlendMode();
1303
- }
1304
- else {
1305
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1306
- }
1307
- }
1308
- }
1309
- }
1310
- }
1311
-
1312
- function strokeText(stroke, ui, canvas, renderOptions) {
1313
- const { strokeAlign } = ui.__;
1314
- const isStrokes = typeof stroke !== 'string';
1315
- switch (strokeAlign) {
1316
- case 'center':
1317
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1318
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1319
- break;
1320
- case 'inside':
1321
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas, renderOptions);
1322
- break;
1323
- case 'outside':
1324
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas, renderOptions);
1325
- break;
1326
- }
1327
- }
1328
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas, renderOptions) {
1329
- const { strokeWidth, __font } = ui.__;
1330
- const out = canvas.getSameCanvas(true);
1331
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1332
- out.font = __font;
1333
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1334
- out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1335
- fillText(ui, out);
1336
- out.blendMode = 'normal';
1337
- if (ui.__worldFlipped || renderOptions.matrix) {
1338
- canvas.copyWorldByReset(out);
1339
- }
1340
- else {
1341
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1342
- }
1343
- out.recycle();
1344
- }
1345
- function drawTextStroke(ui, canvas) {
1346
- let row;
1347
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1348
- for (let i = 0, len = rows.length; i < len; i++) {
1349
- row = rows[i];
1350
- if (row.text) {
1351
- canvas.strokeText(row.text, row.x, row.y);
1352
- }
1353
- else if (row.data) {
1354
- row.data.forEach(charData => {
1355
- canvas.strokeText(charData.char, charData.x, row.y);
1356
- });
1357
- }
1358
- if (decorationY)
1359
- canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1360
- }
1361
- }
1362
- function drawStrokesStyle(strokes, isText, ui, canvas) {
1363
- let item;
1364
- for (let i = 0, len = strokes.length; i < len; i++) {
1365
- item = strokes[i];
1366
- if (item.image && checkImage(ui, canvas, item, false))
1367
- continue;
1368
- if (item.style) {
1369
- canvas.strokeStyle = item.style;
1370
- if (item.blendMode) {
1371
- canvas.saveBlendMode(item.blendMode);
1372
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1373
- 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);
1374
1599
  }
1375
1600
  else {
1376
- 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
+ }
1377
1609
  }
1610
+ return false;
1378
1611
  }
1379
1612
  }
1380
1613
  }
1381
1614
 
1382
- function stroke(stroke, ui, canvas, renderOptions) {
1383
- const options = ui.__;
1384
- const { strokeWidth, strokeAlign, __font } = options;
1385
- if (!strokeWidth)
1386
- return;
1387
- if (__font) {
1388
- strokeText(stroke, ui, canvas, renderOptions);
1389
- }
1390
- else {
1391
- switch (strokeAlign) {
1392
- case 'center':
1393
- canvas.setStroke(stroke, strokeWidth, options);
1394
- canvas.stroke();
1395
- break;
1396
- case 'inside':
1397
- canvas.save();
1398
- canvas.setStroke(stroke, strokeWidth * 2, options);
1399
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1400
- canvas.stroke();
1401
- canvas.restore();
1402
- break;
1403
- case 'outside':
1404
- const out = canvas.getSameCanvas(true);
1405
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1406
- ui.__drawRenderPath(out);
1407
- out.stroke();
1408
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1409
- out.clearWorld(ui.__layout.renderBounds);
1410
- if (ui.__worldFlipped || renderOptions.matrix) {
1411
- canvas.copyWorldByReset(out);
1412
- }
1413
- else {
1414
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1415
- }
1416
- out.recycle();
1417
- break;
1418
- }
1419
- }
1420
- }
1421
- function strokes(strokes, ui, canvas, renderOptions) {
1422
- const options = ui.__;
1423
- const { strokeWidth, strokeAlign, __font } = options;
1424
- if (!strokeWidth)
1425
- return;
1426
- if (__font) {
1427
- strokeText(strokes, ui, canvas, renderOptions);
1428
- }
1429
- else {
1430
- switch (strokeAlign) {
1431
- case 'center':
1432
- canvas.setStroke(undefined, strokeWidth, options);
1433
- drawStrokesStyle(strokes, false, ui, canvas);
1434
- break;
1435
- case 'inside':
1436
- canvas.save();
1437
- canvas.setStroke(undefined, strokeWidth * 2, options);
1438
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1439
- drawStrokesStyle(strokes, false, ui, canvas);
1440
- canvas.restore();
1441
- break;
1442
- case 'outside':
1443
- const { renderBounds } = ui.__layout;
1444
- const out = canvas.getSameCanvas(true);
1445
- ui.__drawRenderPath(out);
1446
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1447
- drawStrokesStyle(strokes, false, ui, out);
1448
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1449
- out.clearWorld(renderBounds);
1450
- if (ui.__worldFlipped || renderOptions.matrix) {
1451
- canvas.copyWorldByReset(out);
1452
- }
1453
- else {
1454
- 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));
1455
1634
  }
1456
- out.recycle();
1457
- break;
1635
+ }
1458
1636
  }
1637
+ return recycleMap;
1459
1638
  }
1639
+ return null;
1460
1640
  }
1461
1641
 
1462
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1463
- function shape(ui, current, options) {
1464
- const canvas = current.getSameCanvas();
1465
- let bounds, matrix, shapeBounds;
1466
- let worldCanvas;
1467
- const { __world } = ui;
1468
- let { scaleX, scaleY } = __world;
1469
- if (scaleX < 0)
1470
- scaleX = -scaleX;
1471
- if (scaleY < 0)
1472
- scaleY = -scaleY;
1473
- if (!current.bounds.includes(__world, options.matrix)) {
1474
- const { renderShapeSpread: spread } = ui.__layout;
1475
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1476
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1477
- if (matrix.a < 1) {
1478
- worldCanvas = current.getSameCanvas();
1479
- ui.__renderShape(worldCanvas, options);
1480
- scaleX *= matrix.a;
1481
- scaleY *= matrix.d;
1482
- }
1483
- shapeBounds = getOuterOf(__world, matrix);
1484
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1485
- if (options.matrix)
1486
- matrix.multiply(options.matrix);
1487
- options = Object.assign(Object.assign({}, options), { matrix });
1488
- }
1489
- else {
1490
- if (options.matrix) {
1491
- scaleX *= options.matrix.a;
1492
- scaleY *= options.matrix.d;
1493
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
1494
- }
1495
- else {
1496
- bounds = shapeBounds = __world;
1497
- }
1498
- worldCanvas = canvas;
1499
- }
1500
- ui.__renderShape(canvas, options);
1501
- return {
1502
- canvas, matrix, bounds,
1503
- worldCanvas, shapeBounds, scaleX, scaleY
1504
- };
1505
- }
1642
+ const PaintImageModule = {
1643
+ image,
1644
+ checkImage,
1645
+ createPattern,
1646
+ recycleImage,
1647
+ createData,
1648
+ getPatternData,
1649
+ fillOrFitMode,
1650
+ clipMode,
1651
+ repeatMode
1652
+ };
1506
1653
 
1507
- const defaultFrom$2 = { x: 0.5, y: 0 };
1508
- const defaultTo$2 = { x: 0.5, y: 1 };
1654
+ const { toPoint: toPoint$2 } = AroundHelper;
1655
+ const realFrom$2 = {};
1656
+ const realTo$2 = {};
1509
1657
  function linearGradient(paint, box) {
1510
1658
  let { from, to, type, blendMode, opacity } = paint;
1511
- from || (from = defaultFrom$2);
1512
- to || (to = defaultTo$2);
1513
- 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);
1514
1662
  applyStops(style, paint.stops, opacity);
1515
1663
  const data = { type, style };
1516
1664
  if (blendMode)
@@ -1521,137 +1669,84 @@ function applyStops(gradient, stops, opacity) {
1521
1669
  let stop;
1522
1670
  for (let i = 0, len = stops.length; i < len; i++) {
1523
1671
  stop = stops[i];
1524
- 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
+ }
1525
1678
  }
1526
1679
  }
1527
1680
 
1528
- const { set: set$1, getAngle: getAngle$1, getDistance: getDistance$1 } = PointHelper;
1529
- const { get: get$1, rotateOfOuter: rotateOfOuter$1, scaleOfOuter: scaleOfOuter$1 } = MatrixHelper;
1530
- const defaultFrom$1 = { x: 0.5, y: 0.5 };
1531
- 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;
1532
1684
  const realFrom$1 = {};
1533
1685
  const realTo$1 = {};
1534
1686
  function radialGradient(paint, box) {
1535
1687
  let { from, to, type, opacity, blendMode, stretch } = paint;
1536
- from || (from = defaultFrom$1);
1537
- to || (to = defaultTo$1);
1538
- const { x, y, width, height } = box;
1539
- set$1(realFrom$1, x + from.x * width, y + from.y * height);
1540
- set$1(realTo$1, x + to.x * width, y + to.y * height);
1541
- let transform;
1542
- if (width !== height || stretch) {
1543
- transform = get$1();
1544
- scaleOfOuter$1(transform, realFrom$1, width / height * (stretch || 1), 1);
1545
- rotateOfOuter$1(transform, realFrom$1, getAngle$1(realFrom$1, realTo$1) + 90);
1546
- }
1688
+ toPoint$1(from || 'center', box, realFrom$1);
1689
+ toPoint$1(to || 'bottom', box, realTo$1);
1547
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));
1548
1691
  applyStops(style, paint.stops, opacity);
1549
- 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;
1550
1696
  if (blendMode)
1551
1697
  data.blendMode = blendMode;
1552
1698
  return data;
1553
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
+ }
1554
1717
 
1555
- const { set, getAngle, getDistance } = PointHelper;
1556
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1557
- const defaultFrom = { x: 0.5, y: 0.5 };
1558
- const defaultTo = { x: 0.5, y: 1 };
1718
+ const { getDistance } = PointHelper;
1719
+ const { toPoint } = AroundHelper;
1559
1720
  const realFrom = {};
1560
1721
  const realTo = {};
1561
1722
  function conicGradient(paint, box) {
1562
1723
  let { from, to, type, opacity, blendMode, stretch } = paint;
1563
- from || (from = defaultFrom);
1564
- to || (to = defaultTo);
1565
- const { x, y, width, height } = box;
1566
- set(realFrom, x + from.x * width, y + from.y * height);
1567
- set(realTo, x + to.x * width, y + to.y * height);
1568
- const transform = get();
1569
- const angle = getAngle(realFrom, realTo);
1570
- if (Platform.conicGradientRotate90) {
1571
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1);
1572
- rotateOfOuter(transform, realFrom, angle + 90);
1573
- }
1574
- else {
1575
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1));
1576
- rotateOfOuter(transform, realFrom, angle);
1577
- }
1724
+ toPoint(from || 'center', box, realFrom);
1725
+ toPoint(to || 'bottom', box, realTo);
1578
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));
1579
1727
  applyStops(style, paint.stops, opacity);
1580
- 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;
1581
1732
  if (blendMode)
1582
1733
  data.blendMode = blendMode;
1583
1734
  return data;
1584
1735
  }
1585
1736
 
1586
- let recycleMap;
1587
- function compute(attrName, ui) {
1588
- const value = [];
1589
- const data = ui.__;
1590
- let item;
1591
- let paints = data.__input[attrName];
1592
- if (!(paints instanceof Array))
1593
- paints = [paints];
1594
- recycleMap = recycleImage(attrName, data);
1595
- for (let i = 0, len = paints.length; i < len; i++) {
1596
- item = getLeafPaint(attrName, paints[i], ui);
1597
- if (item)
1598
- value.push(item);
1599
- }
1600
- data['_' + attrName] = value.length ? value : undefined;
1601
- let isPixel;
1602
- if (paints.length === 1) {
1603
- const paint = paints[0];
1604
- if (paint.type === 'image')
1605
- isPixel = ImageManager$1.isPixel(paint);
1606
- }
1607
- if (attrName === 'fill') {
1608
- data.__pixelFill = isPixel;
1609
- }
1610
- else {
1611
- data.__pixelStroke = isPixel;
1612
- }
1613
- }
1614
- function getLeafPaint(attrName, paint, ui) {
1615
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1616
- return undefined;
1617
- const { boxBounds } = ui.__layout;
1618
- switch (paint.type) {
1619
- case 'solid':
1620
- let { type, blendMode, color, opacity } = paint;
1621
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
1622
- case 'image':
1623
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1624
- case 'linear':
1625
- return linearGradient(paint, boxBounds);
1626
- case 'radial':
1627
- return radialGradient(paint, boxBounds);
1628
- case 'angular':
1629
- return conicGradient(paint, boxBounds);
1630
- default:
1631
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
1632
- }
1633
- }
1634
-
1635
- var UIPaint = /*#__PURE__*/Object.freeze({
1636
- __proto__: null,
1637
- compute: compute,
1638
- drawTextStroke: drawTextStroke,
1639
- fill: fill,
1640
- fillText: fillText,
1641
- fills: fills,
1642
- recycleImage: recycleImage,
1643
- shape: shape,
1644
- stroke: stroke,
1645
- strokeText: strokeText,
1646
- strokes: strokes
1647
- });
1737
+ const PaintGradientModule = {
1738
+ linearGradient,
1739
+ radialGradient,
1740
+ conicGradient,
1741
+ getTransform
1742
+ };
1648
1743
 
1649
1744
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1650
1745
  const tempBounds = {};
1651
1746
  const offsetOutBounds$1 = {};
1652
- function shadow(ui, current, shape, renderOptions) {
1747
+ function shadow(ui, current, shape) {
1653
1748
  let copyBounds, spreadScale;
1654
- const { __world, __layout } = ui;
1749
+ const { __nowWorld: nowWorld, __layout } = ui;
1655
1750
  const { shadow } = ui.__;
1656
1751
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1657
1752
  const other = current.getSameCanvas();
@@ -1666,21 +1761,21 @@ function shadow(ui, current, shape, renderOptions) {
1666
1761
  other.restore();
1667
1762
  other.save();
1668
1763
  if (worldCanvas) {
1669
- other.copyWorld(other, bounds, __world, 'copy');
1670
- copyBounds = __world;
1764
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1765
+ copyBounds = nowWorld;
1671
1766
  }
1672
- 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');
1673
1768
  }
1674
- if (ui.__worldFlipped || renderOptions.matrix) {
1675
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1769
+ if (ui.__worldFlipped) {
1770
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1676
1771
  }
1677
1772
  else {
1678
1773
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1679
1774
  }
1680
1775
  if (end && index < end)
1681
- other.clear();
1776
+ other.clearWorld(copyBounds, true);
1682
1777
  });
1683
- other.recycle();
1778
+ other.recycle(copyBounds);
1684
1779
  }
1685
1780
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1686
1781
  const { bounds, shapeBounds } = shape;
@@ -1711,9 +1806,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1711
1806
 
1712
1807
  const { toOffsetOutBounds } = BoundsHelper;
1713
1808
  const offsetOutBounds = {};
1714
- function innerShadow(ui, current, shape, renderOptions) {
1809
+ function innerShadow(ui, current, shape) {
1715
1810
  let copyBounds, spreadScale;
1716
- const { __world, __layout: __layout } = ui;
1811
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1717
1812
  const { innerShadow } = ui.__;
1718
1813
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1719
1814
  const other = current.getSameCanvas();
@@ -1726,40 +1821,115 @@ function innerShadow(ui, current, shape, renderOptions) {
1726
1821
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1727
1822
  other.restore();
1728
1823
  if (worldCanvas) {
1729
- other.copyWorld(other, bounds, __world, 'copy');
1730
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1731
- copyBounds = __world;
1824
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1825
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
1826
+ copyBounds = nowWorld;
1732
1827
  }
1733
1828
  else {
1734
1829
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1735
1830
  copyBounds = bounds;
1736
1831
  }
1737
1832
  other.fillWorld(copyBounds, item.color, 'source-in');
1738
- if (ui.__worldFlipped || renderOptions.matrix) {
1739
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1833
+ if (ui.__worldFlipped) {
1834
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1740
1835
  }
1741
1836
  else {
1742
1837
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1743
1838
  }
1744
1839
  if (end && index < end)
1745
- other.clear();
1840
+ other.clearWorld(copyBounds, true);
1746
1841
  });
1747
- other.recycle();
1842
+ other.recycle(copyBounds);
1748
1843
  }
1749
1844
 
1750
1845
  function blur(ui, current, origin) {
1751
1846
  const { blur } = ui.__;
1752
- origin.setWorldBlur(blur * ui.__world.a);
1753
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
1847
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
1848
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
1754
1849
  origin.filter = 'none';
1755
1850
  }
1756
1851
 
1757
- var UIEffect = /*#__PURE__*/Object.freeze({
1758
- __proto__: null,
1759
- blur: blur,
1760
- innerShadow: innerShadow,
1761
- shadow: shadow
1762
- });
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
+ }
1763
1933
 
1764
1934
  const money = '¥¥$€££¢¢';
1765
1935
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -1916,7 +2086,8 @@ function createRows(drawData, content, style) {
1916
2086
  if (breakAll) {
1917
2087
  if (wordWidth)
1918
2088
  addWord();
1919
- addRow();
2089
+ if (rowWidth)
2090
+ addRow();
1920
2091
  }
1921
2092
  else {
1922
2093
  if (!afterBreak)
@@ -1924,10 +2095,12 @@ function createRows(drawData, content, style) {
1924
2095
  if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
1925
2096
  if (wordWidth)
1926
2097
  addWord();
1927
- addRow();
2098
+ if (rowWidth)
2099
+ addRow();
1928
2100
  }
1929
2101
  else {
1930
- addRow();
2102
+ if (rowWidth)
2103
+ addRow();
1931
2104
  }
1932
2105
  }
1933
2106
  }
@@ -2022,11 +2195,11 @@ function layoutChar(drawData, style, width, _height) {
2022
2195
  if (mode === WordMode) {
2023
2196
  wordChar = { char: '', x: charX };
2024
2197
  charX = toWordChar(word.data, charX, wordChar);
2025
- if (wordChar.char !== ' ')
2198
+ if (row.isOverflow || wordChar.char !== ' ')
2026
2199
  row.data.push(wordChar);
2027
2200
  }
2028
2201
  else {
2029
- charX = toChar(word.data, charX, row.data);
2202
+ charX = toChar(word.data, charX, row.data, row.isOverflow);
2030
2203
  }
2031
2204
  if (!row.paraEnd && addWordWidth) {
2032
2205
  charX += addWordWidth;
@@ -2053,9 +2226,9 @@ function toWordChar(data, charX, wordChar) {
2053
2226
  });
2054
2227
  return charX;
2055
2228
  }
2056
- function toChar(data, charX, rowData) {
2229
+ function toChar(data, charX, rowData, isOverflow) {
2057
2230
  data.forEach(char => {
2058
- if (char.char !== ' ') {
2231
+ if (isOverflow || char.char !== ' ') {
2059
2232
  char.x = charX;
2060
2233
  rowData.push(char);
2061
2234
  }
@@ -2087,12 +2260,14 @@ function layoutText(drawData, style) {
2087
2260
  for (let i = 0, len = rows.length; i < len; i++) {
2088
2261
  row = rows[i];
2089
2262
  row.x = x;
2090
- switch (textAlign) {
2091
- case 'center':
2092
- row.x += (width - row.width) / 2;
2093
- break;
2094
- case 'right':
2095
- 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
+ }
2096
2271
  }
2097
2272
  if (row.paraStart && paraSpacing && i > 0)
2098
2273
  starY += paraSpacing;
@@ -2128,16 +2303,20 @@ function layoutText(drawData, style) {
2128
2303
  bounds.height = realHeight;
2129
2304
  }
2130
2305
 
2131
- function clipText(drawData, style) {
2306
+ function clipText(drawData, style, x, width) {
2307
+ if (!width)
2308
+ return;
2132
2309
  const { rows, overflow } = drawData;
2133
2310
  let { textOverflow } = style;
2134
2311
  rows.splice(overflow);
2135
- if (textOverflow !== 'hide') {
2136
- if (textOverflow === 'ellipsis')
2312
+ if (textOverflow && textOverflow !== 'show') {
2313
+ if (textOverflow === 'hide')
2314
+ textOverflow = '';
2315
+ else if (textOverflow === 'ellipsis')
2137
2316
  textOverflow = '...';
2138
2317
  let char, charRight;
2139
- const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2140
- const right = style.x + style.width - ellipsisWidth;
2318
+ const ellipsisWidth = textOverflow ? Platform.canvas.measureText(textOverflow).width : 0;
2319
+ const right = x + width - ellipsisWidth;
2141
2320
  const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2142
2321
  list.forEach(row => {
2143
2322
  if (row.isOverflow && row.data) {
@@ -2184,42 +2363,40 @@ function decorationText(drawData, style) {
2184
2363
  }
2185
2364
 
2186
2365
  const { top, right, bottom, left } = Direction4;
2187
- const TextConvert = {
2188
- getDrawData(content, style) {
2189
- if (typeof content !== 'string')
2190
- content = String(content);
2191
- let x = 0, y = 0;
2192
- let width = style.__getInput('width') || 0;
2193
- let height = style.__getInput('height') || 0;
2194
- const { textDecoration, __font, __padding: padding } = style;
2195
- if (padding) {
2196
- if (width) {
2197
- x = padding[left];
2198
- width -= (padding[right] + padding[left]);
2199
- }
2200
- if (height) {
2201
- y = padding[top];
2202
- height -= (padding[top] + padding[bottom]);
2203
- }
2204
- }
2205
- const drawData = {
2206
- bounds: { x, y, width, height },
2207
- rows: [],
2208
- paraNumber: 0,
2209
- font: Platform.canvas.font = __font
2210
- };
2211
- createRows(drawData, content, style);
2212
- if (padding)
2213
- padAutoText(padding, drawData, style, width, height);
2214
- layoutText(drawData, style);
2215
- layoutChar(drawData, style, width);
2216
- if (drawData.overflow)
2217
- clipText(drawData, style);
2218
- if (textDecoration !== 'none')
2219
- decorationText(drawData, style);
2220
- return drawData;
2221
- }
2222
- };
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
+ }
2223
2400
  function padAutoText(padding, drawData, style, width, height) {
2224
2401
  if (!width) {
2225
2402
  switch (style.textAlign) {
@@ -2247,67 +2424,152 @@ function offsetText(drawData, attrName, value) {
2247
2424
  rows[i][attrName] += value;
2248
2425
  }
2249
2426
 
2250
- const ColorConvert = {
2251
- string(color, opacity) {
2252
- if (typeof color === 'string')
2253
- return color;
2254
- let a = color.a === undefined ? 1 : color.a;
2255
- if (opacity)
2256
- a *= opacity;
2257
- const rgb = color.r + ',' + color.g + ',' + color.b;
2258
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2259
- }
2427
+ const TextConvertModule = {
2428
+ getDrawData
2260
2429
  };
2261
2430
 
2262
- 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 = {
2263
2464
  export(leaf, filename, options) {
2264
- Export.running = true;
2465
+ this.running = true;
2466
+ const fileType = FileHelper.fileType(filename);
2467
+ options = FileHelper.getExportOptions(options);
2265
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
+ }
2266
2490
  const { leafer } = leaf;
2267
2491
  if (leafer) {
2492
+ checkLazy(leaf);
2268
2493
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2269
- let quality, blob;
2270
- let { canvas } = leafer;
2271
- let { unreal } = canvas;
2272
- if (unreal) {
2273
- canvas = canvas.getSameCanvas();
2274
- canvas.backgroundColor = leafer.config.fill;
2275
- 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;
2276
2510
  }
2277
- switch (typeof options) {
2278
- case 'object':
2279
- if (options.quality)
2280
- quality = options.quality;
2281
- if (options.blob)
2282
- blob = true;
2283
- break;
2284
- case 'number':
2285
- quality = options;
2286
- break;
2287
- case 'boolean':
2288
- 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);
2289
2537
  }
2290
- let data;
2291
- if (filename.includes('.')) {
2292
- 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
+ if (slice) {
2542
+ leaf = leafer;
2543
+ renderOptions.bounds = canvas.bounds;
2293
2544
  }
2294
- else if (blob) {
2295
- data = yield canvas.toBlob(filename, quality);
2545
+ canvas.save();
2546
+ if (isFrame && fill !== undefined) {
2547
+ const oldFill = leaf.get('fill');
2548
+ leaf.fill = '';
2549
+ leaf.__render(canvas, renderOptions);
2550
+ leaf.fill = oldFill;
2296
2551
  }
2297
2552
  else {
2298
- data = yield canvas.toDataURL(filename, quality);
2553
+ leaf.__render(canvas, renderOptions);
2299
2554
  }
2300
- success({ data });
2301
- resolve();
2302
- Export.running = false;
2303
- if (unreal)
2304
- canvas.recycle();
2555
+ canvas.restore();
2556
+ if (trim) {
2557
+ trimBounds = getTrimBounds(canvas);
2558
+ const old = canvas, { width, height } = trimBounds;
2559
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2560
+ canvas = Creator.canvas(config);
2561
+ canvas.copyWorld(old, trimBounds, config);
2562
+ }
2563
+ if (needFill)
2564
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2565
+ if (onCanvas)
2566
+ onCanvas(canvas);
2567
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2568
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2305
2569
  }));
2306
2570
  }
2307
2571
  else {
2308
- success({ data: false });
2309
- resolve();
2310
- Export.running = false;
2572
+ over({ data: false });
2311
2573
  }
2312
2574
  }));
2313
2575
  }
@@ -2320,13 +2582,64 @@ function addTask(task) {
2320
2582
  tasker.add(() => __awaiter(this, void 0, void 0, function* () { return yield task(resolve); }), { parallel: false });
2321
2583
  });
2322
2584
  }
2585
+ function checkLazy(leaf) {
2586
+ if (leaf.__.__needComputePaint)
2587
+ leaf.__.__computePaint();
2588
+ if (leaf.isBranch)
2589
+ leaf.children.forEach(child => checkLazy(child));
2590
+ }
2591
+
2592
+ const canvas = LeaferCanvasBase.prototype;
2593
+ const debug = Debug.get('@leafer-ui/export');
2594
+ canvas.export = function (filename, options) {
2595
+ const { quality, blob } = FileHelper.getExportOptions(options);
2596
+ if (filename.includes('.')) {
2597
+ return this.saveAs(filename, quality);
2598
+ }
2599
+ else if (blob) {
2600
+ return this.toBlob(filename, quality);
2601
+ }
2602
+ else {
2603
+ return this.toDataURL(filename, quality);
2604
+ }
2605
+ };
2606
+ canvas.toBlob = function (type, quality) {
2607
+ return new Promise((resolve) => {
2608
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2609
+ resolve(blob);
2610
+ }).catch((e) => {
2611
+ debug.error(e);
2612
+ resolve(null);
2613
+ });
2614
+ });
2615
+ };
2616
+ canvas.toDataURL = function (type, quality) {
2617
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
2618
+ };
2619
+ canvas.saveAs = function (filename, quality) {
2620
+ return new Promise((resolve) => {
2621
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2622
+ resolve(true);
2623
+ }).catch((e) => {
2624
+ debug.error(e);
2625
+ resolve(false);
2626
+ });
2627
+ });
2628
+ };
2323
2629
 
2324
- Object.assign(Paint, UIPaint);
2325
- Object.assign(Effect, UIEffect);
2326
- Object.assign(TextConvert$1, TextConvert);
2327
- Object.assign(ColorConvert$1, ColorConvert);
2328
- Object.assign(Export$2, Export);
2630
+ Object.assign(TextConvert, TextConvertModule);
2631
+ Object.assign(ColorConvert, ColorConvertModule);
2632
+ Object.assign(Paint, PaintModule);
2633
+ Object.assign(PaintImage, PaintImageModule);
2634
+ Object.assign(PaintGradient, PaintGradientModule);
2635
+ Object.assign(Effect, EffectModule);
2636
+ Object.assign(Export, ExportModule);
2329
2637
 
2638
+ Object.assign(Creator, {
2639
+ interaction: (target, canvas, selector, options) => new InteractionBase(target, canvas, selector, options),
2640
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2641
+ hitCanvasManager: () => new HitCanvasManager()
2642
+ });
2330
2643
  useCanvas();
2331
2644
 
2332
2645
  export { Layouter, LeaferCanvas, Renderer, Selector, Watcher, useCanvas };