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