1 /* 2 * Copyright (c) 2025 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 16 #ifndef FOUNDATION_ACE_INTERFACES_INNER_API_ACE_KIT_INCLUDE_UI_PROPERTIES_GRADIENT_PROPERTY_H 17 #define FOUNDATION_ACE_INTERFACES_INNER_API_ACE_KIT_INCLUDE_UI_PROPERTIES_GRADIENT_PROPERTY_H 18 19 #include <array> 20 #include <memory> 21 #include <optional> 22 #include <regex> 23 #include <vector> 24 #include <map> 25 #include <functional> 26 27 #include "ui/base/geometry/dimension.h" 28 #include "ui/base/geometry/ng/offset_t.h" 29 #include "ui/base/ace_type.h" 30 #include "ui/base/macros.h" 31 #include "ui/base/utils/utils.h" 32 #include "ui/properties/color.h" 33 #include "ui/properties/linear_color.h" 34 #include "ui/resource/resource_object.h" 35 36 namespace OHOS::Ace::NG { 37 38 constexpr float BOX_END_SIZE = 100.0f; 39 40 enum class GradientDirection { 41 LEFT = 0, 42 TOP, 43 RIGHT, 44 BOTTOM, 45 LEFT_TOP, 46 LEFT_BOTTOM, 47 RIGHT_TOP, 48 RIGHT_BOTTOM, 49 NONE, 50 START_TO_END, 51 END_TO_START, 52 }; 53 54 enum class GradientType { 55 LINEAR, 56 RADIAL, 57 SWEEP, 58 CONIC, 59 }; 60 61 enum class RadialSizeType { 62 CLOSEST_SIDE, 63 CLOSEST_CORNER, 64 FARTHEST_SIDE, 65 FARTHEST_CORNER, 66 NONE, 67 }; 68 69 enum class RadialShapeType { 70 CIRCLE, 71 ELLIPSE, 72 NONE, 73 }; 74 75 enum class SpreadMethod { 76 PAD, 77 REFLECT, 78 REPEAT, 79 }; 80 81 struct LinearGradientInfo { 82 float x1 = 0.0f; 83 float x2 = 0.0f; 84 float y1 = 0.0f; 85 float y2 = 0.0f; 86 bool operator==(const LinearGradientInfo& other) const 87 { 88 return ( 89 NearEqual(x1, other.x1) && NearEqual(x2, other.x2) && NearEqual(y1, other.y1) && NearEqual(y2, other.y2)); 90 } 91 }; 92 93 struct RadialGradientInfo { 94 float r = 0.0f; 95 float cx = 0.0f; 96 float cy = 0.0f; 97 float fx = 0.0f; 98 float fy = 0.0f; 99 bool operator==(const RadialGradientInfo& other) const 100 { 101 return (NearEqual(r, other.r) && NearEqual(cx, other.cx) && NearEqual(cy, other.cy) && 102 NearEqual(fx, other.fx) && NearEqual(fy, other.fy)); 103 } 104 }; 105 106 class GradientColor final { 107 public: 108 GradientColor() = default; 109 ~GradientColor() = default; 110 GradientColor(const Color & color)111 explicit GradientColor(const Color& color) 112 { 113 color_ = color; 114 } 115 116 void SetDimension(double value, DimensionUnit unit = DimensionUnit::PERCENT) 117 { 118 if (value < 0.0) { 119 return; 120 } 121 if (unit == DimensionUnit::PERCENT && value > BOX_END_SIZE) { 122 return; 123 } 124 dimension_ = Dimension(value, unit); 125 } 126 SetDimension(const Dimension & dimension)127 void SetDimension(const Dimension& dimension) 128 { 129 if (dimension.Value() < 0.0) { 130 return; 131 } 132 if (dimension.Unit() == DimensionUnit::PERCENT && dimension.Value() > BOX_END_SIZE) { 133 return; 134 } 135 dimension_ = dimension; 136 } 137 SetHasValue(bool hasValue)138 void SetHasValue(bool hasValue) 139 { 140 hasValue_ = hasValue; 141 } 142 SetColor(const Color & color)143 void SetColor(const Color& color) 144 { 145 color_ = color; 146 } 147 GetColor()148 const Color& GetColor() const 149 { 150 return color_; 151 } 152 SetLinearColor(const LinearColor & linearColor)153 void SetLinearColor(const LinearColor& linearColor) 154 { 155 linearColor_ = linearColor; 156 } 157 GetLinearColor()158 const LinearColor& GetLinearColor() const 159 { 160 return linearColor_; 161 } 162 GetDimension()163 const Dimension& GetDimension() const 164 { 165 return dimension_; 166 } 167 GetHasValue()168 bool GetHasValue() const 169 { 170 return hasValue_; 171 } 172 SetOpacity(double opacity)173 void SetOpacity(double opacity) 174 { 175 opacity_ = opacity; 176 } 177 GetOpacity()178 double GetOpacity() const 179 { 180 return opacity_; 181 } 182 183 bool operator==(const GradientColor& other) const 184 { 185 return (hasValue_ == other.GetHasValue() && color_ == other.GetColor() && dimension_ == other.GetDimension() && 186 opacity_ == other.GetOpacity() && linearColor_ == other.GetLinearColor()); 187 } 188 189 private: 190 bool hasValue_ = true; 191 Color color_ { Color::TRANSPARENT }; 192 LinearColor linearColor_ { LinearColor::TRANSPARENT }; 193 Dimension dimension_ { BOX_END_SIZE, DimensionUnit::PERCENT }; 194 float opacity_ = 1.0f; 195 }; 196 197 struct ACE_EXPORT RadialGradient { 198 // size type 199 std::optional<RadialSizeType> radialSizeType; 200 // shape circle or ellipse 201 std::optional<RadialShapeType> radialShape; 202 // size in x-axis 203 std::optional<Dimension> radialHorizontalSize; 204 // size in y-axis 205 std::optional<Dimension> radialVerticalSize; 206 // center of shape 207 std::optional<Dimension> radialCenterX; 208 std::optional<Dimension> radialCenterY; 209 210 std::optional<Dimension> fRadialCenterX; 211 std::optional<Dimension> fRadialCenterY; 212 213 bool operator==(const RadialGradient& other) const 214 { 215 return (radialSizeType == other.radialSizeType && radialShape == other.radialShape && 216 radialHorizontalSize == other.radialHorizontalSize && radialVerticalSize == other.radialVerticalSize && 217 radialCenterX == other.radialCenterX && radialCenterY == other.radialCenterY && 218 fRadialCenterX == other.fRadialCenterX && fRadialCenterY == other.fRadialCenterY); 219 } 220 }; 221 222 struct ACE_EXPORT LinearGradient { 223 // direction in x-axis 224 std::optional<GradientDirection> linearX; 225 // direction in y-axis 226 std::optional<GradientDirection> linearY; 227 // angle of gradient line in bearing angle 228 std::optional<Dimension> angle; 229 230 std::optional<Dimension> x1; 231 std::optional<Dimension> y1; 232 std::optional<Dimension> x2; 233 std::optional<Dimension> y2; 234 235 // is direction in x-axis IsXAxisLinearGradient236 static bool IsXAxis(GradientDirection direction) 237 { 238 return (direction == GradientDirection::LEFT || direction == GradientDirection::RIGHT || 239 direction == GradientDirection::START_TO_END || direction == GradientDirection::END_TO_START); 240 } 241 242 bool operator==(const LinearGradient& other) const 243 { 244 return (x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2 && linearX == other.linearX && 245 linearY == other.linearY && angle == other.angle); 246 } 247 }; 248 249 struct ACE_EXPORT SweepGradient { 250 // center of x-axis 251 std::optional<Dimension> centerX; 252 // center of y-axis 253 std::optional<Dimension> centerY; 254 // startAngle in degree 255 std::optional<Dimension> startAngle; 256 // endAngle in degree 257 std::optional<Dimension> endAngle; 258 // rotation in degree 259 std::optional<Dimension> rotation; 260 261 bool operator==(const OHOS::Ace::NG::SweepGradient& other) const 262 { 263 return (centerX == other.centerX && centerY == other.centerY && startAngle == other.startAngle && 264 endAngle == other.endAngle && rotation == other.rotation); 265 } 266 }; 267 268 class ACE_FORCE_EXPORT Gradient final { 269 public: 270 ACE_FORCE_EXPORT void AddColor(const GradientColor& color); 271 272 void ClearColors(); 273 IsSweepGradientValid()274 bool IsSweepGradientValid() const 275 { 276 if (sweepGradient_->startAngle.has_value() && sweepGradient_->endAngle.has_value()) { 277 return LessOrEqual(sweepGradient_->startAngle.value().Value(), sweepGradient_->endAngle.value().Value()); 278 } 279 if (sweepGradient_->startAngle.has_value() && !sweepGradient_->endAngle.has_value()) { 280 return LessOrEqual(sweepGradient_->startAngle.value().Value(), 0.0); 281 } 282 if (!sweepGradient_->startAngle.has_value() && sweepGradient_->endAngle.has_value()) { 283 return LessOrEqual(0.0, sweepGradient_->endAngle.value().Value()); 284 } 285 return true; 286 } 287 IsValid()288 bool IsValid() const 289 { 290 if (GetType() == GradientType::SWEEP) { 291 return IsSweepGradientValid() && colors_.size() > 1; 292 } 293 return colors_.size() > 1; 294 } 295 SetRepeat(bool repeat)296 void SetRepeat(bool repeat) 297 { 298 repeat_ = repeat; 299 } 300 GetRepeat()301 bool GetRepeat() const 302 { 303 return repeat_; 304 } 305 GetColors()306 const std::vector<GradientColor>& GetColors() const 307 { 308 return colors_; 309 } 310 GetBeginOffset()311 const std::shared_ptr<OffsetF>& GetBeginOffset() const 312 { 313 return beginOffset_; 314 } 315 SetBeginOffset(const OffsetF & beginOffset)316 void SetBeginOffset(const OffsetF& beginOffset) 317 { 318 beginOffset_ = std::make_shared<OffsetF>(beginOffset); 319 } 320 GetEndOffset()321 const std::shared_ptr<OffsetF>& GetEndOffset() const 322 { 323 return endOffset_; 324 } 325 SetEndOffset(const OffsetF & endOffset)326 void SetEndOffset(const OffsetF& endOffset) 327 { 328 endOffset_ = std::make_shared<OffsetF>(endOffset); 329 } 330 GetInnerRadius()331 double GetInnerRadius() const 332 { 333 return innerRadius_; 334 } 335 SetInnerRadius(double innerRadius)336 void SetInnerRadius(double innerRadius) 337 { 338 innerRadius_ = innerRadius; 339 } 340 GetOuterRadius()341 double GetOuterRadius() const 342 { 343 return outerRadius_; 344 } 345 SetOuterRadius(double outerRadius)346 void SetOuterRadius(double outerRadius) 347 { 348 outerRadius_ = outerRadius; 349 } 350 GetType()351 GradientType GetType() const 352 { 353 return type_; 354 } 355 356 void CreateGradientWithType(GradientType type); 357 ToString()358 std::string ToString() const 359 { 360 return std::string("Gradient (") 361 .append(beginOffset_->ToString()) 362 .append(",") 363 .append(std::to_string(innerRadius_)) 364 .append(" --- ") 365 .append(endOffset_->ToString()) 366 .append(",") 367 .append(std::to_string(outerRadius_)) 368 .append(")"); 369 } 370 GetSweepGradient()371 std::shared_ptr<SweepGradient> GetSweepGradient() 372 { 373 return sweepGradient_; 374 } 375 GetSweepGradient()376 const std::shared_ptr<SweepGradient> GetSweepGradient() const 377 { 378 return sweepGradient_; 379 } 380 SetSweepGradient(const SweepGradient & sweepGradient)381 void SetSweepGradient(const SweepGradient& sweepGradient) 382 { 383 sweepGradient_ = std::make_shared<SweepGradient>(sweepGradient); 384 } 385 GetRadialGradient()386 std::shared_ptr<RadialGradient>& GetRadialGradient() 387 { 388 return radialGradient_; 389 } 390 GetRadialGradient()391 const std::shared_ptr<RadialGradient>& GetRadialGradient() const 392 { 393 return radialGradient_; 394 } 395 SetRadialGradient(const RadialGradient & radialGradient)396 void SetRadialGradient(const RadialGradient& radialGradient) 397 { 398 radialGradient_ = std::make_shared<RadialGradient>(radialGradient); 399 } 400 GetLinearGradient()401 std::shared_ptr<LinearGradient>& GetLinearGradient() 402 { 403 return linearGradient_; 404 } 405 GetLinearGradient()406 const std::shared_ptr<LinearGradient>& GetLinearGradient() const 407 { 408 return linearGradient_; 409 } 410 SetLinearGradient(const LinearGradient & linearGradient)411 void SetLinearGradient(const LinearGradient& linearGradient) 412 { 413 linearGradient_ = std::make_shared<LinearGradient>(linearGradient); 414 } 415 SetDirection(const GradientDirection & direction)416 void SetDirection(const GradientDirection& direction) 417 { 418 if (LinearGradient::IsXAxis(direction)) { 419 linearGradient_->linearX = direction; 420 } else { 421 linearGradient_->linearY = direction; 422 } 423 } 424 SetSpreadMethod(SpreadMethod spreadMethod)425 void SetSpreadMethod(SpreadMethod spreadMethod) 426 { 427 spreadMethod_ = spreadMethod; 428 } 429 SetGradientTransform(const std::string & gradientTransform)430 void SetGradientTransform(const std::string& gradientTransform) 431 { 432 gradientTransform_ = gradientTransform; 433 } 434 GetSpreadMethod()435 SpreadMethod GetSpreadMethod() const 436 { 437 return spreadMethod_; 438 } 439 GetGradientTransform()440 const std::string& GetGradientTransform() const 441 { 442 return gradientTransform_; 443 } 444 GetRadialGradientInfo()445 const std::shared_ptr<RadialGradientInfo>& GetRadialGradientInfo() const 446 { 447 return radialGradientInfo_; 448 } 449 SetRadialGradientInfo(const RadialGradientInfo & radialGradientInfo)450 void SetRadialGradientInfo(const RadialGradientInfo& radialGradientInfo) 451 { 452 radialGradientInfo_ = std::make_shared<RadialGradientInfo>(radialGradientInfo); 453 } 454 GetLinearGradientInfo()455 const std::shared_ptr<LinearGradientInfo> GetLinearGradientInfo() const 456 { 457 return linearGradientInfo_; 458 } 459 SetLinearGradientInfo(const LinearGradientInfo & linearGradientInfo)460 void SetLinearGradientInfo(const LinearGradientInfo& linearGradientInfo) 461 { 462 linearGradientInfo_ = std::make_shared<LinearGradientInfo>(linearGradientInfo); 463 } 464 465 template<class T> CmpSharedPtr(const std::shared_ptr<T> & a,const std::shared_ptr<T> & b)466 static bool CmpSharedPtr(const std::shared_ptr<T>& a, const std::shared_ptr<T>& b) 467 { 468 if (a == b) { 469 return true; 470 } 471 if (a && b) { 472 return *a == *b; 473 } 474 return false; 475 } 476 477 bool operator==(const Gradient& other) const 478 { 479 return (type_ == other.GetType() && repeat_ == other.GetRepeat() && colors_ == other.GetColors() && 480 CmpSharedPtr(radialGradient_, other.GetRadialGradient()) && 481 CmpSharedPtr(linearGradient_, other.GetLinearGradient()) && 482 CmpSharedPtr(sweepGradient_, other.GetSweepGradient()) && 483 beginOffset_ == other.GetBeginOffset() && 484 endOffset_ == other.GetEndOffset() && spreadMethod_ == other.GetSpreadMethod() && 485 gradientTransform_ == other.GetGradientTransform() && 486 linearGradientInfo_ == other.GetLinearGradientInfo() && 487 radialGradientInfo_ == other.GetRadialGradientInfo()); 488 } 489 490 bool operator!=(const Gradient& other) const 491 { 492 return !(*this == other); 493 } 494 struct resourceUpdater { 495 RefPtr<ResourceObject> resObj; 496 std::function<void(const RefPtr<ResourceObject>&, NG::Gradient&)> updateFunc; 497 }; 498 std::map<std::string, resourceUpdater> resMap_; 499 AddResource(const std::string & key,const RefPtr<ResourceObject> & resObj,std::function<void (const RefPtr<ResourceObject> &,NG::Gradient &)> && updateFunc)500 void AddResource( 501 const std::string& key, 502 const RefPtr<ResourceObject>& resObj, 503 std::function<void(const RefPtr<ResourceObject>&, NG::Gradient&)>&& updateFunc) 504 { 505 if (resObj == nullptr || !updateFunc) { 506 return; 507 } 508 resMap_[key] = {resObj, std::move(updateFunc)}; 509 } 510 ReloadResources()511 void ReloadResources() 512 { 513 for (const auto& [key, resourceUpdater] : resMap_) { 514 resourceUpdater.updateFunc(resourceUpdater.resObj, *this); 515 } 516 } 517 518 private: 519 GradientType type_ = GradientType::LINEAR; 520 bool repeat_ = false; 521 std::vector<GradientColor> colors_; 522 // for RadialGradient 523 std::shared_ptr<RadialGradient> radialGradient_; 524 // for LinearGradient 525 std::shared_ptr<LinearGradient> linearGradient_; 526 // for SweepGradient 527 std::shared_ptr<SweepGradient> sweepGradient_; 528 // used for CanvasLinearGradient 529 std::shared_ptr<OffsetF> beginOffset_; 530 std::shared_ptr<OffsetF> endOffset_; 531 // used for CanvasRadialGradient 532 float innerRadius_ = 0.0f; 533 float outerRadius_ = 0.0; 534 SpreadMethod spreadMethod_ = SpreadMethod::PAD; 535 std::string gradientTransform_; 536 std::shared_ptr<LinearGradientInfo> linearGradientInfo_; 537 std::shared_ptr<RadialGradientInfo> radialGradientInfo_; 538 }; 539 540 541 class LinearGradientBlurPara final { 542 public: 543 Dimension blurRadius_; 544 std::vector<std::pair<float, float>> fractionStops_; 545 GradientDirection direction_; 546 LinearGradientBlurPara(const Dimension blurRadius,const std::vector<std::pair<float,float>> fractionStops,const GradientDirection direction)547 LinearGradientBlurPara(const Dimension blurRadius, 548 const std::vector<std::pair<float, float>>fractionStops, const GradientDirection direction) 549 : blurRadius_(blurRadius), fractionStops_(fractionStops), direction_(direction) {} 550 bool operator==(const LinearGradientBlurPara& other) const 551 { 552 return NearEqual(blurRadius_, other.blurRadius_) && NearEqual(fractionStops_, other.fractionStops_) && 553 NearEqual(direction_, other.direction_); 554 } 555 556 ~LinearGradientBlurPara() = default; 557 }; 558 559 class MagnifierParams final { 560 public: 561 float factor_ = 0.f; 562 float width_ = 0.f; 563 float height_ = 0.f; 564 float borderWidth_ = 0.f; 565 float cornerRadius_ = 0.f; 566 float offsetX_ = 0.f; 567 float offsetY_ = 0.f; 568 569 float shadowOffsetX_ = 0.f; 570 float shadowOffsetY_ = 0.f; 571 float shadowSize_ = 0.f; 572 float shadowStrength_ = 0.f; 573 574 bool changed_ = false; 575 576 // rgba 577 uint32_t gradientMaskColor1_ = 0x00000000; 578 uint32_t gradientMaskColor2_ = 0x00000000; 579 uint32_t outerContourColor1_ = 0x00000000; 580 uint32_t outerContourColor2_ = 0x00000000; 581 582 bool operator==(const MagnifierParams& other) const 583 { 584 return NearEqual(factor_, other.factor_) && NearEqual(width_, other.width_) && 585 NearEqual(height_, other.height_) && NearEqual(borderWidth_, other.borderWidth_) && 586 NearEqual(cornerRadius_, other.cornerRadius_) && NearEqual(offsetX_, other.offsetX_) && 587 NearEqual(offsetY_, other.offsetY_) && NearEqual(shadowOffsetX_, other.shadowOffsetX_) && 588 NearEqual(shadowOffsetY_, other.shadowOffsetY_) && NearEqual(shadowSize_, other.shadowSize_) && 589 NearEqual(shadowStrength_, other.shadowStrength_) && 590 NearEqual(gradientMaskColor1_, other.gradientMaskColor1_) && 591 NearEqual(gradientMaskColor2_, other.gradientMaskColor2_) && 592 NearEqual(outerContourColor1_, other.outerContourColor1_) && 593 NearEqual(outerContourColor2_, other.outerContourColor2_) && 594 changed_ == other.changed_; 595 } 596 MagnifierParams() = default; 597 ~MagnifierParams() = default; 598 }; 599 600 } // namespace OHOS::Ace::NG 601 602 #endif // FOUNDATION_ACE_INTERFACES_INNER_API_ACE_KIT_INCLUDE_UI_PROPERTIES_GRADIENT_PROPERTY_H 603