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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.esm.js CHANGED
@@ -1,9 +1,10 @@
1
- import { LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, Platform, AnimateEvent, ResizeEvent, BoundsHelper, Creator, LeaferCanvasBase, canvasPatch, LeaferImage, InteractionBase, FileHelper, MatrixHelper, ImageEvent, PointHelper, Direction4, TaskProcessor } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, Creator, LeaferImage, defineKey, FileHelper, LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, ResizeEvent, BoundsHelper, Answer, MatrixHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
4
  import { writeFileSync } from 'fs';
5
- import { ColorConvert as ColorConvert$1, ImageManager as ImageManager$1, Paint, Effect, TextConvert as TextConvert$1, Export as Export$2 } from '@leafer-ui/core';
5
+ import { InteractionBase, HitCanvasManager } from '@leafer-ui/core';
6
6
  export * from '@leafer-ui/core';
7
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
7
8
 
8
9
  /******************************************************************************
9
10
  Copyright (c) Microsoft Corporation.
@@ -37,6 +38,73 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
37
38
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
38
39
  };
39
40
 
41
+ class LeaferCanvas extends LeaferCanvasBase {
42
+ get allowBackgroundColor() { return true; }
43
+ init() {
44
+ this.__createView();
45
+ this.__createContext();
46
+ this.resize(this.config);
47
+ if (Platform.roundRectPatch) {
48
+ this.context.__proto__.roundRect = null;
49
+ canvasPatch(this.context.__proto__);
50
+ }
51
+ }
52
+ __createView() {
53
+ this.view = Platform.origin.createCanvas(1, 1);
54
+ }
55
+ updateViewSize() {
56
+ const { width, height, pixelRatio } = this;
57
+ this.view.width = Math.ceil(width * pixelRatio);
58
+ this.view.height = Math.ceil(height * pixelRatio);
59
+ this.clientBounds = this.bounds;
60
+ }
61
+ }
62
+
63
+ const { mineType, fileType } = FileHelper;
64
+ Object.assign(Creator, {
65
+ canvas: (options, manager) => new LeaferCanvas(options, manager),
66
+ image: (options) => new LeaferImage(options)
67
+ });
68
+ function useCanvas(canvasType, power) {
69
+ Platform.canvasType = canvasType;
70
+ if (!Platform.origin) {
71
+ if (canvasType === 'skia') {
72
+ const { Canvas, loadImage } = power;
73
+ Platform.origin = {
74
+ createCanvas: (width, height, format) => new Canvas(width, height, format),
75
+ canvasToDataURL: (canvas, type, quality) => canvas.toDataURLSync(type, { quality }),
76
+ canvasToBolb: (canvas, type, quality) => canvas.toBuffer(type, { quality }),
77
+ canvasSaveAs: (canvas, filename, quality) => canvas.saveAs(filename, { quality }),
78
+ download(_url, _filename) { return undefined; },
79
+ loadImage(src) { return loadImage(Platform.image.getRealURL(src)); }
80
+ };
81
+ Platform.roundRectPatch = true;
82
+ }
83
+ else if (canvasType === 'napi') {
84
+ const { Canvas, loadImage } = power;
85
+ Platform.origin = {
86
+ createCanvas: (width, height, format) => new Canvas(width, height, format),
87
+ canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
88
+ canvasToBolb: (canvas, type, quality) => __awaiter(this, void 0, void 0, function* () { return canvas.toBuffer(mineType(type), quality); }),
89
+ canvasSaveAs: (canvas, filename, quality) => __awaiter(this, void 0, void 0, function* () { return writeFileSync(filename, canvas.toBuffer(mineType(fileType(filename)), quality)); }),
90
+ download(_url, _filename) { return undefined; },
91
+ loadImage(src) { return loadImage(Platform.image.getRealURL(src)); }
92
+ };
93
+ }
94
+ Platform.ellipseToCurve = true;
95
+ Platform.event = {
96
+ stopDefault(_origin) { },
97
+ stopNow(_origin) { },
98
+ stop(_origin) { }
99
+ };
100
+ Platform.canvas = Creator.canvas();
101
+ }
102
+ }
103
+ Platform.name = 'node';
104
+ Platform.requestRender = function (render) { setTimeout(render); };
105
+ defineKey(Platform, 'devicePixelRatio', { get() { return 1; } });
106
+ Platform.conicGradientSupport = true;
107
+
40
108
  class Watcher {
41
109
  get childrenChanged() { return this.hasAdd || this.hasRemove || this.hasVisible; }
42
110
  get updatedList() {
@@ -218,7 +286,7 @@ class LayoutBlockData {
218
286
  }
219
287
 
220
288
  const { updateAllMatrix, updateAllChange } = LeafHelper;
221
- const debug$1 = Debug.get('Layouter');
289
+ const debug$2 = Debug.get('Layouter');
222
290
  class Layouter {
223
291
  constructor(target, userConfig) {
224
292
  this.totalTimes = 0;
@@ -253,7 +321,7 @@ class Layouter {
253
321
  target.emitEvent(new LayoutEvent(LayoutEvent.END, this.layoutedBlocks, this.times));
254
322
  }
255
323
  catch (e) {
256
- debug$1.error(e);
324
+ debug$2.error(e);
257
325
  }
258
326
  this.layoutedBlocks = null;
259
327
  }
@@ -267,9 +335,9 @@ class Layouter {
267
335
  }
268
336
  layoutOnce() {
269
337
  if (this.layouting)
270
- return debug$1.warn('layouting');
338
+ return debug$2.warn('layouting');
271
339
  if (this.times > 3)
272
- return debug$1.warn('layout max times');
340
+ return debug$2.warn('layout max times');
273
341
  this.times++;
274
342
  this.totalTimes++;
275
343
  this.layouting = true;
@@ -335,9 +403,11 @@ class Layouter {
335
403
  updateAllChange(target);
336
404
  }
337
405
  addExtra(leaf) {
338
- const block = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
339
- block.updatedList.add(leaf);
340
- block.beforeBounds.add(leaf.__world);
406
+ if (!this.__updatedList.has(leaf)) {
407
+ const { updatedList, beforeBounds } = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
408
+ updatedList.length ? beforeBounds.add(leaf.__world) : beforeBounds.set(leaf.__world);
409
+ updatedList.add(leaf);
410
+ }
341
411
  }
342
412
  createBlock(data) {
343
413
  return new LayoutBlockData(data);
@@ -371,7 +441,7 @@ class Layouter {
371
441
  }
372
442
  }
373
443
 
374
- const debug = Debug.get('Renderer');
444
+ const debug$1 = Debug.get('Renderer');
375
445
  class Renderer {
376
446
  get needFill() { return !!(!this.canvas.allowBackgroundColor && this.config.fill); }
377
447
  constructor(target, canvas, userConfig) {
@@ -409,7 +479,7 @@ class Renderer {
409
479
  const { target } = this;
410
480
  this.times = 0;
411
481
  this.totalBounds = new Bounds();
412
- debug.log(target.innerName, '--->');
482
+ debug$1.log(target.innerName, '--->');
413
483
  try {
414
484
  this.emitRender(RenderEvent.START);
415
485
  this.renderOnce(callback);
@@ -418,9 +488,9 @@ class Renderer {
418
488
  }
419
489
  catch (e) {
420
490
  this.rendering = false;
421
- debug.error(e);
491
+ debug$1.error(e);
422
492
  }
423
- debug.log('-------------|');
493
+ debug$1.log('-------------|');
424
494
  }
425
495
  renderAgain() {
426
496
  if (this.rendering) {
@@ -432,9 +502,9 @@ class Renderer {
432
502
  }
433
503
  renderOnce(callback) {
434
504
  if (this.rendering)
435
- return debug.warn('rendering');
505
+ return debug$1.warn('rendering');
436
506
  if (this.times > 3)
437
- return debug.warn('render max times');
507
+ return debug$1.warn('render max times');
438
508
  this.times++;
439
509
  this.totalTimes++;
440
510
  this.rendering = true;
@@ -447,6 +517,10 @@ class Renderer {
447
517
  }
448
518
  else {
449
519
  this.requestLayout();
520
+ if (this.ignore) {
521
+ this.ignore = this.rendering = false;
522
+ return;
523
+ }
450
524
  this.emitRender(RenderEvent.BEFORE);
451
525
  if (this.config.usePartRender && this.totalTimes > 1) {
452
526
  this.partRender();
@@ -467,7 +541,7 @@ class Renderer {
467
541
  partRender() {
468
542
  const { canvas, updateBlocks: list } = this;
469
543
  if (!list)
470
- return debug.warn('PartRender: need update attr');
544
+ return debug$1.warn('PartRender: need update attr');
471
545
  this.mergeBlocks();
472
546
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
473
547
  this.clipRender(block); });
@@ -483,7 +557,7 @@ class Renderer {
483
557
  canvas.clear();
484
558
  }
485
559
  else {
486
- bounds.spread(1 + 1 / this.canvas.pixelRatio).ceil();
560
+ bounds.spread(10 + 1 / this.canvas.pixelRatio).ceil();
487
561
  canvas.clearWorld(bounds, true);
488
562
  canvas.clipWorld(bounds, true);
489
563
  }
@@ -507,14 +581,14 @@ class Renderer {
507
581
  if (Debug.showRepaint)
508
582
  this.canvas.strokeWorld(bounds, 'red');
509
583
  this.target.__render(this.canvas, options);
510
- this.renderBounds = realBounds || bounds;
584
+ this.renderBounds = realBounds = realBounds || bounds;
511
585
  this.renderOptions = options;
512
- this.totalBounds.isEmpty() ? this.totalBounds = this.renderBounds : this.totalBounds.add(this.renderBounds);
586
+ this.totalBounds.isEmpty() ? this.totalBounds = realBounds : this.totalBounds.add(realBounds);
513
587
  if (Debug.showHitView)
514
588
  this.renderHitView(options);
515
589
  if (Debug.showBoundsView)
516
590
  this.renderBoundsView(options);
517
- this.canvas.updateRender();
591
+ this.canvas.updateRender(realBounds);
518
592
  }
519
593
  renderHitView(_options) { }
520
594
  renderBoundsView(_options) { }
@@ -536,12 +610,12 @@ class Renderer {
536
610
  const startTime = Date.now();
537
611
  Platform.requestRender(() => {
538
612
  this.FPS = Math.min(60, Math.ceil(1000 / (Date.now() - startTime)));
539
- if (this.changed) {
540
- if (this.running && this.canvas.view)
613
+ if (this.running) {
614
+ this.target.emit(AnimateEvent.FRAME);
615
+ if (this.changed && this.canvas.view)
541
616
  this.render();
617
+ this.target.emit(RenderEvent.NEXT);
542
618
  }
543
- if (this.running)
544
- this.target.emit(AnimateEvent.FRAME);
545
619
  if (this.target)
546
620
  this.__requestRender();
547
621
  });
@@ -554,9 +628,12 @@ class Renderer {
554
628
  const bounds = new Bounds(0, 0, width, height);
555
629
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
556
630
  this.addBlock(this.canvas.bounds);
557
- this.target.forceUpdate('blendMode');
631
+ this.target.forceUpdate('surface');
632
+ return;
558
633
  }
559
634
  }
635
+ this.addBlock(new Bounds(0, 0, 1, 1));
636
+ this.changed = true;
560
637
  }
561
638
  __onLayoutEnd(event) {
562
639
  if (event.data)
@@ -567,7 +644,7 @@ class Renderer {
567
644
  empty = (!leaf.__world.width || !leaf.__world.height);
568
645
  if (empty) {
569
646
  if (!leaf.isLeafer)
570
- debug.tip(leaf.innerName, ': empty');
647
+ debug$1.tip(leaf.innerName, ': empty');
571
648
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
572
649
  }
573
650
  return empty;
@@ -594,23 +671,13 @@ class Renderer {
594
671
  if (this.target) {
595
672
  this.stop();
596
673
  this.__removeListenEvents();
597
- this.target = null;
598
- this.canvas = null;
599
- this.config = null;
674
+ this.target = this.canvas = this.config = null;
600
675
  }
601
676
  }
602
677
  }
603
678
 
604
- var AnswerType;
605
- (function (AnswerType) {
606
- AnswerType[AnswerType["No"] = 0] = "No";
607
- AnswerType[AnswerType["Yes"] = 1] = "Yes";
608
- AnswerType[AnswerType["NoAndSkip"] = 2] = "NoAndSkip";
609
- AnswerType[AnswerType["YesAndSkip"] = 3] = "YesAndSkip";
610
- })(AnswerType || (AnswerType = {}));
611
-
612
679
  const { hitRadiusPoint } = BoundsHelper;
613
- class Pather {
680
+ class Picker {
614
681
  constructor(target, selector) {
615
682
  this.target = target;
616
683
  this.selector = selector;
@@ -622,33 +689,41 @@ class Pather {
622
689
  options = {};
623
690
  const through = options.through || false;
624
691
  const ignoreHittable = options.ignoreHittable || false;
692
+ const target = options.target || this.target;
625
693
  this.exclude = options.exclude || null;
626
694
  this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius };
627
- this.findList = [];
628
- this.eachFind(this.target.children, this.target.__onlyHitMask);
629
- const list = this.findList;
630
- const leaf = this.getBestMatchLeaf();
695
+ this.findList = new LeafList(options.findList);
696
+ if (!options.findList)
697
+ this.hitBranch(target);
698
+ const { list } = this.findList;
699
+ const leaf = this.getBestMatchLeaf(list, options.bottomList, ignoreHittable);
631
700
  const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf);
632
701
  this.clear();
633
- return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf };
702
+ return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf };
634
703
  }
635
- getBestMatchLeaf() {
636
- const { findList: targets } = this;
637
- if (targets.length > 1) {
704
+ getBestMatchLeaf(list, bottomList, ignoreHittable) {
705
+ if (list.length) {
638
706
  let find;
639
- this.findList = [];
707
+ this.findList = new LeafList();
640
708
  const { x, y } = this.point;
641
709
  const point = { x, y, radiusX: 0, radiusY: 0 };
642
- for (let i = 0, len = targets.length; i < len; i++) {
643
- find = targets[i];
644
- if (LeafHelper.worldHittable(find)) {
710
+ for (let i = 0, len = list.length; i < len; i++) {
711
+ find = list[i];
712
+ if (ignoreHittable || LeafHelper.worldHittable(find)) {
645
713
  this.hitChild(find, point);
646
714
  if (this.findList.length)
647
- return this.findList[0];
715
+ return this.findList.list[0];
648
716
  }
649
717
  }
650
718
  }
651
- return targets[0];
719
+ if (bottomList) {
720
+ for (let i = 0, len = bottomList.length; i < len; i++) {
721
+ this.hitChild(bottomList[i].target, this.point, bottomList[i].proxy);
722
+ if (this.findList.length)
723
+ return this.findList.list[0];
724
+ }
725
+ }
726
+ return list[0];
652
727
  }
653
728
  getPath(leaf) {
654
729
  const path = new LeafList();
@@ -660,7 +735,7 @@ class Pather {
660
735
  return path;
661
736
  }
662
737
  getHitablePath(leaf) {
663
- const path = this.getPath(leaf);
738
+ const path = this.getPath(leaf && leaf.hittable ? leaf : null);
664
739
  let item, hittablePath = new LeafList();
665
740
  for (let i = path.list.length - 1; i > -1; i--) {
666
741
  item = path.list[i];
@@ -690,12 +765,15 @@ class Pather {
690
765
  }
691
766
  return throughPath;
692
767
  }
768
+ hitBranch(branch) {
769
+ this.eachFind(branch.children, branch.__onlyHitMask);
770
+ }
693
771
  eachFind(children, hitMask) {
694
772
  let child, hit;
695
773
  const { point } = this, len = children.length;
696
774
  for (let i = len - 1; i > -1; i--) {
697
775
  child = children[i];
698
- if (!child.__.visible || (hitMask && !child.__.isMask))
776
+ if (!child.__.visible || (hitMask && !child.__.mask))
699
777
  continue;
700
778
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
701
779
  if (child.isBranch) {
@@ -711,11 +789,15 @@ class Pather {
711
789
  }
712
790
  }
713
791
  }
714
- hitChild(child, point) {
792
+ hitChild(child, point, proxy) {
715
793
  if (this.exclude && this.exclude.has(child))
716
794
  return;
717
- if (child.__hitWorld(point))
718
- this.findList.push(child);
795
+ if (child.__hitWorld(point)) {
796
+ const { parent } = child;
797
+ if (parent && parent.__hasMask && !child.__.mask && !parent.children.some(item => item.__.mask && item.__hitWorld(point)))
798
+ return;
799
+ this.findList.add(proxy || child);
800
+ }
719
801
  }
720
802
  clear() {
721
803
  this.point = null;
@@ -727,7 +809,8 @@ class Pather {
727
809
  }
728
810
  }
729
811
 
730
- const { Yes, NoAndSkip, YesAndSkip } = AnswerType;
812
+ const { Yes, NoAndSkip, YesAndSkip } = Answer;
813
+ const idCondition = {}, classNameCondition = {}, tagCondition = {};
731
814
  class Selector {
732
815
  constructor(target, userConfig) {
733
816
  this.config = {};
@@ -737,12 +820,13 @@ class Selector {
737
820
  id: (leaf, name) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
738
821
  innerId: (leaf, innerId) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
739
822
  className: (leaf, name) => leaf.className === name ? 1 : 0,
740
- tag: (leaf, name) => leaf.__tag === name ? 1 : 0
823
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0,
824
+ tags: (leaf, nameMap) => nameMap[leaf.__tag] ? 1 : 0
741
825
  };
742
826
  this.target = target;
743
827
  if (userConfig)
744
828
  this.config = DataHelper.default(userConfig, this.config);
745
- this.pather = new Pather(target, this);
829
+ this.picker = new Picker(target, this);
746
830
  this.__listenEvents();
747
831
  }
748
832
  getBy(condition, branch, one, options) {
@@ -753,12 +837,25 @@ class Selector {
753
837
  case 'string':
754
838
  switch (condition[0]) {
755
839
  case '#':
756
- const leaf = this.getById(condition.substring(1), branch);
757
- return one ? leaf : (leaf ? [leaf] : []);
840
+ idCondition.id = condition.substring(1), condition = idCondition;
841
+ break;
758
842
  case '.':
759
- return this.getByMethod(this.methods.className, branch, one, condition.substring(1));
843
+ classNameCondition.className = condition.substring(1), condition = classNameCondition;
844
+ break;
760
845
  default:
761
- return this.getByMethod(this.methods.tag, branch, one, condition);
846
+ tagCondition.tag = condition, condition = tagCondition;
847
+ }
848
+ case 'object':
849
+ if (condition.id !== undefined) {
850
+ const leaf = this.getById(condition.id, branch);
851
+ return one ? leaf : (leaf ? [leaf] : []);
852
+ }
853
+ else if (condition.tag) {
854
+ const { tag } = condition, isArray = tag instanceof Array;
855
+ return this.getByMethod(isArray ? this.methods.tags : this.methods.tag, branch, one, isArray ? DataHelper.toMap(tag) : tag);
856
+ }
857
+ else {
858
+ return this.getByMethod(this.methods.className, branch, one, condition.className);
762
859
  }
763
860
  case 'function':
764
861
  return this.getByMethod(condition, branch, one, options);
@@ -767,7 +864,7 @@ class Selector {
767
864
  getByPoint(hitPoint, hitRadius, options) {
768
865
  if (Platform.name === 'node')
769
866
  this.target.emit(LayoutEvent.CHECK_UPDATE);
770
- return this.pather.getByPoint(hitPoint, hitRadius, options);
867
+ return this.picker.getByPoint(hitPoint, hitRadius, options);
771
868
  }
772
869
  getByInnerId(innerId, branch) {
773
870
  const cache = this.innerIdMap[innerId];
@@ -843,7 +940,7 @@ class Selector {
843
940
  destroy() {
844
941
  if (this.__eventIds.length) {
845
942
  this.__removeListenEvents();
846
- this.pather.destroy();
943
+ this.picker.destroy();
847
944
  this.findLeaf = null;
848
945
  this.innerIdMap = {};
849
946
  this.idMap = {};
@@ -859,483 +956,91 @@ Object.assign(Creator, {
859
956
  });
860
957
  Platform.layout = Layouter.fullLayout;
861
958
 
862
- class LeaferCanvas extends LeaferCanvasBase {
863
- get allowBackgroundColor() { return true; }
864
- init() {
865
- this.__createView();
866
- this.__createContext();
867
- this.resize(this.config);
868
- if (Platform.roundRectPatch) {
869
- this.context.__proto__.roundRect = null;
870
- canvasPatch(this.context.__proto__);
871
- }
872
- }
873
- __createView() {
874
- this.view = Platform.origin.createCanvas(1, 1);
875
- }
876
- updateViewSize() {
877
- const { width, height, pixelRatio } = this;
878
- this.view.width = width * pixelRatio;
879
- this.view.height = height * pixelRatio;
880
- this.clientBounds = this.bounds;
881
- }
882
- }
883
-
884
- const { mineType, fileType } = FileHelper;
885
- Object.assign(Creator, {
886
- canvas: (options, manager) => new LeaferCanvas(options, manager),
887
- image: (options) => new LeaferImage(options),
888
- hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
889
- interaction: (target, canvas, selector, options) => { return new InteractionBase(target, canvas, selector, options); }
890
- });
891
- function useCanvas(canvasType, power) {
892
- Platform.canvasType = canvasType;
893
- if (!Platform.origin) {
894
- if (canvasType === 'skia') {
895
- const { Canvas, loadImage } = power;
896
- Platform.origin = {
897
- createCanvas: (width, height, format) => new Canvas(width, height, format),
898
- canvasToDataURL: (canvas, type, quality) => canvas.toDataURLSync(type, { quality }),
899
- canvasToBolb: (canvas, type, quality) => canvas.toBuffer(type, { quality }),
900
- canvasSaveAs: (canvas, filename, quality) => canvas.saveAs(filename, { quality }),
901
- loadImage
902
- };
903
- Platform.roundRectPatch = true;
959
+ function fillText(ui, canvas) {
960
+ let row;
961
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
962
+ for (let i = 0, len = rows.length; i < len; i++) {
963
+ row = rows[i];
964
+ if (row.text) {
965
+ canvas.fillText(row.text, row.x, row.y);
904
966
  }
905
- else if (canvasType === 'napi') {
906
- const { Canvas, loadImage } = power;
907
- Platform.origin = {
908
- createCanvas: (width, height, format) => new Canvas(width, height, format),
909
- canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
910
- canvasToBolb: (canvas, type, quality) => __awaiter(this, void 0, void 0, function* () { return canvas.toBuffer(mineType(type), quality); }),
911
- canvasSaveAs: (canvas, filename, quality) => __awaiter(this, void 0, void 0, function* () { return writeFileSync(filename, canvas.toBuffer(mineType(fileType(filename)), quality)); }),
912
- loadImage
913
- };
967
+ else if (row.data) {
968
+ row.data.forEach(charData => {
969
+ canvas.fillText(charData.char, charData.x, row.y);
970
+ });
914
971
  }
915
- Platform.ellipseToCurve = true;
916
- Platform.event = {
917
- stopDefault(_origin) { },
918
- stopNow(_origin) { },
919
- stop(_origin) { }
920
- };
921
- Platform.canvas = Creator.canvas();
972
+ if (decorationY)
973
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
922
974
  }
923
975
  }
924
- Platform.name = 'node';
925
- Platform.requestRender = function (render) { setTimeout(render); };
926
- Platform.devicePixelRatio = 1;
927
- Platform.conicGradientSupport = true;
928
976
 
929
- let origin = {};
930
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper, rotate } = MatrixHelper;
931
- function fillOrFitMode(data, mode, box, width, height, rotation) {
932
- const transform = get$4();
933
- const swap = rotation && rotation !== 180;
934
- const sw = box.width / (swap ? height : width);
935
- const sh = box.height / (swap ? width : height);
936
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
937
- const x = box.x + (box.width - width * scale) / 2;
938
- const y = box.y + (box.height - height * scale) / 2;
939
- translate$1(transform, x, y);
940
- scaleHelper(transform, scale);
941
- if (rotation)
942
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
943
- data.scaleX = data.scaleY = scale;
944
- data.transform = transform;
945
- }
946
- function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
947
- const transform = get$4();
948
- translate$1(transform, box.x, box.y);
949
- if (x || y)
950
- translate$1(transform, x, y);
951
- if (scaleX) {
952
- scaleHelper(transform, scaleX, scaleY);
953
- data.scaleX = transform.a;
954
- data.scaleY = transform.d;
955
- }
956
- if (rotation)
957
- rotate(transform, rotation);
958
- data.transform = transform;
977
+ function fill(fill, ui, canvas) {
978
+ canvas.fillStyle = fill;
979
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
959
980
  }
960
- function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation) {
961
- const transform = get$4();
962
- if (rotation) {
963
- rotate(transform, rotation);
964
- switch (rotation) {
965
- case 90:
966
- translate$1(transform, height, 0);
967
- break;
968
- case 180:
969
- translate$1(transform, width, height);
970
- break;
971
- case 270:
972
- translate$1(transform, 0, width);
973
- break;
981
+ function fills(fills, ui, canvas) {
982
+ let item;
983
+ const { windingRule, __font } = ui.__;
984
+ for (let i = 0, len = fills.length; i < len; i++) {
985
+ item = fills[i];
986
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
987
+ continue;
988
+ if (item.style) {
989
+ canvas.fillStyle = item.style;
990
+ if (item.transform) {
991
+ canvas.save();
992
+ canvas.transform(item.transform);
993
+ if (item.blendMode)
994
+ canvas.blendMode = item.blendMode;
995
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
996
+ canvas.restore();
997
+ }
998
+ else {
999
+ if (item.blendMode) {
1000
+ canvas.saveBlendMode(item.blendMode);
1001
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1002
+ canvas.restoreBlendMode();
1003
+ }
1004
+ else {
1005
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1006
+ }
1007
+ }
974
1008
  }
975
1009
  }
976
- origin.x = box.x;
977
- origin.y = box.y;
978
- if (x || y)
979
- origin.x += x, origin.y += y;
980
- translate$1(transform, origin.x, origin.y);
981
- if (scaleX) {
982
- scaleOfOuter$2(transform, origin, scaleX, scaleY);
983
- data.scaleX = scaleX;
984
- data.scaleY = scaleY;
985
- }
986
- data.transform = transform;
987
1010
  }
988
1011
 
989
- const { get: get$3, translate } = MatrixHelper;
990
- function createData(leafPaint, image, paint, box) {
991
- let { width, height } = image;
992
- const { opacity, mode, offset, scale, size, rotation, blendMode, repeat } = paint;
993
- const sameBox = box.width === width && box.height === height;
994
- if (blendMode)
995
- leafPaint.blendMode = blendMode;
996
- const data = leafPaint.data = { mode };
997
- let x, y, scaleX, scaleY;
998
- if (offset)
999
- x = offset.x, y = offset.y;
1000
- if (size) {
1001
- scaleX = (typeof size === 'number' ? size : size.width) / width;
1002
- scaleY = (typeof size === 'number' ? size : size.height) / height;
1003
- }
1004
- else if (scale) {
1005
- scaleX = typeof scale === 'number' ? scale : scale.x;
1006
- scaleY = typeof scale === 'number' ? scale : scale.y;
1007
- }
1008
- switch (mode) {
1009
- case 'strench':
1010
- if (!sameBox)
1011
- width = box.width, height = box.height;
1012
- if (box.x || box.y) {
1013
- data.transform = get$3();
1014
- translate(data.transform, box.x, box.y);
1015
- }
1012
+ function strokeText(stroke, ui, canvas) {
1013
+ const { strokeAlign } = ui.__;
1014
+ const isStrokes = typeof stroke !== 'string';
1015
+ switch (strokeAlign) {
1016
+ case 'center':
1017
+ canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1018
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1016
1019
  break;
1017
- case 'clip':
1018
- if (offset || scaleX || rotation)
1019
- clipMode(data, box, x, y, scaleX, scaleY, rotation);
1020
+ case 'inside':
1021
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1020
1022
  break;
1021
- case 'repeat':
1022
- if (!sameBox || scaleX || rotation)
1023
- repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation);
1024
- if (!repeat)
1025
- data.repeat = 'repeat';
1023
+ case 'outside':
1024
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1026
1025
  break;
1027
- case 'fit':
1028
- case 'cover':
1029
- default:
1030
- if (!sameBox || rotation)
1031
- fillOrFitMode(data, mode, box, width, height, rotation);
1032
1026
  }
1033
- data.width = width;
1034
- data.height = height;
1035
- if (opacity)
1036
- data.opacity = opacity;
1037
- if (repeat)
1038
- data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1039
1027
  }
1040
-
1041
- function image(ui, attrName, attrValue, box, firstUse) {
1042
- const leafPaint = { type: attrValue.type };
1043
- const image = leafPaint.image = ImageManager.get(attrValue);
1044
- const event = (firstUse || image.loading) && { target: ui, image, attrName, attrValue };
1045
- if (image.ready) {
1046
- if (hasNaturalSize(ui, attrName, image))
1047
- createData(leafPaint, image, attrValue, box);
1048
- if (firstUse) {
1049
- emit(ImageEvent.LOAD, event);
1050
- emit(ImageEvent.LOADED, event);
1051
- }
1052
- }
1053
- else if (image.error) {
1054
- if (firstUse) {
1055
- ui.forceUpdate('surface');
1056
- event.error = image.error;
1057
- emit(ImageEvent.ERROR, event);
1058
- }
1028
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1029
+ const { __strokeWidth, __font } = ui.__;
1030
+ const out = canvas.getSameCanvas(true, true);
1031
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1032
+ out.font = __font;
1033
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1034
+ out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1035
+ fillText(ui, out);
1036
+ out.blendMode = 'normal';
1037
+ if (ui.__worldFlipped) {
1038
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1059
1039
  }
1060
1040
  else {
1061
- if (firstUse)
1062
- emit(ImageEvent.LOAD, event);
1063
- leafPaint.loadId = image.load(() => {
1064
- if (!ui.destroyed) {
1065
- if (hasNaturalSize(ui, attrName, image)) {
1066
- createData(leafPaint, image, attrValue, box);
1067
- ui.forceUpdate('surface');
1068
- }
1069
- emit(ImageEvent.LOADED, event);
1070
- }
1071
- }, (error) => {
1072
- ui.forceUpdate('surface');
1073
- event.error = error;
1074
- emit(ImageEvent.ERROR, event);
1075
- });
1076
- }
1077
- return leafPaint;
1078
- }
1079
- function hasNaturalSize(ui, attrName, image) {
1080
- if (attrName === 'fill' && !ui.__.__naturalWidth) {
1081
- const { __: d } = ui;
1082
- d.__naturalWidth = image.width;
1083
- d.__naturalHeight = image.height;
1084
- if (!d.__getInput('width') || !d.__getInput('height')) {
1085
- ui.forceUpdate('width');
1086
- if (ui.__proxyData) {
1087
- ui.setProxyAttr('width', ui.__.width);
1088
- ui.setProxyAttr('height', ui.__.height);
1089
- }
1090
- return false;
1091
- }
1092
- }
1093
- return true;
1094
- }
1095
- function emit(type, data) {
1096
- if (data.target.hasEvent(type))
1097
- data.target.emitEvent(new ImageEvent(type, data));
1098
- }
1099
-
1100
- const Export$1 = {};
1101
-
1102
- const { get: get$2, scale, copy: copy$1 } = MatrixHelper;
1103
- function createPattern(ui, paint, pixelRatio) {
1104
- let { scaleX, scaleY } = ui.__world;
1105
- const id = scaleX + '-' + scaleY;
1106
- if (paint.patternId !== id && !ui.destroyed) {
1107
- scaleX = Math.abs(scaleX);
1108
- scaleY = Math.abs(scaleY);
1109
- const { image, data } = paint;
1110
- let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1111
- if (sx) {
1112
- imageMatrix = get$2();
1113
- copy$1(imageMatrix, transform);
1114
- scale(imageMatrix, 1 / sx, 1 / sy);
1115
- scaleX *= sx;
1116
- scaleY *= sy;
1117
- }
1118
- scaleX *= pixelRatio;
1119
- scaleY *= pixelRatio;
1120
- width *= scaleX;
1121
- height *= scaleY;
1122
- const size = width * height;
1123
- if (!repeat) {
1124
- if (size > Platform.image.maxCacheSize)
1125
- return false;
1126
- }
1127
- let maxSize = Platform.image.maxPatternSize;
1128
- if (!image.isSVG) {
1129
- const imageSize = image.width * image.height;
1130
- if (maxSize > imageSize)
1131
- maxSize = imageSize;
1132
- }
1133
- if (size > maxSize)
1134
- imageScale = Math.sqrt(size / maxSize);
1135
- if (imageScale) {
1136
- scaleX /= imageScale;
1137
- scaleY /= imageScale;
1138
- width /= imageScale;
1139
- height /= imageScale;
1140
- }
1141
- if (sx) {
1142
- scaleX /= sx;
1143
- scaleY /= sy;
1144
- }
1145
- if (transform || scaleX !== 1 || scaleY !== 1) {
1146
- if (!imageMatrix) {
1147
- imageMatrix = get$2();
1148
- if (transform)
1149
- copy$1(imageMatrix, transform);
1150
- }
1151
- scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1152
- }
1153
- const pattern = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), repeat || (Platform.origin.noRepeat || 'no-repeat'));
1154
- try {
1155
- if (paint.transform)
1156
- paint.transform = null;
1157
- if (imageMatrix)
1158
- pattern.setTransform ? pattern.setTransform(imageMatrix) : paint.transform = imageMatrix;
1159
- }
1160
- catch (_a) {
1161
- paint.transform = imageMatrix;
1162
- }
1163
- paint.style = pattern;
1164
- paint.patternId = id;
1165
- return true;
1166
- }
1167
- else {
1168
- return false;
1169
- }
1170
- }
1171
-
1172
- const { abs } = Math;
1173
- function checkImage(ui, canvas, paint, allowPaint) {
1174
- const { scaleX, scaleY } = ui.__world;
1175
- if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1176
- return false;
1177
- }
1178
- else {
1179
- const { data } = paint;
1180
- if (allowPaint) {
1181
- if (!data.repeat) {
1182
- let { width, height } = data;
1183
- width *= abs(scaleX) * canvas.pixelRatio;
1184
- height *= abs(scaleY) * canvas.pixelRatio;
1185
- if (data.scaleX) {
1186
- width *= data.scaleX;
1187
- height *= data.scaleY;
1188
- }
1189
- allowPaint = width * height > Platform.image.maxCacheSize;
1190
- }
1191
- else {
1192
- allowPaint = false;
1193
- }
1194
- }
1195
- if (allowPaint) {
1196
- canvas.save();
1197
- canvas.clip();
1198
- if (paint.blendMode)
1199
- canvas.blendMode = paint.blendMode;
1200
- if (data.opacity)
1201
- canvas.opacity *= data.opacity;
1202
- if (data.transform)
1203
- canvas.transform(data.transform);
1204
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1205
- canvas.restore();
1206
- return true;
1207
- }
1208
- else {
1209
- if (!paint.style || Export$1.running) {
1210
- createPattern(ui, paint, canvas.pixelRatio);
1211
- }
1212
- else {
1213
- if (!paint.patternTask) {
1214
- paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1215
- paint.patternTask = null;
1216
- if (canvas.bounds.hit(ui.__world))
1217
- createPattern(ui, paint, canvas.pixelRatio);
1218
- ui.forceUpdate('surface');
1219
- }), 300);
1220
- }
1221
- }
1222
- return false;
1223
- }
1041
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1224
1042
  }
1225
- }
1226
-
1227
- function recycleImage(attrName, data) {
1228
- const paints = data['_' + attrName];
1229
- if (paints instanceof Array) {
1230
- let image, recycleMap, input, url;
1231
- for (let i = 0, len = paints.length; i < len; i++) {
1232
- image = paints[i].image;
1233
- url = image && image.url;
1234
- if (url) {
1235
- if (!recycleMap)
1236
- recycleMap = {};
1237
- recycleMap[url] = true;
1238
- ImageManager.recycle(image);
1239
- if (image.loading) {
1240
- if (!input) {
1241
- input = (data.__input && data.__input[attrName]) || [];
1242
- if (!(input instanceof Array))
1243
- input = [input];
1244
- }
1245
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1246
- }
1247
- }
1248
- }
1249
- return recycleMap;
1250
- }
1251
- return null;
1252
- }
1253
-
1254
- function fillText(ui, canvas) {
1255
- let row;
1256
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1257
- for (let i = 0, len = rows.length; i < len; i++) {
1258
- row = rows[i];
1259
- if (row.text) {
1260
- canvas.fillText(row.text, row.x, row.y);
1261
- }
1262
- else if (row.data) {
1263
- row.data.forEach(charData => {
1264
- canvas.fillText(charData.char, charData.x, row.y);
1265
- });
1266
- }
1267
- if (decorationY)
1268
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1269
- }
1270
- }
1271
-
1272
- function fill(fill, ui, canvas) {
1273
- canvas.fillStyle = fill;
1274
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1275
- }
1276
- function fills(fills, ui, canvas) {
1277
- let item;
1278
- const { windingRule, __font } = ui.__;
1279
- for (let i = 0, len = fills.length; i < len; i++) {
1280
- item = fills[i];
1281
- if (item.image && checkImage(ui, canvas, item, !__font))
1282
- continue;
1283
- if (item.style) {
1284
- canvas.fillStyle = item.style;
1285
- if (item.transform) {
1286
- canvas.save();
1287
- canvas.transform(item.transform);
1288
- if (item.blendMode)
1289
- canvas.blendMode = item.blendMode;
1290
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1291
- canvas.restore();
1292
- }
1293
- else {
1294
- if (item.blendMode) {
1295
- canvas.saveBlendMode(item.blendMode);
1296
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1297
- canvas.restoreBlendMode();
1298
- }
1299
- else {
1300
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1301
- }
1302
- }
1303
- }
1304
- }
1305
- }
1306
-
1307
- function strokeText(stroke, ui, canvas, renderOptions) {
1308
- const { strokeAlign } = ui.__;
1309
- const isStrokes = typeof stroke !== 'string';
1310
- switch (strokeAlign) {
1311
- case 'center':
1312
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1313
- isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1314
- break;
1315
- case 'inside':
1316
- drawAlignStroke('inside', stroke, isStrokes, ui, canvas, renderOptions);
1317
- break;
1318
- case 'outside':
1319
- drawAlignStroke('outside', stroke, isStrokes, ui, canvas, renderOptions);
1320
- break;
1321
- }
1322
- }
1323
- function drawAlignStroke(align, stroke, isStrokes, ui, canvas, renderOptions) {
1324
- const { strokeWidth, __font } = ui.__;
1325
- const out = canvas.getSameCanvas(true);
1326
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1327
- out.font = __font;
1328
- isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1329
- out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1330
- fillText(ui, out);
1331
- out.blendMode = 'normal';
1332
- if (ui.__worldFlipped || renderOptions.matrix) {
1333
- canvas.copyWorldByReset(out);
1334
- }
1335
- else {
1336
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1337
- }
1338
- out.recycle();
1043
+ out.recycle(ui.__nowWorld);
1339
1044
  }
1340
1045
  function drawTextStroke(ui, canvas) {
1341
1046
  let row;
@@ -1358,7 +1063,7 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
1358
1063
  let item;
1359
1064
  for (let i = 0, len = strokes.length; i < len; i++) {
1360
1065
  item = strokes[i];
1361
- if (item.image && checkImage(ui, canvas, item, false))
1066
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1362
1067
  continue;
1363
1068
  if (item.style) {
1364
1069
  canvas.strokeStyle = item.style;
@@ -1374,138 +1079,567 @@ function drawStrokesStyle(strokes, isText, ui, canvas) {
1374
1079
  }
1375
1080
  }
1376
1081
 
1377
- function stroke(stroke, ui, canvas, renderOptions) {
1082
+ function stroke(stroke, ui, canvas) {
1378
1083
  const options = ui.__;
1379
- const { strokeWidth, strokeAlign, __font } = options;
1380
- if (!strokeWidth)
1084
+ const { __strokeWidth, strokeAlign, __font } = options;
1085
+ if (!__strokeWidth)
1381
1086
  return;
1382
1087
  if (__font) {
1383
- strokeText(stroke, ui, canvas, renderOptions);
1088
+ strokeText(stroke, ui, canvas);
1384
1089
  }
1385
1090
  else {
1386
1091
  switch (strokeAlign) {
1387
1092
  case 'center':
1388
- canvas.setStroke(stroke, strokeWidth, options);
1093
+ canvas.setStroke(stroke, __strokeWidth, options);
1389
1094
  canvas.stroke();
1390
1095
  break;
1391
1096
  case 'inside':
1392
1097
  canvas.save();
1393
- canvas.setStroke(stroke, strokeWidth * 2, options);
1098
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1394
1099
  options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1395
1100
  canvas.stroke();
1396
1101
  canvas.restore();
1397
1102
  break;
1398
1103
  case 'outside':
1399
- const out = canvas.getSameCanvas(true);
1400
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1104
+ const out = canvas.getSameCanvas(true, true);
1105
+ out.setStroke(stroke, __strokeWidth * 2, options);
1401
1106
  ui.__drawRenderPath(out);
1402
1107
  out.stroke();
1403
1108
  options.windingRule ? out.clip(options.windingRule) : out.clip();
1404
1109
  out.clearWorld(ui.__layout.renderBounds);
1405
- if (ui.__worldFlipped || renderOptions.matrix) {
1406
- canvas.copyWorldByReset(out);
1110
+ if (ui.__worldFlipped) {
1111
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1112
+ }
1113
+ else {
1114
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1115
+ }
1116
+ out.recycle(ui.__nowWorld);
1117
+ break;
1118
+ }
1119
+ }
1120
+ }
1121
+ function strokes(strokes, ui, canvas) {
1122
+ const options = ui.__;
1123
+ const { __strokeWidth, strokeAlign, __font } = options;
1124
+ if (!__strokeWidth)
1125
+ return;
1126
+ if (__font) {
1127
+ strokeText(strokes, ui, canvas);
1128
+ }
1129
+ else {
1130
+ switch (strokeAlign) {
1131
+ case 'center':
1132
+ canvas.setStroke(undefined, __strokeWidth, options);
1133
+ drawStrokesStyle(strokes, false, ui, canvas);
1134
+ break;
1135
+ case 'inside':
1136
+ canvas.save();
1137
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1138
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1139
+ drawStrokesStyle(strokes, false, ui, canvas);
1140
+ canvas.restore();
1141
+ break;
1142
+ case 'outside':
1143
+ const { renderBounds } = ui.__layout;
1144
+ const out = canvas.getSameCanvas(true, true);
1145
+ ui.__drawRenderPath(out);
1146
+ out.setStroke(undefined, __strokeWidth * 2, options);
1147
+ drawStrokesStyle(strokes, false, ui, out);
1148
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1149
+ out.clearWorld(renderBounds);
1150
+ if (ui.__worldFlipped) {
1151
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1407
1152
  }
1408
1153
  else {
1409
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1154
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1410
1155
  }
1411
- out.recycle();
1156
+ out.recycle(ui.__nowWorld);
1412
1157
  break;
1413
1158
  }
1414
1159
  }
1415
1160
  }
1416
- function strokes(strokes, ui, canvas, renderOptions) {
1417
- const options = ui.__;
1418
- const { strokeWidth, strokeAlign, __font } = options;
1419
- if (!strokeWidth)
1420
- return;
1421
- if (__font) {
1422
- strokeText(strokes, ui, canvas, renderOptions);
1161
+
1162
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1163
+ function shape(ui, current, options) {
1164
+ const canvas = current.getSameCanvas();
1165
+ const nowWorld = ui.__nowWorld;
1166
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1167
+ let { scaleX, scaleY } = nowWorld;
1168
+ if (scaleX < 0)
1169
+ scaleX = -scaleX;
1170
+ if (scaleY < 0)
1171
+ scaleY = -scaleY;
1172
+ if (current.bounds.includes(nowWorld)) {
1173
+ worldCanvas = canvas;
1174
+ bounds = shapeBounds = nowWorld;
1175
+ }
1176
+ else {
1177
+ const { renderShapeSpread: spread } = ui.__layout;
1178
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, scaleX === scaleY ? spread * scaleX : [spread * scaleY, spread * scaleX]) : current.bounds, nowWorld);
1179
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1180
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1181
+ if (fitMatrix.a < 1) {
1182
+ worldCanvas = current.getSameCanvas();
1183
+ ui.__renderShape(worldCanvas, options);
1184
+ scaleX *= fitScaleX;
1185
+ scaleY *= fitScaleY;
1186
+ }
1187
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1188
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1189
+ if (options.matrix) {
1190
+ const { matrix } = options;
1191
+ fitMatrix.multiply(matrix);
1192
+ fitScaleX *= matrix.scaleX;
1193
+ fitScaleY *= matrix.scaleY;
1194
+ }
1195
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1196
+ }
1197
+ ui.__renderShape(canvas, options);
1198
+ return {
1199
+ canvas, matrix: fitMatrix, bounds,
1200
+ worldCanvas, shapeBounds, scaleX, scaleY
1201
+ };
1202
+ }
1203
+
1204
+ let recycleMap;
1205
+ function compute(attrName, ui) {
1206
+ const data = ui.__, leafPaints = [];
1207
+ let paints = data.__input[attrName], hasOpacityPixel;
1208
+ if (!(paints instanceof Array))
1209
+ paints = [paints];
1210
+ recycleMap = PaintImage.recycleImage(attrName, data);
1211
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1212
+ item = getLeafPaint(attrName, paints[i], ui);
1213
+ if (item)
1214
+ leafPaints.push(item);
1215
+ }
1216
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1217
+ if (leafPaints.length && leafPaints[0].image)
1218
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1219
+ if (attrName === 'fill') {
1220
+ data.__pixelFill = hasOpacityPixel;
1221
+ }
1222
+ else {
1223
+ data.__pixelStroke = hasOpacityPixel;
1224
+ }
1225
+ }
1226
+ function getLeafPaint(attrName, paint, ui) {
1227
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1228
+ return undefined;
1229
+ const { boxBounds } = ui.__layout;
1230
+ switch (paint.type) {
1231
+ case 'solid':
1232
+ let { type, blendMode, color, opacity } = paint;
1233
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1234
+ case 'image':
1235
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1236
+ case 'linear':
1237
+ return PaintGradient.linearGradient(paint, boxBounds);
1238
+ case 'radial':
1239
+ return PaintGradient.radialGradient(paint, boxBounds);
1240
+ case 'angular':
1241
+ return PaintGradient.conicGradient(paint, boxBounds);
1242
+ default:
1243
+ return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1244
+ }
1245
+ }
1246
+
1247
+ const PaintModule = {
1248
+ compute,
1249
+ fill,
1250
+ fills,
1251
+ fillText,
1252
+ stroke,
1253
+ strokes,
1254
+ strokeText,
1255
+ drawTextStroke,
1256
+ shape
1257
+ };
1258
+
1259
+ let origin = {};
1260
+ const { get: get$3, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, scale: scaleHelper, rotate } = MatrixHelper;
1261
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1262
+ const transform = get$3();
1263
+ translate$1(transform, box.x + x, box.y + y);
1264
+ scaleHelper(transform, scaleX, scaleY);
1265
+ if (rotation)
1266
+ rotateOfOuter$1(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1267
+ data.transform = transform;
1268
+ }
1269
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
1270
+ const transform = get$3();
1271
+ translate$1(transform, box.x + x, box.y + y);
1272
+ if (scaleX)
1273
+ scaleHelper(transform, scaleX, scaleY);
1274
+ if (rotation)
1275
+ rotate(transform, rotation);
1276
+ data.transform = transform;
1277
+ }
1278
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align) {
1279
+ const transform = get$3();
1280
+ if (rotation) {
1281
+ if (align === 'center') {
1282
+ rotateOfOuter$1(transform, { x: width / 2, y: height / 2 }, rotation);
1283
+ }
1284
+ else {
1285
+ rotate(transform, rotation);
1286
+ switch (rotation) {
1287
+ case 90:
1288
+ translate$1(transform, height, 0);
1289
+ break;
1290
+ case 180:
1291
+ translate$1(transform, width, height);
1292
+ break;
1293
+ case 270:
1294
+ translate$1(transform, 0, width);
1295
+ break;
1296
+ }
1297
+ }
1298
+ }
1299
+ origin.x = box.x + x;
1300
+ origin.y = box.y + y;
1301
+ translate$1(transform, origin.x, origin.y);
1302
+ if (scaleX)
1303
+ scaleOfOuter$1(transform, origin, scaleX, scaleY);
1304
+ data.transform = transform;
1305
+ }
1306
+
1307
+ const { get: get$2, translate } = MatrixHelper;
1308
+ const tempBox = new Bounds();
1309
+ const tempPoint = {};
1310
+ function createData(leafPaint, image, paint, box) {
1311
+ const { blendMode } = paint;
1312
+ if (blendMode)
1313
+ leafPaint.blendMode = blendMode;
1314
+ leafPaint.data = getPatternData(paint, box, image);
1315
+ }
1316
+ function getPatternData(paint, box, image) {
1317
+ let { width, height } = image;
1318
+ if (paint.padding)
1319
+ box = tempBox.set(box).shrink(paint.padding);
1320
+ const { opacity, mode, align, offset, scale, size, rotation, repeat } = paint;
1321
+ const sameBox = box.width === width && box.height === height;
1322
+ const data = { mode };
1323
+ const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1324
+ const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1325
+ let x = 0, y = 0, scaleX, scaleY;
1326
+ if (!mode || mode === 'cover' || mode === 'fit') {
1327
+ if (!sameBox || rotation) {
1328
+ const sw = box.width / swapWidth, sh = box.height / swapHeight;
1329
+ scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1330
+ x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1331
+ }
1332
+ }
1333
+ else if (size) {
1334
+ scaleX = (typeof size === 'number' ? size : size.width) / width;
1335
+ scaleY = (typeof size === 'number' ? size : size.height) / height;
1336
+ }
1337
+ else if (scale) {
1338
+ scaleX = typeof scale === 'number' ? scale : scale.x;
1339
+ scaleY = typeof scale === 'number' ? scale : scale.y;
1340
+ }
1341
+ if (align) {
1342
+ const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1343
+ if (scaleX)
1344
+ imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1345
+ AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1346
+ x += tempPoint.x, y += tempPoint.y;
1347
+ }
1348
+ if (offset)
1349
+ x += offset.x, y += offset.y;
1350
+ switch (mode) {
1351
+ case 'strench':
1352
+ if (!sameBox)
1353
+ width = box.width, height = box.height;
1354
+ break;
1355
+ case 'normal':
1356
+ case 'clip':
1357
+ if (x || y || scaleX || rotation)
1358
+ clipMode(data, box, x, y, scaleX, scaleY, rotation);
1359
+ break;
1360
+ case 'repeat':
1361
+ if (!sameBox || scaleX || rotation)
1362
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1363
+ if (!repeat)
1364
+ data.repeat = 'repeat';
1365
+ break;
1366
+ case 'fit':
1367
+ case 'cover':
1368
+ default:
1369
+ if (scaleX)
1370
+ fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1371
+ }
1372
+ if (!data.transform) {
1373
+ if (box.x || box.y) {
1374
+ data.transform = get$2();
1375
+ translate(data.transform, box.x, box.y);
1376
+ }
1377
+ }
1378
+ if (scaleX && mode !== 'strench') {
1379
+ data.scaleX = scaleX;
1380
+ data.scaleY = scaleY;
1381
+ }
1382
+ data.width = width;
1383
+ data.height = height;
1384
+ if (opacity)
1385
+ data.opacity = opacity;
1386
+ if (repeat)
1387
+ data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1388
+ return data;
1389
+ }
1390
+
1391
+ let cache, box = new Bounds();
1392
+ const { isSame } = BoundsHelper;
1393
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1394
+ let leafPaint, event;
1395
+ const image = ImageManager.get(paint);
1396
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1397
+ leafPaint = cache.leafPaint;
1398
+ }
1399
+ else {
1400
+ leafPaint = { type: paint.type, image };
1401
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1402
+ }
1403
+ if (firstUse || image.loading)
1404
+ event = { image, attrName, attrValue: paint };
1405
+ if (image.ready) {
1406
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1407
+ if (firstUse) {
1408
+ onLoad(ui, event);
1409
+ onLoadSuccess(ui, event);
1410
+ }
1411
+ }
1412
+ else if (image.error) {
1413
+ if (firstUse)
1414
+ onLoadError(ui, event, image.error);
1415
+ }
1416
+ else {
1417
+ ignoreRender(ui, true);
1418
+ if (firstUse)
1419
+ onLoad(ui, event);
1420
+ leafPaint.loadId = image.load(() => {
1421
+ ignoreRender(ui, false);
1422
+ if (!ui.destroyed) {
1423
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1424
+ if (image.hasOpacityPixel)
1425
+ ui.__layout.hitCanvasChanged = true;
1426
+ ui.forceUpdate('surface');
1427
+ }
1428
+ onLoadSuccess(ui, event);
1429
+ }
1430
+ leafPaint.loadId = null;
1431
+ }, (error) => {
1432
+ ignoreRender(ui, false);
1433
+ onLoadError(ui, event, error);
1434
+ leafPaint.loadId = null;
1435
+ });
1436
+ }
1437
+ return leafPaint;
1438
+ }
1439
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1440
+ if (attrName === 'fill' && !ui.__.__naturalWidth) {
1441
+ const data = ui.__;
1442
+ data.__naturalWidth = image.width / data.pixelRatio;
1443
+ data.__naturalHeight = image.height / data.pixelRatio;
1444
+ if (data.__autoSide) {
1445
+ ui.forceUpdate('width');
1446
+ if (ui.__proxyData) {
1447
+ ui.setProxyAttr('width', data.width);
1448
+ ui.setProxyAttr('height', data.height);
1449
+ }
1450
+ return false;
1451
+ }
1452
+ }
1453
+ if (!leafPaint.data)
1454
+ createData(leafPaint, image, paint, boxBounds);
1455
+ return true;
1456
+ }
1457
+ function onLoad(ui, event) {
1458
+ emit(ui, ImageEvent.LOAD, event);
1459
+ }
1460
+ function onLoadSuccess(ui, event) {
1461
+ emit(ui, ImageEvent.LOADED, event);
1462
+ }
1463
+ function onLoadError(ui, event, error) {
1464
+ event.error = error;
1465
+ ui.forceUpdate('surface');
1466
+ emit(ui, ImageEvent.ERROR, event);
1467
+ }
1468
+ function emit(ui, type, data) {
1469
+ if (ui.hasEvent(type))
1470
+ ui.emitEvent(new ImageEvent(type, data));
1471
+ }
1472
+ function ignoreRender(ui, value) {
1473
+ const { leafer } = ui;
1474
+ if (leafer && leafer.viewReady)
1475
+ leafer.renderer.ignore = value;
1476
+ }
1477
+
1478
+ const { get: get$1, scale, copy: copy$1 } = MatrixHelper;
1479
+ const { ceil, abs: abs$1 } = Math;
1480
+ function createPattern(ui, paint, pixelRatio) {
1481
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1482
+ const id = scaleX + '-' + scaleY;
1483
+ if (paint.patternId !== id && !ui.destroyed) {
1484
+ scaleX = abs$1(scaleX);
1485
+ scaleY = abs$1(scaleY);
1486
+ const { image, data } = paint;
1487
+ let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1488
+ if (sx) {
1489
+ imageMatrix = get$1();
1490
+ copy$1(imageMatrix, transform);
1491
+ scale(imageMatrix, 1 / sx, 1 / sy);
1492
+ scaleX *= sx;
1493
+ scaleY *= sy;
1494
+ }
1495
+ scaleX *= pixelRatio;
1496
+ scaleY *= pixelRatio;
1497
+ width *= scaleX;
1498
+ height *= scaleY;
1499
+ const size = width * height;
1500
+ if (!repeat) {
1501
+ if (size > Platform.image.maxCacheSize)
1502
+ return false;
1503
+ }
1504
+ let maxSize = Platform.image.maxPatternSize;
1505
+ if (!image.isSVG) {
1506
+ const imageSize = image.width * image.height;
1507
+ if (maxSize > imageSize)
1508
+ maxSize = imageSize;
1509
+ }
1510
+ if (size > maxSize)
1511
+ imageScale = Math.sqrt(size / maxSize);
1512
+ if (imageScale) {
1513
+ scaleX /= imageScale;
1514
+ scaleY /= imageScale;
1515
+ width /= imageScale;
1516
+ height /= imageScale;
1517
+ }
1518
+ if (sx) {
1519
+ scaleX /= sx;
1520
+ scaleY /= sy;
1521
+ }
1522
+ if (transform || scaleX !== 1 || scaleY !== 1) {
1523
+ if (!imageMatrix) {
1524
+ imageMatrix = get$1();
1525
+ if (transform)
1526
+ copy$1(imageMatrix, transform);
1527
+ }
1528
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1529
+ }
1530
+ const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, opacity);
1531
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1532
+ paint.style = pattern;
1533
+ paint.patternId = id;
1534
+ return true;
1535
+ }
1536
+ else {
1537
+ return false;
1538
+ }
1539
+ }
1540
+
1541
+ const { abs } = Math;
1542
+ function checkImage(ui, canvas, paint, allowPaint) {
1543
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1544
+ if (!paint.data || (paint.patternId === scaleX + '-' + scaleY && !Export.running)) {
1545
+ return false;
1423
1546
  }
1424
1547
  else {
1425
- switch (strokeAlign) {
1426
- case 'center':
1427
- canvas.setStroke(undefined, strokeWidth, options);
1428
- drawStrokesStyle(strokes, false, ui, canvas);
1429
- break;
1430
- case 'inside':
1431
- canvas.save();
1432
- canvas.setStroke(undefined, strokeWidth * 2, options);
1433
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1434
- drawStrokesStyle(strokes, false, ui, canvas);
1435
- canvas.restore();
1436
- break;
1437
- case 'outside':
1438
- const { renderBounds } = ui.__layout;
1439
- const out = canvas.getSameCanvas(true);
1440
- ui.__drawRenderPath(out);
1441
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1442
- drawStrokesStyle(strokes, false, ui, out);
1443
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1444
- out.clearWorld(renderBounds);
1445
- if (ui.__worldFlipped || renderOptions.matrix) {
1446
- canvas.copyWorldByReset(out);
1548
+ const { data } = paint;
1549
+ if (allowPaint) {
1550
+ if (!data.repeat) {
1551
+ let { width, height } = data;
1552
+ width *= abs(scaleX) * canvas.pixelRatio;
1553
+ height *= abs(scaleY) * canvas.pixelRatio;
1554
+ if (data.scaleX) {
1555
+ width *= data.scaleX;
1556
+ height *= data.scaleY;
1447
1557
  }
1448
- else {
1449
- canvas.copyWorldToInner(out, ui.__world, renderBounds);
1558
+ allowPaint = (width * height > Platform.image.maxCacheSize) || Export.running;
1559
+ }
1560
+ else {
1561
+ allowPaint = false;
1562
+ }
1563
+ }
1564
+ if (allowPaint) {
1565
+ canvas.save();
1566
+ canvas.clip();
1567
+ if (paint.blendMode)
1568
+ canvas.blendMode = paint.blendMode;
1569
+ if (data.opacity)
1570
+ canvas.opacity *= data.opacity;
1571
+ if (data.transform)
1572
+ canvas.transform(data.transform);
1573
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1574
+ canvas.restore();
1575
+ return true;
1576
+ }
1577
+ else {
1578
+ if (!paint.style || Export.running) {
1579
+ createPattern(ui, paint, canvas.pixelRatio);
1580
+ }
1581
+ else {
1582
+ if (!paint.patternTask) {
1583
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1584
+ paint.patternTask = null;
1585
+ if (canvas.bounds.hit(ui.__nowWorld))
1586
+ createPattern(ui, paint, canvas.pixelRatio);
1587
+ ui.forceUpdate('surface');
1588
+ }), 300);
1450
1589
  }
1451
- out.recycle();
1452
- break;
1590
+ }
1591
+ return false;
1453
1592
  }
1454
1593
  }
1455
1594
  }
1456
1595
 
1457
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1458
- function shape(ui, current, options) {
1459
- const canvas = current.getSameCanvas();
1460
- let bounds, matrix, shapeBounds;
1461
- let worldCanvas;
1462
- const { __world } = ui;
1463
- let { scaleX, scaleY } = __world;
1464
- if (scaleX < 0)
1465
- scaleX = -scaleX;
1466
- if (scaleY < 0)
1467
- scaleY = -scaleY;
1468
- if (!current.bounds.includes(__world, options.matrix)) {
1469
- const { renderShapeSpread: spread } = ui.__layout;
1470
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1471
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1472
- if (matrix.a < 1) {
1473
- worldCanvas = current.getSameCanvas();
1474
- ui.__renderShape(worldCanvas, options);
1475
- scaleX *= matrix.a;
1476
- scaleY *= matrix.d;
1477
- }
1478
- shapeBounds = getOuterOf(__world, matrix);
1479
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1480
- if (options.matrix)
1481
- matrix.multiply(options.matrix);
1482
- options = Object.assign(Object.assign({}, options), { matrix });
1483
- }
1484
- else {
1485
- if (options.matrix) {
1486
- scaleX *= options.matrix.a;
1487
- scaleY *= options.matrix.d;
1488
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
1489
- }
1490
- else {
1491
- bounds = shapeBounds = __world;
1596
+ function recycleImage(attrName, data) {
1597
+ const paints = data['_' + attrName];
1598
+ if (paints instanceof Array) {
1599
+ let image, recycleMap, input, url;
1600
+ for (let i = 0, len = paints.length; i < len; i++) {
1601
+ image = paints[i].image;
1602
+ url = image && image.url;
1603
+ if (url) {
1604
+ if (!recycleMap)
1605
+ recycleMap = {};
1606
+ recycleMap[url] = true;
1607
+ ImageManager.recycle(image);
1608
+ if (image.loading) {
1609
+ if (!input) {
1610
+ input = (data.__input && data.__input[attrName]) || [];
1611
+ if (!(input instanceof Array))
1612
+ input = [input];
1613
+ }
1614
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1615
+ }
1616
+ }
1492
1617
  }
1493
- worldCanvas = canvas;
1618
+ return recycleMap;
1494
1619
  }
1495
- ui.__renderShape(canvas, options);
1496
- return {
1497
- canvas, matrix, bounds,
1498
- worldCanvas, shapeBounds, scaleX, scaleY
1499
- };
1620
+ return null;
1500
1621
  }
1501
1622
 
1502
- const defaultFrom$2 = { x: 0.5, y: 0 };
1503
- const defaultTo$2 = { x: 0.5, y: 1 };
1623
+ const PaintImageModule = {
1624
+ image,
1625
+ checkImage,
1626
+ createPattern,
1627
+ recycleImage,
1628
+ createData,
1629
+ getPatternData,
1630
+ fillOrFitMode,
1631
+ clipMode,
1632
+ repeatMode
1633
+ };
1634
+
1635
+ const { toPoint: toPoint$2 } = AroundHelper;
1636
+ const realFrom$2 = {};
1637
+ const realTo$2 = {};
1504
1638
  function linearGradient(paint, box) {
1505
1639
  let { from, to, type, blendMode, opacity } = paint;
1506
- from || (from = defaultFrom$2);
1507
- to || (to = defaultTo$2);
1508
- 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);
1640
+ toPoint$2(from || 'top', box, realFrom$2);
1641
+ toPoint$2(to || 'bottom', box, realTo$2);
1642
+ const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1509
1643
  applyStops(style, paint.stops, opacity);
1510
1644
  const data = { type, style };
1511
1645
  if (blendMode)
@@ -1516,137 +1650,84 @@ function applyStops(gradient, stops, opacity) {
1516
1650
  let stop;
1517
1651
  for (let i = 0, len = stops.length; i < len; i++) {
1518
1652
  stop = stops[i];
1519
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
1653
+ if (typeof stop === 'string') {
1654
+ gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1655
+ }
1656
+ else {
1657
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1658
+ }
1520
1659
  }
1521
1660
  }
1522
1661
 
1523
- const { set: set$1, getAngle: getAngle$1, getDistance: getDistance$1 } = PointHelper;
1524
- const { get: get$1, rotateOfOuter: rotateOfOuter$1, scaleOfOuter: scaleOfOuter$1 } = MatrixHelper;
1525
- const defaultFrom$1 = { x: 0.5, y: 0.5 };
1526
- const defaultTo$1 = { x: 0.5, y: 1 };
1662
+ const { getAngle, getDistance: getDistance$1 } = PointHelper;
1663
+ const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1664
+ const { toPoint: toPoint$1 } = AroundHelper;
1527
1665
  const realFrom$1 = {};
1528
1666
  const realTo$1 = {};
1529
1667
  function radialGradient(paint, box) {
1530
1668
  let { from, to, type, opacity, blendMode, stretch } = paint;
1531
- from || (from = defaultFrom$1);
1532
- to || (to = defaultTo$1);
1533
- const { x, y, width, height } = box;
1534
- set$1(realFrom$1, x + from.x * width, y + from.y * height);
1535
- set$1(realTo$1, x + to.x * width, y + to.y * height);
1536
- let transform;
1537
- if (width !== height || stretch) {
1538
- transform = get$1();
1539
- scaleOfOuter$1(transform, realFrom$1, width / height * (stretch || 1), 1);
1540
- rotateOfOuter$1(transform, realFrom$1, getAngle$1(realFrom$1, realTo$1) + 90);
1541
- }
1669
+ toPoint$1(from || 'center', box, realFrom$1);
1670
+ toPoint$1(to || 'bottom', box, realTo$1);
1542
1671
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1543
1672
  applyStops(style, paint.stops, opacity);
1544
- const data = { type, style, transform };
1673
+ const data = { type, style };
1674
+ const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1675
+ if (transform)
1676
+ data.transform = transform;
1545
1677
  if (blendMode)
1546
1678
  data.blendMode = blendMode;
1547
1679
  return data;
1548
1680
  }
1681
+ function getTransform(box, from, to, stretch, rotate90) {
1682
+ let transform;
1683
+ const { width, height } = box;
1684
+ if (width !== height || stretch) {
1685
+ const angle = getAngle(from, to);
1686
+ transform = get();
1687
+ if (rotate90) {
1688
+ scaleOfOuter(transform, from, width / height * (stretch || 1), 1);
1689
+ rotateOfOuter(transform, from, angle + 90);
1690
+ }
1691
+ else {
1692
+ scaleOfOuter(transform, from, 1, width / height * (stretch || 1));
1693
+ rotateOfOuter(transform, from, angle);
1694
+ }
1695
+ }
1696
+ return transform;
1697
+ }
1549
1698
 
1550
- const { set, getAngle, getDistance } = PointHelper;
1551
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1552
- const defaultFrom = { x: 0.5, y: 0.5 };
1553
- const defaultTo = { x: 0.5, y: 1 };
1699
+ const { getDistance } = PointHelper;
1700
+ const { toPoint } = AroundHelper;
1554
1701
  const realFrom = {};
1555
1702
  const realTo = {};
1556
1703
  function conicGradient(paint, box) {
1557
1704
  let { from, to, type, opacity, blendMode, stretch } = paint;
1558
- from || (from = defaultFrom);
1559
- to || (to = defaultTo);
1560
- const { x, y, width, height } = box;
1561
- set(realFrom, x + from.x * width, y + from.y * height);
1562
- set(realTo, x + to.x * width, y + to.y * height);
1563
- const transform = get();
1564
- const angle = getAngle(realFrom, realTo);
1565
- if (Platform.conicGradientRotate90) {
1566
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1);
1567
- rotateOfOuter(transform, realFrom, angle + 90);
1568
- }
1569
- else {
1570
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1));
1571
- rotateOfOuter(transform, realFrom, angle);
1572
- }
1705
+ toPoint(from || 'center', box, realFrom);
1706
+ toPoint(to || 'bottom', box, realTo);
1573
1707
  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));
1574
1708
  applyStops(style, paint.stops, opacity);
1575
- const data = { type, style, transform };
1709
+ const data = { type, style };
1710
+ const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1711
+ if (transform)
1712
+ data.transform = transform;
1576
1713
  if (blendMode)
1577
1714
  data.blendMode = blendMode;
1578
1715
  return data;
1579
1716
  }
1580
1717
 
1581
- let recycleMap;
1582
- function compute(attrName, ui) {
1583
- const value = [];
1584
- const data = ui.__;
1585
- let item;
1586
- let paints = data.__input[attrName];
1587
- if (!(paints instanceof Array))
1588
- paints = [paints];
1589
- recycleMap = recycleImage(attrName, data);
1590
- for (let i = 0, len = paints.length; i < len; i++) {
1591
- item = getLeafPaint(attrName, paints[i], ui);
1592
- if (item)
1593
- value.push(item);
1594
- }
1595
- data['_' + attrName] = value.length ? value : undefined;
1596
- let isPixel;
1597
- if (paints.length === 1) {
1598
- const paint = paints[0];
1599
- if (paint.type === 'image')
1600
- isPixel = ImageManager$1.isPixel(paint);
1601
- }
1602
- if (attrName === 'fill') {
1603
- data.__pixelFill = isPixel;
1604
- }
1605
- else {
1606
- data.__pixelStroke = isPixel;
1607
- }
1608
- }
1609
- function getLeafPaint(attrName, paint, ui) {
1610
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1611
- return undefined;
1612
- const { boxBounds } = ui.__layout;
1613
- switch (paint.type) {
1614
- case 'solid':
1615
- let { type, blendMode, color, opacity } = paint;
1616
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
1617
- case 'image':
1618
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1619
- case 'linear':
1620
- return linearGradient(paint, boxBounds);
1621
- case 'radial':
1622
- return radialGradient(paint, boxBounds);
1623
- case 'angular':
1624
- return conicGradient(paint, boxBounds);
1625
- default:
1626
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
1627
- }
1628
- }
1629
-
1630
- var UIPaint = /*#__PURE__*/Object.freeze({
1631
- __proto__: null,
1632
- compute: compute,
1633
- drawTextStroke: drawTextStroke,
1634
- fill: fill,
1635
- fillText: fillText,
1636
- fills: fills,
1637
- recycleImage: recycleImage,
1638
- shape: shape,
1639
- stroke: stroke,
1640
- strokeText: strokeText,
1641
- strokes: strokes
1642
- });
1718
+ const PaintGradientModule = {
1719
+ linearGradient,
1720
+ radialGradient,
1721
+ conicGradient,
1722
+ getTransform
1723
+ };
1643
1724
 
