@leafer-ui/node 1.0.0-rc.2 → 1.0.0-rc.21

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