• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16interface Frame {
17  x: number;
18  y: number;
19  width: number;
20  height: number;
21}
22
23interface Vector2 {
24  x: number
25  y: number
26}
27
28interface Vector3 {
29  x: number;
30  y: number;
31  z: number;
32}
33
34type Transform = [
35  number,
36  number,
37  number,
38  number,
39  number,
40  number,
41  number,
42  number,
43  number,
44  number,
45  number,
46  number,
47  number,
48  number,
49  number,
50  number
51];
52
53enum BorderStyle {
54  SOLID = 0,
55  DASHED,
56  DOTTED,
57  NONE
58}
59
60type EdgeStyles = {
61  top?: BorderStyle;
62  right?: BorderStyle;
63  bottom?: BorderStyle;
64  left?: BorderStyle;
65};
66
67interface Edges {
68  left: number,
69  right: number,
70  top: number,
71  bottom: number,
72}
73
74type EdgeWidths = Edges;
75
76type EdgeColors = Edges;
77
78interface Corners {
79  topLeft: number,
80  topRight: number,
81  bottomLeft: number,
82  bottomRight: number
83}
84
85type BorderRadiuses = Corners;
86
87interface Rect {
88  left: number,
89  right: number,
90  top: number,
91  bottom: number
92}
93
94interface CornerRadius {
95  topLeft: Vector2,
96  topRight: Vector2,
97  bottomLeft: Vector2,
98  bottomRight: Vector2
99}
100
101interface RoundRect {
102  rect: Rect,
103  corners: CornerRadius
104}
105
106interface Circle {
107  centerX: number,
108  centerY: number,
109  radius: number
110}
111
112interface CommandPath {
113  commands: string
114}
115
116class ShapeMask {
117  public rect: Rect | null = null;
118  public roundRect: RoundRect | null = null;
119  public circle: Circle | null = null;
120  public oval: Rect | null = null;
121  public path: CommandPath | null = null;
122  public fillColor: number = 0XFF000000;
123  public strokeColor: number = 0XFF000000;
124  public strokeWidth: number = 0;
125  setRectShape(rect: Rect) {
126    this.rect = rect;
127    this.roundRect = null;
128    this.circle = null;
129    this.oval = null;
130    this.path = null;
131  }
132  setRoundRectShape(roundRect: RoundRect) {
133    this.roundRect = roundRect;
134    this.rect = null;
135    this.circle = null;
136    this.oval = null;
137    this.path = null;
138  }
139  setCircleShape(circle: Circle) {
140    this.circle = circle;
141    this.rect = null;
142    this.roundRect = null;
143    this.oval = null;
144    this.path = null;
145  }
146  setOvalShape(oval: Rect) {
147    this.oval = oval;
148    this.rect = null;
149    this.circle = null;
150    this.roundRect = null;
151    this.path = null;
152  }
153  setCommandPath(path: CommandPath) {
154    this.path = path;
155    this.oval = null;
156    this.rect = null;
157    this.circle = null;
158    this.roundRect = null;
159  }
160}
161
162class RenderNode {
163  private childrenList: Array<RenderNode>;
164  private nodePtr: number | null;
165  private parentRenderNode: RenderNode | null;
166  private backgroundColorValue: number;
167  private clipToFrameValue: boolean;
168  private frameValue: Frame;
169  private opacityValue: number;
170  private pivotValue: Vector2;
171  private rotationValue: Vector3;
172  private scaleValue: Vector2;
173  private shadowColorValue: number;
174  private shadowOffsetValue: Vector2;
175  private shadowAlphaValue: number;
176  private shadowElevationValue: number;
177  private shadowRadiusValue: number;
178  private transformValue: Transform;
179  private translationValue: Vector2;
180  private baseNode_ : __JSBaseNode__;
181  private borderStyleValue: EdgeStyles;
182  private borderWidthValue: EdgeWidths;
183  private borderColorValue: EdgeColors;
184  private borderRadiusValue: BorderRadiuses;
185  private shapeMaskValue: ShapeMask;
186
187  constructor(type: string) {
188    this.nodePtr = null;
189    this.childrenList = [];
190    this.parentRenderNode = null;
191    this.backgroundColorValue = 0;
192    this.clipToFrameValue = false;
193    this.frameValue = { x: 0, y: 0, width: 0, height: 0 };
194    this.opacityValue = 1.0;
195    this.pivotValue = { x: 0.5, y: 0.5 };
196    this.rotationValue = { x: 0, y: 0, z: 0 };
197    this.scaleValue = { x: 1.0, y: 1.0 };
198    this.shadowColorValue = 0;
199    this.shadowOffsetValue = { x: 0, y: 0 };
200    this.shadowAlphaValue = 0;
201    this.shadowElevationValue = 0;
202    this.shadowRadiusValue = 0;
203    this.transformValue = [1, 0, 0, 0,
204      0, 1, 0, 0,
205      0, 0, 1, 0,
206      0, 0, 0, 1];
207    this.translationValue = { x: 0, y: 0 };
208    if (type === 'FrameNode') {
209      return;
210    }
211    this.baseNode_ = new __JSBaseNode__();
212    this.baseNode_.draw = this.draw;
213    this.nodePtr = this.baseNode_.createRenderNode(this);
214  }
215
216  set backgroundColor(color: number) {
217    this.backgroundColorValue = this.checkUndefinedOrNullWithDefaultValue<number>(color, 0);
218    GetUINativeModule().renderNode.setBackgroundColor(this.nodePtr, this.backgroundColorValue);
219  }
220  set clipToFrame(useClip: boolean) {
221    this.clipToFrameValue = this.checkUndefinedOrNullWithDefaultValue<boolean>(useClip, false);
222    GetUINativeModule().renderNode.setClipToFrame(this.nodePtr, this.clipToFrameValue);
223  }
224  set frame(frame: Frame) {
225    if (frame === undefined || frame === null) {
226      this.frameValue = { x: 0, y: 0, width: 0, height: 0 };
227    } else {
228      this.size = { width: frame.width, height: frame.height };
229      this.position = { x: frame.x, y: frame.y };
230    }
231  }
232  set opacity(value: number) {
233    this.opacityValue = this.checkUndefinedOrNullWithDefaultValue<number>(value, 1.0);
234    GetUINativeModule().common.setOpacity(this.nodePtr, this.opacityValue);
235  }
236  set pivot(pivot: Vector2) {
237    if (pivot === undefined || pivot === null) {
238      this.pivotValue = { x: 0.5, y: 0.5 };
239    } else {
240      this.pivotValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(pivot.x, 0.5);
241      this.pivotValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(pivot.y, 0.5);
242    }
243    GetUINativeModule().renderNode.setPivot(this.nodePtr, this.pivotValue.x, this.pivotValue.y);
244  }
245  set position(position: Vector2) {
246    if (position === undefined || position === null) {
247      this.frameValue.x = 0;
248      this.frameValue.y = 0;
249    } else {
250      this.frameValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(position.x, 0);
251      this.frameValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(position.y, 0);
252    }
253    GetUINativeModule().common.setPosition(this.nodePtr, this.frameValue.x, this.frameValue.y);
254  }
255  set rotation(rotation: Vector3) {
256    if (rotation === undefined || rotation === null) {
257      this.rotationValue = { x: 0, y: 0, z: 0 };
258    } else {
259      this.rotationValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.x, 0);
260      this.rotationValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.y, 0);
261      this.rotationValue.z = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.z, 0);
262    }
263    GetUINativeModule().renderNode.setRotation(this.nodePtr, this.rotationValue.x, this.rotationValue.y, this.rotationValue.z);
264  }
265  set scale(scale: Vector2) {
266    if (scale === undefined || scale === null) {
267      this.scaleValue = { x: 1.0, y: 1.0 };
268    } else {
269      this.scaleValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(scale.x, 1.0);
270      this.scaleValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(scale.y, 1.0);
271    }
272    GetUINativeModule().renderNode.setScale(this.nodePtr, this.scaleValue.x, this.scaleValue.y);
273  }
274  set shadowColor(color: number) {
275    this.shadowColorValue = this.checkUndefinedOrNullWithDefaultValue<number>(color, 0);
276    GetUINativeModule().renderNode.setShadowColor(this.nodePtr, this.shadowColorValue);
277  }
278  set shadowOffset(offset: Vector2) {
279    if (offset === undefined || offset === null) {
280      this.shadowOffsetValue = { x: 0, y: 0 };
281    } else {
282      this.shadowOffsetValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(offset.x, 0);
283      this.shadowOffsetValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(offset.y, 0);
284    }
285    GetUINativeModule().renderNode.setShadowOffset(this.nodePtr, this.shadowOffsetValue.x, this.shadowOffsetValue.y);
286  }
287  set shadowAlpha(alpha: number) {
288    this.shadowAlphaValue = this.checkUndefinedOrNullWithDefaultValue<number>(alpha, 0);
289    GetUINativeModule().renderNode.setShadowAlpha(this.nodePtr, this.shadowAlphaValue);
290  }
291  set shadowElevation(elevation: number) {
292    this.shadowElevationValue = this.checkUndefinedOrNullWithDefaultValue<number>(elevation, 0);
293    GetUINativeModule().renderNode.setShadowElevation(this.nodePtr, this.shadowElevationValue);
294  }
295  set shadowRadius(radius: number) {
296    this.shadowRadiusValue = this.checkUndefinedOrNullWithDefaultValue<number>(radius, 0);
297    GetUINativeModule().renderNode.setShadowRadius(this.nodePtr, this.shadowRadiusValue);
298  }
299  set size(size: Size) {
300    if (size === undefined || size === null) {
301      this.frameValue.width = 0;
302      this.frameValue.height = 0;
303    } else {
304      this.frameValue.width = this.checkUndefinedOrNullWithDefaultValue<number>(size.width, 0);
305      this.frameValue.height = this.checkUndefinedOrNullWithDefaultValue<number>(size.height, 0);
306    }
307    GetUINativeModule().renderNode.setSize(this.nodePtr, this.frameValue.width, this.frameValue.height);
308  }
309  set transform(transform: Transform) {
310    if (transform === undefined || transform === null) {
311      this.transformValue = [1, 0, 0, 0,
312        0, 1, 0, 0,
313        0, 0, 1, 0,
314        0, 0, 0, 1];
315    } else {
316      let i: number = 0;
317      while (i < transform.length && i < 16) {
318        if (i % 5 === 0) {
319          this.transformValue[i] = this.checkUndefinedOrNullWithDefaultValue<number>(transform[i], 1);
320        } else {
321          this.transformValue[i] = this.checkUndefinedOrNullWithDefaultValue<number>(transform[i], 0);
322        }
323        i = i + 1;
324      }
325    }
326    GetUINativeModule().common.setTransform(this.nodePtr, this.transformValue);
327  }
328  set translation(translation: Vector2) {
329    if (translation === undefined || translation === null) {
330      this.translationValue = { x: 0, y: 0 };
331    } else {
332      this.translationValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(translation.x, 0);
333      this.translationValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(translation.y, 0);
334    }
335    GetUINativeModule().renderNode.setTranslate(this.nodePtr, this.translationValue.x, this.translationValue.y, 0);
336  }
337  get backgroundColor(): number {
338    return this.backgroundColorValue;
339  }
340  get clipToFrame(): boolean {
341    return this.clipToFrameValue;
342  }
343  get opacity(): number {
344    return this.opacityValue;
345  }
346  get frame(): Frame {
347    return this.frameValue;
348  }
349  get pivot(): Vector2 {
350    return this.pivotValue;
351  }
352  get position(): Vector2 {
353    return { x: this.frameValue.x, y: this.frameValue.y };
354  }
355  get rotation(): Vector3 {
356    return this.rotationValue;
357  }
358  get scale(): Vector2 {
359    return this.scaleValue;
360  }
361  get shadowColor(): number {
362    return this.shadowColorValue;
363  }
364  get shadowOffset(): Vector2 {
365    return this.shadowOffsetValue;
366  }
367  get shadowAlpha(): number {
368    return this.shadowAlphaValue;
369  }
370  get shadowElevation(): number {
371    return this.shadowElevationValue;
372  }
373  get shadowRadius(): number {
374    return this.shadowRadiusValue;
375  }
376  get size(): Size {
377    return { width: this.frameValue.width, height: this.frameValue.height };
378  }
379  get transform(): Transform {
380    return this.transformValue;
381  }
382  get translation(): Vector2 {
383    return this.translationValue;
384  }
385  checkUndefinedOrNullWithDefaultValue<T>(arg: T, defaultValue: T): T {
386    if (arg === undefined || arg === null) {
387      return defaultValue;
388    } else {
389      return arg;
390    }
391  }
392  appendChild(node: RenderNode) {
393    if (node === undefined || node === null) {
394      return;
395    }
396    if (this.childrenList.findIndex(element => element === node) !== -1) {
397      return;
398    }
399    this.childrenList.push(node);
400    node.parentRenderNode = this;
401    GetUINativeModule().renderNode.appendChild(this.nodePtr, node.nodePtr);
402  }
403  insertChildAfter(child: RenderNode, sibling: RenderNode | null) {
404    if (child === undefined || child === null) {
405      return;
406    }
407    let indexOfNode: number = this.childrenList.findIndex(element => element === child);
408    if (indexOfNode !== -1) {
409      return;
410    }
411    child.parentRenderNode = this;
412    let indexOfSibling = this.childrenList.findIndex(element => element === sibling);
413    if (indexOfSibling === -1) {
414      sibling === null;
415    }
416    if (sibling === undefined || sibling === null) {
417      this.childrenList.splice(0, 0, child);
418      GetUINativeModule().renderNode.insertChildAfter(this.nodePtr, child.nodePtr, null);
419    } else {
420      this.childrenList.splice(indexOfSibling + 1, 0, child);
421      GetUINativeModule().renderNode.insertChildAfter(this.nodePtr, child.nodePtr, sibling.nodePtr);
422    }
423  }
424  removeChild(node: RenderNode) {
425    if (node === undefined || node === null) {
426      return;
427    }
428    const index = this.childrenList.findIndex(element => element === node);
429    if (index === -1) {
430      return;
431    }
432    const child = this.childrenList[index];
433    child.parentRenderNode = null;
434    this.childrenList.splice(index, 1);
435    GetUINativeModule().renderNode.removeChild(this.nodePtr, node.nodePtr);
436  }
437  clearChildren() {
438    this.childrenList = new Array<RenderNode>();
439    GetUINativeModule().renderNode.clearChildren(this.nodePtr);
440  }
441  getChild(index: number): RenderNode | null {
442    if (this.childrenList.length > index && index >= 0) {
443      return this.childrenList[index];
444    }
445    return null;
446  }
447  getFirstChild(): RenderNode | null {
448    if (this.childrenList.length > 0) {
449      return this.childrenList[0];
450    }
451    return null;
452  }
453  getNextSibling(): RenderNode | null {
454    if (this.parentRenderNode === undefined || this.parentRenderNode === null) {
455      return null;
456    }
457    let siblingList = this.parentRenderNode.childrenList;
458    const index = siblingList.findIndex(element => element === this);
459    if (index === -1) {
460      return null;
461    }
462    return this.parentRenderNode.getChild(index + 1);
463  }
464  getPreviousSibling(): RenderNode | null {
465    if (this.parentRenderNode === undefined || this.parentRenderNode === null) {
466      return null;
467    }
468    let siblingList = this.parentRenderNode.childrenList;
469    const index = siblingList.findIndex(element => element === this);
470    if (index === -1) {
471      return null;
472    }
473    return this.parentRenderNode.getChild(index - 1);
474  }
475  setNodePtr(nodePtr: number | null) {
476    this.nodePtr = nodePtr;
477  }
478  setBaseNode(baseNode: BaseNode | null) {
479    this.baseNode_ = baseNode;
480  }
481  dispose() {
482    this.baseNode_.dispose()
483  }
484  getNodePtr(): number | null {
485    return this.nodePtr;
486  }
487  draw(context) {
488  }
489  invalidate() {
490    GetUINativeModule().renderNode.invalidate(this.nodePtr);
491  }
492  set borderStyle(style: EdgeStyles) {
493    if (style === undefined || style === null) {
494      this.borderStyleValue = { left: BorderStyle.NONE, top: BorderStyle.NONE, right: BorderStyle.NONE, bottom: BorderStyle.NONE };
495    } else {
496      this.borderStyleValue = style;
497    }
498    GetUINativeModule().renderNode.setBorderStyle(this.nodePtr, this.borderStyleValue.left, this.borderStyleValue.top, this.borderStyleValue.right, this.borderStyleValue.bottom);
499  }
500  get borderStyle(): EdgeStyles {
501    return this.borderStyleValue;
502  }
503  set borderWidth(width: EdgeWidths) {
504    if (width === undefined || width === null) {
505      this.borderWidthValue = { left: 0, top: 0, right: 0, bottom: 0 };
506    } else {
507      this.borderWidthValue = width;
508    }
509    GetUINativeModule().renderNode.setBorderWidth(this.nodePtr, this.borderWidthValue.left, this.borderWidthValue.top, this.borderWidthValue.right, this.borderWidthValue.bottom);
510  }
511  get borderWidth(): EdgeWidths {
512    return this.borderWidthValue;
513  }
514  set borderColor(color: EdgeColors) {
515    if (color === undefined || color === null) {
516      this.borderColorValue = { left: 0XFF000000, top: 0XFF000000, right: 0XFF000000, bottom: 0XFF000000 };
517    } else {
518      this.borderColorValue = color;
519    }
520    GetUINativeModule().renderNode.setBorderColor(this.nodePtr, this.borderColorValue.left, this.borderColorValue.top, this.borderColorValue.right, this.borderColorValue.bottom);
521  }
522  get borderColor(): EdgeColors {
523    return this.borderColorValue;
524  }
525  set borderRadius(radius: BorderRadiuses) {
526    if (radius === undefined || radius === null) {
527      this.borderRadiusValue = { topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0 };
528    } else {
529      this.borderRadiusValue = radius;
530    }
531    GetUINativeModule().renderNode.setBorderRadius(this.nodePtr, this.borderRadiusValue.topLeft, this.borderRadiusValue.topRight, this.borderRadiusValue.bottomLeft, this.borderRadiusValue.bottomRight);
532  }
533  get borderRadius(): BorderRadiuses {
534    return this.borderRadiusValue;
535  }
536  set shapeMask(shapeMask: ShapeMask) {
537    if (shapeMask === undefined || shapeMask === null) {
538      this.shapeMaskValue = new ShapeMask();
539    } else {
540      this.shapeMaskValue = shapeMask;
541    }
542    if (this.shapeMaskValue.rect !== null) {
543      const rectMask = this.shapeMaskValue.rect;
544      GetUINativeModule().renderNode.setRectMask(this.nodePtr, rectMask.left, rectMask.top, rectMask.right, rectMask.bottom, this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth);
545    } else if (this.shapeMaskValue.circle !== null) {
546      const circle = this.shapeMaskValue.circle;
547      GetUINativeModule().renderNode.setCircleMask(this.nodePtr, circle.centerX, circle.centerY, circle.radius, this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth);
548    } else if (this.shapeMaskValue.roundRect !== null) {
549      const reoundRect = this.shapeMask.roundRect;
550      const corners = reoundRect.corners;
551      const rect = reoundRect.rect;
552      GetUINativeModule().renderNode.setRoundRectMask(
553        this.nodePtr,
554        corners.topLeft.x,
555        corners.topLeft.y,
556        corners.topRight.x,
557        corners.topRight.y,
558        corners.bottomLeft.x,
559        corners.bottomLeft.y,
560        corners.bottomRight.x,
561        corners.bottomRight.y,
562        rect.left,
563        rect.top,
564        rect.right,
565        rect.bottom,
566        this.shapeMaskValue.fillColor,
567        this.shapeMaskValue.strokeColor,
568        this.shapeMaskValue.strokeWidth);
569    } else if (this.shapeMaskValue.oval !== null) {
570      const oval = this.shapeMaskValue.oval;
571      GetUINativeModule().renderNode.setOvalMask(this.nodePtr, oval.left, oval.top, oval.right, oval.bottom, this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth);
572    } else if (this.shapeMaskValue.path !== null) {
573      const path = this.shapeMaskValue.path;
574      GetUINativeModule().renderNode.setPath(this.nodePtr, path.commands, this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth);
575    }
576  }
577  get shapeMask(): ShapeMask {
578    return this.shapeMaskValue;
579  }
580}
581
582function edgeColors(all: number): EdgeColors {
583  return { left: all, top: all, right: all, bottom: all };
584}
585
586function edgeWidths(all: number): EdgeWidths {
587  return { left: all, top: all, right: all, bottom: all };
588}
589
590function borderStyles(all: BorderStyle): EdgeStyles {
591  return { left: all, top: all, right: all, bottom: all };
592}
593
594function borderRadiuses(all: number): BorderRadiuses {
595  return { topLeft: all, topRight: all, bottomLeft: all, bottomRight: all };
596}
597