1644
1725
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1645
1726
  const tempBounds = {};
1646
1727
  const offsetOutBounds$1 = {};
1647
- function shadow(ui, current, shape, renderOptions) {
1728
+ function shadow(ui, current, shape) {
1648
1729
  let copyBounds, spreadScale;
1649
- const { __world, __layout } = ui;
1730
+ const { __nowWorld: nowWorld, __layout } = ui;
1650
1731
  const { shadow } = ui.__;
1651
1732
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1652
1733
  const other = current.getSameCanvas();
@@ -1661,21 +1742,21 @@ function shadow(ui, current, shape, renderOptions) {
1661
1742
  other.restore();
1662
1743
  other.save();
1663
1744
  if (worldCanvas) {
1664
- other.copyWorld(other, bounds, __world, 'copy');
1665
- copyBounds = __world;
1745
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1746
+ copyBounds = nowWorld;
1666
1747
  }
1667
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1748
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1668
1749
  }
1669
- if (ui.__worldFlipped || renderOptions.matrix) {
1670
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1750
+ if (ui.__worldFlipped) {
1751
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1671
1752
  }
1672
1753
  else {
1673
1754
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1674
1755
  }
1675
1756
  if (end && index < end)
1676
- other.clear();
1757
+ other.clearWorld(copyBounds, true);
1677
1758
  });
1678
- other.recycle();
1759
+ other.recycle(copyBounds);
1679
1760
  }
