From 095d72f112a8262ae9059a2479dccfbd320a4d8d Mon Sep 17 00:00:00 2001 From: youbing Date: Mon, 8 May 2023 19:30:51 +0800 Subject: [PATCH] Description: Modification of Arc-shaped Text Layout Algorithm IssueNo: https://gitee.com/openharmony/graphic_ui/issues/I71DPY Feature or Bugfix: Feature Binary Source:No Signed-off-by: youbing54 --- frameworks/common/typed_text.cpp | 16 ++++++ frameworks/common/typed_text.h | 2 + frameworks/components/ui_arc_label.cpp | 17 ++++-- frameworks/draw/draw_label.cpp | 64 +++++++++++++++++++---- frameworks/draw/draw_label.h | 19 ++++++- interfaces/kits/components/ui_arc_label.h | 14 +++++ 6 files changed, 116 insertions(+), 16 deletions(-) diff --git a/frameworks/common/typed_text.cpp b/frameworks/common/typed_text.cpp index 617fb6c..6fd41c2 100644 --- a/frameworks/common/typed_text.cpp +++ b/frameworks/common/typed_text.cpp @@ -162,6 +162,22 @@ float TypedText::GetAngleForArcLen(float len, return (direct == TEXT_DIRECT_LTR) ? angle : -angle; } +float TypedText::GetAngleForArcLen(uint16_t letterWidth, int16_t letterSpace, uint16_t radius) +{ + if (radius == 0) { + return 0.0f; + } + const int TWOX_COEFFICIENT = 2; + const float FLOATING_POINT_TWO = 2.0f; + float sinA = (letterWidth + letterSpace) / (FLOATING_POINT_TWO * radius); + float a = asin(sinA); + if (a >= -EPSINON && a <= EPSINON) { + return 0.0f; + } + + return static_cast(TWOX_COEFFICIENT * a * SEMICIRCLE_IN_DEGREE / UI_PI); +} + void TypedText::GetArcLetterPos(const Point& arcCenter, uint16_t radius, float angle, float& posX, float& posY) { posX = arcCenter.x + (static_cast(radius) * Sin(angle)); diff --git a/frameworks/common/typed_text.h b/frameworks/common/typed_text.h index 63e7403..9c0a84a 100644 --- a/frameworks/common/typed_text.h +++ b/frameworks/common/typed_text.h @@ -74,6 +74,8 @@ public: UITextLanguageDirect direct, TextOrientation orientation); + static float GetAngleForArcLen(uint16_t letterWidth, int16_t letterSpace, uint16_t radius); + static void GetArcLetterPos(const Point& arcCenter, uint16_t radius, float angle, float& posX, float& posY); #else // _FONT_TOOL diff --git a/frameworks/components/ui_arc_label.cpp b/frameworks/components/ui_arc_label.cpp index 5923b92..8b85dd5 100644 --- a/frameworks/components/ui_arc_label.cpp +++ b/frameworks/components/ui_arc_label.cpp @@ -24,6 +24,7 @@ namespace OHOS { UIArcLabel::UIArcLabel() : arcLabelText_(nullptr), + compatibilityMode_(true), needRefresh_(false), textSize_({0, 0}), radius_(0), @@ -138,7 +139,8 @@ void UIArcLabel::DrawArcText(BufferInfo& gfxDstBuffer, center.x = arcTextInfo_.arcCenter.x + GetRect().GetX(); center.y = arcTextInfo_.arcCenter.y + GetRect().GetY(); DrawLabel::DrawArcText(gfxDstBuffer, mask, arcLabelText_->GetText(), center, arcLabelText_->GetFontId(), - arcLabelText_->GetFontSize(), arcTextInfo, orientation, *style_, opaScale); + arcLabelText_->GetFontSize(), arcTextInfo, + orientation, *style_, opaScale, compatibilityMode_); } Rect UIArcLabel::GetArcTextRect(const char* text, uint16_t fontId, uint8_t fontSize, const Point& arcCenter, @@ -173,8 +175,11 @@ void UIArcLabel::ReMeasure() int16_t arcTextWidth = textRect.GetWidth(); int16_t arcTextHeight = textRect.GetHeight(); - SetPosition(textRect.GetX(), textRect.GetY()); - Resize(arcTextWidth, arcTextHeight); + if (compatibilityMode_) { + SetPosition(textRect.GetX(), textRect.GetY()); + Resize(arcTextWidth, arcTextHeight); + } + arcTextInfo_.arcCenter.x = arcCenter_.x - GetX() + style_->borderWidth_ + style_->paddingLeft_; arcTextInfo_.arcCenter.y = arcCenter_.y - GetY() + style_->borderWidth_ + style_->paddingTop_; textSize_.x = arcTextWidth; @@ -189,7 +194,11 @@ void UIArcLabel::MeasureArcTextInfo() return; } uint16_t letterHeight = UIFont::GetInstance()->GetHeight(arcLabelText_->GetFontId(), arcLabelText_->GetFontSize()); - arcTextInfo_.radius = ((orientation_ == TextOrientation::INSIDE) ? radius_ : (radius_ - letterHeight)); + if (compatibilityMode_) { + arcTextInfo_.radius = ((orientation_ == TextOrientation::INSIDE) ? radius_ : (radius_ - letterHeight)); + } else { + arcTextInfo_.radius = radius_; + } if (arcTextInfo_.radius == 0) { return; } diff --git a/frameworks/draw/draw_label.cpp b/frameworks/draw/draw_label.cpp index a75610b..7100613 100644 --- a/frameworks/draw/draw_label.cpp +++ b/frameworks/draw/draw_label.cpp @@ -144,7 +144,8 @@ void DrawLabel::DrawArcText(BufferInfo& gfxDstBuffer, const ArcTextInfo arcTextInfo, TextOrientation orientation, const Style& style, - OpacityType opaScale) + OpacityType opaScale, + bool compatibilityMode) { if ((text == nullptr) || (arcTextInfo.lineStart == arcTextInfo.lineEnd) || (arcTextInfo.radius == 0)) { GRAPHIC_LOGE("DrawLabel::DrawArcText invalid parameter\n"); @@ -176,13 +177,41 @@ void DrawLabel::DrawArcText(BufferInfo& gfxDstBuffer, break; } letterWidth = UIFont::GetInstance()->GetWidth(letter, fontId, fontSize, 0); - if ((tmp == arcTextInfo.lineStart) && xorFlag) { + if (!DrawLabel::CalculateAngle(letterWidth, letterHeight, style.letterSpace_, + arcTextInfo, xorFlag, tmp, orientation, + posX, posY, rotateAngle, angle, + arcCenter, compatibilityMode)) { + continue; + } + + DrawLetterWithRotate(gfxDstBuffer, mask, fontId, fontSize, letter, Point { MATH_ROUND(posX), MATH_ROUND(posY) }, + static_cast(rotateAngle), style.textColor_, opaScale, compatibilityMode); + } +} + +bool DrawLabel::CalculateAngle(uint16_t letterWidth, + uint16_t letterHeight, + int16_t letterSpace, + const ArcTextInfo arcTextInfo, + bool xorFlag, + uint32_t index, + TextOrientation orientation, + float& posX, + float& posY, + float& rotateAngle, + float& angle, + const Point& arcCenter, + bool compatibilityMode) +{ + const int DIVIDER_BY_TWO = 2; + if (compatibilityMode) { + if ((index == arcTextInfo.lineStart) && xorFlag) { angle += TypedText::GetAngleForArcLen(static_cast(letterWidth), letterHeight, arcTextInfo.radius, arcTextInfo.direct, orientation); } - uint16_t arcLen = letterWidth + style.letterSpace_; + uint16_t arcLen = letterWidth + letterSpace; if (arcLen == 0) { - continue; + return false; } float incrementAngle = TypedText::GetAngleForArcLen(static_cast(arcLen), letterHeight, arcTextInfo.radius, arcTextInfo.direct, orientation); @@ -190,14 +219,26 @@ void DrawLabel::DrawArcText(BufferInfo& gfxDstBuffer, rotateAngle = (orientation == TextOrientation::INSIDE) ? angle : (angle - SEMICIRCLE_IN_DEGREE); // 2: half - float fineTuningAngle = incrementAngle * (static_cast(letterWidth) / (2 * arcLen)); + float fineTuningAngle = incrementAngle * (static_cast(letterWidth) / (DIVIDER_BY_TWO * arcLen)); rotateAngle += (xorFlag ? -fineTuningAngle : fineTuningAngle); TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY); angle += incrementAngle; + } else { + if ((index == arcTextInfo.lineStart) && xorFlag) { + angle += TypedText::GetAngleForArcLen(letterWidth, letterSpace, arcTextInfo.radius); + } + float incrementAngle = TypedText::GetAngleForArcLen(letterWidth, letterSpace, arcTextInfo.radius); + if (incrementAngle >= -EPSINON && incrementAngle <= EPSINON) { + return false; + } - DrawLetterWithRotate(gfxDstBuffer, mask, fontId, fontSize, letter, Point { MATH_ROUND(posX), MATH_ROUND(posY) }, - static_cast(rotateAngle), style.textColor_, opaScale); + float fineTuningAngle = incrementAngle / DIVIDER_BY_TWO; + rotateAngle = xorFlag ? (angle - SEMICIRCLE_IN_DEGREE - fineTuningAngle) : (angle + fineTuningAngle); + TypedText::GetArcLetterPos(arcCenter, arcTextInfo.radius, angle, posX, posY); + angle = xorFlag ? (angle - incrementAngle) : (angle + incrementAngle); } + + return true; } void DrawLabel::DrawLetterWithRotate(BufferInfo& gfxDstBuffer, @@ -208,7 +249,8 @@ void DrawLabel::DrawLetterWithRotate(BufferInfo& gfxDstBuffer, const Point& pos, int16_t rotateAngle, const ColorType& color, - OpacityType opaScale) + OpacityType opaScale, + bool compatibilityMode) { UIFont* fontEngine = UIFont::GetInstance(); FontHeader head; @@ -226,11 +268,13 @@ void DrawLabel::DrawLetterWithRotate(BufferInfo& gfxDstBuffer, } uint8_t fontWeight = fontEngine->GetFontWeight(fontId); ColorMode colorMode = fontEngine->GetColorType(fontId); + + int16_t offset = compatibilityMode ? head.ascender : 0; Rect rectLetter; - rectLetter.SetPosition(pos.x + node.left, pos.y + head.ascender - node.top); + rectLetter.SetPosition(pos.x + node.left, pos.y + offset - node.top); rectLetter.Resize(node.cols, node.rows); TransformMap transMap(rectLetter); - transMap.Rotate(rotateAngle, Vector2(-node.left, node.top - head.ascender)); + transMap.Rotate(rotateAngle, Vector2(-node.left, node.top - offset)); TransformDataInfo letterTranDataInfo = {ImageHeader{colorMode, 0, 0, 0, node.cols, node.rows}, fontMap, fontWeight, BlurLevel::LEVEL0, TransformAlgorithm::BILINEAR}; BaseGfxEngine::GetInstance()->DrawTransform(gfxDstBuffer, mask, Point { 0, 0 }, color, opaScale, transMap, diff --git a/frameworks/draw/draw_label.h b/frameworks/draw/draw_label.h index 28e08d9..c43e34e 100644 --- a/frameworks/draw/draw_label.h +++ b/frameworks/draw/draw_label.h @@ -30,7 +30,21 @@ public: static void DrawArcText(BufferInfo& gfxDstBuffer, const Rect& mask, const char* text, const Point& arcCenter, uint16_t fontId, uint8_t fontSize, const ArcTextInfo arcTextInfo, - TextOrientation orientation, const Style& style, uint8_t opaScale); + TextOrientation orientation, const Style& style, uint8_t opaScale, bool compatibilityMode); + + static bool CalculateAngle(uint16_t letterWidth, + uint16_t letterHeight, + int16_t letterSpace, + const ArcTextInfo arcTextInfo, + bool xorFlag, + uint32_t index, + TextOrientation orientation, + float& posX, + float& posY, + float& rotateAngle, + float& angle, + const Point& arcCenter, + bool compatibilityMode); static void DrawLetterWithRotate(BufferInfo& gfxDstBuffer, const Rect& mask, @@ -40,7 +54,8 @@ public: const Point& pos, int16_t rotateAngle, const ColorType& color, - OpacityType opaScale); + OpacityType opaScale, + bool compatibilityMode); static uint8_t GetLineMaxLetterSize(const char* text, uint16_t lineLength, uint16_t fontId, uint8_t fontSize, uint16_t letterIndex, SizeSpan* sizeSpans); diff --git a/interfaces/kits/components/ui_arc_label.h b/interfaces/kits/components/ui_arc_label.h index 7ba60b7..f6444f5 100644 --- a/interfaces/kits/components/ui_arc_label.h +++ b/interfaces/kits/components/ui_arc_label.h @@ -327,6 +327,19 @@ public: return orientation_; } + /** + * @brief Is it compatible with older versions. + * + * @param compatibilityMode Indicates compatible with older versions. + */ + void SetCompatibilityMode(bool compatibilityMode) + { + if (compatibilityMode_ != compatibilityMode) { + compatibilityMode_ = compatibilityMode; + RefreshArcLabel(); + } + } + /** * @brief Draws an arc text. * @@ -338,6 +351,7 @@ public: protected: Text* arcLabelText_; + bool compatibilityMode_; virtual void InitArcLabelText() {