@leafer-ui/miniapp 1.0.0-rc.3 → 1.0.0-rc.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,220 @@
1
- import { LeafList, DataHelper, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, BoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, Platform, AnimateEvent, ResizeEvent, Creator, LeaferCanvasBase, canvasPatch, canvasSizeAttrs, InteractionHelper, InteractionBase, LeaferImage, FileHelper, MatrixHelper, ImageEvent, PointHelper, MathHelper, TaskProcessor } from '@leafer/core';
1
+ import { LeaferCanvasBase, Platform, canvasPatch, DataHelper, canvasSizeAttrs, ResizeEvent, Creator, LeaferImage, FileHelper, LeafList, RenderEvent, ChildEvent, WatchEvent, PropertyEvent, LeafHelper, BranchHelper, Bounds, LeafBoundsHelper, Debug, LeafLevelList, LayoutEvent, Run, ImageManager, AnimateEvent, BoundsHelper, Answer, MatrixHelper, AlignHelper, ImageEvent, AroundHelper, PointHelper, Direction4, TwoPointBoundsHelper, TaskProcessor, Matrix } from '@leafer/core';
2
2
  export * from '@leafer/core';
3
3
  export { LeaferImage } from '@leafer/core';
4
- import { ColorConvert as ColorConvert$1, Paint, Effect, TextConvert as TextConvert$1, Export as Export$1, Platform as Platform$1 } from '@leafer-ui/core';
4
+ import { InteractionHelper, InteractionBase, HitCanvasManager, Platform as Platform$1 } from '@leafer-ui/core';
5
5
  export * from '@leafer-ui/core';
6
+ import { PaintImage, ColorConvert, PaintGradient, Export, Group, TextConvert, Paint, Effect } from '@leafer-ui/draw';
7
+
8
+ class LeaferCanvas extends LeaferCanvasBase {
9
+ get allowBackgroundColor() { return false; }
10
+ init() {
11
+ let { view } = this.config;
12
+ if (view) {
13
+ if (typeof view === 'string') {
14
+ if (view[0] !== '#')
15
+ view = '#' + view;
16
+ this.viewSelect = Platform.miniapp.select(view);
17
+ }
18
+ else if (view.fields) {
19
+ this.viewSelect = view;
20
+ }
21
+ else {
22
+ this.initView(view);
23
+ }
24
+ if (this.viewSelect)
25
+ Platform.miniapp.getSizeView(this.viewSelect).then(sizeView => {
26
+ this.initView(sizeView);
27
+ });
28
+ }
29
+ else {
30
+ this.initView();
31
+ }
32
+ }
33
+ initView(view) {
34
+ if (!view) {
35
+ view = {};
36
+ this.__createView();
37
+ }
38
+ else {
39
+ this.view = view.view || view;
40
+ }
41
+ this.__createContext();
42
+ const { width, height, pixelRatio } = this.config;
43
+ const size = { width: width || view.width, height: height || view.height, pixelRatio };
44
+ this.resize(size);
45
+ if (this.context.roundRect) {
46
+ this.roundRect = function (x, y, width, height, radius) {
47
+ this.context.roundRect(x, y, width, height, typeof radius === 'number' ? [radius] : radius);
48
+ };
49
+ }
50
+ canvasPatch(this.context.__proto__);
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
+ }
60
+ updateClientBounds(callback) {
61
+ if (this.viewSelect)
62
+ Platform.miniapp.getBounds(this.viewSelect).then(bounds => {
63
+ this.clientBounds = bounds;
64
+ if (callback)
65
+ callback();
66
+ });
67
+ }
68
+ startAutoLayout(_autoBounds, listener) {
69
+ this.resizeListener = listener;
70
+ this.checkSize = this.checkSize.bind(this);
71
+ Platform.miniapp.onWindowResize(this.checkSize);
72
+ }
73
+ checkSize() {
74
+ if (this.viewSelect) {
75
+ setTimeout(() => {
76
+ this.updateClientBounds(() => {
77
+ const { width, height } = this.clientBounds;
78
+ const { pixelRatio } = this;
79
+ const size = { width, height, pixelRatio };
80
+ if (!this.isSameSize(size)) {
81
+ const oldSize = {};
82
+ DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
83
+ this.resize(size);
84
+ if (this.width !== undefined)
85
+ this.resizeListener(new ResizeEvent(size, oldSize));
86
+ }
87
+ });
88
+ }, 500);
89
+ }
90
+ }
91
+ stopAutoLayout() {
92
+ this.autoLayout = false;
93
+ this.resizeListener = null;
94
+ Platform.miniapp.offWindowResize(this.checkSize);
95
+ }
96
+ }
97
+
98
+ const { mineType, fileType } = FileHelper;
99
+ Object.assign(Creator, {
100
+ canvas: (options, manager) => new LeaferCanvas(options, manager),
101
+ image: (options) => new LeaferImage(options)
102
+ });
103
+ function useCanvas(_canvasType, app) {
104
+ if (!Platform.origin) {
105
+ Platform.origin = {
106
+ createCanvas: (width, height, _format) => app.createOffscreenCanvas({ type: '2d', width, height }),
107
+ canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
108
+ canvasToBolb: (canvas, type, quality) => canvas.toBuffer(type, { quality }),
109
+ canvasSaveAs: (canvas, filePath, quality) => {
110
+ let data = canvas.toDataURL(mineType(fileType(filePath)), quality);
111
+ data = data.substring(data.indexOf('64,') + 3);
112
+ return Platform.origin.download(data, filePath);
113
+ },
114
+ download(data, filePath) {
115
+ return new Promise((resolve, reject) => {
116
+ let toAlbum;
117
+ if (!filePath.includes('/')) {
118
+ filePath = `${app.env.USER_DATA_PATH}/` + filePath;
119
+ toAlbum = true;
120
+ }
121
+ const fs = app.getFileSystemManager();
122
+ fs.writeFile({
123
+ filePath,
124
+ data,
125
+ encoding: 'base64',
126
+ success() {
127
+ if (toAlbum) {
128
+ Platform.miniapp.saveToAlbum(filePath).then(() => {
129
+ fs.unlink({ filePath });
130
+ resolve();
131
+ });
132
+ }
133
+ else {
134
+ resolve();
135
+ }
136
+ },
137
+ fail(error) {
138
+ reject(error);
139
+ }
140
+ });
141
+ });
142
+ },
143
+ loadImage(src) {
144
+ return new Promise((resolve, reject) => {
145
+ const img = Platform.canvas.view.createImage();
146
+ img.onload = () => { resolve(img); };
147
+ img.onerror = (error) => { reject(error); };
148
+ img.src = Platform.image.getRealURL(src);
149
+ });
150
+ },
151
+ noRepeat: 'repeat-x'
152
+ };
153
+ Platform.miniapp = {
154
+ select(name) {
155
+ return app.createSelectorQuery().select(name);
156
+ },
157
+ getBounds(select) {
158
+ return new Promise((resolve) => {
159
+ select.boundingClientRect().exec((res) => {
160
+ const rect = res[1];
161
+ resolve({ x: rect.top, y: rect.left, width: rect.width, height: rect.height });
162
+ });
163
+ });
164
+ },
165
+ getSizeView(select) {
166
+ return new Promise((resolve) => {
167
+ select.fields({ node: true, size: true }).exec((res) => {
168
+ const data = res[0];
169
+ resolve({ view: data.node, width: data.width, height: data.height });
170
+ });
171
+ });
172
+ },
173
+ saveToAlbum(path) {
174
+ return new Promise((resolve) => {
175
+ app.getSetting({
176
+ success: (res) => {
177
+ if (res.authSetting['scope.writePhotosAlbum']) {
178
+ app.saveImageToPhotosAlbum({
179
+ filePath: path,
180
+ success() { resolve(true); }
181
+ });
182
+ }
183
+ else {
184
+ app.authorize({
185
+ scope: 'scope.writePhotosAlbum',
186
+ success: () => {
187
+ app.saveImageToPhotosAlbum({
188
+ filePath: path,
189
+ success() { resolve(true); }
190
+ });
191
+ },
192
+ fail: () => { }
193
+ });
194
+ }
195
+ }
196
+ });
197
+ });
198
+ },
199
+ onWindowResize(fun) {
200
+ app.onWindowResize(fun);
201
+ },
202
+ offWindowResize(fun) {
203
+ app.offWindowResize(fun);
204
+ }
205
+ };
206
+ Platform.event = {
207
+ stopDefault(_origin) { },
208
+ stopNow(_origin) { },
209
+ stop(_origin) { }
210
+ };
211
+ Platform.canvas = Creator.canvas();
212
+ Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
213
+ }
214
+ }
215
+ Platform.name = 'miniapp';
216
+ Platform.requestRender = function (render) { Platform.canvas.view.requestAnimationFrame(render); };
217
+ Platform.devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
6
218
 
7
219
  class Watcher {
8
220
  get childrenChanged() { return this.hasAdd || this.hasRemove || this.hasVisible; }
@@ -10,7 +222,7 @@ class Watcher {
10
222
  if (this.hasRemove) {
11
223
  const updatedList = new LeafList();
12
224
  this.__updatedList.list.forEach(item => { if (item.leafer)
13
- updatedList.push(item); });
225
+ updatedList.add(item); });
14
226
  return updatedList;
15
227
  }
16
228
  else {
@@ -45,7 +257,7 @@ class Watcher {
45
257
  this.target.emit(RenderEvent.REQUEST);
46
258
  }
47
259
  __onAttrChange(event) {
48
- this.__updatedList.push(event.target);
260
+ this.__updatedList.add(event.target);
49
261
  this.update();
50
262
  }
51
263
  __onChildEvent(event) {
@@ -55,12 +267,12 @@ class Watcher {
55
267
  }
56
268
  else {
57
269
  this.hasRemove = true;
58
- this.__updatedList.push(event.parent);
270
+ this.__updatedList.add(event.parent);
59
271
  }
60
272
  this.update();
61
273
  }
62
274
  __pushChild(child) {
63
- this.__updatedList.push(child);
275
+ this.__updatedList.add(child);
64
276
  if (child.isBranch)
65
277
  this.__loopChildren(child);
66
278
  }
@@ -99,22 +311,22 @@ class Watcher {
99
311
  }
100
312
  }
101
313
 
102
- const { updateAllWorldMatrix: updateAllWorldMatrix$1, updateAllWorldOpacity } = LeafHelper;
314
+ const { updateAllMatrix: updateAllMatrix$1, updateBounds: updateOneBounds, updateAllWorldOpacity } = LeafHelper;
103
315
  const { pushAllChildBranch, pushAllParent } = BranchHelper;