1680
1761
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1681
1762
  const { bounds, shapeBounds } = shape;
@@ -1706,9 +1787,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1706
1787
 
1707
1788
  const { toOffsetOutBounds } = BoundsHelper;
1708
1789
  const offsetOutBounds = {};
1709
- function innerShadow(ui, current, shape, renderOptions) {
1790
+ function innerShadow(ui, current, shape) {
1710
1791
  let copyBounds, spreadScale;
1711
- const { __world, __layout: __layout } = ui;
1792
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1712
1793
  const { innerShadow } = ui.__;
1713
1794
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1714
1795
  const other = current.getSameCanvas();
@@ -1721,40 +1802,115 @@ function innerShadow(ui, current, shape, renderOptions) {
1721
1802
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1722
1803
  other.restore();
1723
1804
  if (worldCanvas) {
1724
- other.copyWorld(other, bounds, __world, 'copy');
1725
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1726
- copyBounds = __world;
1805
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1806
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
1807
+ copyBounds = nowWorld;
1727
1808
  }
1728
1809
  else {
1729
1810
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1730
1811
  copyBounds = bounds;
1731
1812
  }
1732
1813
  other.fillWorld(copyBounds, item.color, 'source-in');
1733
- if (ui.__worldFlipped || renderOptions.matrix) {
1734
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1814
+ if (ui.__worldFlipped) {
1815
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1735
1816
  }
1736
1817
  else {
1737
1818
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1738
1819
  }
1739
1820
  if (end && index < end)
1740
- other.clear();
1821
+ other.clearWorld(copyBounds, true);
1741
1822
  });
1742
- other.recycle();
1823
+ other.recycle(copyBounds);
1743
1824
  }
1744
1825
 
1745
1826
  function blur(ui, current, origin) {
1746
1827
  const { blur } = ui.__;
1747
- origin.setWorldBlur(blur * ui.__world.a);
1748
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
1828
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
1829
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
1749
1830
  origin.filter = 'none';
1750
1831
  }
1751
1832
 
1752
- var UIEffect = /*#__PURE__*/Object.freeze({
1753
- __proto__: null,
1754
- blur: blur,
1755
- innerShadow: innerShadow,
1756
- shadow: shadow
1757
- });
1833
+ function backgroundBlur(_ui, _current, _shape) {
1834
+ }
1835
+
1836
+ const EffectModule = {
1837
+ shadow,
1838
+ innerShadow,
1839
+ blur,
1840
+ backgroundBlur
1841
+ };
1842
+
1843
+ const { excludeRenderBounds } = LeafBoundsHelper;
1844
+ Group.prototype.__renderMask = function (canvas, options) {
1845
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
1846
+ const { children } = this;
1847
+ for (let i = 0, len = children.length; i < len; i++) {
1848
+ child = children[i];
1849
+ if (child.__.mask) {
1850
+ if (currentMask) {
1851
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1852
+ maskCanvas = contentCanvas = null;
1853
+ }
1854
+ if (child.__.mask === 'path') {
1855
+ if (child.opacity < 1) {
1856
+ currentMask = 'opacity-path';
1857
+ maskOpacity = child.opacity;
1858
+ if (!contentCanvas)
1859
+ contentCanvas = getCanvas(canvas);
1860
+ }
1861
+ else {
1862
+ currentMask = 'path';
1863
+ canvas.save();
1864
+ }
1865
+ child.__clip(contentCanvas || canvas, options);
1866
+ }
1867
+ else {
1868
+ currentMask = 'alpha';
1869
+ if (!maskCanvas)
1870
+ maskCanvas = getCanvas(canvas);
1871
+ if (!contentCanvas)
1872
+ contentCanvas = getCanvas(canvas);
1873
+ child.__render(maskCanvas, options);
1874
+ }
1875
+ if (child.__.mask !== 'clipping')
1876
+ continue;
1877
+ }
1878
+ if (excludeRenderBounds(child, options))
1879
+ continue;
1880
+ child.__render(contentCanvas || canvas, options);
1881
+ }
1882
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
1883
+ };
1884
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
1885
+ switch (maskMode) {
1886
+ case 'alpha':
1887
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
1888
+ break;
1889
+ case 'opacity-path':
1890
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
1891
+ break;
1892
+ case 'path':
1893
+ canvas.restore();
1894
+ }
1895
+ }
1896
+ function getCanvas(canvas) {
1897
+ return canvas.getSameCanvas(false, true);
1898
+ }
1899
+ function usePixelMask(leaf, canvas, content, mask) {
1900
+ const realBounds = leaf.__nowWorld;
1901
+ content.resetTransform();
1902
+ content.opacity = 1;
1903
+ content.useMask(mask, realBounds);
1904
+ mask.recycle(realBounds);
1905
+ copyContent(leaf, canvas, content, 1);
1906
+ }
1907
+ function copyContent(leaf, canvas, content, maskOpacity) {
1908
+ const realBounds = leaf.__nowWorld;
1909
+ canvas.resetTransform();
1910
+ canvas.opacity = maskOpacity;
1911
+ canvas.copyWorld(content, realBounds);
1912
+ content.recycle(realBounds);
1913
+ }
1758
1914
 
