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 EdgesT<T> { 68 left: T, 69 right: T, 70 top: T, 71 bottom: T, 72} 73interface SizeT<T> { 74 width: T; 75 height: T; 76} 77 78enum LengthUnit { 79 PX = 0, 80 VP = 1, 81 FP = 2, 82 PERCENT = 3, 83 LPX = 4, 84} 85 86enum LengthMetricsUnit { 87 DEFAULT = 0, 88 PX = 1, 89} 90 91type EdgeWidths = EdgesT<Number>; 92 93type EdgeColors = EdgesT<Number>; 94 95interface Corners { 96 topLeft: number, 97 topRight: number, 98 bottomLeft: number, 99 bottomRight: number 100} 101 102type BorderRadiuses = Corners; 103 104interface Rect { 105 left: number, 106 right: number, 107 top: number, 108 bottom: number 109} 110 111interface CornerRadius { 112 topLeft: Vector2, 113 topRight: Vector2, 114 bottomLeft: Vector2, 115 bottomRight: Vector2 116} 117 118interface RoundRect { 119 rect: Rect, 120 corners: CornerRadius 121} 122 123interface Circle { 124 centerX: number, 125 centerY: number, 126 radius: number 127} 128 129interface CommandPath { 130 commands: string 131} 132 133class LengthMetrics { 134 public unit: LengthUnit; 135 public value: number; 136 constructor(value: number, unit?: LengthUnit) { 137 if (unit in LengthUnit) { 138 this.unit = unit; 139 this.value = value; 140 } else { 141 this.unit = LengthUnit.VP; 142 this.value = unit === undefined ? value : 0; 143 } 144 } 145 static px(value: number) { 146 return new LengthMetrics(value, LengthUnit.PX); 147 } 148 static vp(value: number) { 149 return new LengthMetrics(value, LengthUnit.VP); 150 } 151 static fp(value: number) { 152 return new LengthMetrics(value, LengthUnit.FP); 153 } 154 static percent(value: number) { 155 return new LengthMetrics(value, LengthUnit.PERCENT); 156 } 157 static lpx(value: number) { 158 return new LengthMetrics(value, LengthUnit.LPX); 159 } 160 static resource(res: Resource) { 161 let length:Array<number> = getUINativeModule().nativeUtils.resoureToLengthMetrics(res); 162 return new LengthMetrics(length[0], length[1]); 163 } 164} 165 166declare interface Resource {} 167declare type BusinessError = any 168 169declare enum Color { 170 White, 171 Black, 172 Blue, 173 Brown, 174 Gray, 175 Green, 176 Grey, 177 Orange, 178 Pink, 179 Red, 180 Yellow, 181 Transparent, 182} 183 184declare type ResourceColor = Color | number | string | Resource; 185 186const MAX_CHANNEL_VALUE = 0xFF; 187const MAX_ALPHA_VALUE = 1; 188const ERROR_CODE_RESOURCE_GET_FAILED = 180003; 189const ERROR_CODE_COLOR_PARAMETER_INCORRECT = 401; 190 191class ColorMetrics { 192 private red_: number; 193 private green_: number; 194 private blue_: number; 195 private alpha_: number; 196 private static clamp(value: number): number { 197 return Math.min(Math.max(value, 0), MAX_CHANNEL_VALUE); 198 } 199 private constructor(red: number, green: number, blue: number, alpha: number = MAX_CHANNEL_VALUE) { 200 this.red_ = ColorMetrics.clamp(red); 201 this.green_ = ColorMetrics.clamp(green); 202 this.blue_ = ColorMetrics.clamp(blue); 203 this.alpha_ = ColorMetrics.clamp(alpha); 204 } 205 private toNumeric(): number { 206 return (this.alpha_ << 24) + (this.red_ << 16) + (this.green_ << 8) + this.blue_; 207 } 208 static numeric(value: number): ColorMetrics { 209 const red = (value >> 16) & 0x000000FF; 210 const green = (value >> 8) & 0x000000FF; 211 const blue = value & 0x000000FF; 212 const alpha = (value >> 24) & 0x000000FF; 213 if (alpha === 0) { 214 return new ColorMetrics(red, green, blue); 215 } 216 return new ColorMetrics(red, green, blue, alpha); 217 } 218 static rgba(red: number, green: number, blue: number, alpha: number = MAX_ALPHA_VALUE): ColorMetrics { 219 return new ColorMetrics(red, green, blue, alpha * MAX_CHANNEL_VALUE); 220 } 221 222 private static rgbOrRGBA(format: string): ColorMetrics { 223 const rgbPattern = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i; 224 const rgbaPattern = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+(\.\d+)?)\s*\)$/i; 225 226 const rgbMatch = rgbPattern.exec(format); 227 const rgbaMatch = rgbaPattern.exec(format); 228 229 if (rgbMatch) { 230 const [, red, green, blue] = rgbMatch; 231 return new ColorMetrics(Number.parseInt(red, 10), Number.parseInt(green, 10), Number.parseInt(blue, 10)); 232 } else if (rgbaMatch) { 233 const [, red, green, blue, alpha] = rgbaMatch; 234 return new ColorMetrics(Number.parseInt(red, 10), Number.parseInt(green, 10), Number.parseInt(blue, 10), Number.parseFloat(alpha) * MAX_CHANNEL_VALUE); 235 } else { 236 const error = new Error('Parameter error. The format of the input color string is not RGB or RGBA.') as BusinessError; 237 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 238 throw error; 239 } 240 } 241 242 static resourceColor(color: ResourceColor): ColorMetrics { 243 if (color === undefined || color === null) { 244 const error = new Error('Parameter error. The type of the input color parameter is not ResourceColor.') as BusinessError; 245 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 246 throw error; 247 } 248 let chanels: Array<number> = []; 249 if (typeof color === 'object') { 250 chanels = getUINativeModule().nativeUtils.parseResourceColor(color); 251 if (chanels === undefined) { 252 const error = new Error('Failed to obtain the color resource.') as BusinessError; 253 error.code = ERROR_CODE_RESOURCE_GET_FAILED; 254 throw error; 255 } 256 const red = chanels[0]; 257 const green = chanels[1]; 258 const blue = chanels[2]; 259 const alpha = chanels[3]; 260 return new ColorMetrics(red, green, blue, alpha); 261 } else if (typeof color === 'number') { 262 return ColorMetrics.numeric(color); 263 } else if (typeof color === 'string') { 264 if (ColorMetrics.isHexFormat(color)) { 265 return ColorMetrics.hex(color); 266 } else { 267 return ColorMetrics.rgbOrRGBA(color); 268 } 269 } else { 270 const error = new Error('Parameter error. The type of the input color parameter is not ResourceColor.') as BusinessError; 271 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 272 throw error; 273 } 274 } 275 private static isHexFormat(format: string): boolean { 276 return /#(([0-9A-Fa-f]{3})|([0-9A-Fa-f]{6})|([0-9A-Fa-f]{4})|([0-9A-Fa-f]{8}))/.test(format); 277 } 278 279 private static hex(hexFormat: string): ColorMetrics { 280 let r: number = 0; 281 let g: number = 0; 282 let b: number = 0; 283 let a: number = 255; 284 if (hexFormat.length === 4) { 285 r = parseInt(hexFormat.slice(1, 2).repeat(2), 16); 286 g = parseInt(hexFormat.slice(2, 3).repeat(2), 16); 287 b = parseInt(hexFormat.slice(3).repeat(2), 16); 288 } else if (hexFormat.length === 7) { 289 r = parseInt(hexFormat.slice(1, 3), 16); 290 g = parseInt(hexFormat.slice(3, 5), 16); 291 b = parseInt(hexFormat.slice(5), 16); 292 } else if (hexFormat.length === 5) { 293 a = parseInt(hexFormat.slice(1, 2).repeat(2), 16); 294 r = parseInt(hexFormat.slice(2, 3).repeat(2), 16); 295 g = parseInt(hexFormat.slice(3, 4).repeat(2), 16); 296 b = parseInt(hexFormat.slice(4).repeat(2), 16); 297 } else if (hexFormat.length === 9) { 298 a = parseInt(hexFormat.slice(1, 3), 16); 299 r = parseInt(hexFormat.slice(3, 5), 16); 300 g = parseInt(hexFormat.slice(5, 7), 16); 301 b = parseInt(hexFormat.slice(7), 16); 302 } 303 return new ColorMetrics(r, g, b, a); 304 } 305 blendColor(overlayColor: ColorMetrics): ColorMetrics { 306 if (overlayColor === undefined || overlayColor === null) { 307 const error = new Error('Parameter error. The type of the input parameter is not ColorMetrics.') as BusinessError; 308 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 309 throw error; 310 } 311 const chanels = getUINativeModule().nativeUtils.blendColor(this.toNumeric(), overlayColor.toNumeric()); 312 if (chanels === undefined) { 313 const error = new Error('Parameter error. The type of the input parameter is not ColorMetrics.') as BusinessError; 314 error.code = ERROR_CODE_COLOR_PARAMETER_INCORRECT; 315 throw error; 316 } 317 const red = chanels[0]; 318 const green = chanels[1]; 319 const blue = chanels[2]; 320 const alpha = chanels[3]; 321 return new ColorMetrics(red, green, blue, alpha); 322 } 323 get color(): string { 324 return `rgba(${this.red_}, ${this.green_}, ${this.blue_}, ${this.alpha_ / MAX_CHANNEL_VALUE})`; 325 } 326 get red(): number { 327 return this.red_; 328 } 329 get green(): number { 330 return this.green_; 331 } 332 get blue(): number { 333 return this.blue_; 334 } 335 get alpha(): number { 336 return this.alpha_; 337 } 338} 339 340class BaseShape { 341 public rect: Rect | null = null; 342 public roundRect: RoundRect | null = null; 343 public circle: Circle | null = null; 344 public oval: Rect | null = null; 345 public path: CommandPath | null = null; 346 setRectShape(rect: Rect) { 347 this.rect = rect; 348 this.roundRect = null; 349 this.circle = null; 350 this.oval = null; 351 this.path = null; 352 } 353 setRoundRectShape(roundRect: RoundRect) { 354 this.roundRect = roundRect; 355 this.rect = null; 356 this.circle = null; 357 this.oval = null; 358 this.path = null; 359 } 360 setCircleShape(circle: Circle) { 361 this.circle = circle; 362 this.rect = null; 363 this.roundRect = null; 364 this.oval = null; 365 this.path = null; 366 } 367 setOvalShape(oval: Rect) { 368 this.oval = oval; 369 this.rect = null; 370 this.circle = null; 371 this.roundRect = null; 372 this.path = null; 373 } 374 setCommandPath(path: CommandPath) { 375 this.path = path; 376 this.oval = null; 377 this.rect = null; 378 this.circle = null; 379 this.roundRect = null; 380 } 381} 382 383class ShapeClip extends BaseShape { } 384 385class ShapeMask extends BaseShape { 386 public fillColor: number = 0XFF000000; 387 public strokeColor: number = 0XFF000000; 388 public strokeWidth: number = 0; 389} 390 391class RenderNode { 392 private childrenList: Array<RenderNode>; 393 private nodePtr: NodePtr; 394 private parentRenderNode: WeakRef<RenderNode> | null; 395 private backgroundColorValue: number; 396 private clipToFrameValue: boolean; 397 private frameValue: Frame; 398 private opacityValue: number; 399 private pivotValue: Vector2; 400 private rotationValue: Vector3; 401 private scaleValue: Vector2; 402 private shadowColorValue: number; 403 private shadowOffsetValue: Vector2; 404 private labelValue: string; 405 private shadowAlphaValue: number; 406 private shadowElevationValue: number; 407 private shadowRadiusValue: number; 408 private transformValue: Transform; 409 private translationValue: Vector2; 410 private baseNode_: __JSBaseNode__; 411 private borderStyleValue: EdgeStyles; 412 private borderWidthValue: EdgeWidths; 413 private borderColorValue: EdgeColors; 414 private borderRadiusValue: BorderRadiuses; 415 private shapeMaskValue: ShapeMask; 416 private shapeClipValue: ShapeClip; 417 private _nativeRef: NativeStrongRef; 418 private _frameNode: WeakRef<FrameNode>; 419 private lengthMetricsUnitValue: LengthMetricsUnit; 420 private markNodeGroupValue: boolean; 421 private apiTargetVersion: number; 422 423 constructor(type: string) { 424 this.nodePtr = null; 425 this.childrenList = []; 426 this.parentRenderNode = null; 427 this.backgroundColorValue = 0; 428 this.apiTargetVersion = getUINativeModule().common.getApiTargetVersion(); 429 this.clipToFrameValue = true; 430 if (this.apiTargetVersion && this.apiTargetVersion < 12) { 431 this.clipToFrameValue = false; 432 } 433 this.frameValue = { x: 0, y: 0, width: 0, height: 0 }; 434 this.opacityValue = 1.0; 435 this.pivotValue = { x: 0.5, y: 0.5 }; 436 this.rotationValue = { x: 0, y: 0, z: 0 }; 437 this.scaleValue = { x: 1.0, y: 1.0 }; 438 this.shadowColorValue = 0; 439 this.shadowOffsetValue = { x: 0, y: 0 }; 440 this.labelValue = ''; 441 this.shadowAlphaValue = 0; 442 this.shadowElevationValue = 0; 443 this.shadowRadiusValue = 0; 444 this.transformValue = [1, 0, 0, 0, 445 0, 1, 0, 0, 446 0, 0, 1, 0, 447 0, 0, 0, 1]; 448 this.translationValue = { x: 0, y: 0 }; 449 this.lengthMetricsUnitValue = LengthMetricsUnit.DEFAULT; 450 this.markNodeGroupValue = false; 451 if (type === 'BuilderRootFrameNode' || type === 'CustomFrameNode') { 452 return; 453 } 454 this._nativeRef = getUINativeModule().renderNode.createRenderNode(this); 455 this.nodePtr = this._nativeRef?.getNativeHandle(); 456 if (this.apiTargetVersion && this.apiTargetVersion < 12) { 457 this.clipToFrame = false; 458 } else { 459 this.clipToFrame = true; 460 } 461 } 462 463 set backgroundColor(color: number) { 464 this.backgroundColorValue = this.checkUndefinedOrNullWithDefaultValue<number>(color, 0); 465 getUINativeModule().renderNode.setBackgroundColor(this.nodePtr, this.backgroundColorValue); 466 } 467 set clipToFrame(useClip: boolean) { 468 this.clipToFrameValue = this.checkUndefinedOrNullWithDefaultValue<boolean>(useClip, true); 469 getUINativeModule().renderNode.setClipToFrame(this.nodePtr, this.clipToFrameValue); 470 } 471 set frame(frame: Frame) { 472 if (frame === undefined || frame === null) { 473 this.frameValue = { x: 0, y: 0, width: 0, height: 0 }; 474 } else { 475 this.size = { width: frame.width, height: frame.height }; 476 this.position = { x: frame.x, y: frame.y }; 477 } 478 } 479 set opacity(value: number) { 480 this.opacityValue = this.checkUndefinedOrNullWithDefaultValue<number>(value, 1.0); 481 getUINativeModule().common.setOpacity(this.nodePtr, this.opacityValue); 482 } 483 set pivot(pivot: Vector2) { 484 if (pivot === undefined || pivot === null) { 485 this.pivotValue = { x: 0.5, y: 0.5 }; 486 } else { 487 this.pivotValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(pivot.x, 0.5); 488 this.pivotValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(pivot.y, 0.5); 489 } 490 getUINativeModule().renderNode.setPivot(this.nodePtr, this.pivotValue.x, this.pivotValue.y); 491 } 492 set position(position: Vector2) { 493 if (position === undefined || position === null) { 494 this.frameValue.x = 0; 495 this.frameValue.y = 0; 496 } else { 497 this.frameValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(position.x, 0); 498 this.frameValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(position.y, 0); 499 } 500 getUINativeModule().renderNode.setPosition(this.nodePtr, this.frameValue.x, this.frameValue.y, this.lengthMetricsUnitValue); 501 } 502 set rotation(rotation: Vector3) { 503 if (rotation === undefined || rotation === null) { 504 this.rotationValue = { x: 0, y: 0, z: 0 }; 505 } else { 506 this.rotationValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.x, 0); 507 this.rotationValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.y, 0); 508 this.rotationValue.z = this.checkUndefinedOrNullWithDefaultValue<number>(rotation.z, 0); 509 } 510 getUINativeModule().renderNode.setRotation(this.nodePtr, this.rotationValue.x, this.rotationValue.y, this.rotationValue.z, this.lengthMetricsUnitValue); 511 } 512 set scale(scale: Vector2) { 513 if (scale === undefined || scale === null) { 514 this.scaleValue = { x: 1.0, y: 1.0 }; 515 } else { 516 this.scaleValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(scale.x, 1.0); 517 this.scaleValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(scale.y, 1.0); 518 } 519 getUINativeModule().renderNode.setScale(this.nodePtr, this.scaleValue.x, this.scaleValue.y); 520 } 521 set shadowColor(color: number) { 522 this.shadowColorValue = this.checkUndefinedOrNullWithDefaultValue<number>(color, 0); 523 getUINativeModule().renderNode.setShadowColor(this.nodePtr, this.shadowColorValue); 524 } 525 set shadowOffset(offset: Vector2) { 526 if (offset === undefined || offset === null) { 527 this.shadowOffsetValue = { x: 0, y: 0 }; 528 } else { 529 this.shadowOffsetValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(offset.x, 0); 530 this.shadowOffsetValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(offset.y, 0); 531 } 532 getUINativeModule().renderNode.setShadowOffset(this.nodePtr, this.shadowOffsetValue.x, this.shadowOffsetValue.y, this.lengthMetricsUnitValue); 533 } 534 set label(label: string) { 535 this.labelValue = this.checkUndefinedOrNullWithDefaultValue<string>(label, ''); 536 getUINativeModule().renderNode.setLabel(this.nodePtr, this.labelValue); 537 } 538 set shadowAlpha(alpha: number) { 539 this.shadowAlphaValue = this.checkUndefinedOrNullWithDefaultValue<number>(alpha, 0); 540 getUINativeModule().renderNode.setShadowAlpha(this.nodePtr, this.shadowAlphaValue); 541 } 542 set shadowElevation(elevation: number) { 543 this.shadowElevationValue = this.checkUndefinedOrNullWithDefaultValue<number>(elevation, 0); 544 getUINativeModule().renderNode.setShadowElevation(this.nodePtr, this.shadowElevationValue); 545 } 546 set shadowRadius(radius: number) { 547 this.shadowRadiusValue = this.checkUndefinedOrNullWithDefaultValue<number>(radius, 0); 548 getUINativeModule().renderNode.setShadowRadius(this.nodePtr, this.shadowRadiusValue); 549 } 550 set size(size: Size) { 551 if (size === undefined || size === null) { 552 this.frameValue.width = 0; 553 this.frameValue.height = 0; 554 } else { 555 this.frameValue.width = this.checkUndefinedOrNullWithDefaultValue<number>(size.width, 0); 556 this.frameValue.height = this.checkUndefinedOrNullWithDefaultValue<number>(size.height, 0); 557 } 558 getUINativeModule().renderNode.setSize(this.nodePtr, this.frameValue.width, this.frameValue.height, this.lengthMetricsUnitValue); 559 } 560 set transform(transform: Transform) { 561 if (transform === undefined || transform === null) { 562 this.transformValue = [1, 0, 0, 0, 563 0, 1, 0, 0, 564 0, 0, 1, 0, 565 0, 0, 0, 1]; 566 } else { 567 let i: number = 0; 568 while (i < transform.length && i < 16) { 569 if (i % 5 === 0) { 570 this.transformValue[i] = this.checkUndefinedOrNullWithDefaultValue<number>(transform[i], 1); 571 } else { 572 this.transformValue[i] = this.checkUndefinedOrNullWithDefaultValue<number>(transform[i], 0); 573 } 574 i = i + 1; 575 } 576 } 577 getUINativeModule().common.setTransform(this.nodePtr, this.transformValue); 578 } 579 set translation(translation: Vector2) { 580 if (translation === undefined || translation === null) { 581 this.translationValue = { x: 0, y: 0 }; 582 } else { 583 this.translationValue.x = this.checkUndefinedOrNullWithDefaultValue<number>(translation.x, 0); 584 this.translationValue.y = this.checkUndefinedOrNullWithDefaultValue<number>(translation.y, 0); 585 } 586 getUINativeModule().renderNode.setTranslate(this.nodePtr, this.translationValue.x, this.translationValue.y, 0); 587 } 588 set lengthMetricsUnit(unit: LengthMetricsUnit) { 589 if (unit === undefined || unit == null) { 590 this.lengthMetricsUnitValue = LengthMetricsUnit.DEFAULT; 591 } else { 592 this.lengthMetricsUnitValue = unit; 593 } 594 } 595 set markNodeGroup(isNodeGroup) { 596 if (isNodeGroup === undefined || isNodeGroup === null) { 597 this.markNodeGroupValue = false; 598 } else { 599 this.markNodeGroupValue = isNodeGroup; 600 } 601 getUINativeModule().renderNode.setMarkNodeGroup(this.nodePtr, this.markNodeGroupValue); 602 } 603 get backgroundColor(): number { 604 return this.backgroundColorValue; 605 } 606 get clipToFrame(): boolean { 607 return this.clipToFrameValue; 608 } 609 get opacity(): number { 610 return this.opacityValue; 611 } 612 get frame(): Frame { 613 return this.frameValue; 614 } 615 get pivot(): Vector2 { 616 return this.pivotValue; 617 } 618 get position(): Vector2 { 619 return { x: this.frameValue.x, y: this.frameValue.y }; 620 } 621 get rotation(): Vector3 { 622 return this.rotationValue; 623 } 624 get scale(): Vector2 { 625 return this.scaleValue; 626 } 627 get shadowColor(): number { 628 return this.shadowColorValue; 629 } 630 get shadowOffset(): Vector2 { 631 return this.shadowOffsetValue; 632 } 633 get label(): string { 634 return this.labelValue; 635 } 636 get shadowAlpha(): number { 637 return this.shadowAlphaValue; 638 } 639 get shadowElevation(): number { 640 return this.shadowElevationValue; 641 } 642 get shadowRadius(): number { 643 return this.shadowRadiusValue; 644 } 645 get size(): Size { 646 return { width: this.frameValue.width, height: this.frameValue.height }; 647 } 648 get transform(): Transform { 649 return this.transformValue; 650 } 651 get translation(): Vector2 { 652 return this.translationValue; 653 } 654 get lengthMetricsUnit(): LengthMetricsUnit { 655 return this.lengthMetricsUnitValue; 656 } 657 get markNodeGroup() { 658 return this.markNodeGroupValue; 659 } 660 checkUndefinedOrNullWithDefaultValue<T>(arg: T, defaultValue: T): T { 661 if (arg === undefined || arg === null) { 662 return defaultValue; 663 } else { 664 return arg; 665 } 666 } 667 appendChild(node: RenderNode) { 668 if (node === undefined || node === null) { 669 return; 670 } 671 if (this.childrenList.findIndex(element => element === node) !== -1) { 672 return; 673 } 674 this.childrenList.push(node); 675 node.parentRenderNode = new WeakRef(this); 676 getUINativeModule().renderNode.appendChild(this.nodePtr, node.nodePtr); 677 } 678 insertChildAfter(child: RenderNode, sibling: RenderNode | null) { 679 if (child === undefined || child === null) { 680 return; 681 } 682 let indexOfNode: number = this.childrenList.findIndex(element => element === child); 683 if (indexOfNode !== -1) { 684 return; 685 } 686 child.parentRenderNode = new WeakRef(this); 687 let indexOfSibling = this.childrenList.findIndex(element => element === sibling); 688 if (indexOfSibling === -1) { 689 sibling === null; 690 } 691 if (sibling === undefined || sibling === null) { 692 this.childrenList.splice(0, 0, child); 693 getUINativeModule().renderNode.insertChildAfter(this.nodePtr, child.nodePtr, null); 694 } else { 695 this.childrenList.splice(indexOfSibling + 1, 0, child); 696 getUINativeModule().renderNode.insertChildAfter(this.nodePtr, child.nodePtr, sibling.nodePtr); 697 } 698 } 699 removeChild(node: RenderNode) { 700 if (node === undefined || node === null) { 701 return; 702 } 703 const index = this.childrenList.findIndex(element => element === node); 704 if (index === -1) { 705 return; 706 } 707 const child = this.childrenList[index]; 708 child.parentRenderNode = null; 709 this.childrenList.splice(index, 1); 710 getUINativeModule().renderNode.removeChild(this.nodePtr, node.nodePtr); 711 } 712 clearChildren() { 713 this.childrenList = new Array<RenderNode>(); 714 getUINativeModule().renderNode.clearChildren(this.nodePtr); 715 } 716 getChild(index: number): RenderNode | null { 717 if (this.childrenList.length > index && index >= 0) { 718 return this.childrenList[index]; 719 } 720 return null; 721 } 722 getFirstChild(): RenderNode | null { 723 if (this.childrenList.length > 0) { 724 return this.childrenList[0]; 725 } 726 return null; 727 } 728 getNextSibling(): RenderNode | null { 729 if (this.parentRenderNode === undefined || this.parentRenderNode === null) { 730 return null; 731 } 732 let parent = this.parentRenderNode.deref(); 733 if (parent === undefined || parent === null) { 734 return null; 735 } 736 let siblingList = parent.childrenList; 737 const index = siblingList.findIndex(element => element === this); 738 if (index === -1) { 739 return null; 740 } 741 return parent.getChild(index + 1); 742 } 743 getPreviousSibling(): RenderNode | null { 744 if (this.parentRenderNode === undefined || this.parentRenderNode === null) { 745 return null; 746 } 747 let parent = this.parentRenderNode.deref(); 748 if (parent === undefined || parent === null) { 749 return null; 750 } 751 let siblingList = parent.childrenList; 752 const index = siblingList.findIndex(element => element === this); 753 if (index === -1) { 754 return null; 755 } 756 return parent.getChild(index - 1); 757 } 758 setFrameNode(frameNode: WeakRef<FrameNode>) { 759 this._frameNode = frameNode; 760 } 761 762 setNodePtr(nativeRef: NativeStrongRef) { 763 this._nativeRef = nativeRef; 764 this.nodePtr = this._nativeRef?.getNativeHandle(); 765 } 766 767 setBaseNode(baseNode: BaseNode | null) { 768 this.baseNode_ = baseNode; 769 } 770 resetNodePtr(): void { 771 this.nodePtr = null; 772 this._nativeRef = null; 773 } 774 dispose() { 775 this._nativeRef?.dispose(); 776 this.baseNode_?.disposeNode(); 777 this._frameNode?.deref()?.resetNodePtr(); 778 this._nativeRef = null; 779 this.nodePtr = null; 780 } 781 getNodePtr(): NodePtr { 782 return this.nodePtr; 783 } 784 785 invalidate() { 786 getUINativeModule().renderNode.invalidate(this.nodePtr); 787 } 788 set borderStyle(style: EdgeStyles) { 789 if (style === undefined || style === null) { 790 this.borderStyleValue = { left: BorderStyle.NONE, top: BorderStyle.NONE, right: BorderStyle.NONE, bottom: BorderStyle.NONE }; 791 } else { 792 this.borderStyleValue = style; 793 } 794 getUINativeModule().renderNode.setBorderStyle( 795 this.nodePtr, this.borderStyleValue.left, this.borderStyleValue.top, this.borderStyleValue.right, this.borderStyleValue.bottom); 796 } 797 get borderStyle(): EdgeStyles { 798 return this.borderStyleValue; 799 } 800 set borderWidth(width: EdgeWidths) { 801 if (width === undefined || width === null) { 802 this.borderWidthValue = { left: 0, top: 0, right: 0, bottom: 0 }; 803 } else { 804 this.borderWidthValue = width; 805 } 806 getUINativeModule().renderNode.setBorderWidth( 807 this.nodePtr, this.borderWidthValue.left, this.borderWidthValue.top, 808 this.borderWidthValue.right, this.borderWidthValue.bottom, this.lengthMetricsUnitValue); 809 } 810 get borderWidth(): EdgeWidths { 811 return this.borderWidthValue; 812 } 813 set borderColor(color: EdgeColors) { 814 if (color === undefined || color === null) { 815 this.borderColorValue = { left: 0XFF000000, top: 0XFF000000, right: 0XFF000000, bottom: 0XFF000000 }; 816 } else { 817 this.borderColorValue = color; 818 } 819 getUINativeModule().renderNode.setBorderColor( 820 this.nodePtr, this.borderColorValue.left, this.borderColorValue.top, this.borderColorValue.right, this.borderColorValue.bottom); 821 } 822 get borderColor(): EdgeColors { 823 return this.borderColorValue; 824 } 825 set borderRadius(radius: BorderRadiuses) { 826 if (radius === undefined || radius === null) { 827 this.borderRadiusValue = { topLeft: 0, topRight: 0, bottomLeft: 0, bottomRight: 0 }; 828 } else { 829 this.borderRadiusValue = radius; 830 } 831 getUINativeModule().renderNode.setBorderRadius( 832 this.nodePtr, this.borderRadiusValue.topLeft, this.borderRadiusValue.topRight, 833 this.borderRadiusValue.bottomLeft, this.borderRadiusValue.bottomRight, this.lengthMetricsUnitValue); 834 } 835 get borderRadius(): BorderRadiuses { 836 return this.borderRadiusValue; 837 } 838 set shapeMask(shapeMask: ShapeMask) { 839 if (shapeMask === undefined || shapeMask === null) { 840 this.shapeMaskValue = new ShapeMask(); 841 } else { 842 this.shapeMaskValue = shapeMask; 843 } 844 if (this.shapeMaskValue.rect !== null) { 845 const rectMask = this.shapeMaskValue.rect; 846 getUINativeModule().renderNode.setRectMask( 847 this.nodePtr, rectMask.left, rectMask.top, rectMask.right, rectMask.bottom, 848 this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 849 } else if (this.shapeMaskValue.circle !== null) { 850 const circle = this.shapeMaskValue.circle; 851 getUINativeModule().renderNode.setCircleMask( 852 this.nodePtr, circle.centerX, circle.centerY, circle.radius, 853 this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 854 } else if (this.shapeMaskValue.roundRect !== null) { 855 const roundRect = this.shapeMask.roundRect; 856 const corners = roundRect.corners; 857 const rect = roundRect.rect; 858 getUINativeModule().renderNode.setRoundRectMask( 859 this.nodePtr, 860 corners.topLeft.x, 861 corners.topLeft.y, 862 corners.topRight.x, 863 corners.topRight.y, 864 corners.bottomLeft.x, 865 corners.bottomLeft.y, 866 corners.bottomRight.x, 867 corners.bottomRight.y, 868 rect.left, 869 rect.top, 870 rect.right, 871 rect.bottom, 872 this.shapeMaskValue.fillColor, 873 this.shapeMaskValue.strokeColor, 874 this.shapeMaskValue.strokeWidth); 875 } else if (this.shapeMaskValue.oval !== null) { 876 const oval = this.shapeMaskValue.oval; 877 getUINativeModule().renderNode.setOvalMask( 878 this.nodePtr, oval.left, oval.top, oval.right, oval.bottom, 879 this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 880 } else if (this.shapeMaskValue.path !== null) { 881 const path = this.shapeMaskValue.path; 882 getUINativeModule().renderNode.setPath( 883 this.nodePtr, path.commands, this.shapeMaskValue.fillColor, this.shapeMaskValue.strokeColor, this.shapeMaskValue.strokeWidth); 884 } 885 } 886 get shapeMask(): ShapeMask { 887 return this.shapeMaskValue; 888 } 889 set shapeClip(shapeClip: ShapeClip) { 890 if (shapeClip === undefined || shapeClip === null) { 891 this.shapeClipValue = new ShapeClip(); 892 } else { 893 this.shapeClipValue = shapeClip; 894 } 895 if (this.shapeClipValue.rect !== null) { 896 const rectClip = this.shapeClipValue.rect; 897 getUINativeModule().renderNode.setRectClip( 898 this.nodePtr, rectClip.left, rectClip.top, rectClip.right, rectClip.bottom); 899 } else if (this.shapeClipValue.circle !== null) { 900 const circle = this.shapeClipValue.circle; 901 getUINativeModule().renderNode.setCircleClip( 902 this.nodePtr, circle.centerX, circle.centerY, circle.radius); 903 } else if (this.shapeClipValue.roundRect !== null) { 904 const roundRect = this.shapeClipValue.roundRect; 905 const corners = roundRect.corners; 906 const rect = roundRect.rect; 907 getUINativeModule().renderNode.setRoundRectClip( 908 this.nodePtr, 909 corners.topLeft.x, 910 corners.topLeft.y, 911 corners.topRight.x, 912 corners.topRight.y, 913 corners.bottomLeft.x, 914 corners.bottomLeft.y, 915 corners.bottomRight.x, 916 corners.bottomRight.y, 917 rect.left, 918 rect.top, 919 rect.right, 920 rect.bottom); 921 } else if (this.shapeClipValue.oval !== null) { 922 const oval = this.shapeClipValue.oval; 923 getUINativeModule().renderNode.setOvalClip( 924 this.nodePtr, oval.left, oval.top, oval.right, oval.bottom, 925 ); 926 } else if (this.shapeClipValue.path !== null) { 927 const path = this.shapeClipValue.path; 928 getUINativeModule().renderNode.setPathClip( 929 this.nodePtr, path.commands); 930 } 931 } 932 get shapeClip(): ShapeClip { 933 this.shapeClipValue = this.shapeClipValue ? this.shapeClipValue : new ShapeClip(); 934 return this.shapeClipValue; 935 } 936} 937 938function edgeColors(all: number): EdgeColors { 939 return { left: all, top: all, right: all, bottom: all }; 940} 941 942function edgeWidths(all: number): EdgeWidths { 943 return { left: all, top: all, right: all, bottom: all }; 944} 945 946function borderStyles(all: BorderStyle): EdgeStyles { 947 return { left: all, top: all, right: all, bottom: all }; 948} 949 950function borderRadiuses(all: number): BorderRadiuses { 951 return { topLeft: all, topRight: all, bottomLeft: all, bottomRight: all }; 952} 953