104
316
  function updateMatrix(updateList, levelList) {
105
317
  let layout;
106
318
  updateList.list.forEach(leaf => {
107
319
  layout = leaf.__layout;
108
- if (levelList.without(leaf) && !layout.useZoomProxy) {
320
+ if (levelList.without(leaf) && !layout.proxyZoom) {
109
321
  if (layout.matrixChanged) {
110
- updateAllWorldMatrix$1(leaf);
111
- levelList.push(leaf);
322
+ updateAllMatrix$1(leaf, true);
323
+ levelList.add(leaf);
112
324
  if (leaf.isBranch)
113
325
  pushAllChildBranch(leaf, levelList);
114
326
  pushAllParent(leaf, levelList);
115
327
  }
116
328
  else if (layout.boundsChanged) {
117
- levelList.push(leaf);
329
+ levelList.add(leaf);
118
330
  if (leaf.isBranch)
119
331
  leaf.__tempNumber = 0;
120
332
  pushAllParent(leaf, levelList);
@@ -123,20 +335,21 @@ function updateMatrix(updateList, levelList) {
123
335
  });
124
336
  }
125
337
  function updateBounds(boundsList) {
126
- let itemList, branch;
338
+ let list, branch, children;
127
339
  boundsList.sort(true);
128
340
  boundsList.levels.forEach(level => {
129
- itemList = boundsList.levelMap[level];
130
- for (let i = 0, len = itemList.length; i < len; i++) {
131
- branch = itemList[i];
341
+ list = boundsList.levelMap[level];
342
+ for (let i = 0, len = list.length; i < len; i++) {
343
+ branch = list[i];
132
344
  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();
345
+ children = branch.children;
346
+ for (let j = 0, jLen = children.length; j < jLen; j++) {
347
+ if (!children[j].isBranch) {
348
+ updateOneBounds(children[j]);
136
349
  }
137
350
  }
138
351
  }
139
- branch.__updateWorldBounds();
352
+ updateOneBounds(branch);
140
353
  }
141
354
  });
142
355
  }
@@ -149,7 +362,7 @@ function updateChange(updateList) {
149
362
  }
150
363
 
151
364
  const { worldBounds } = LeafBoundsHelper;
152
- const { setByListWithHandle } = BoundsHelper;
365
+ const bigBounds = { x: 0, y: 0, width: 100000, height: 100000 };
153
366
  class LayoutBlockData {
154
367
  constructor(list) {
155
368
  this.updatedBounds = new Bounds();
@@ -160,14 +373,20 @@ class LayoutBlockData {
160
373
  this.updatedList = list;
161
374
  }
162
375
  setBefore() {
163
- setByListWithHandle(this.beforeBounds, this.updatedList.list, worldBounds);
376
+ this.beforeBounds.setListWithFn(this.updatedList.list, worldBounds);
164
377
  }
165
378
  setAfter() {
166
- setByListWithHandle(this.afterBounds, this.updatedList.list, worldBounds);
167
- this.updatedBounds.setByList([this.beforeBounds, this.afterBounds]);
379
+ const { list } = this.updatedList;
380
+ if (list.some(leaf => leaf.noBounds)) {
381
+ this.afterBounds.set(bigBounds);
382
+ }
383
+ else {
384
+ this.afterBounds.setListWithFn(list, worldBounds);
385
+ }
386
+ this.updatedBounds.setList([this.beforeBounds, this.afterBounds]);
168
387
  }
169
388
  merge(data) {
170
- this.updatedList.pushList(data.updatedList.list);
389
+ this.updatedList.addList(data.updatedList.list);
171
390
  this.beforeBounds.add(data.beforeBounds);
172
391
  this.afterBounds.add(data.afterBounds);
173
392
  this.updatedBounds.add(data.updatedBounds);
@@ -177,9 +396,8 @@ class LayoutBlockData {
177
396
  }
178
397
  }
179
398
 
180
- const { updateAllWorldMatrix, updateAllChange } = LeafHelper;
181
- const { pushAllBranchStack, updateWorldBoundsByBranchStack } = BranchHelper;
182
- const debug$1 = Debug.get('Layouter');
399
+ const { updateAllMatrix, updateAllChange } = LeafHelper;
400
+ const debug$2 = Debug.get('Layouter');
183
401
  class Layouter {
184
402
  constructor(target, userConfig) {
185
403
  this.totalTimes = 0;
@@ -214,7 +432,7 @@ class Layouter {
214
432
  target.emitEvent(new LayoutEvent(LayoutEvent.END, this.layoutedBlocks, this.times));
215
433
  }
216
434
  catch (e) {
217
- debug$1.error(e);
435
+ debug$2.error(e);
218
436
  }
219
437
  this.layoutedBlocks = null;
220
438
  }
@@ -228,9 +446,9 @@ class Layouter {
228
446
  }
229
447
  layoutOnce() {
230
448
  if (this.layouting)
231
- return debug$1.warn('layouting');
449
+ return debug$2.warn('layouting');
232
450
  if (this.times > 3)
233
- return debug$1.warn('layout max times');
451
+ return debug$2.warn('layout max times');
234
452
  this.times++;
235
453
  this.totalTimes++;
236
454
  this.layouting = true;
@@ -255,12 +473,15 @@ class Layouter {
255
473
  const { target, __updatedList: updateList } = this;
256
474
  const { BEFORE, LAYOUT, AFTER } = LayoutEvent;
257
475
  const blocks = this.getBlocks(updateList);
258
- blocks.forEach(item => { item.setBefore(); });
476
+ blocks.forEach(item => item.setBefore());
259
477
  target.emitEvent(new LayoutEvent(BEFORE, blocks, this.times));
478
+ this.extraBlock = null;
260
479
  updateList.sort();
261
480
  updateMatrix(updateList, this.__levelList);
262
481
  updateBounds(this.__levelList);
263
482
  updateChange(updateList);
483
+ if (this.extraBlock)
484
+ blocks.push(this.extraBlock);
264
485
  blocks.forEach(item => item.setAfter());
265
486
  target.emitEvent(new LayoutEvent(LAYOUT, blocks, this.times));
266
487
  target.emitEvent(new LayoutEvent(AFTER, blocks, this.times));
@@ -283,17 +504,22 @@ class Layouter {
283
504
  Run.end(t);
284
505
  }
285
506
  static fullLayout(target) {
286
- updateAllWorldMatrix(target);
507
+ updateAllMatrix(target, true);
287
508
  if (target.isBranch) {
288
- const branchStack = [target];
289
- pushAllBranchStack(target, branchStack);
290
- updateWorldBoundsByBranchStack(branchStack);
509
+ BranchHelper.updateBounds(target);
291
510
  }
292
511
  else {
293
- target.__updateWorldBounds();
512
+ LeafHelper.updateBounds(target);
294
513
  }
295
514
  updateAllChange(target);
296
515
  }
516
+ addExtra(leaf) {
517
+ if (!this.__updatedList.has(leaf)) {
518
+ const { updatedList, beforeBounds } = this.extraBlock || (this.extraBlock = new LayoutBlockData([]));
519
+ updatedList.length ? beforeBounds.add(leaf.__world) : beforeBounds.set(leaf.__world);
520
+ updatedList.add(leaf);
521
+ }
522
+ }
297
523
  createBlock(data) {
298
524
  return new LayoutBlockData(data);
299
525
  }
@@ -321,13 +547,12 @@ class Layouter {
321
547
  if (this.target) {
322
548
  this.stop();
323
549
  this.__removeListenEvents();
324
- this.target = null;
325
- this.config = null;
550
+ this.target = this.config = null;
326
551
  }
327
552
  }
328
553
  }
329
554
 
330
- const debug = Debug.get('Renderer');
555
+ const debug$1 = Debug.get('Renderer');
331
556
  class Renderer {
332
557
  get needFill() { return !!(!this.canvas.allowBackgroundColor && this.config.fill); }
333
558
  constructor(target, canvas, userConfig) {
@@ -365,7 +590,7 @@ class Renderer {
365
590
  const { target } = this;
366
591
  this.times = 0;
367
592
  this.totalBounds = new Bounds();
368
- debug.log(target.innerName, '--->');
593
+ debug$1.log(target.innerName, '--->');
369
594
  try {
370
595
  this.emitRender(RenderEvent.START);
371
596
  this.renderOnce(callback);
@@ -374,9 +599,9 @@ class Renderer {
374
599
  }
375
600
  catch (e) {
376
601
  this.rendering = false;
377
- debug.error(e);
602
+ debug$1.error(e);
378
603
  }
379
- debug.log('-------------|');
604
+ debug$1.log('-------------|');
380
605
  }
381
606
  renderAgain() {
382
607
  if (this.rendering) {
@@ -388,9 +613,9 @@ class Renderer {
388
613
  }
389
614
  renderOnce(callback) {
390
615
  if (this.rendering)
391
- return debug.warn('rendering');
616
+ return debug$1.warn('rendering');
392
617
  if (this.times > 3)
393
- return debug.warn('render max times');
618
+ return debug$1.warn('render max times');
394
619
  this.times++;
395
620
  this.totalTimes++;
396
621
  this.rendering = true;
@@ -403,6 +628,10 @@ class Renderer {
403
628
  }
404
629
  else {
405
630
  this.requestLayout();
631
+ if (this.ignore) {
632
+ this.ignore = this.rendering = false;
633
+ return;
634
+ }
406
635
  this.emitRender(RenderEvent.BEFORE);
407
636
  if (this.config.usePartRender && this.totalTimes > 1) {
408
637
  this.partRender();
@@ -423,9 +652,8 @@ class Renderer {
423
652
  partRender() {
424
653
  const { canvas, updateBlocks: list } = this;
425
654
  if (!list)
426
- return debug.warn('PartRender: need update attr');
427
- if (list.some(block => block.includes(this.target.__world)))
428
- this.mergeBlocks();
655
+ return debug$1.warn('PartRender: need update attr');
656
+ this.mergeBlocks();
429
657
  list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty())
430
658
  this.clipRender(block); });
431
659
  }
@@ -434,17 +662,17 @@ class Renderer {
434
662
  const { canvas } = this;
435
663
  const bounds = block.getIntersect(canvas.bounds);
436
664
  const includes = block.includes(this.target.__world);
437
- const realBounds = new Bounds().copy(bounds);
665
+ const realBounds = new Bounds(bounds);
438
666
  canvas.save();
439
667
  if (includes && !Debug.showRepaint) {
440
668
  canvas.clear();
441
669
  }
442
670
  else {
443
- bounds.spread(1 + 1 / this.canvas.pixelRatio).ceil();
671
+ bounds.spread(10 + 1 / this.canvas.pixelRatio).ceil();
444
672
  canvas.clearWorld(bounds, true);
445
673
  canvas.clipWorld(bounds, true);
446
674
  }
447
- this.__render(bounds, realBounds);
675
+ this.__render(bounds, includes, realBounds);
448
676
  canvas.restore();
449
677
  Run.end(t);
450
678
  }
@@ -453,12 +681,12 @@ class Renderer {
453
681
  const { canvas } = this;
454
682
  canvas.save();
455
683
  canvas.clear();
456
- this.__render(canvas.bounds);
684
+ this.__render(canvas.bounds, true);
457
685
  canvas.restore();
458
686
  Run.end(t);
459
687
  }
460
- __render(bounds, realBounds) {
461
- const options = (bounds === null || bounds === void 0 ? void 0 : bounds.includes(this.target.__world)) ? {} : { bounds };
688
+ __render(bounds, includes, realBounds) {
689
+ const options = bounds.includes(this.target.__world) ? { includes } : { bounds, includes };
462
690
  if (this.needFill)
463
691
  this.canvas.fillWorld(bounds, this.config.fill);
464
692
  if (Debug.showRepaint)
@@ -484,7 +712,7 @@ class Renderer {
484
712
  const { updateBlocks: list } = this;
485
713
  if (list) {
486
714
  const bounds = new Bounds();
487
- bounds.setByList(list);
715
+ bounds.setList(list);
488
716
  list.length = 0;
489
717
  list.push(bounds);
490
718
  }
@@ -493,12 +721,12 @@ class Renderer {
493
721
  const startTime = Date.now();
494
722
  Platform.requestRender(() => {
495
723
  this.FPS = Math.min(60, Math.ceil(1000 / (Date.now() - startTime)));
496
- if (this.changed) {
497
- if (this.running && this.canvas.view)
724
+ if (this.running) {
725
+ this.target.emit(AnimateEvent.FRAME);
726
+ if (this.changed && this.canvas.view)
498
727
  this.render();
728
+ this.target.emit(RenderEvent.NEXT);
499
729
  }
500
- if (this.running)
501
- this.target.emit(AnimateEvent.FRAME);
502
730
  if (this.target)
503
731
  this.__requestRender();
504
732
  });
@@ -511,9 +739,12 @@ class Renderer {
511
739
  const bounds = new Bounds(0, 0, width, height);
512
740
  if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
513
741
  this.addBlock(this.canvas.bounds);
514
- this.target.forceUpdate('blendMode');
742
+ this.target.forceUpdate('surface');
743
+ return;
515
744
  }
516
745
  }
746
+ this.addBlock(new Bounds(0, 0, 1, 1));
747
+ this.changed = true;
517
748
  }
518
749
  __onLayoutEnd(event) {
519
750
  if (event.data)
@@ -524,7 +755,7 @@ class Renderer {
524
755
  empty = (!leaf.__world.width || !leaf.__world.height);
525
756
  if (empty) {
526
757
  if (!leaf.isLeafer)
527
- debug.warn(leaf.innerName, ': empty');
758
+ debug$1.tip(leaf.innerName, ': empty');
528
759
  empty = (!leaf.isBranch || leaf.isBranchLeaf);
529
760
  }
530
761
  return empty;
@@ -551,15 +782,13 @@ class Renderer {
551
782
  if (this.target) {
552
783
  this.stop();
553
784
  this.__removeListenEvents();
554
- this.target = null;
555
- this.canvas = null;
556
- this.config = null;
785
+ this.target = this.canvas = this.config = null;
557
786
  }
558
787
  }
559
788
  }
560
789
 
561
790
  const { hitRadiusPoint } = BoundsHelper;
562
- class FindPath {
791
+ class Picker {
563
792
  constructor(target, selector) {
564
793
  this.target = target;
565
794
  this.selector = selector;
@@ -571,51 +800,59 @@ class FindPath {
571
800
  options = {};
572
801
  const through = options.through || false;
573
802
  const ignoreHittable = options.ignoreHittable || false;
803
+ const target = options.target || this.target;
574
804
  this.exclude = options.exclude || null;
575
805
  this.point = { x: hitPoint.x, y: hitPoint.y, radiusX: hitRadius, radiusY: hitRadius };
576
- this.findList = [];
577
- this.eachFind(this.target.children, this.target.__onlyHitMask);
578
- const list = this.findList;
579
- const leaf = this.getBestMatchLeaf();
806
+ this.findList = new LeafList(options.findList);
807
+ if (!options.findList)
808
+ this.hitBranch(target);
809
+ const { list } = this.findList;
810
+ const leaf = this.getBestMatchLeaf(list, options.bottomList, ignoreHittable);
580
811
  const path = ignoreHittable ? this.getPath(leaf) : this.getHitablePath(leaf);
581
812
  this.clear();
582
- return through ? { path, leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, leaf };
813
+ return through ? { path, target: leaf, throughPath: list.length ? this.getThroughPath(list) : path } : { path, target: leaf };
583
814
  }
584
- getBestMatchLeaf() {
585
- const { findList: targets } = this;
586
- if (targets.length > 1) {
815
+ getBestMatchLeaf(list, bottomList, ignoreHittable) {
816
+ if (list.length) {
587
817
  let find;
588
- this.findList = [];
818
+ this.findList = new LeafList();
589
819
  const { x, y } = this.point;
590
820
  const point = { x, y, radiusX: 0, radiusY: 0 };
591
- for (let i = 0, len = targets.length; i < len; i++) {
592
- find = targets[i];
593
- if (LeafHelper.worldHittable(find)) {
821
+ for (let i = 0, len = list.length; i < len; i++) {
822
+ find = list[i];
823
+ if (ignoreHittable || LeafHelper.worldHittable(find)) {
594
824
  this.hitChild(find, point);
595
825
  if (this.findList.length)
596
- return this.findList[0];
826
+ return this.findList.list[0];
597
827
  }
598
828
  }
599
829
  }
600
- return targets[0];
830
+ if (bottomList) {
831
+ for (let i = 0, len = bottomList.length; i < len; i++) {
832
+ this.hitChild(bottomList[i].target, this.point, bottomList[i].proxy);
833
+ if (this.findList.length)
834
+ return this.findList.list[0];
835
+ }
836
+ }
837
+ return list[0];
601
838
  }
602
839
  getPath(leaf) {
603
840
  const path = new LeafList();
604
841
  while (leaf) {
605
- path.push(leaf);
842
+ path.add(leaf);
606
843
  leaf = leaf.parent;
607
844
  }
608
- path.push(this.target);
845
+ path.add(this.target);
609
846
  return path;
610
847
  }
611
848
  getHitablePath(leaf) {
612
- const path = this.getPath(leaf);
849
+ const path = this.getPath(leaf && leaf.hittable ? leaf : null);
613
850
  let item, hittablePath = new LeafList();
614
851
  for (let i = path.list.length - 1; i > -1; i--) {
615
852
  item = path.list[i];
616
853
  if (!item.__.hittable)
617
854
  break;
618
- hittablePath.unshift(item);
855
+ hittablePath.addAt(item, 0);
619
856
  if (!item.__.hitChildren)
620
857
  break;
621
858
  }
@@ -634,17 +871,20 @@ class FindPath {
634
871
  leaf = path.list[j];
635
872
  if (nextPath && nextPath.has(leaf))
636
873
  break;
637
- throughPath.push(leaf);
874
+ throughPath.add(leaf);
638
875
  }
639
876
  }
640
877
  return throughPath;
641
878
  }
879
+ hitBranch(branch) {
880
+ this.eachFind(branch.children, branch.__onlyHitMask);
881
+ }
642
882
  eachFind(children, hitMask) {
643
883
  let child, hit;
644
884
  const { point } = this, len = children.length;
645
885
  for (let i = len - 1; i > -1; i--) {
646
886
  child = children[i];
647
- if (!child.__.visible || (hitMask && !child.__.isMask))
887
+ if (!child.__.visible || (hitMask && !child.__.mask))
648
888
  continue;
649
889
  hit = child.__.hitRadius ? true : hitRadiusPoint(child.__world, point);
650
890
  if (child.isBranch) {
@@ -660,11 +900,15 @@ class FindPath {
660
900
  }
661
901
  }
662
902
  }
663
- hitChild(child, point) {
903
+ hitChild(child, point, proxy) {
664
904
  if (this.exclude && this.exclude.has(child))
665
905
  return;
666
- if (child.__hitWorld(point))
667
- this.findList.push(child);
906
+ if (child.__hitWorld(point)) {
907
+ const { parent } = child;
908
+ if (parent && parent.__hasMask && !child.__.mask && !parent.children.some(item => item.__.mask && item.__hitWorld(point)))
909
+ return;
910
+ this.findList.add(proxy || child);
911
+ }
668
912
  }
669
913
  clear() {
670
914
  this.point = null;
@@ -676,134 +920,141 @@ class FindPath {
676
920
  }
677
921
  }
678
922
 
923
+ const { Yes, NoAndSkip, YesAndSkip } = Answer;
924
+ const idCondition = {}, classNameCondition = {}, tagCondition = {};
679
925
  class Selector {
680
926
  constructor(target, userConfig) {
681
927
  this.config = {};
682
- this.innerIdList = {};
683
- this.idList = {};
684
- this.classNameList = {};
685
- this.tagNameList = {};
928
+ this.innerIdMap = {};
929
+ this.idMap = {};
930
+ this.methods = {
931
+ id: (leaf, name) => leaf.id === name ? (this.idMap[name] = leaf, 1) : 0,
932
+ innerId: (leaf, innerId) => leaf.innerId === innerId ? (this.innerIdMap[innerId] = leaf, 1) : 0,
933
+ className: (leaf, name) => leaf.className === name ? 1 : 0,
934
+ tag: (leaf, name) => leaf.__tag === name ? 1 : 0,
935
+ tags: (leaf, nameMap) => nameMap[leaf.__tag] ? 1 : 0
936
+ };
686
937
  this.target = target;
687
938
  if (userConfig)
688
939
  this.config = DataHelper.default(userConfig, this.config);
689
- this.findPath = new FindPath(target, this);
940
+ this.picker = new Picker(target, this);
690
941
  this.__listenEvents();
691
942
  }
943
+ getBy(condition, branch, one, options) {
944
+ switch (typeof condition) {
945
+ case 'number':
946
+ const leaf = this.getByInnerId(condition, branch);
947
+ return one ? leaf : (leaf ? [leaf] : []);
948
+ case 'string':
949
+ switch (condition[0]) {
950
+ case '#':
951
+ idCondition.id = condition.substring(1), condition = idCondition;
952
+ break;
953
+ case '.':
954
+ classNameCondition.className = condition.substring(1), condition = classNameCondition;
955
+ break;
956
+ default:
957
+ tagCondition.tag = condition, condition = tagCondition;
958
+ }
959
+ case 'object':
960
+ if (condition.id !== undefined) {
961
+ const leaf = this.getById(condition.id, branch);
962
+ return one ? leaf : (leaf ? [leaf] : []);
963
+ }
964
+ else if (condition.tag) {
965
+ const { tag } = condition, isArray = tag instanceof Array;
966
+ return this.getByMethod(isArray ? this.methods.tags : this.methods.tag, branch, one, isArray ? DataHelper.toMap(tag) : tag);
967
+ }
968
+ else {
969
+ return this.getByMethod(this.methods.className, branch, one, condition.className);
970
+ }
971
+ case 'function':
972
+ return this.getByMethod(condition, branch, one, options);
973
+ }
974
+ }
692
975
  getByPoint(hitPoint, hitRadius, options) {
693
976
  if (Platform.name === 'node')
694
977
  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
- }
978
+ return this.picker.getByPoint(hitPoint, hitRadius, options);
710
979
  }
711
- getByInnerId(name, branch) {
712
- let cache = this.innerIdList[name];
980
+ getByInnerId(innerId, branch) {
981
+ const cache = this.innerIdMap[innerId];
713
982
  if (cache)
714
983
  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;
984
+ this.eachFind(this.toChildren(branch), this.methods.innerId, null, innerId);
985
+ return this.findLeaf;
729
986
  }
730
- getById(name, branch) {
731
- let cache = this.idList[name];
732
- if (cache)
987
+ getById(id, branch) {
988
+ const cache = this.idMap[id];
989
+ if (cache && LeafHelper.hasParent(cache, branch || this.target))
733
990
  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;
991
+ this.eachFind(this.toChildren(branch), this.methods.id, null, id);
992
+ return this.findLeaf;
770
993
  }
771
- loopFind(branch, find) {
772
- if (find(branch))
773
- return;
774
- const { children } = branch;
775
- 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);
781
- }
994
+ getByClassName(className, branch) {
995
+ return this.getByMethod(this.methods.className, branch, false, className);
782
996
  }
783
- __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;
997
+ getByTag(tag, branch) {
998
+ return this.getByMethod(this.methods.tag, branch, false, tag);
789
999
  }
790
- __listenEvents() {
791
- this.__eventIds = [
792
- this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this)
793
- ];
1000
+ getByMethod(method, branch, one, options) {
1001
+ const list = one ? null : [];
1002
+ this.eachFind(this.toChildren(branch), method, list, options);
1003
+ return list || this.findLeaf;
794
1004
  }
795
- __removeListenEvents() {
796
- this.target.off_(this.__eventIds);
1005
+ eachFind(children, method, list, options) {
1006
+ let child, result;
1007
+ for (let i = 0, len = children.length; i < len; i++) {
1008
+ child = children[i];
1009
+ result = method(child, options);
1010
+ if (result === Yes || result === YesAndSkip) {
1011
+ if (list) {
1012
+ list.push(child);
1013
+ }
1014
+ else {
1015
+ this.findLeaf = child;
1016
+ return;
1017
+ }
1018
+ }
1019
+ if (child.isBranch && result < NoAndSkip)
1020
+ this.eachFind(child.children, method, list, options);
1021
+ }
1022
+ }
1023
+ toChildren(branch) {
1024
+ this.findLeaf = null;
1025
+ return [branch || this.target];
1026
+ }
1027
+ __onRemoveChild(event) {
1028
+ const { id, innerId } = event.child;
1029
+ if (this.idMap[id])
1030
+ delete this.idMap[id];
1031
+ if (this.innerIdMap[innerId])
1032
+ delete this.innerIdMap[innerId];
1033
+ }
1034
+ __checkIdChange(event) {
1035
+ if (event.attrName === 'id') {
1036
+ const id = event.oldValue;
1037
+ if (this.idMap[id])
1038
+ delete this.idMap[id];
1039
+ }
1040
+ }
1041
+ __listenEvents() {
1042
+ this.__eventIds = [
1043
+ this.target.on_(ChildEvent.REMOVE, this.__onRemoveChild, this),
1044
+ this.target.on_(PropertyEvent.CHANGE, this.__checkIdChange, this)
1045
+ ];
1046
+ }
1047
+ __removeListenEvents() {
1048
+ this.target.off_(this.__eventIds);
797
1049
  this.__eventIds.length = 0;
798
1050
  }
799
1051
  destroy() {
800
1052
  if (this.__eventIds.length) {
801
1053
  this.__removeListenEvents();
802
- this.findPath.destroy();
803
- this.innerIdList = {};
804
- this.idList = {};
805
- this.classNameList = {};
806
- this.tagNameList = {};
1054
+ this.picker.destroy();
1055
+ this.findLeaf = null;
1056
+ this.innerIdMap = {};
1057
+ this.idMap = {};
807
1058
  }
808
1059
  }
809
1060
  }
@@ -816,96 +1067,6 @@ Object.assign(Creator, {
816
1067
  });
817
1068
  Platform.layout = Layouter.fullLayout;
818
1069
 
819
- class LeaferCanvas extends LeaferCanvasBase {
820
- get allowBackgroundColor() { return false; }
821
- init() {
822
- let { view } = this.config;
823
- if (view) {
824
- if (typeof view === 'string') {
825
- if (view[0] !== '#')
826
- view = '#' + view;
827
- this.viewSelect = Platform.miniapp.select(view);
828
- }
829
- else if (view.fields) {
830
- this.viewSelect = view;
831
- }
832
- else {
833
- this.initView(view);
834
- }
835
- if (this.viewSelect)
836
- Platform.miniapp.getSizeView(this.viewSelect).then(sizeView => {
837
- this.initView(sizeView);
838
- });
839
- }
840
- else {
841
- this.initView();
842
- }
843
- }
844
- initView(view) {
845
- if (!view) {
846
- view = {};
847
- this.__createView();
848
- }
849
- else {
850
- this.view = view.view || view;
851
- }
852
- this.__createContext();
853
- const { width, height, pixelRatio } = this.config;
854
- const size = { width: width || view.width, height: height || view.height, pixelRatio };
855
- this.resize(size);
856
- if (this.context.roundRect) {
857
- this.roundRect = function (x, y, width, height, radius) {
858
- this.context.roundRect(x, y, width, height, typeof radius === 'number' ? [radius] : radius);
859
- };
860
- }
861
- canvasPatch(this.context.__proto__);
862
- }
863
- __createView() {
864
- this.view = Platform.origin.createCanvas(1, 1);
865
- }
866
- updateViewSize() {
867
- const { width, height, pixelRatio } = this;
868
- this.view.width = width * pixelRatio;
869
- this.view.height = height * pixelRatio;
870
- }
871
- updateClientBounds(callback) {
872
- if (this.viewSelect)
873
- Platform.miniapp.getBounds(this.viewSelect).then(bounds => {
874
- this.clientBounds = bounds;
875
- if (callback)
876
- callback();
877
- });
878
- }
879
- startAutoLayout(_autoBounds, listener) {
880
- this.resizeListener = listener;
881
- this.checkSize = this.checkSize.bind(this);
882
- Platform.miniapp.onWindowResize(this.checkSize);
883
- }
884
- checkSize() {
885
- if (this.viewSelect) {
886
- setTimeout(() => {
887
- this.updateClientBounds(() => {
888
- const { width, height } = this.clientBounds;
889
- const { pixelRatio } = this;
890
- const size = { width, height, pixelRatio };
891
- if (!this.isSameSize(size)) {
892
- const oldSize = {};
893
- DataHelper.copyAttrs(oldSize, this, canvasSizeAttrs);
894
- this.resize(size);
895
- if (this.width !== undefined)
896
- this.resizeListener(new ResizeEvent(size, oldSize));
897
- }
898
- });
899
- }, 500);
900
- }
901
- }
902
- stopAutoLayout() {
903
- this.autoLayout = false;
904
- this.resizeListener = null;
905
- Platform.miniapp.offWindowResize(this.checkSize);
906
- }
907
- }
908
-
909
1070
  const PointerEventHelper = {
910
1071
  convertTouch(e, local) {
911
1072
  const touch = PointerEventHelper.getTouch(e);
@@ -938,15 +1099,12 @@ class Interaction extends InteractionBase {
938
1099
  this.onTouchCancel();
939
1100
  }
940
1101
  }
941
- getLocal(p, updateClient) {
942
- if (updateClient)
943
- this.canvas.updateClientBounds();
944
- if (p.x !== undefined) {
945
- return { x: p.x, y: p.y };
1102
+ getLocal(clientPoint, updateClient) {
1103
+ if (clientPoint.x !== undefined) {
1104
+ return { x: clientPoint.x, y: clientPoint.y };
946
1105
  }
947
1106
  else {
948
- const { clientBounds } = this.canvas;
949
- return { x: p.clientX - clientBounds.x, y: p.clientY - clientBounds.y };
1107
+ return super.getLocal(clientPoint, updateClient);
950
1108
  }
951
1109
  }
952
1110
  getTouches(touches) {
@@ -1014,263 +1172,586 @@ class Interaction extends InteractionBase {
1014
1172
  }
1015
1173
  }
1016
1174
 
1017
- const { mineType, fileType } = FileHelper;
1018
- Object.assign(Creator, {
1019
- canvas: (options, manager) => new LeaferCanvas(options, manager),
1020
- image: (options) => new LeaferImage(options),
1021
- hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
1022
- interaction: (target, canvas, selector, options) => { return new Interaction(target, canvas, selector, options); }
1023
- });
1024
- function useCanvas(_canvasType, app) {
1025
- if (!Platform.origin) {
1026
- Platform.origin = {
1027
- createCanvas: (width, height, _format) => app.createOffscreenCanvas({ type: '2d', width, height }),
1028
- canvasToDataURL: (canvas, type, quality) => canvas.toDataURL(mineType(type), quality),
1029
- canvasToBolb: (canvas, type, quality) => canvas.toBuffer(type, { quality }),
1030
- canvasSaveAs: (canvas, filePath, quality) => {
1031
- return new Promise((resolve, reject) => {
1032
- let data = canvas.toDataURL(mineType(fileType(filePath)), quality);
1033
- data = data.substring(data.indexOf('64,') + 3);
1034
- let toAlbum;
1035
- if (!filePath.includes('/')) {
1036
- filePath = `${app.env.USER_DATA_PATH}/` + filePath;
1037
- toAlbum = true;
1038
- }
1039
- const fs = app.getFileSystemManager();
1040
- fs.writeFile({
1041
- filePath,
1042
- data,
1043
- encoding: 'base64',
1044
- success() {
1045
- if (toAlbum) {
1046
- Platform.miniapp.saveToAlbum(filePath).then(() => {
1047
- fs.unlink({ filePath });
1048
- });
1049
- }
1050
- resolve();
1051
- },
1052
- fail(error) {
1053
- reject(error);
1054
- }
1055
- });
1056
- });
1057
- },
1058
- loadImage(url) {
1059
- return new Promise((resolve, reject) => {
1060
- const img = Platform.canvas.view.createImage();
1061
- img.onload = () => { resolve(img); };
1062
- img.onerror = (error) => { reject(error); };
1063
- img.src = url;
1064
- });
1065
- },
1066
- noRepeat: 'repeat-x'
1067
- };
1068
- Platform.miniapp = {
1069
- select(name) {
1070
- return app.createSelectorQuery().select(name);
1071
- },
1072
- getBounds(select) {
1073
- return new Promise((resolve) => {
1074
- select.boundingClientRect().exec((res) => {
1075
- const rect = res[1];
1076
- resolve({ x: rect.top, y: rect.left, width: rect.width, height: rect.height });
1077
- });
1078
- });
1079
- },
1080
- getSizeView(select) {
1081
- return new Promise((resolve) => {
1082
- select.fields({ node: true, size: true }).exec((res) => {
1083
- const data = res[0];
1084
- resolve({ view: data.node, width: data.width, height: data.height });
1085
- });
1086
- });
1087
- },
1088
- saveToAlbum(path) {
1089
- return new Promise((resolve) => {
1090
- app.getSetting({
1091
- success: (res) => {
1092
- if (res.authSetting['scope.writePhotosAlbum']) {
1093
- app.saveImageToPhotosAlbum({
1094
- filePath: path,
1095
- success() { resolve(true); }
1096
- });
1097
- }
1098
- else {
1099
- app.authorize({
1100
- scope: 'scope.writePhotosAlbum',
1101
- success: () => {
1102
- app.saveImageToPhotosAlbum({
1103
- filePath: path,
1104
- success() { resolve(true); }
1105
- });
1106
- },
1107
- fail: () => { }
1108
- });
1109
- }
1110
- }
1111
- });
1112
- });
1113
- },
1114
- onWindowResize(fun) {
1115
- app.onWindowResize(fun);
1116
- },
1117
- offWindowResize(fun) {
1118
- app.offWindowResize(fun);
1119
- }
1120
- };
1121
- Platform.canvas = Creator.canvas();
1122
- Platform.conicGradientSupport = !!Platform.canvas.context.createConicGradient;
1175
+ function fillText(ui, canvas) {
1176
+ let row;
1177
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1178
+ for (let i = 0, len = rows.length; i < len; i++) {
1179
+ row = rows[i];
1180
+ if (row.text) {
1181
+ canvas.fillText(row.text, row.x, row.y);
1182
+ }
1183
+ else if (row.data) {
1184
+ row.data.forEach(charData => {
1185
+ canvas.fillText(charData.char, charData.x, row.y);
1186
+ });
1187
+ }
1188
+ if (decorationY)
1189
+ canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1123
1190
  }
1124
1191
  }
1125
- Platform.name = 'miniapp';
1126
- Platform.requestRender = function (render) { Platform.canvas.view.requestAnimationFrame(render); };
1127
- Platform.devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
1128
- Platform.realtimeLayout = true;
1129
1192
 
1130
- const { get: get$4, rotateOfOuter: rotateOfOuter$2, translate: translate$1, scaleOfOuter: scaleOfOuter$2, scale: scaleHelper$1, rotate } = MatrixHelper;
1131
- function fillOrFitMode(data, mode, box, width, height, rotation) {
1132
- const transform = get$4();
1133
- const swap = rotation && rotation !== 180;
1134
- const sw = box.width / (swap ? height : width);
1135
- const sh = box.height / (swap ? width : height);
1136
- const scale = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1137
- const x = box.x + (box.width - width * scale) / 2;
1138
- const y = box.y + (box.height - height * scale) / 2;
1139
- translate$1(transform, x, y);
1140
- scaleHelper$1(transform, scale);
1141
- if (rotation)
1142
- rotateOfOuter$2(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1143
- data.scaleX = data.scaleY = scale;
1144
- data.transform = transform;
1193
+ function fill(fill, ui, canvas) {
1194
+ canvas.fillStyle = fill;
1195
+ ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1145
1196
  }
1146
- function clipMode(data, box, offset, scale, rotation) {
1147
- const transform = get$4();
1148
- translate$1(transform, box.x, box.y);
1149
- if (offset)
1150
- translate$1(transform, offset.x, offset.y);
1151
- if (scale) {
1152
- typeof scale === 'number' ? scaleHelper$1(transform, scale) : scaleHelper$1(transform, scale.x, scale.y);
1153
- data.scaleX = transform.a;
1154
- data.scaleY = transform.d;
1197
+ function fills(fills, ui, canvas) {
1198
+ let item;
1199
+ const { windingRule, __font } = ui.__;
1200
+ for (let i = 0, len = fills.length; i < len; i++) {
1201
+ item = fills[i];
1202
+ if (item.image && PaintImage.checkImage(ui, canvas, item, !__font))
1203
+ continue;
1204
+ if (item.style) {
1205
+ canvas.fillStyle = item.style;
1206
+ if (item.transform) {
1207
+ canvas.save();
1208
+ canvas.transform(item.transform);
1209
+ if (item.blendMode)
1210
+ canvas.blendMode = item.blendMode;
1211
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1212
+ canvas.restore();
1213
+ }
1214
+ else {
1215
+ if (item.blendMode) {
1216
+ canvas.saveBlendMode(item.blendMode);
1217
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1218
+ canvas.restoreBlendMode();
1219
+ }
1220
+ else {
1221
+ __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1222
+ }
1223
+ }
1224
+ }
1155
1225
  }
1156
- if (rotation)
1157
- rotate(transform, rotation);
1158
- data.transform = transform;
1159
1226
  }
1160
- function repeatMode(data, box, width, height, scale, rotation) {
1161
- const transform = get$4();
1162
- if (rotation) {
1163
- rotate(transform, rotation);
1164
- switch (rotation) {
1165
- case 90:
1166
- translate$1(transform, height, 0);
1227
+
1228
+ function strokeText(stroke, ui, canvas) {
1229
+ const { strokeAlign } = ui.__;
1230
+ const isStrokes = typeof stroke !== 'string';
1231
+ switch (strokeAlign) {
1232
+ case 'center':
1233
+ canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1234
+ isStrokes ? drawStrokesStyle(stroke, true, ui, canvas) : drawTextStroke(ui, canvas);
1235
+ break;
1236
+ case 'inside':
1237
+ drawAlignStroke('inside', stroke, isStrokes, ui, canvas);
1238
+ break;
1239
+ case 'outside':
1240
+ drawAlignStroke('outside', stroke, isStrokes, ui, canvas);
1241
+ break;
1242
+ }
1243
+ }
1244
+ function drawAlignStroke(align, stroke, isStrokes, ui, canvas) {
1245
+ const { __strokeWidth, __font } = ui.__;
1246
+ const out = canvas.getSameCanvas(true, true);
1247
+ out.setStroke(isStrokes ? undefined : stroke, __strokeWidth * 2, ui.__);
1248
+ out.font = __font;
1249
+ isStrokes ? drawStrokesStyle(stroke, true, ui, out) : drawTextStroke(ui, out);
1250
+ out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1251
+ fillText(ui, out);
1252
+ out.blendMode = 'normal';
1253
+ if (ui.__worldFlipped) {
1254
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1255
+ }
1256
+ else {
1257
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1258
+ }
1259
+ out.recycle(ui.__nowWorld);
1260
+ }
1261
+ function drawTextStroke(ui, canvas) {
1262
+ let row;
1263
+ const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1264
+ for (let i = 0, len = rows.length; i < len; i++) {
1265
+ row = rows[i];
1266
+ if (row.text) {
1267
+ canvas.strokeText(row.text, row.x, row.y);
1268
+ }
1269
+ else if (row.data) {
1270
+ row.data.forEach(charData => {
1271
+ canvas.strokeText(charData.char, charData.x, row.y);
1272
+ });
1273
+ }
1274
+ if (decorationY)
1275
+ canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1276
+ }
1277
+ }
1278
+ function drawStrokesStyle(strokes, isText, ui, canvas) {
1279
+ let item;
1280
+ for (let i = 0, len = strokes.length; i < len; i++) {
1281
+ item = strokes[i];
1282
+ if (item.image && PaintImage.checkImage(ui, canvas, item, false))
1283
+ continue;
1284
+ if (item.style) {
1285
+ canvas.strokeStyle = item.style;
1286
+ if (item.blendMode) {
1287
+ canvas.saveBlendMode(item.blendMode);
1288
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1289
+ canvas.restoreBlendMode();
1290
+ }
1291
+ else {
1292
+ isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1293
+ }
1294
+ }
1295
+ }
1296
+ }
1297
+
1298
+ function stroke(stroke, ui, canvas) {
1299
+ const options = ui.__;
1300
+ const { __strokeWidth, strokeAlign, __font } = options;
1301
+ if (!__strokeWidth)
1302
+ return;
1303
+ if (__font) {
1304
+ strokeText(stroke, ui, canvas);
1305
+ }
1306
+ else {
1307
+ switch (strokeAlign) {
1308
+ case 'center':
1309
+ canvas.setStroke(stroke, __strokeWidth, options);
1310
+ canvas.stroke();
1311
+ break;
1312
+ case 'inside':
1313
+ canvas.save();
1314
+ canvas.setStroke(stroke, __strokeWidth * 2, options);
1315
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1316
+ canvas.stroke();
1317
+ canvas.restore();
1318
+ break;
1319
+ case 'outside':
1320
+ const out = canvas.getSameCanvas(true, true);
1321
+ out.setStroke(stroke, __strokeWidth * 2, options);
1322
+ ui.__drawRenderPath(out);
1323
+ out.stroke();
1324
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1325
+ out.clearWorld(ui.__layout.renderBounds);
1326
+ if (ui.__worldFlipped) {
1327
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1328
+ }
1329
+ else {
1330
+ canvas.copyWorldToInner(out, ui.__nowWorld, ui.__layout.renderBounds);
1331
+ }
1332
+ out.recycle(ui.__nowWorld);
1167
1333
  break;
1168
- case 180:
1169
- translate$1(transform, width, height);
1334
+ }
1335
+ }
1336
+ }
1337
+ function strokes(strokes, ui, canvas) {
1338
+ const options = ui.__;
1339
+ const { __strokeWidth, strokeAlign, __font } = options;
1340
+ if (!__strokeWidth)
1341
+ return;
1342
+ if (__font) {
1343
+ strokeText(strokes, ui, canvas);
1344
+ }
1345
+ else {
1346
+ switch (strokeAlign) {
1347
+ case 'center':
1348
+ canvas.setStroke(undefined, __strokeWidth, options);
1349
+ drawStrokesStyle(strokes, false, ui, canvas);
1350
+ break;
1351
+ case 'inside':
1352
+ canvas.save();
1353
+ canvas.setStroke(undefined, __strokeWidth * 2, options);
1354
+ options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1355
+ drawStrokesStyle(strokes, false, ui, canvas);
1356
+ canvas.restore();
1170
1357
  break;
1171
- case 270:
1172
- translate$1(transform, 0, width);
1358
+ case 'outside':
1359
+ const { renderBounds } = ui.__layout;
1360
+ const out = canvas.getSameCanvas(true, true);
1361
+ ui.__drawRenderPath(out);
1362
+ out.setStroke(undefined, __strokeWidth * 2, options);
1363
+ drawStrokesStyle(strokes, false, ui, out);
1364
+ options.windingRule ? out.clip(options.windingRule) : out.clip();
1365
+ out.clearWorld(renderBounds);
1366
+ if (ui.__worldFlipped) {
1367
+ canvas.copyWorldByReset(out, ui.__nowWorld);
1368
+ }
1369
+ else {
1370
+ canvas.copyWorldToInner(out, ui.__nowWorld, renderBounds);
1371
+ }
1372
+ out.recycle(ui.__nowWorld);
1173
1373
  break;
1174
1374
  }
1175
1375
  }
1176
- translate$1(transform, box.x, box.y);
1177
- if (scale) {
1178
- scaleOfOuter$2(transform, box, scale);
1179
- data.scaleX = data.scaleY = scale;
1376
+ }
1377
+
1378
+ const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1379
+ function shape(ui, current, options) {
1380
+ const canvas = current.getSameCanvas();
1381
+ const nowWorld = ui.__nowWorld;
1382
+ let bounds, fitMatrix, shapeBounds, worldCanvas;
1383
+ let { scaleX, scaleY } = nowWorld;
1384
+ if (scaleX < 0)
1385
+ scaleX = -scaleX;
1386
+ if (scaleY < 0)
1387
+ scaleY = -scaleY;
1388
+ if (current.bounds.includes(nowWorld)) {
1389
+ worldCanvas = canvas;
1390
+ bounds = shapeBounds = nowWorld;
1391
+ }
1392
+ else {
1393
+ const { renderShapeSpread: spread } = ui.__layout;
1394
+ const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, scaleX === scaleY ? spread * scaleX : [spread * scaleY, spread * scaleX]) : current.bounds, nowWorld);
1395
+ fitMatrix = current.bounds.getFitMatrix(worldClipBounds);
1396
+ let { a: fitScaleX, d: fitScaleY } = fitMatrix;
1397
+ if (fitMatrix.a < 1) {
1398
+ worldCanvas = current.getSameCanvas();
1399
+ ui.__renderShape(worldCanvas, options);
1400
+ scaleX *= fitScaleX;
1401
+ scaleY *= fitScaleY;
1402
+ }
1403
+ shapeBounds = getOuterOf(nowWorld, fitMatrix);
1404
+ bounds = getByMove(shapeBounds, -fitMatrix.e, -fitMatrix.f);
1405
+ if (options.matrix) {
1406
+ const { matrix } = options;
1407
+ fitMatrix.multiply(matrix);
1408
+ fitScaleX *= matrix.scaleX;
1409
+ fitScaleY *= matrix.scaleY;
1410
+ }
1411
+ options = Object.assign(Object.assign({}, options), { matrix: fitMatrix.withScale(fitScaleX, fitScaleY) });
1180
1412
  }
1413
+ ui.__renderShape(canvas, options);
1414
+ return {
1415
+ canvas, matrix: fitMatrix, bounds,
1416
+ worldCanvas, shapeBounds, scaleX, scaleY
1417
+ };
1418
+ }
1419
+
1420
+ let recycleMap;
1421
+ function compute(attrName, ui) {
1422
+ const data = ui.__, leafPaints = [];
1423
+ let paints = data.__input[attrName], hasOpacityPixel;
1424
+ if (!(paints instanceof Array))
1425
+ paints = [paints];
1426
+ recycleMap = PaintImage.recycleImage(attrName, data);
1427
+ for (let i = 0, len = paints.length, item; i < len; i++) {
1428
+ item = getLeafPaint(attrName, paints[i], ui);
1429
+ if (item)
1430
+ leafPaints.push(item);
1431
+ }
1432
+ data['_' + attrName] = leafPaints.length ? leafPaints : undefined;
1433
+ if (leafPaints.length && leafPaints[0].image)
1434
+ hasOpacityPixel = leafPaints[0].image.hasOpacityPixel;
1435
+ if (attrName === 'fill') {
1436
+ data.__pixelFill = hasOpacityPixel;
1437
+ }
1438
+ else {
1439
+ data.__pixelStroke = hasOpacityPixel;
1440
+ }
1441
+ }
1442
+ function getLeafPaint(attrName, paint, ui) {
1443
+ if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1444
+ return undefined;
1445
+ const { boxBounds } = ui.__layout;
1446
+ switch (paint.type) {
1447
+ case 'solid':
1448
+ let { type, blendMode, color, opacity } = paint;
1449
+ return { type, blendMode, style: ColorConvert.string(color, opacity) };
1450
+ case 'image':
1451
+ return PaintImage.image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1452
+ case 'linear':
1453
+ return PaintGradient.linearGradient(paint, boxBounds);
1454
+ case 'radial':
1455
+ return PaintGradient.radialGradient(paint, boxBounds);
1456
+ case 'angular':
1457
+ return PaintGradient.conicGradient(paint, boxBounds);
1458
+ default:
1459
+ return paint.r !== undefined ? { type: 'solid', style: ColorConvert.string(paint) } : undefined;
1460
+ }
1461
+ }
1462
+
1463
+ const PaintModule = {
1464
+ compute,
1465
+ fill,
1466
+ fills,
1467
+ fillText,
1468
+ stroke,
1469
+ strokes,
1470
+ strokeText,
1471
+ drawTextStroke,
1472
+ shape
1473
+ };
1474
+
1475
+ let origin = {};
1476
+ const { get: get$3, rotateOfOuter: rotateOfOuter$1, translate: translate$1, scaleOfOuter: scaleOfOuter$1, scale: scaleHelper, rotate } = MatrixHelper;
1477
+ function fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation) {
1478
+ const transform = get$3();
1479
+ translate$1(transform, box.x + x, box.y + y);
1480
+ scaleHelper(transform, scaleX, scaleY);
1481
+ if (rotation)
1482
+ rotateOfOuter$1(transform, { x: box.x + box.width / 2, y: box.y + box.height / 2 }, rotation);
1483
+ data.transform = transform;
1484
+ }
1485
+ function clipMode(data, box, x, y, scaleX, scaleY, rotation) {
1486
+ const transform = get$3();
1487
+ translate$1(transform, box.x + x, box.y + y);
1488
+ if (scaleX)
1489
+ scaleHelper(transform, scaleX, scaleY);
1490
+ if (rotation)
1491
+ rotate(transform, rotation);
1492
+ data.transform = transform;
1493
+ }
1494
+ function repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align) {
1495
+ const transform = get$3();
1496
+ if (rotation) {
1497
+ if (align === 'center') {
1498
+ rotateOfOuter$1(transform, { x: width / 2, y: height / 2 }, rotation);
1499
+ }
1500
+ else {
1501
+ rotate(transform, rotation);
1502
+ switch (rotation) {
1503
+ case 90:
1504
+ translate$1(transform, height, 0);
1505
+ break;
1506
+ case 180:
1507
+ translate$1(transform, width, height);
1508
+ break;
1509
+ case 270:
1510
+ translate$1(transform, 0, width);
1511
+ break;
1512
+ }
1513
+ }
1514
+ }
1515
+ origin.x = box.x + x;
1516
+ origin.y = box.y + y;
1517
+ translate$1(transform, origin.x, origin.y);
1518
+ if (scaleX)
1519
+ scaleOfOuter$1(transform, origin, scaleX, scaleY);
1181
1520
  data.transform = transform;
1182
1521
  }
1183
1522
 
1184
- const { get: get$3, translate } = MatrixHelper;
1523
+ const { get: get$2, translate } = MatrixHelper;
1524
+ const tempBox = new Bounds();
1525
+ const tempPoint = {};
1185
1526
  function createData(leafPaint, image, paint, box) {
1186
- let { width, height } = image;
1187
- const { opacity, mode, offset, scale, rotation, blendMode } = paint;
1188
- const sameBox = box.width === width && box.height === height;
1527
+ const { blendMode } = paint;
1189
1528
  if (blendMode)
1190
1529
  leafPaint.blendMode = blendMode;
1191
- const data = leafPaint.data = { mode };
1530
+ leafPaint.data = getPatternData(paint, box, image);
1531
+ }
1532
+ function getPatternData(paint, box, image) {
1533
+ let { width, height } = image;
1534
+ if (paint.padding)
1535
+ box = tempBox.set(box).shrink(paint.padding);
1536
+ const { opacity, mode, align, offset, scale, size, rotation, repeat } = paint;
1537
+ const sameBox = box.width === width && box.height === height;
1538
+ const data = { mode };
1539
+ const swapSize = align !== 'center' && (rotation || 0) % 180 === 90;
1540
+ const swapWidth = swapSize ? height : width, swapHeight = swapSize ? width : height;
1541
+ let x = 0, y = 0, scaleX, scaleY;
1542
+ if (!mode || mode === 'cover' || mode === 'fit') {
1543
+ if (!sameBox || rotation) {
1544
+ const sw = box.width / swapWidth, sh = box.height / swapHeight;
1545
+ scaleX = scaleY = mode === 'fit' ? Math.min(sw, sh) : Math.max(sw, sh);
1546
+ x += (box.width - width * scaleX) / 2, y += (box.height - height * scaleY) / 2;
1547
+ }
1548
+ }
1549
+ else if (size) {
1550
+ scaleX = (typeof size === 'number' ? size : size.width) / width;
1551
+ scaleY = (typeof size === 'number' ? size : size.height) / height;
1552
+ }
1553
+ else if (scale) {
1554
+ scaleX = typeof scale === 'number' ? scale : scale.x;
1555
+ scaleY = typeof scale === 'number' ? scale : scale.y;
1556
+ }
1557
+ if (align) {
1558
+ const imageBounds = { x, y, width: swapWidth, height: swapHeight };
1559
+ if (scaleX)
1560
+ imageBounds.width *= scaleX, imageBounds.height *= scaleY;
1561
+ AlignHelper.toPoint(align, imageBounds, box, tempPoint, true);
1562
+ x += tempPoint.x, y += tempPoint.y;
1563
+ }
1564
+ if (offset)
1565
+ x += offset.x, y += offset.y;
1192
1566
  switch (mode) {
1193
1567
  case 'strench':
1194
1568
  if (!sameBox)
1195
1569
  width = box.width, height = box.height;
1196
- if (box.x || box.y) {
1197
- data.transform = get$3();
1198
- translate(data.transform, box.x, box.y);
1199
- }
1200
1570
  break;
1571
+ case 'normal':
1201
1572
  case 'clip':
1202
- if (offset || scale || rotation)
1203
- clipMode(data, box, offset, scale, rotation);
1573
+ if (x || y || scaleX || rotation)
1574
+ clipMode(data, box, x, y, scaleX, scaleY, rotation);
1204
1575
  break;
1205
1576
  case 'repeat':
1206
- if (!sameBox || scale || rotation)
1207
- repeatMode(data, box, width, height, scale, rotation);
1577
+ if (!sameBox || scaleX || rotation)
1578
+ repeatMode(data, box, width, height, x, y, scaleX, scaleY, rotation, align);
1579
+ if (!repeat)
1580
+ data.repeat = 'repeat';
1208
1581
  break;
1209
1582
  case 'fit':
1210
1583
  case 'cover':
1211
1584
  default:
1212
- if (!sameBox || rotation)
1213
- fillOrFitMode(data, mode, box, width, height, rotation);
1585
+ if (scaleX)
1586
+ fillOrFitMode(data, box, x, y, scaleX, scaleY, rotation);
1587
+ }
1588
+ if (!data.transform) {
1589
+ if (box.x || box.y) {
1590
+ data.transform = get$2();
1591
+ translate(data.transform, box.x, box.y);
1592
+ }
1593
+ }
1594
+ if (scaleX && mode !== 'strench') {
1595
+ data.scaleX = scaleX;
1596
+ data.scaleY = scaleY;
1214
1597
  }
1215
1598
  data.width = width;
1216
1599
  data.height = height;
1217
1600
  if (opacity)
1218
1601
  data.opacity = opacity;
1602
+ if (repeat)
1603
+ data.repeat = typeof repeat === 'string' ? (repeat === 'x' ? 'repeat-x' : 'repeat-y') : 'repeat';
1604
+ return data;
1219
1605
  }
1220
1606
 
1221
- function image(ui, attrName, attrValue, box, firstUse) {
1222
- const leafPaint = { type: attrValue.type };
1223
- const image = leafPaint.image = ImageManager.get(attrValue);
1224
- const event = (firstUse || image.loading) && { target: ui, image, attrName, attrValue };
1607
+ let cache, box = new Bounds();
1608
+ const { isSame } = BoundsHelper;
1609
+ function image(ui, attrName, paint, boxBounds, firstUse) {
1610
+ let leafPaint, event;
1611
+ const image = ImageManager.get(paint);
1612
+ if (cache && paint === cache.paint && isSame(boxBounds, cache.boxBounds)) {
1613
+ leafPaint = cache.leafPaint;
1614
+ }
1615
+ else {
1616
+ leafPaint = { type: paint.type, image };
1617
+ cache = image.use > 1 ? { leafPaint, paint, boxBounds: box.set(boxBounds) } : null;
1618
+ }
1619
+ if (firstUse || image.loading)
1620
+ event = { image, attrName, attrValue: paint };
1225
1621
  if (image.ready) {
1226
- if (hasNaturalSize(ui, attrName, image))
1227
- createData(leafPaint, image, attrValue, box);
1622
+ checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds);
1228
1623
  if (firstUse) {
1229
- emit(ImageEvent.LOAD, event);
1230
- emit(ImageEvent.LOADED, event);
1624
+ onLoad(ui, event);
1625
+ onLoadSuccess(ui, event);
1231
1626
  }
1232
1627
  }
1233
1628
  else if (image.error) {
1234
- if (firstUse) {
1235
- ui.forceUpdate('surface');
1236
- event.error = image.error;
1237
- emit(ImageEvent.ERROR, event);
1238
- }
1629
+ if (firstUse)
1630
+ onLoadError(ui, event, image.error);
1239
1631
  }
1240
1632
  else {
1633
+ ignoreRender(ui, true);
1241
1634
  if (firstUse)
1242
- emit(ImageEvent.LOAD, event);
1635
+ onLoad(ui, event);
1243
1636
  leafPaint.loadId = image.load(() => {
1637
+ ignoreRender(ui, false);
1244
1638
  if (!ui.destroyed) {
1245
- if (hasNaturalSize(ui, attrName, image)) {
1246
- createData(leafPaint, image, attrValue, box);
1639
+ if (checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds)) {
1640
+ if (image.hasOpacityPixel)
1641
+ ui.__layout.hitCanvasChanged = true;
1247
1642
  ui.forceUpdate('surface');
1248
1643
  }
1249
- emit(ImageEvent.LOADED, event);
1644
+ onLoadSuccess(ui, event);
1250
1645
  }
1646
+ leafPaint.loadId = null;
1251
1647
  }, (error) => {
1252
- ui.forceUpdate('surface');
1253
- event.error = error;
1254
- emit(ImageEvent.ERROR, event);
1648
+ ignoreRender(ui, false);
1649
+ onLoadError(ui, event, error);
1650
+ leafPaint.loadId = null;
1255
1651
  });
1256
1652
  }
1257
1653
  return leafPaint;
1258
1654
  }
1259
- function hasNaturalSize(ui, attrName, image) {
1655
+ function checkSizeAndCreateData(ui, attrName, paint, image, leafPaint, boxBounds) {
1260
1656
  if (attrName === 'fill' && !ui.__.__naturalWidth) {
1261
- const { __: d } = ui;
1262
- d.__naturalWidth = image.width;
1263
- d.__naturalHeight = image.height;
1264
- if (!d.__getInput('width') || !d.__getInput('height')) {
1657
+ const data = ui.__;
1658
+ data.__naturalWidth = image.width / data.pixelRatio;
1659
+ data.__naturalHeight = image.height / data.pixelRatio;
1660
+ if (data.__autoSide) {
1265
1661
  ui.forceUpdate('width');
1662
+ if (ui.__proxyData) {
1663
+ ui.setProxyAttr('width', data.width);
1664
+ ui.setProxyAttr('height', data.height);
1665
+ }
1266
1666
  return false;
1267
1667
  }
1268
1668
  }
1669
+ if (!leafPaint.data)
1670
+ createData(leafPaint, image, paint, boxBounds);
1269
1671
  return true;
1270
1672
  }
1271
- function emit(type, data) {
1272
- if (data.target.hasEvent(type))
1273
- data.target.emitEvent(new ImageEvent(type, data));
1673
+ function onLoad(ui, event) {
1674
+ emit(ui, ImageEvent.LOAD, event);
1675
+ }
1676
+ function onLoadSuccess(ui, event) {
1677
+ emit(ui, ImageEvent.LOADED, event);
1678
+ }
1679
+ function onLoadError(ui, event, error) {
1680
+ event.error = error;
1681
+ ui.forceUpdate('surface');
1682
+ emit(ui, ImageEvent.ERROR, event);
1683
+ }
1684
+ function emit(ui, type, data) {
1685
+ if (ui.hasEvent(type))
1686
+ ui.emitEvent(new ImageEvent(type, data));
1687
+ }
1688
+ function ignoreRender(ui, value) {
1689
+ const { leafer } = ui;
1690
+ if (leafer && leafer.viewReady)
1691
+ leafer.renderer.ignore = value;
1692
+ }
1693
+
1694
+ const { get: get$1, scale, copy: copy$1 } = MatrixHelper;
1695
+ const { ceil, abs: abs$1 } = Math;
1696
+ function createPattern(ui, paint, pixelRatio) {
1697
+ let { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1698
+ const id = scaleX + '-' + scaleY;
1699
+ if (paint.patternId !== id && !ui.destroyed) {
1700
+ scaleX = abs$1(scaleX);
1701
+ scaleY = abs$1(scaleY);
1702
+ const { image, data } = paint;
1703
+ let imageScale, imageMatrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, repeat } = data;
1704
+ if (sx) {
1705
+ imageMatrix = get$1();
1706
+ copy$1(imageMatrix, transform);
1707
+ scale(imageMatrix, 1 / sx, 1 / sy);
1708
+ scaleX *= sx;
1709
+ scaleY *= sy;
1710
+ }
1711
+ scaleX *= pixelRatio;
1712
+ scaleY *= pixelRatio;
1713
+ width *= scaleX;
1714
+ height *= scaleY;
1715
+ const size = width * height;
1716
+ if (!repeat) {
1717
+ if (size > Platform.image.maxCacheSize)
1718
+ return false;
1719
+ }
1720
+ let maxSize = Platform.image.maxPatternSize;
1721
+ if (!image.isSVG) {
1722
+ const imageSize = image.width * image.height;
1723
+ if (maxSize > imageSize)
1724
+ maxSize = imageSize;
1725
+ }
1726
+ if (size > maxSize)
1727
+ imageScale = Math.sqrt(size / maxSize);
1728
+ if (imageScale) {
1729
+ scaleX /= imageScale;
1730
+ scaleY /= imageScale;
1731
+ width /= imageScale;
1732
+ height /= imageScale;
1733
+ }
1734
+ if (sx) {
1735
+ scaleX /= sx;
1736
+ scaleY /= sy;
1737
+ }
1738
+ if (transform || scaleX !== 1 || scaleY !== 1) {
1739
+ if (!imageMatrix) {
1740
+ imageMatrix = get$1();
1741
+ if (transform)
1742
+ copy$1(imageMatrix, transform);
1743
+ }
1744
+ scale(imageMatrix, 1 / scaleX, 1 / scaleY);
1745
+ }
1746
+ const canvas = image.getCanvas(ceil(width) || 1, ceil(height) || 1, opacity);
1747
+ const pattern = image.getPattern(canvas, repeat || (Platform.origin.noRepeat || 'no-repeat'), imageMatrix, paint);
1748
+ paint.style = pattern;
1749
+ paint.patternId = id;
1750
+ return true;
1751
+ }
1752
+ else {
1753
+ return false;
1754
+ }
1274
1755
  }
1275
1756
 
1276
1757
  /******************************************************************************
@@ -1305,381 +1786,108 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
1305
1786
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1306
1787
  };
1307
1788
 
1308
- const { get: get$2, scale: scaleHelper, copy: copy$1 } = MatrixHelper;
1309
- function createPattern(ui, paint, pixelRatio) {
1310
- let { scaleX, scaleY } = ui.__world;
1311
- const id = scaleX + '-' + scaleY;
1312
- if (paint.patternId !== id && !ui.destroyed) {
1313
- paint.patternId = id;
1314
- scaleX = Math.abs(scaleX);
1315
- scaleY = Math.abs(scaleY);
1316
- const { image, data } = paint;
1317
- const maxWidth = image.isSVG ? 4096 : Math.min(image.width, 4096);
1318
- const maxHeight = image.isSVG ? 4096 : Math.min(image.height, 4096);
1319
- let scale, matrix, { width, height, scaleX: sx, scaleY: sy, opacity, transform, mode } = data;
1320
- if (sx) {
1321
- matrix = get$2();
1322
- copy$1(matrix, transform);
1323
- scaleHelper(matrix, 1 / sx, 1 / sy);
1324
- scaleX *= sx;
1325
- scaleY *= sy;
1326
- }
1327
- scaleX *= pixelRatio;
1328
- scaleY *= pixelRatio;
1329
- width *= scaleX;
1330
- height *= scaleY;
1331
- if (width > maxWidth || height > maxHeight) {
1332
- scale = Math.max(width / maxWidth, height / maxHeight);
1333
- }
1334
- if (scale) {
1335
- scaleX /= scale;
1336
- scaleY /= scale;
1337
- width /= scale;
1338
- height /= scale;
1339
- }
1340
- if (sx) {
1341
- scaleX /= sx;
1342
- scaleY /= sy;
1343
- }
1344
- if (transform || scaleX !== 1 || scaleY !== 1) {
1345
- if (!matrix) {
1346
- matrix = get$2();
1347
- if (transform)
1348
- copy$1(matrix, transform);
1349
- }
1350
- scaleHelper(matrix, 1 / scaleX, 1 / scaleY);
1351
- }
1352
- const style = Platform.canvas.createPattern(image.getCanvas(width < 1 ? 1 : width, height < 1 ? 1 : height, opacity), mode === 'repeat' ? 'repeat' : (Platform.origin.noRepeat || 'no-repeat'));
1353
- try {
1354
- if (paint.transform)
1355
- paint.transform = null;
1356
- if (matrix)
1357
- style.setTransform ? style.setTransform(matrix) : paint.transform = matrix;
1358
- }
1359
- catch (_a) {
1360
- paint.transform = matrix;
1361
- }
1362
- paint.style = style;
1363
- return true;
1364
- }
1365
- else {
1366
- return false;
1367
- }
1368
- }
1369
-
1789
+ const { abs } = Math;
1370
1790
  function checkImage(ui, canvas, paint, allowPaint) {
1371
- const { scaleX, scaleY } = ui.__world;
1791
+ const { scaleX, scaleY } = ImageManager.patternLocked ? ui.__world : ui.__nowWorld;
1372
1792
  if (!paint.data || paint.patternId === scaleX + '-' + scaleY) {
1373
1793
  return false;
1374
1794
  }
1375
1795
  else {
1796
+ const { data } = paint;
1376
1797
  if (allowPaint) {
1377
- if (paint.image.isSVG && paint.data.mode !== 'repeat') {
1378
- let { width, height } = paint.data;
1379
- width *= scaleX * canvas.pixelRatio;
1380
- height *= scaleY * canvas.pixelRatio;
1381
- allowPaint = width > 4096 || height > 4096;
1382
- }
1383
- else {
1384
- allowPaint = false;
1385
- }
1386
- }
1387
- if (allowPaint) {
1388
- canvas.save();
1389
- canvas.clip();
1390
- const { data } = paint;
1391
- if (paint.blendMode)
1392
- canvas.blendMode = paint.blendMode;
1393
- if (data.opacity)
1394
- canvas.opacity *= data.opacity;
1395
- if (data.transform)
1396
- canvas.transform(data.transform);
1397
- canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1398
- canvas.restore();
1399
- return true;
1400
- }
1401
- else {
1402
- if (!paint.style) {
1403
- createPattern(ui, paint, canvas.pixelRatio);
1404
- }
1405
- else {
1406
- ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1407
- if (canvas.bounds.hit(ui.__world) && createPattern(ui, paint, canvas.pixelRatio))
1408
- ui.forceUpdate('surface');
1409
- }), 300);
1410
- }
1411
- return false;
1412
- }
1413
- }
1414
- }
1415
-
1416
- function recycleImage(data, attrName) {
1417
- const paints = (attrName === 'fill' ? data._fill : data._stroke);
1418
- if (paints instanceof Array) {
1419
- let image, recycleMap, input, url;
1420
- for (let i = 0, len = paints.length; i < len; i++) {
1421
- image = paints[i].image;
1422
- url = image && image.url;
1423
- if (url) {
1424
- if (!recycleMap)
1425
- recycleMap = {};
1426
- recycleMap[url] = true;
1427
- ImageManager.recycle(image);
1428
- if (image.loading) {
1429
- if (!input) {
1430
- input = (data.__input && data.__input[attrName]) || [];
1431
- if (!(input instanceof Array))
1432
- input = [input];
1433
- }
1434
- image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1798
+ if (!data.repeat) {
1799
+ let { width, height } = data;
1800
+ width *= abs(scaleX) * canvas.pixelRatio;
1801
+ height *= abs(scaleY) * canvas.pixelRatio;
1802
+ if (data.scaleX) {
1803
+ width *= data.scaleX;
1804
+ height *= data.scaleY;
1435
1805
  }
1436
- }
1437
- }
1438
- return recycleMap;
1439
- }
1440
- return null;
1441
- }
1442
-
1443
- function fillText(ui, canvas) {
1444
- let row;
1445
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1446
- for (let i = 0, len = rows.length; i < len; i++) {
1447
- row = rows[i];
1448
- if (row.text) {
1449
- canvas.fillText(row.text, row.x, row.y);
1450
- }
1451
- else if (row.data) {
1452
- row.data.forEach(charData => {
1453
- canvas.fillText(charData.char, charData.x, row.y);
1454
- });
1455
- }
1456
- if (decorationY)
1457
- canvas.fillRect(row.x, row.y + decorationY, row.width, decorationHeight);
1458
- }
1459
- }
1460
-
1461
- function fill(ui, canvas, fill) {
1462
- canvas.fillStyle = fill;
1463
- ui.__.__font ? fillText(ui, canvas) : (ui.__.windingRule ? canvas.fill(ui.__.windingRule) : canvas.fill());
1464
- }
1465
- function fills(ui, canvas, fills) {
1466
- let item;
1467
- const { windingRule, __font } = ui.__;
1468
- for (let i = 0, len = fills.length; i < len; i++) {
1469
- item = fills[i];
1470
- if (item.image && checkImage(ui, canvas, item, !__font))
1471
- continue;
1472
- if (item.style) {
1473
- canvas.fillStyle = item.style;
1474
- if (item.transform) {
1475
- canvas.save();
1476
- canvas.transform(item.transform);
1477
- if (item.blendMode)
1478
- canvas.blendMode = item.blendMode;
1479
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1480
- canvas.restore();
1806
+ allowPaint = (width * height > Platform.image.maxCacheSize) || Export.running;
1481
1807
  }
1482
1808
  else {
1483
- if (item.blendMode) {
1484
- canvas.saveBlendMode(item.blendMode);
1485
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1486
- canvas.restoreBlendMode();
1487
- }
1488
- else {
1489
- __font ? fillText(ui, canvas) : (windingRule ? canvas.fill(windingRule) : canvas.fill());
1490
- }
1809
+ allowPaint = false;
1491
1810
  }
1492
1811
  }
1493
- }
1494
- }
1495
-
1496
- function strokeText(ui, canvas, stroke) {
1497
- const { strokeAlign } = ui.__;
1498
- const isStrokes = typeof stroke !== 'string';
1499
- switch (strokeAlign) {
1500
- case 'center':
1501
- canvas.setStroke(isStrokes ? undefined : stroke, ui.__.strokeWidth, ui.__);
1502
- isStrokes ? drawStrokesStyle(ui, stroke, canvas, true) : drawTextStroke(ui, canvas);
1503
- break;
1504
- case 'inside':
1505
- drawAlignStroke(ui, canvas, stroke, 'inside', isStrokes);
1506
- break;
1507
- case 'outside':
1508
- drawAlignStroke(ui, canvas, stroke, 'outside', isStrokes);
1509
- break;
1510
- }
1511
- }
1512
- function drawAlignStroke(ui, canvas, stroke, align, isStrokes) {
1513
- const { strokeWidth, __font } = ui.__;
1514
- const out = canvas.getSameCanvas(true);
1515
- out.setStroke(isStrokes ? undefined : stroke, strokeWidth * 2, ui.__);
1516
- out.font = __font;
1517
- isStrokes ? drawStrokesStyle(ui, stroke, out, true) : drawTextStroke(ui, out);
1518
- out.blendMode = align === 'outside' ? 'destination-out' : 'destination-in';
1519
- fillText(ui, out);
1520
- out.blendMode = 'normal';
1521
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1522
- out.recycle();
1523
- }
1524
- function drawTextStroke(ui, canvas) {
1525
- let row;
1526
- const { rows, decorationY, decorationHeight } = ui.__.__textDrawData;
1527
- for (let i = 0, len = rows.length; i < len; i++) {
1528
- row = rows[i];
1529
- if (row.text) {
1530
- canvas.strokeText(row.text, row.x, row.y);
1531
- }
1532
- else if (row.data) {
1533
- row.data.forEach(charData => {
1534
- canvas.strokeText(charData.char, charData.x, row.y);
1535
- });
1536
- }
1537
- if (decorationY)
1538
- canvas.strokeRect(row.x, row.y + decorationY, row.width, decorationHeight);
1539
- }
1540
- }
1541
- function drawStrokesStyle(ui, strokes, canvas, isText) {
1542
- let item;
1543
- for (let i = 0, len = strokes.length; i < len; i++) {
1544
- item = strokes[i];
1545
- if (item.image && checkImage(ui, canvas, item, false))
1546
- continue;
1547
- if (item.style) {
1548
- canvas.strokeStyle = item.style;
1549
- if (item.blendMode) {
1550
- canvas.saveBlendMode(item.blendMode);
1551
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1552
- canvas.restoreBlendMode();
1812
+ if (allowPaint) {
1813
+ canvas.save();
1814
+ canvas.clip();
1815
+ if (paint.blendMode)
1816
+ canvas.blendMode = paint.blendMode;
1817
+ if (data.opacity)
1818
+ canvas.opacity *= data.opacity;
1819
+ if (data.transform)
1820
+ canvas.transform(data.transform);
1821
+ canvas.drawImage(paint.image.view, 0, 0, data.width, data.height);
1822
+ canvas.restore();
1823
+ return true;
1824
+ }
1825
+ else {
1826
+ if (!paint.style || Export.running) {
1827
+ createPattern(ui, paint, canvas.pixelRatio);
1553
1828
  }
1554
1829
  else {
1555
- isText ? drawTextStroke(ui, canvas) : canvas.stroke();
1830
+ if (!paint.patternTask) {
1831
+ paint.patternTask = ImageManager.patternTasker.add(() => __awaiter(this, void 0, void 0, function* () {
1832
+ paint.patternTask = null;
1833
+ if (canvas.bounds.hit(ui.__nowWorld))
1834
+ createPattern(ui, paint, canvas.pixelRatio);
1835
+ ui.forceUpdate('surface');
1836
+ }), 300);
1837
+ }
1556
1838
  }
1839
+ return false;
1557
1840
  }
1558
1841
  }
1559
1842
  }
1560
1843
 
1561
- function stroke(ui, canvas, stroke) {
1562
- const options = ui.__;
1563
- const { strokeWidth, strokeAlign, __font } = options;
1564
- if (!strokeWidth)
1565
- return;
1566
- if (__font) {
1567
- strokeText(ui, canvas, stroke);
1568
- }
1569
- else {
1570
- switch (strokeAlign) {
1571
- case 'center':
1572
- canvas.setStroke(stroke, strokeWidth, options);
1573
- canvas.stroke();
1574
- break;
1575
- case 'inside':
1576
- canvas.save();
1577
- canvas.setStroke(stroke, strokeWidth * 2, options);
1578
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1579
- canvas.stroke();
1580
- canvas.restore();
1581
- break;
1582
- case 'outside':
1583
- const out = canvas.getSameCanvas(true);
1584
- out.setStroke(stroke, strokeWidth * 2, ui.__);
1585
- ui.__drawRenderPath(out);
1586
- out.stroke();
1587
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1588
- out.clearWorld(ui.__layout.renderBounds);
1589
- canvas.copyWorldToInner(out, ui.__world, ui.__layout.renderBounds);
1590
- out.recycle();
1591
- break;
1592
- }
1593
- }
1594
- }
1595
- function strokes(ui, canvas, strokes) {
1596
- const options = ui.__;
1597
- const { strokeWidth, strokeAlign, __font } = options;
1598
- if (!strokeWidth)
1599
- return;
1600
- if (__font) {
1601
- strokeText(ui, canvas, strokes);
1602
- }
1603
- else {
1604
- switch (strokeAlign) {
1605
- case 'center':
1606
- canvas.setStroke(undefined, strokeWidth, options);
1607
- drawStrokesStyle(ui, strokes, canvas);
1608
- break;
1609
- case 'inside':
1610
- canvas.save();
1611
- canvas.setStroke(undefined, strokeWidth * 2, options);
1612
- options.windingRule ? canvas.clip(options.windingRule) : canvas.clip();
1613
- drawStrokesStyle(ui, strokes, canvas);
1614
- canvas.restore();
1615
- break;
1616
- case 'outside':
1617
- const { renderBounds } = ui.__layout;
1618
- const out = canvas.getSameCanvas(true);
1619
- ui.__drawRenderPath(out);
1620
- out.setStroke(undefined, strokeWidth * 2, ui.__);
1621
- drawStrokesStyle(ui, strokes, out);
1622
- options.windingRule ? out.clip(options.windingRule) : out.clip();
1623
- out.clearWorld(renderBounds);
1624
- canvas.copyWorldToInner(out, ui.__world, renderBounds);
1625
- out.recycle();
1626
- break;
1844
+ function recycleImage(attrName, data) {
1845
+ const paints = data['_' + attrName];
1846
+ if (paints instanceof Array) {
1847
+ let image, recycleMap, input, url;
1848
+ for (let i = 0, len = paints.length; i < len; i++) {
1849
+ image = paints[i].image;
1850
+ url = image && image.url;
1851
+ if (url) {
1852
+ if (!recycleMap)
1853
+ recycleMap = {};
1854
+ recycleMap[url] = true;
1855
+ ImageManager.recycle(image);
1856
+ if (image.loading) {
1857
+ if (!input) {
1858
+ input = (data.__input && data.__input[attrName]) || [];
1859
+ if (!(input instanceof Array))
1860
+ input = [input];
1861
+ }
1862
+ image.unload(paints[i].loadId, !input.some((item) => item.url === url));
1863
+ }
1864
+ }
1627
1865
  }
1866
+ return recycleMap;
1628
1867
  }
1868
+ return null;
1629
1869
  }
1630
1870
 
1631
- const { getSpread, getOuterOf, getByMove, getIntersectData } = BoundsHelper;
1632
- function shape(ui, current, options) {
1633
- const canvas = current.getSameCanvas();
1634
- let bounds, matrix, shapeBounds;
1635
- let worldCanvas;
1636
- const { __world } = ui;
1637
- let { scaleX, scaleY } = __world;
1638
- if (scaleX < 0)
1639
- scaleX = -scaleX;
1640
- if (scaleY < 0)
1641
- scaleY = -scaleY;
1642
- if (!current.bounds.includes(__world, options.matrix)) {
1643
- const { renderShapeSpread: spread } = ui.__layout;
1644
- const worldClipBounds = getIntersectData(spread ? getSpread(current.bounds, spread * scaleX, spread * scaleY) : current.bounds, __world, options.matrix);
1645
- matrix = current.bounds.getFitMatrix(worldClipBounds);
1646
- if (matrix.a < 1) {
1647
- worldCanvas = current.getSameCanvas();
1648
- ui.__renderShape(worldCanvas, options);
1649
- scaleX *= matrix.a;
1650
- scaleY *= matrix.d;
1651
- }
1652
- shapeBounds = getOuterOf(__world, matrix);
1653
- bounds = getByMove(shapeBounds, -matrix.e, -matrix.f);
1654
- if (options.matrix)
1655
- matrix.multiply(options.matrix);
1656
- options = Object.assign(Object.assign({}, options), { matrix });
1657
- }
1658
- else {
1659
- if (options.matrix) {
1660
- scaleX *= options.matrix.a;
1661
- scaleY *= options.matrix.d;
1662
- bounds = shapeBounds = getOuterOf(__world, options.matrix);
1663
- }
1664
- else {
1665
- bounds = shapeBounds = __world;
1666
- }
1667
- worldCanvas = canvas;
1668
- }
1669
- ui.__renderShape(canvas, options);
1670
- return {
1671
- canvas, matrix, bounds,
1672
- worldCanvas, shapeBounds, scaleX, scaleY
1673
- };
1674
- }
1871
+ const PaintImageModule = {
1872
+ image,
1873
+ checkImage,
1874
+ createPattern,
1875
+ recycleImage,
1876
+ createData,
1877
+ getPatternData,
1878
+ fillOrFitMode,
1879
+ clipMode,
1880
+ repeatMode
1881
+ };
1675
1882
 
1676
- const defaultFrom$2 = { x: 0.5, y: 0 };
1677
- const defaultTo$2 = { x: 0.5, y: 1 };
1883
+ const { toPoint: toPoint$2 } = AroundHelper;
1884
+ const realFrom$2 = {};
1885
+ const realTo$2 = {};
1678
1886
  function linearGradient(paint, box) {
1679
1887
  let { from, to, type, blendMode, opacity } = paint;
1680
- from || (from = defaultFrom$2);
1681
- to || (to = defaultTo$2);
1682
- const style = Platform.canvas.createLinearGradient(box.x + from.x * box.width, box.y + from.y * box.height, box.x + to.x * box.width, box.y + to.y * box.height);
1888
+ toPoint$2(from || 'top', box, realFrom$2);
1889
+ toPoint$2(to || 'bottom', box, realTo$2);
1890
+ const style = Platform.canvas.createLinearGradient(realFrom$2.x, realFrom$2.y, realTo$2.x, realTo$2.y);
1683
1891
  applyStops(style, paint.stops, opacity);
1684
1892
  const data = { type, style };
1685
1893
  if (blendMode)
@@ -1690,124 +1898,84 @@ function applyStops(gradient, stops, opacity) {
1690
1898
  let stop;
1691
1899
  for (let i = 0, len = stops.length; i < len; i++) {
1692
1900
  stop = stops[i];
1693
- gradient.addColorStop(stop.offset, ColorConvert$1.string(stop.color, opacity));
1901
+ if (typeof stop === 'string') {
1902
+ gradient.addColorStop(i / (len - 1), ColorConvert.string(stop, opacity));
1903
+ }
1904
+ else {
1905
+ gradient.addColorStop(stop.offset, ColorConvert.string(stop.color, opacity));
1906
+ }
1694
1907
  }
1695
1908
  }
1696
1909
 
1697
- const { set: set$1, getAngle: getAngle$1, getDistance: getDistance$1 } = PointHelper;
1698
- const { get: get$1, rotateOfOuter: rotateOfOuter$1, scaleOfOuter: scaleOfOuter$1 } = MatrixHelper;
1699
- const defaultFrom$1 = { x: 0.5, y: 0.5 };
1700
- const defaultTo$1 = { x: 0.5, y: 1 };
1910
+ const { getAngle, getDistance: getDistance$1 } = PointHelper;
1911
+ const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1912
+ const { toPoint: toPoint$1 } = AroundHelper;
1701
1913
  const realFrom$1 = {};
1702
1914
  const realTo$1 = {};
1703
1915
  function radialGradient(paint, box) {
1704
1916
  let { from, to, type, opacity, blendMode, stretch } = paint;
1705
- from || (from = defaultFrom$1);
1706
- to || (to = defaultTo$1);
1707
- const { x, y, width, height } = box;
1708
- set$1(realFrom$1, x + from.x * width, y + from.y * height);
1709
- set$1(realTo$1, x + to.x * width, y + to.y * height);
1710
- let transform;
1711
- if (width !== height || stretch) {
1712
- transform = get$1();
1713
- scaleOfOuter$1(transform, realFrom$1, width / height * (stretch || 1), 1);
1714
- rotateOfOuter$1(transform, realFrom$1, getAngle$1(realFrom$1, realTo$1) + 90);
1715
- }
1917
+ toPoint$1(from || 'center', box, realFrom$1);
1918
+ toPoint$1(to || 'bottom', box, realTo$1);
1716
1919
  const style = Platform.canvas.createRadialGradient(realFrom$1.x, realFrom$1.y, 0, realFrom$1.x, realFrom$1.y, getDistance$1(realFrom$1, realTo$1));
1717
1920
  applyStops(style, paint.stops, opacity);
1718
- const data = { type, style, transform };
1921
+ const data = { type, style };
1922
+ const transform = getTransform(box, realFrom$1, realTo$1, stretch, true);
1923
+ if (transform)
1924
+ data.transform = transform;
1719
1925
  if (blendMode)
1720
1926
  data.blendMode = blendMode;
1721
1927
  return data;
1722
1928
  }
1929
+ function getTransform(box, from, to, stretch, rotate90) {
1930
+ let transform;
1931
+ const { width, height } = box;
1932
+ if (width !== height || stretch) {
1933
+ const angle = getAngle(from, to);
1934
+ transform = get();
1935
+ if (rotate90) {
1936
+ scaleOfOuter(transform, from, width / height * (stretch || 1), 1);
1937
+ rotateOfOuter(transform, from, angle + 90);
1938
+ }
1939
+ else {
1940
+ scaleOfOuter(transform, from, 1, width / height * (stretch || 1));
1941
+ rotateOfOuter(transform, from, angle);
1942
+ }
1943
+ }
1944
+ return transform;
1945
+ }
1723
1946
 
1724
- const { set, getAngle, getDistance } = PointHelper;
1725
- const { get, rotateOfOuter, scaleOfOuter } = MatrixHelper;
1726
- const defaultFrom = { x: 0.5, y: 0.5 };
1727
- const defaultTo = { x: 0.5, y: 1 };
1947
+ const { getDistance } = PointHelper;
1948
+ const { toPoint } = AroundHelper;
1728
1949
  const realFrom = {};
1729
1950
  const realTo = {};
1730
1951
  function conicGradient(paint, box) {
1731
1952
  let { from, to, type, opacity, blendMode, stretch } = paint;
1732
- from || (from = defaultFrom);
1733
- to || (to = defaultTo);
1734
- const { x, y, width, height } = box;
1735
- set(realFrom, x + from.x * width, y + from.y * height);
1736
- set(realTo, x + to.x * width, y + to.y * height);
1737
- const transform = get();
1738
- const angle = getAngle(realFrom, realTo);
1739
- if (Platform.conicGradientRotate90) {
1740
- scaleOfOuter(transform, realFrom, width / height * (stretch || 1), 1);
1741
- rotateOfOuter(transform, realFrom, angle + 90);
1742
- }
1743
- else {
1744
- scaleOfOuter(transform, realFrom, 1, width / height * (stretch || 1));
1745
- rotateOfOuter(transform, realFrom, angle);
1746
- }
1953
+ toPoint(from || 'center', box, realFrom);
1954
+ toPoint(to || 'bottom', box, realTo);
1747
1955
  const style = Platform.conicGradientSupport ? Platform.canvas.createConicGradient(0, realFrom.x, realFrom.y) : Platform.canvas.createRadialGradient(realFrom.x, realFrom.y, 0, realFrom.x, realFrom.y, getDistance(realFrom, realTo));
1748
1956
  applyStops(style, paint.stops, opacity);
1749
- const data = { type, style, transform };
1957
+ const data = { type, style };
1958
+ const transform = getTransform(box, realFrom, realTo, stretch || 1, Platform.conicGradientRotate90);
1959
+ if (transform)
1960
+ data.transform = transform;
1750
1961
  if (blendMode)
1751
1962
  data.blendMode = blendMode;
1752
1963
  return data;
1753
1964
  }
1754
1965
 
1755
- let recycleMap;
1756
- function compute(ui, attrName) {
1757
- const value = [];
1758
- let item;
1759
- let paints = ui.__.__input[attrName];
1760
- if (!(paints instanceof Array))
1761
- paints = [paints];
1762
- recycleMap = recycleImage(ui.__, attrName);
1763
- for (let i = 0, len = paints.length; i < len; i++) {
1764
- item = getLeafPaint(ui, paints[i], attrName);
1765
- if (item)
1766
- value.push(item);
1767
- }
1768
- ui.__['_' + attrName] = value.length ? value : undefined;
1769
- }
1770
- function getLeafPaint(ui, paint, attrName) {
1771
- if (typeof paint !== 'object' || paint.visible === false || paint.opacity === 0)
1772
- return undefined;
1773
- const { boxBounds } = ui.__layout;
1774
- switch (paint.type) {
1775
- case 'solid':
1776
- let { type, blendMode, color, opacity } = paint;
1777
- return { type, blendMode, style: ColorConvert$1.string(color, opacity) };
1778
- case 'image':
1779
- return image(ui, attrName, paint, boxBounds, !recycleMap || !recycleMap[paint.url]);
1780
- case 'linear':
1781
- return linearGradient(paint, boxBounds);
1782
- case 'radial':
1783
- return radialGradient(paint, boxBounds);
1784
- case 'angular':
1785
- return conicGradient(paint, boxBounds);
1786
- default:
1787
- return paint.r ? { type: 'solid', style: ColorConvert$1.string(paint) } : undefined;
1788
- }
1789
- }
1790
-
1791
- var UIPaint = /*#__PURE__*/Object.freeze({
1792
- __proto__: null,
1793
- compute: compute,
1794
- drawTextStroke: drawTextStroke,
1795
- fill: fill,
1796
- fillText: fillText,
1797
- fills: fills,
1798
- recycleImage: recycleImage,
1799
- shape: shape,
1800
- stroke: stroke,
1801
- strokeText: strokeText,
1802
- strokes: strokes
1803
- });
1966
+ const PaintGradientModule = {
1967
+ linearGradient,
1968
+ radialGradient,
1969
+ conicGradient,
1970
+ getTransform
1971
+ };
1804
1972
 
1805
1973
  const { copy, toOffsetOutBounds: toOffsetOutBounds$1 } = BoundsHelper;
1806
1974
  const tempBounds = {};
1807
1975
  const offsetOutBounds$1 = {};
1808
- function shadow(ui, current, shape, _options) {
1976
+ function shadow(ui, current, shape) {
1809
1977
  let copyBounds, spreadScale;
1810
- const { __world, __layout } = ui;
1978
+ const { __nowWorld: nowWorld, __layout } = ui;
1811
1979
  const { shadow } = ui.__;
1812
1980
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1813
1981
  const other = current.getSameCanvas();
@@ -1822,21 +1990,21 @@ function shadow(ui, current, shape, _options) {
1822
1990
  other.restore();
1823
1991
  other.save();
1824
1992
  if (worldCanvas) {
1825
- other.copyWorld(other, bounds, __world, 'copy');
1826
- copyBounds = __world;
1993
+ other.copyWorld(other, bounds, nowWorld, 'copy');
1994
+ copyBounds = nowWorld;
1827
1995
  }
1828
- worldCanvas ? other.copyWorld(worldCanvas, __world, __world, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1996
+ worldCanvas ? other.copyWorld(worldCanvas, nowWorld, nowWorld, 'destination-out') : other.copyWorld(shape.canvas, shapeBounds, bounds, 'destination-out');
1829
1997
  }
1830
- if (ui.__hasMirror) {
1831
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
1998
+ if (ui.__worldFlipped) {
1999
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1832
2000
  }
1833
2001
  else {
1834
2002
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1835
2003
  }
1836
2004
  if (end && index < end)
1837
- other.clear();
2005
+ other.clearWorld(copyBounds, true);
1838
2006
  });
1839
- other.recycle();
2007
+ other.recycle(copyBounds);
1840
2008
  }
1841
2009
  function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1842
2010
  const { bounds, shapeBounds } = shape;
@@ -1867,9 +2035,9 @@ function drawWorldShadow(canvas, outBounds, spreadScale, shape) {
1867
2035
 
1868
2036
  const { toOffsetOutBounds } = BoundsHelper;
1869
2037
  const offsetOutBounds = {};
1870
- function innerShadow(ui, current, shape, _options) {
2038
+ function innerShadow(ui, current, shape) {
1871
2039
  let copyBounds, spreadScale;
1872
- const { __world, __layout: __layout } = ui;
2040
+ const { __nowWorld: nowWorld, __layout: __layout } = ui;
1873
2041
  const { innerShadow } = ui.__;
1874
2042
  const { worldCanvas, bounds, shapeBounds, scaleX, scaleY } = shape;
1875
2043
  const other = current.getSameCanvas();
@@ -1882,40 +2050,115 @@ function innerShadow(ui, current, shape, _options) {
1882
2050
  drawWorldShadow(other, offsetOutBounds, spreadScale, shape);
1883
2051
  other.restore();
1884
2052
  if (worldCanvas) {
1885
- other.copyWorld(other, bounds, __world, 'copy');
1886
- other.copyWorld(worldCanvas, __world, __world, 'source-out');
1887
- copyBounds = __world;
2053
+ other.copyWorld(other, bounds, nowWorld, 'copy');
2054
+ other.copyWorld(worldCanvas, nowWorld, nowWorld, 'source-out');
2055
+ copyBounds = nowWorld;
1888
2056
  }
1889
2057
  else {
1890
2058
  other.copyWorld(shape.canvas, shapeBounds, bounds, 'source-out');
1891
2059
  copyBounds = bounds;
1892
2060
  }
1893
2061
  other.fillWorld(copyBounds, item.color, 'source-in');
1894
- if (ui.__hasMirror) {
1895
- current.copyWorldByReset(other, copyBounds, __world, item.blendMode);
2062
+ if (ui.__worldFlipped) {
2063
+ current.copyWorldByReset(other, copyBounds, nowWorld, item.blendMode);
1896
2064
  }
1897
2065
  else {
1898
2066
  current.copyWorldToInner(other, copyBounds, __layout.renderBounds, item.blendMode);
1899
2067
  }
1900
2068
  if (end && index < end)
1901
- other.clear();
2069
+ other.clearWorld(copyBounds, true);
1902
2070
  });
1903
- other.recycle();
2071
+ other.recycle(copyBounds);
1904
2072
  }
1905
2073
 
1906
2074
  function blur(ui, current, origin) {
1907
2075
  const { blur } = ui.__;
1908
- origin.setWorldBlur(blur * ui.__world.a);
1909
- origin.copyWorldToInner(current, ui.__world, ui.__layout.renderBounds);
2076
+ origin.setWorldBlur(blur * ui.__nowWorld.a);
2077
+ origin.copyWorldToInner(current, ui.__nowWorld, ui.__layout.renderBounds);
1910
2078
  origin.filter = 'none';
1911
2079
  }
1912
2080
 
1913
- var UIEffect = /*#__PURE__*/Object.freeze({
1914
- __proto__: null,
1915
- blur: blur,
1916
- innerShadow: innerShadow,
1917
- shadow: shadow
1918
- });
2081
+ function backgroundBlur(_ui, _current, _shape) {
2082
+ }
2083
+
2084
+ const EffectModule = {
2085
+ shadow,
2086
+ innerShadow,
2087
+ blur,
2088
+ backgroundBlur
2089
+ };
2090
+
2091
+ const { excludeRenderBounds } = LeafBoundsHelper;
2092
+ Group.prototype.__renderMask = function (canvas, options) {
2093
+ let child, maskCanvas, contentCanvas, maskOpacity, currentMask;
2094
+ const { children } = this;
2095
+ for (let i = 0, len = children.length; i < len; i++) {
2096
+ child = children[i];
2097
+ if (child.__.mask) {
2098
+ if (currentMask) {
2099
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
2100
+ maskCanvas = contentCanvas = null;
2101
+ }
2102
+ if (child.__.mask === 'path') {
2103
+ if (child.opacity < 1) {
2104
+ currentMask = 'opacity-path';
2105
+ maskOpacity = child.opacity;
2106
+ if (!contentCanvas)
2107
+ contentCanvas = getCanvas(canvas);
2108
+ }
2109
+ else {
2110
+ currentMask = 'path';
2111
+ canvas.save();
2112
+ }
2113
+ child.__clip(contentCanvas || canvas, options);
2114
+ }
2115
+ else {
2116
+ currentMask = 'alpha';
2117
+ if (!maskCanvas)
2118
+ maskCanvas = getCanvas(canvas);
2119
+ if (!contentCanvas)
2120
+ contentCanvas = getCanvas(canvas);
2121
+ child.__render(maskCanvas, options);
2122
+ }
2123
+ if (child.__.mask !== 'clipping')
2124
+ continue;
2125
+ }
2126
+ if (excludeRenderBounds(child, options))
2127
+ continue;
2128
+ child.__render(contentCanvas || canvas, options);
2129
+ }
2130
+ maskEnd(this, currentMask, canvas, contentCanvas, maskCanvas, maskOpacity);
2131
+ };
2132
+ function maskEnd(leaf, maskMode, canvas, contentCanvas, maskCanvas, maskOpacity) {
2133
+ switch (maskMode) {
2134
+ case 'alpha':
2135
+ usePixelMask(leaf, canvas, contentCanvas, maskCanvas);
2136
+ break;
2137
+ case 'opacity-path':
2138
+ copyContent(leaf, canvas, contentCanvas, maskOpacity);
2139
+ break;
2140
+ case 'path':
2141
+ canvas.restore();
2142
+ }
2143
+ }
2144
+ function getCanvas(canvas) {
2145
+ return canvas.getSameCanvas(false, true);
2146
+ }
2147
+ function usePixelMask(leaf, canvas, content, mask) {
2148
+ const realBounds = leaf.__nowWorld;
2149
+ content.resetTransform();
2150
+ content.opacity = 1;
2151
+ content.useMask(mask, realBounds);
2152
+ mask.recycle(realBounds);
2153
+ copyContent(leaf, canvas, content, 1);
2154
+ }
2155
+ function copyContent(leaf, canvas, content, maskOpacity) {
2156
+ const realBounds = leaf.__nowWorld;
2157
+ canvas.resetTransform();
2158
+ canvas.opacity = maskOpacity;
2159
+ canvas.copyWorld(content, realBounds);
2160
+ content.recycle(realBounds);
2161
+ }
1919
2162
 
1920
2163
  const money = '¥¥$€££¢¢';
1921
2164
  const letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
@@ -2040,6 +2283,8 @@ function createRows(drawData, content, style) {
2040
2283
  const { width, height } = bounds;
2041
2284
  const charMode = width || height || __letterSpacing || (textCase !== 'none');
2042
2285
  if (charMode) {
2286
+ const wrap = style.textWrap !== 'none';
2287
+ const breakAll = style.textWrap === 'break';
2043
2288
  paraStart = true;
2044
2289
  lastCharType = null;
2045
2290
  startCharSize = charWidth = charSize = wordWidth = rowWidth = 0;
@@ -2066,16 +2311,26 @@ function createRows(drawData, content, style) {
2066
2311
  langBreak = (charType === Single && (lastCharType === Single || lastCharType === Letter)) || (lastCharType === Single && charType !== After);
2067
2312
  afterBreak = ((charType === Before || charType === Single) && (lastCharType === Symbol || lastCharType === After));
2068
2313
  realWidth = paraStart && paraIndent ? width - paraIndent : width;
2069
- if (width && rowWidth + wordWidth + charWidth > realWidth) {
2070
- if (!afterBreak)
2071
- afterBreak = charType === Letter && lastCharType == After;
2072
- if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2314
+ if (wrap && (width && rowWidth + wordWidth + charWidth > realWidth)) {
2315
+ if (breakAll) {
2073
2316
  if (wordWidth)
2074
2317
  addWord();
2075
- addRow();
2318
+ if (rowWidth)
2319
+ addRow();
2076
2320
  }
2077
2321
  else {
2078
- addRow();
2322
+ if (!afterBreak)
2323
+ afterBreak = charType === Letter && lastCharType == After;
2324
+ if (langBreak || afterBreak || charType === Break || charType === Before || charType === Single || (wordWidth + charWidth > realWidth)) {
2325
+ if (wordWidth)
2326
+ addWord();
2327
+ if (rowWidth)
2328
+ addRow();
2329
+ }
2330
+ else {
2331
+ if (rowWidth)
2332
+ addRow();
2333
+ }
2079
2334
  }
2080
2335
  }
2081
2336
  if (char === ' ' && paraStart !== true && (rowWidth + wordWidth) === 0) ;
@@ -2145,7 +2400,7 @@ function addRow() {
2145
2400
 
2146
2401
  const CharMode = 0;
2147
2402
  const WordMode = 1;
2148
- const RowMode = 2;
2403
+ const TextMode = 2;
2149
2404
  function layoutChar(drawData, style, width, _height) {
2150
2405
  const { rows } = drawData;
2151
2406
  const { textAlign, paraIndent, letterSpacing } = style;
@@ -2154,15 +2409,12 @@ function layoutChar(drawData, style, width, _height) {
2154
2409
  if (row.words) {
2155
2410
  indentWidth = paraIndent && row.paraStart ? paraIndent : 0;
2156
2411
  addWordWidth = (width && textAlign === 'justify' && row.words.length > 1) ? (width - row.width - indentWidth) / (row.words.length - 1) : 0;
2157
- mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : RowMode);
2158
- if (mode === RowMode) {
2159
- row.text = '';
2412
+ mode = (letterSpacing || row.isOverflow) ? CharMode : (addWordWidth > 0.01 ? WordMode : TextMode);
2413
+ if (row.isOverflow && !letterSpacing)
2414
+ row.textMode = true;
2415
+ if (mode === TextMode) {
2160
2416
  row.x += indentWidth;
2161
- row.words.forEach(word => {
2162
- word.data.forEach(char => {
2163
- row.text += char.char;
2164
- });
2165
- });
2417
+ toTextChar$1(row);
2166
2418
  }
2167
2419
  else {
2168
2420
  row.x += indentWidth;
@@ -2172,11 +2424,11 @@ function layoutChar(drawData, style, width, _height) {
2172
2424
  if (mode === WordMode) {
2173
2425
  wordChar = { char: '', x: charX };
2174
2426
  charX = toWordChar(word.data, charX, wordChar);
2175
- if (wordChar.char !== ' ')
2427
+ if (row.isOverflow || wordChar.char !== ' ')
2176
2428
  row.data.push(wordChar);
2177
2429
  }
2178
2430
  else {
2179
- charX = toChar(word.data, charX, row.data);
2431
+ charX = toChar(word.data, charX, row.data, row.isOverflow);
2180
2432
  }
2181
2433
  if (!row.paraEnd && addWordWidth) {
2182
2434
  charX += addWordWidth;
@@ -2188,6 +2440,14 @@ function layoutChar(drawData, style, width, _height) {
2188
2440
  }
2189
2441
  });
2190
2442
  }
2443
+ function toTextChar$1(row) {
2444
+ row.text = '';
2445
+ row.words.forEach(word => {
2446
+ word.data.forEach(char => {
2447
+ row.text += char.char;
2448
+ });
2449
+ });
2450
+ }
2191
2451
  function toWordChar(data, charX, wordChar) {
2192
2452
  data.forEach(char => {
2193
2453
  wordChar.char += char.char;
@@ -2195,9 +2455,9 @@ function toWordChar(data, charX, wordChar) {
2195
2455
  });
2196
2456
  return charX;
2197
2457
  }
2198
- function toChar(data, charX, rowData) {
2458
+ function toChar(data, charX, rowData, isOverflow) {
2199
2459
  data.forEach(char => {
2200
- if (char.char !== ' ') {
2460
+ if (isOverflow || char.char !== ' ') {
2201
2461
  char.x = charX;
2202
2462
  rowData.push(char);
2203
2463
  }
@@ -2208,10 +2468,10 @@ function toChar(data, charX, rowData) {
2208
2468
 
2209
2469
  function layoutText(drawData, style) {
2210
2470
  const { rows, bounds } = drawData;
2211
- const { __lineHeight, __baseLine, __letterSpacing, textAlign, verticalAlign, paraSpacing, textOverflow } = style;
2471
+ const { __lineHeight, __baseLine, __letterSpacing, __clipText, textAlign, verticalAlign, paraSpacing } = style;
2212
2472
  let { x, y, width, height } = bounds, realHeight = __lineHeight * rows.length + (paraSpacing ? paraSpacing * (drawData.paraNumber - 1) : 0);
2213
2473
  let starY = __baseLine;
2214
- if (textOverflow !== 'show' && realHeight > height) {
2474
+ if (__clipText && realHeight > height) {
2215
2475
  realHeight = Math.max(height, __lineHeight);
2216
2476
  drawData.overflow = rows.length;
2217
2477
  }
@@ -2229,12 +2489,14 @@ function layoutText(drawData, style) {
2229
2489
  for (let i = 0, len = rows.length; i < len; i++) {
2230
2490
  row = rows[i];
2231
2491
  row.x = x;
2232
- switch (textAlign) {
2233
- case 'center':
2234
- row.x += (width - row.width) / 2;
2235
- break;
2236
- case 'right':
2237
- row.x += width - row.width;
2492
+ if (row.width < width || (row.width > width && !__clipText)) {
2493
+ switch (textAlign) {
2494
+ case 'center':
2495
+ row.x += (width - row.width) / 2;
2496
+ break;
2497
+ case 'right':
2498
+ row.x += width - row.width;
2499
+ }
2238
2500
  }
2239
2501
  if (row.paraStart && paraSpacing && i > 0)
2240
2502
  starY += paraSpacing;
@@ -2260,39 +2522,62 @@ function layoutText(drawData, style) {
2260
2522
  bounds.x = rowX;
2261
2523
  if (rowWidth > bounds.width)
2262
2524
  bounds.width = rowWidth;
2525
+ if (__clipText && width && width < rowWidth) {
2526
+ row.isOverflow = true;
2527
+ if (!drawData.overflow)
2528
+ drawData.overflow = rows.length;
2529
+ }
2263
2530
  }
2264
2531
  bounds.y = y;
2265
2532
  bounds.height = realHeight;
2266
2533
  }
2267
2534
 
2268
- function clipText(drawData, textOverflow) {
2535
+ function clipText(drawData, style, x, width) {
2536
+ if (!width)
2537
+ return;
2269
2538
  const { rows, overflow } = drawData;
2539
+ let { textOverflow } = style;
2270
2540
  rows.splice(overflow);
2271
- if (textOverflow !== 'hide') {
2272
- if (textOverflow === 'ellipsis')
2541
+ if (textOverflow && textOverflow !== 'show') {
2542
+ if (textOverflow === 'hide')
2543
+ textOverflow = '';
2544
+ else if (textOverflow === 'ellipsis')
2273
2545
  textOverflow = '...';
2274
- const ellipsisWidth = Platform.canvas.measureText(textOverflow).width;
2275
- const row = rows[overflow - 1];
2276
- let char, end = row.data.length - 1, charRight;
2277
- const { x, width } = drawData.bounds;
2546
+ let char, charRight;
2547
+ const ellipsisWidth = textOverflow ? Platform.canvas.measureText(textOverflow).width : 0;
2278
2548
  const right = x + width - ellipsisWidth;
2279
- for (let i = end; i > -1; i--) {
2280
- char = row.data[i];
2281
- charRight = char.x + char.width;
2282
- if (i === end && charRight < right) {
2283
- break;
2284
- }
2285
- else if (charRight < right && char.char !== ' ') {
2286
- row.data.splice(i + 1);
2287
- row.width -= char.width;
2288
- break;
2549
+ const list = style.textWrap === 'none' ? rows : [rows[overflow - 1]];
2550
+ list.forEach(row => {
2551
+ if (row.isOverflow && row.data) {
2552
+ let end = row.data.length - 1;
2553
+ for (let i = end; i > -1; i--) {
2554
+ char = row.data[i];
2555
+ charRight = char.x + char.width;
2556
+ if (i === end && charRight < right) {
2557
+ break;
2558
+ }
2559
+ else if (charRight < right && char.char !== ' ') {
2560
+ row.data.splice(i + 1);
2561
+ row.width -= char.width;
2562
+ break;
2563
+ }
2564
+ row.width -= char.width;
2565
+ }
2566
+ row.width += ellipsisWidth;
2567
+ row.data.push({ char: textOverflow, x: charRight });
2568
+ if (row.textMode)
2569
+ toTextChar(row);
2289
2570
  }
2290
- row.width -= char.width;
2291
- }
2292
- row.width += ellipsisWidth;
2293
- row.data.push({ char: textOverflow, x: charRight });
2571
+ });
2294
2572
  }
2295
2573
  }
2574
+ function toTextChar(row) {
2575
+ row.text = '';
2576
+ row.data.forEach(char => {
2577
+ row.text += char.char;
2578
+ });
2579
+ row.data = null;
2580
+ }
2296
2581
 
2297
2582
  function decorationText(drawData, style) {
2298
2583
  const { fontSize } = style;
@@ -2306,100 +2591,214 @@ function decorationText(drawData, style) {
2306
2591
  }
2307
2592
  }
2308
2593
 
2309
- const TextConvert = {
2310
- getDrawData(content, style) {
2311
- if (typeof content !== 'string')
2312
- content = String(content);
2313
- let x = 0, y = 0;
2314
- let width = style.__getInput('width') || 0;
2315
- let height = style.__getInput('height') || 0;
2316
- const { textDecoration, textOverflow, __font, padding } = style;
2317
- if (padding) {
2318
- const [top, right, bottom, left] = MathHelper.fourNumber(padding);
2319
- if (width) {
2320
- x = left;
2321
- width -= (right + left);
2322
- }
2323
- if (height) {
2324
- y = top;
2325
- height -= (top + bottom);
2326
- }
2594
+ const { top, right, bottom, left } = Direction4;
2595
+ function getDrawData(content, style) {
2596
+ if (typeof content !== 'string')
2597
+ content = String(content);
2598
+ let x = 0, y = 0;
2599
+ let width = style.__getInput('width') || 0;
2600
+ let height = style.__getInput('height') || 0;
2601
+ const { textDecoration, __font, __padding: padding } = style;
2602
+ if (padding) {
2603
+ if (width) {
2604
+ x = padding[left];
2605
+ width -= (padding[right] + padding[left]);
2606
+ }
2607
+ if (height) {
2608
+ y = padding[top];
2609
+ height -= (padding[top] + padding[bottom]);
2610
+ }
2611
+ }
2612
+ const drawData = {
2613
+ bounds: { x, y, width, height },
2614
+ rows: [],
2615
+ paraNumber: 0,
2616
+ font: Platform.canvas.font = __font
2617
+ };
2618
+ createRows(drawData, content, style);
2619
+ if (padding)
2620
+ padAutoText(padding, drawData, style, width, height);
2621
+ layoutText(drawData, style);
2622
+ layoutChar(drawData, style, width);
2623
+ if (drawData.overflow)
2624
+ clipText(drawData, style, x, width);
2625
+ if (textDecoration !== 'none')
2626
+ decorationText(drawData, style);
2627
+ return drawData;
2628
+ }
2629
+ function padAutoText(padding, drawData, style, width, height) {
2630
+ if (!width) {
2631
+ switch (style.textAlign) {
2632
+ case 'left':
2633
+ offsetText(drawData, 'x', padding[left]);
2634
+ break;
2635
+ case 'right':
2636
+ offsetText(drawData, 'x', -padding[right]);
2637
+ }
2638
+ }
2639
+ if (!height) {
2640
+ switch (style.verticalAlign) {
2641
+ case 'top':
2642
+ offsetText(drawData, 'y', padding[top]);
2643
+ break;
2644
+ case 'bottom':
2645
+ offsetText(drawData, 'y', -padding[bottom]);
2327
2646
  }
2328
- const drawData = {
2329
- bounds: { x, y, width, height },
2330
- rows: [],
2331
- paraNumber: 0,
2332
- font: Platform.canvas.font = __font
2333
- };
2334
- createRows(drawData, content, style);
2335
- layoutText(drawData, style);
2336
- layoutChar(drawData, style, width);
2337
- if (drawData.overflow)
2338
- clipText(drawData, textOverflow);
2339
- if (textDecoration !== 'none')
2340
- decorationText(drawData, style);
2341
- return drawData;
2342
2647
  }
2648
+ }
2649
+ function offsetText(drawData, attrName, value) {
2650
+ const { bounds, rows } = drawData;
2651
+ bounds[attrName] += value;
2652
+ for (let i = 0; i < rows.length; i++)
2653
+ rows[i][attrName] += value;
2654
+ }
2655
+
2656
+ const TextConvertModule = {
2657
+ getDrawData
2343
2658
  };
2344
2659
 
2345
- const ColorConvert = {
2346
- string(color, opacity) {
2347
- if (typeof color === 'string')
2348
- return color;
2349
- let a = color.a === undefined ? 1 : color.a;
2350
- if (opacity)
2351
- a *= opacity;
2352
- const rgb = color.r + ',' + color.g + ',' + color.b;
2353
- return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2354
- }
2660
+ function string(color, opacity) {
2661
+ if (typeof color === 'string')
2662
+ return color;
2663
+ let a = color.a === undefined ? 1 : color.a;
2664
+ if (opacity)
2665
+ a *= opacity;
2666
+ const rgb = color.r + ',' + color.g + ',' + color.b;
2667
+ return a === 1 ? 'rgb(' + rgb + ')' : 'rgba(' + rgb + ',' + a + ')';
2668
+ }
2669
+
2670
+ const ColorConvertModule = {
2671
+ string
2355
2672
  };
2356
2673
 
2357
- const Export = {
2674
+ const { setPoint, addPoint, toBounds } = TwoPointBoundsHelper;
2675
+ function getTrimBounds(canvas) {
2676
+ const { width, height } = canvas.view;
2677
+ const { data } = canvas.context.getImageData(0, 0, width, height);
2678
+ let x, y, pointBounds, index = 0;
2679
+ for (let i = 0; i < data.length; i += 4) {
2680
+ if (data[i + 3] !== 0) {
2681
+ x = index % width;
2682
+ y = (index - x) / width;
2683
+ pointBounds ? addPoint(pointBounds, x, y) : setPoint(pointBounds = {}, x, y);
2684
+ }
2685
+ index++;
2686
+ }
2687
+ const bounds = new Bounds();
2688
+ toBounds(pointBounds, bounds);
2689
+ return bounds.scale(1 / canvas.pixelRatio).ceil();
2690
+ }
2691
+
2692
+ const ExportModule = {
2358
2693
  export(leaf, filename, options) {
2694
+ this.running = true;
2695
+ const fileType = FileHelper.fileType(filename);
2696
+ options = FileHelper.getExportOptions(options);
2359
2697
  return addTask((success) => new Promise((resolve) => {
2698
+ const over = (result) => {
2699
+ success(result);
2700
+ resolve();
2701
+ this.running = false;
2702
+ };
2703
+ const { toURL } = Platform;
2704
+ const { download } = Platform.origin;
2705
+ if (filename === 'json') {
2706
+ return over({ data: leaf.toJSON(options.json) });
2707
+ }
2708
+ else if (fileType === 'json') {
2709
+ download(toURL(JSON.stringify(leaf.toJSON(options.json)), 'text'), filename);
2710
+ return over({ data: true });
2711
+ }
2712
+ if (filename === 'svg') {
2713
+ return over({ data: leaf.toSVG() });
2714
+ }
2715
+ else if (fileType === 'svg') {
2716
+ download(toURL(leaf.toSVG(), 'svg'), filename);
2717
+ return over({ data: true });
2718
+ }
2360
2719
  const { leafer } = leaf;
2361
2720
  if (leafer) {
2721
+ checkLazy(leaf);
2362
2722
  leafer.waitViewCompleted(() => __awaiter(this, void 0, void 0, function* () {
2363
- let quality, blob;
2364
- let { canvas } = leafer;
2365
- let { unreal } = canvas;
2366
- if (unreal) {
2367
- canvas = canvas.getSameCanvas();
2368
- canvas.backgroundColor = leafer.config.fill;
2369
- leafer.__render(canvas, {});
2723
+ let renderBounds, trimBounds, scaleX = 1, scaleY = 1;
2724
+ const { worldTransform, isLeafer, isFrame } = leaf;
2725
+ const { slice, trim, onCanvas } = options;
2726
+ let scale = options.scale || 1;
2727
+ let pixelRatio = options.pixelRatio || 1;
2728
+ const smooth = options.smooth === undefined ? leafer.config.smooth : options.smooth;
2729
+ const contextSettings = options.contextSettings || leafer.config.contextSettings;
2730
+ if (leaf.isApp) {
2731
+ scale *= pixelRatio;
2732
+ pixelRatio = leaf.app.pixelRatio;
2370
2733
  }
2371
- switch (typeof options) {
2372
- case 'object':
2373
- if (options.quality)
2374
- quality = options.quality;
2375
- if (options.blob)
2376
- blob = true;
2377
- break;
2378
- case 'number':
2379
- quality = options;
2380
- break;
2381
- case 'boolean':
2382
- blob = options;
2734
+ const screenshot = options.screenshot || leaf.isApp;
2735
+ const fill = (isLeafer && screenshot) ? (options.fill === undefined ? leaf.fill : options.fill) : options.fill;
2736
+ const needFill = FileHelper.isOpaqueImage(filename) || fill, matrix = new Matrix();
2737
+ if (screenshot) {
2738
+ renderBounds = screenshot === true ? (isLeafer ? leafer.canvas.bounds : leaf.worldRenderBounds) : screenshot;
2739
+ }
2740
+ else {
2741
+ let relative = options.relative || (isLeafer ? 'inner' : 'local');
2742
+ scaleX = worldTransform.scaleX;
2743
+ scaleY = worldTransform.scaleY;
2744
+ switch (relative) {
2745
+ case 'inner':
2746
+ matrix.set(worldTransform);
2747
+ break;
2748
+ case 'local':
2749
+ matrix.set(worldTransform).divide(leaf.localTransform);
2750
+ scaleX /= leaf.scaleX;
2751
+ scaleY /= leaf.scaleY;
2752
+ break;
2753
+ case 'world':
2754
+ scaleX = 1;
2755
+ scaleY = 1;
2756
+ break;
2757
+ case 'page':
2758
+ relative = leaf.leafer;
2759
+ default:
2760
+ matrix.set(worldTransform).divide(leaf.getTransform(relative));
2761
+ const l = relative.worldTransform;
2762
+ scaleX /= scaleX / l.scaleX;
2763
+ scaleY /= scaleY / l.scaleY;
2764
+ }
2765
+ renderBounds = leaf.getBounds('render', relative);
2383
2766
  }
2384
- let data;
2385
- if (filename.includes('.')) {
2386
- data = yield canvas.saveAs(filename, quality);
2767
+ const { x, y, width, height } = new Bounds(renderBounds).scale(scale);
2768
+ let canvas = Creator.canvas({ width: Math.round(width), height: Math.round(height), pixelRatio, smooth, contextSettings });
2769
+ const renderOptions = { matrix: matrix.scale(1 / scale).invert().translate(-x, -y).withScale(1 / scaleX * scale, 1 / scaleY * scale) };
2770
+ if (slice) {
2771
+ leaf = leafer;
2772
+ renderOptions.bounds = canvas.bounds;
2387
2773
  }
2388
- else if (blob) {
2389
- data = yield canvas.toBlob(filename, quality);
2774
+ canvas.save();
2775
+ if (isFrame && fill !== undefined) {
2776
+ const oldFill = leaf.get('fill');
2777
+ leaf.fill = '';
2778
+ leaf.__render(canvas, renderOptions);
2779
+ leaf.fill = oldFill;
2390
2780
  }
2391
2781
  else {
2392
- data = yield canvas.toDataURL(filename, quality);
2782
+ leaf.__render(canvas, renderOptions);
2783
+ }
2784
+ canvas.restore();
2785
+ if (trim) {
2786
+ trimBounds = getTrimBounds(canvas);
2787
+ const old = canvas, { width, height } = trimBounds;
2788
+ const config = { x: 0, y: 0, width, height, pixelRatio };
2789
+ canvas = Creator.canvas(config);
2790
+ canvas.copyWorld(old, trimBounds, config);
2393
2791
  }
2394
- success({ data });
2395
- resolve();
2396
- if (unreal)
2397
- canvas.recycle();
2792
+ if (needFill)
2793
+ canvas.fillWorld(canvas.bounds, fill || '#FFFFFF', 'destination-over');
2794
+ if (onCanvas)
2795
+ onCanvas(canvas);
2796
+ const data = filename === 'canvas' ? canvas : yield canvas.export(filename, options);
2797
+ over({ data, width: canvas.pixelWidth, height: canvas.pixelHeight, renderBounds, trimBounds });
2398
2798
  }));
2399
2799
  }
2400
2800
  else {
2401
- success({ data: false });
2402
- resolve();
2801
+ over({ data: false });
2403
2802
  }
2404
2803
  }));
2405
2804
  }
@@ -2412,13 +2811,64 @@ function addTask(task) {
2412
2811
  tasker.add(() => __awaiter(this, void 0, void 0, function* () { return yield task(resolve); }), { parallel: false });
2413
2812
  });
2414
2813
  }
2814
+ function checkLazy(leaf) {
2815
+ if (leaf.__.__needComputePaint)
2816
+ leaf.__.__computePaint();
2817
+ if (leaf.isBranch)
2818
+ leaf.children.forEach(child => checkLazy(child));
2819
+ }
2820
+
2821
+ const canvas = LeaferCanvasBase.prototype;
2822
+ const debug = Debug.get('@leafer-ui/export');
2823
+ canvas.export = function (filename, options) {
2824
+ const { quality, blob } = FileHelper.getExportOptions(options);
2825
+ if (filename.includes('.')) {
2826
+ return this.saveAs(filename, quality);
2827
+ }
2828
+ else if (blob) {
2829
+ return this.toBlob(filename, quality);
2830
+ }
2831
+ else {
2832
+ return this.toDataURL(filename, quality);
2833
+ }
2834
+ };
2835
+ canvas.toBlob = function (type, quality) {
2836
+ return new Promise((resolve) => {
2837
+ Platform.origin.canvasToBolb(this.view, type, quality).then((blob) => {
2838
+ resolve(blob);
2839
+ }).catch((e) => {
2840
+ debug.error(e);
2841
+ resolve(null);
2842
+ });
2843
+ });
2844
+ };
2845
+ canvas.toDataURL = function (type, quality) {
2846
+ return Platform.origin.canvasToDataURL(this.view, type, quality);
2847
+ };
2848
+ canvas.saveAs = function (filename, quality) {
2849
+ return new Promise((resolve) => {
2850
+ Platform.origin.canvasSaveAs(this.view, filename, quality).then(() => {
2851
+ resolve(true);
2852
+ }).catch((e) => {
2853
+ debug.error(e);
2854
+ resolve(false);
2855
+ });
2856
+ });
2857
+ };
2415
2858
 
2416
- Object.assign(Paint, UIPaint);
2417
- Object.assign(Effect, UIEffect);
2418
- Object.assign(TextConvert$1, TextConvert);
2419
- Object.assign(ColorConvert$1, ColorConvert);
2420
- Object.assign(Export$1, Export);
2859
+ Object.assign(TextConvert, TextConvertModule);
2860
+ Object.assign(ColorConvert, ColorConvertModule);
2861
+ Object.assign(Paint, PaintModule);
2862
+ Object.assign(PaintImage, PaintImageModule);
2863
+ Object.assign(PaintGradient, PaintGradientModule);
2864
+ Object.assign(Effect, EffectModule);
2865
+ Object.assign(Export, ExportModule);
2421
2866
 
2867
+ Object.assign(Creator, {
2868
+ interaction: (target, canvas, selector, options) => new Interaction(target, canvas, selector, options),
2869
+ hitCanvas: (options, manager) => new LeaferCanvas(options, manager),
2870
+ hitCanvasManager: () => new HitCanvasManager()
2871
+ });
2422
2872
  try {
2423
2873
  useCanvas('wx', wx);
2424
2874
  }