1759
1915
  const money = '¥¥$€££¢¢';
1760
1916
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -1911,7 +2067,8 @@ function createRows(drawData, content, style) {
1911
2067
  if (breakAll) {
1912
2068
  if (wordWidth)
1913
2069
  addWord();
1914
- addRow();
2070
+ if (rowWidth)
2071
+ addRow();
1915
2072
  }
1916
2073
  else {
1917
2074
  if (!afterBreak)
@@ -1919,10 +2076,12 @@ function createRows(drawData, content, style) {
1919
2076
  if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
1920
2077
  if (wordWidth)
1921
2078
  addWord();
1922
- addRow();
2079
+ if (rowWidth)
2080
+ addRow();
1923
2081
  }
1924
2082
  else {
1925
- addRow();
2083
+ if (rowWidth)
2084
+ addRow();
1926
2085
  }
1927
2086
  }
1928
2087
  }
@@ -2017,11 +2176,11 @@ function layoutChar(drawData, style, width, _height) {
2017
2176
  if (mode === WordMode) {
2018
2177
  wordChar = { char: '', x: charX };
2019
2178
  charX = toWordChar(word.data, charX, wordChar);
2020
- if (wordChar.char !== ' ')
2179
+ if (row.isOverflow || wordChar.char !== ' ')
2021
2180
  row.data.push(wordChar);
2022
2181
  }
2023
2182
  else {
2024
- charX = toChar(word.data, charX, row.data);
2183
+ charX = toChar(word.data, charX, row.data, row.isOverflow);
2025
2184
  }
2026
2185
  if (!row.paraEnd && addWordWidth) {
2027
2186
  charX += addWordWidth;
@@ -2048,9 +2207,9 @@ function toWordChar(data, charX, wordChar) {
2048
2207
  });
2049
2208
  return charX;
2050
2209
  }
2051
- function toChar(data, charX, rowData) {
2210
+ function toChar(data, charX, rowData, isOverflow) {
2052
2211
  data.forEach(char => {
2053
- if (char.char !== ' ') {
2212
+ if (isOverflow || char.char !== ' ') {
2054
2213
  char.x = charX;
2055
2214
  rowData.push(char);
2056
2215
  }
@@ -2082,12 +2241,14 @@ function layoutText(drawData, style) {
2082
2241
  for (let i = 0, len = rows.length; i < len; i++) {
2083
2242
  row = rows[i];
2084
2243
  row.x = x;
2085
- switch (textAlign) {
2086
- case 'center':
2087
- row.x += (width - row.width) / 2;
2088
- break;
2089
- case 'right':
2090
- row.x += width - row.width;
2244
+ if (row.width < width || (row.width > width && !__clipText)) {
2245
+ switch (textAlign) {
2246
+ case 'center':
2247
+ row.x += (width - row.width) / 2;
2248
+ break;
2249
+ case 'right':
2250
+ row.x += width - row.width;
2251
+ }
2091
2252
  }
2092
2253
  if (row.paraStart && paraSpacing && i > 0)
2093
2254
  starY += paraSpacing;
@@ -2123,16 +2284,20 @@ function layoutText(drawData, style) {
2123
2284
  bounds.height = realHeight;
2124
2285
  }
2125
2286
 
2126
- function clipText(drawData, style) {
2287
+ function clipText(drawData, style, x, width) {
2288
+ if (!width)
2289
+ return;
2127
2290
  const { rows, overflow } = drawData;
2128
2291
  let { textOverflow } = style;
2129
2292
  rows.splice(overflow);
2130
- if (textOverflow !== 'hide') {
2131
- if (textOverflow === 'ellipsis')
2293
+ if (textOverflow && textOverflow !== 'show') {
2294
+ if (textOverflow === 'hide')
2295
+ textOverflow = '';
2296
+ else if (textOverflow === 'ellipsis')
2132
2297
  textOverflow = '...';
2133
2298
  let char, charRight;
2134
- const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2135
- const right = style.x + style.width - ellipsisWidth;
2299
+ const ellipsisWidth = textOverflow ? Platform.canvas.measureText(textOverflow).width : 0;
2300
+ const right = x + width - ellipsisWidth;
2136
2301
  const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2137
2302
  list.forEach(row => {
2138
2303
  if (row.isOverflow && row.data) {
@@ -2179,42 +2344,40 @@ function decorationText(drawData, style) {
2179
2344
  }
2180
2345
 
2181
2346
  const { top, right, bottom, left } = Direction4;
2182
- const TextConvert = {
2183
- getDrawData(content, style) {
2184
- if (typeof content !== 'string')
2185
- content = String(content);
2186
- let x = 0, y = 0;
2187
- let width = style.__getInput('width') || 0;
2188
- let height = style.__getInput('height') || 0;
2189
- const { textDecoration, __font, __padding: padding } = style;
2190
- if (padding) {
2191
- if (width) {
2192
- x = padding[left];
2193
- width -= (padding[right] + padding[left]);
2194
- }
2195
- if (height) {
2196
- y = padding[top];
2197
- height -= (padding[top] + padding[bottom]);
2198
- }
2199
- }
2200
- const drawData = {
2201
- bounds: { x, y, width, height },
2202
- rows: [],
2203
- paraNumber: 0,
2204
- font: Platform.canvas.font = __font
2205
- };
2206
- createRows(drawData, content, style);
2207
- if (padding)
2208
- padAutoText(padding, drawData, style, width, height);
2209
- layoutText(drawData, style);
2210
- layoutChar(drawData, style, width);
2211
- if (drawData.overflow)
2212
- clipText(drawData, style);
2213
- if (textDecoration !== 'none')
2214
- decorationText(drawData, style);
2215
- return drawData;
2216
- }
2217
- };
2347
+ function getDrawData(content, style) {
2348
+ if (typeof content !== 'string')
2349
+ content = String(content);
2350
+ let x = 0, y = 0;
2351
+ let width = style.__getInput('width') || 0;
2352
+ let height = style.__getInput('height') || 0;
2353
+ const { textDecoration, __font, __padding: padding } = style;
2354
+ if (padding) {
2355
+ if (width) {
2356
+ x = padding[left];
2357
+ width -= (padding[right] + padding[left]);
2358
+ }
2359
+ if (height) {
2360
+ y = padding[top];
2361
+ height -= (padding[top] + padding[bottom]);
2362
+ }
2363
+ }
2364
+ const drawData = {
2365
+ bounds: { x, y, width, height },
2366
+ rows: [],
2367
+ paraNumber: 0,
2368
+ font: Platform.canvas.font = __font
2369
+ };
2370
+ createRows(drawData, content, style);
2371
+ if (padding)
2372
+ padAutoText(padding, drawData, style, width, height);
2373
+ layoutText(drawData, style);
2374
+ layoutChar(drawData, style, width);
2375
+ if (drawData.overflow)
2376
+ clipText(drawData, style, x, width);
2377
+ if (textDecoration !== 'none')
2378
+ decorationText(drawData, style);
2379
+ return drawData;
2380
+ }
2218
2381
  function padAutoText(padding, drawData, style, width, height) {
2219
2382
  if (!width) {
2220
2383
  switch (style.textAlign) {
@@ -2242,67 +2405,157 @@ function offsetText(drawData, attrName, value) {
2242
2405
  rows[i][attrName] += value;
2243
2406
  }
2244
2407
 
2245
- const ColorConvert = {
2246
- string(color, opacity) {
2247
- if (typeof color === 'string')
2248
- return color;
2249
- let a = color.a === undefined ? 1 : color.a;
2250
- if (opacity)
2251
- a *= opacity;
2252
- const rgb = color.r + ',' + color.g + ',' + color.b;
2253
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2254
- }
2408
+ const TextConvertModule = {
2409
+ getDrawData
2410
+ };
2411
+
2412
+ function string(color, opacity) {
2413
+ if (typeof color === 'string')
2414
+ return color;
2415
+ let a = color.a === undefined ? 1 : color.a;
2416
+ if (opacity)
2417
+ a *= opacity;
2418
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2419
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2420
+ }
2421
+
2422
+ const ColorConvertModule = {
2423
+ string
2255
2424
  };
2256
2425
 
2257
- const Export = {
2426
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2427
+ function getTrimBounds(canvas) {
2428
+ const { width, height } = canvas.view;
2429
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2430
+ let x, y, pointBounds, index = 0;
2431
+ for (let i = 0; i < data.length; i += 4) {
2432
+ if (data[i + 3] !== 0) {
2433
+ x = index % width;
2434
+ y = (index - x) / width;
2435
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2436
+ }
2437
+ index++;
2438
+ }
2439
+ const bounds = new Bounds();
2440
+ toBounds(pointBounds, bounds);
2441
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2442
+ }
2443
+
2444
+ const ExportModule = {
2258
2445
  export(leaf, filename, options) {
2259
- Export.running = true;
2446
+ this.running = true;
2447
+ const fileType = FileHelper.fileType(filename);
2448
+ options = FileHelper.getExportOptions(options);
2260
2449
  return addTask((success) => new Promise((resolve) => {
2450
+ const over = (result) => {
2451
+ success(result);
2452
+ resolve();
2453
+ this.running = false;
2454
+ };
2455
+ const { toURL } = Platform;
2456
+ const { download } = Platform.origin;
2457
+ if (filename === 'json') {
2458
+ return over({ data: leaf.toJSON(options.json) });
2459
+ }
2460
+ else if (fileType === 'json') {
2461
+ download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename);
2462
+ return over({ data: true });
2463
+ }
2464
+ if (filename === 'svg') {
2465
+ return over({ data: leaf.toSVG() });
2466
+ }
2467
+ else if (fileType === 'svg') {
2468
+ download(toURL(leaf.toSVG(), 'svg'), filename);
2469
+ return over({ data: true });
2470
+ }
2261
2471
  const { leafer } = leaf;
2262
2472
  if (leafer) {
2473
+ checkLazy(leaf);
2263
2474
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2264
- let quality, blob;
2265
- let { canvas } = leafer;
2266
- let { unreal } = canvas;
2267
- if (unreal) {
2268
- canvas = canvas.getSameCanvas();
2269
- canvas.backgroundColor = leafer.config.fill;
2270
- leafer.__render(canvas, {});
2475
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2476
+ const { worldTransform, isLeafer, isFrame } = leaf;
2477
+ const { slice, trim, onCanvas } = options;
2478
+ let scale = options.scale || 1;
2479
+ let pixelRatio = options.pixelRatio || 1;
2480
+ const smooth = options.smooth === undefined ? leafer.config.smooth : options.smooth;
2481
+ const contextSettings = options.contextSettings || leafer.config.contextSettings;
2482
+ if (leaf.isApp) {
2483
+ scale *= pixelRatio;
2484
+ pixelRatio = leaf.app.pixelRatio;
2485
+ }
2486
+ const screenshot = options.screenshot || leaf.isApp;
2487
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2488
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2489
+ if (screenshot) {
2490
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2271
2491
  }
2272
- switch (typeof options) {
2273
- case 'object':
2274
- if (options.quality)
2275
- quality = options.quality;
2276
- if (options.blob)
2277
- blob = true;
2278
- break;
2279
- case 'number':
2280
- quality = options;
2281
- break;
2282
- case 'boolean':
2283
- blob = options;
2492
+ else {
2493
+ let relative = options.relative || (isLeafer ? 'inner' : 'local');
2494
+ scaleX = worldTransform.scaleX;
2495
+ scaleY = worldTransform.scaleY;
2496
+ switch (relative) {
2497
+ case 'inner':
2498
+ matrix.set(worldTransform);
2499
+ break;
2500
+ case 'local':
2501
+ matrix.set(worldTransform).divide(leaf.localTransform);
2502
+ scaleX /= leaf.scaleX;
2503
+ scaleY /= leaf.scaleY;
2504
+ break;
2505
+ case 'world':
2506
+ scaleX = 1;
2507
+ scaleY = 1;
2508
+ break;
2509
+ case 'page':
2510
+ relative = leaf.leafer;
2511
+ default:
2512
+ matrix.set(worldTransform).divide(leaf.getTransform(relative));
2513
+ const l = relative.worldTransform;
2514
+ scaleX /= scaleX / l.scaleX;
2515
+ scaleY /= scaleY / l.scaleY;
2516
+ }
2517
+ renderBounds = leaf.getBounds('render', relative);
2284
2518
  }
2285
- let data;
2286
- if (filename.includes('.')) {
2287
- data = yield canvas.saveAs(filename, quality);
2519
+ const { x, y, width, height } = new Bounds(renderBounds).scale(scale);
2520
+ let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio, smooth, contextSettings });
2521
+ const renderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) };
2522
+ let sliceLeaf;
2523
+ if (slice) {
2524
+ sliceLeaf = leaf;
2525
+ sliceLeaf.__worldOpacity = 0;
2526
+ leaf = leafer;
2527
+ renderOptions.bounds = canvas.bounds;
2288
2528
  }
2289
- else if (blob) {
2290
- data = yield canvas.toBlob(filename, quality);
2529
+ canvas.save();
2530
+ if (isFrame && fill !== undefined) {
2531
+ const oldFill = leaf.get('fill');
2532
+ leaf.fill = '';
2533
+ leaf.__render(canvas, renderOptions);
2534
+ leaf.fill = oldFill;
2291
2535
  }
2292
2536
  else {
2293
- data = yield canvas.toDataURL(filename, quality);
2537
+ leaf.__render(canvas, renderOptions);
2294
2538
  }
2295
- success({ data });
2296
- resolve();
2297
- Export.running = false;
2298
- if (unreal)
2299
- canvas.recycle();
2539
+ canvas.restore();
2540
+ if (sliceLeaf)
2541
+ sliceLeaf.__updateWorldOpacity();
2542
+ if (trim) {
2543
+ trimBounds = getTrimBounds(canvas);
2544
+ const old = canvas, { width, height } = trimBounds;
2545
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2546
+ canvas = Creator.canvas(config);
2547
+ canvas.copyWorld(old, trimBounds, config);
2548
+ }
2549
+ if (needFill)
2550
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2551
+ if (onCanvas)
2552
+ onCanvas(canvas);
2553
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2554
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2300
2555
  }));
2301
2556
  }
2302
2557
  else {
2303
- success({ data: false });
2304
- resolve();
2305
- Export.running = false;
2558
+ over({ data: false });
2306
2559
  }
2307
2560
  }));
2308
2561
  }
@@ -2315,11 +2568,63 @@ function addTask(task) {
2315
2568
  tasker.add(() => __awaiter(this, void 0, void 0, function* () { return yield task(resolve); }), { parallel: false });
2316
2569
  });
2317
2570
  }
2571
+ function checkLazy(leaf) {
2572
+ if (leaf.__.__needComputePaint)
2573
+ leaf.__.__computePaint();
2574
+ if (leaf.isBranch)
2575
+ leaf.children.forEach(child => checkLazy(child));
2576
+ }
2577
+
2578
+ const canvas = LeaferCanvasBase.prototype;
2579
+ const debug = Debug.get('@leafer-ui/export');
2580
+ canvas.export = function (filename, options) {
2581
+ const { quality, blob } = FileHelper.getExportOptions(options);
2582
+ if (filename.includes('.')) {
2583
+ return this.saveAs(filename, quality);
2584
+ }
2585
+ else if (blob) {
2586
+ return this.toBlob(filename, quality);
2587
+ }
2588
+ else {
2589
+ return this.toDataURL(filename, quality);
2590
+ }
2591
+ };
2592
+ canvas.toBlob = function (type, quality) {
2593
+ return new Promise((resolve) => {
2594
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2595
+ resolve(blob);
2596
+ }).catch((e) => {
2597
+ debug.error(e);
2598
+ resolve(null);
2599
+ });
2600
+ });
2601
+ };
2602
+ canvas.toDataURL = function (type, quality) {
2603
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
2604
+ };
2605
+ canvas.saveAs = function (filename, quality) {
2606
+ return new Promise((resolve) => {
2607
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2608
+ resolve(true);
2609
+ }).catch((e) => {
2610
+ debug.error(e);
2611
+ resolve(false);
2612
+ });
2613
+ });
2614
+ };
2318
2615
 
2319
- Object.assign(Paint, UIPaint);
2320
- Object.assign(Effect, UIEffect);
2321
- Object.assign(TextConvert$1, TextConvert);
2322
- Object.assign(ColorConvert$1, ColorConvert);
2323
- Object.assign(Export$2, Export);
2616
+ Object.assign(TextConvert, TextConvertModule);
2617
+ Object.assign(ColorConvert, ColorConvertModule);
2618
+ Object.assign(Paint, PaintModule);
2619
+ Object.assign(PaintImage, PaintImageModule);
2620
+ Object.assign(PaintGradient, PaintGradientModule);
2621
+ Object.assign(Effect, EffectModule);
2622
+ Object.assign(Export, ExportModule);
2623
+
2624
+ Object.assign(Creator, {
2625
+ interaction: (target, canvas, selector, options) => { return new InteractionBase(target, canvas, selector, options); },
2626
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2627
+ hitCanvasManager: () => new HitCanvasManager()
2628
+ });
2324
2629
 
2325
2630
  export { Layouter, LeaferCanvas, Renderer, Selector, Watcher, useCanvas };