已合并
Add lineHeight and lineSpacing ability #2040
FTL1ght创建于 2025年8月25日
Add lineHeight and lineSpacing ability #2040
已合并
FTL1ght创建于 2025年8月25日
refs/pull/2040/head合入到master
18 个文件变更+428-55
Mm133/modules/skparagraph/include/ParagraphStyle.h+6-2
@@ -153,18 +153,19 @@ struct ParagraphStyle {
153 153 
154 bool operator==(const ParagraphStyle& rhs) const {154 bool operator==(const ParagraphStyle& rhs) const {
155#ifdef ENABLE_TEXT_ENHANCE155#ifdef ENABLE_TEXT_ENHANCE
156- return this->fHeight == rhs.fHeight && this->fEllipsis == rhs.fEllipsis &&156+ return nearlyEqual(this->fHeight, rhs.fHeight) && this->fEllipsis == rhs.fEllipsis &&
157 this->fEllipsisUtf16 == rhs.fEllipsisUtf16 &&157 this->fEllipsisUtf16 == rhs.fEllipsisUtf16 &&
158 this->fTextDirection == rhs.fTextDirection && this->fTextAlign == rhs.fTextAlign &&158 this->fTextDirection == rhs.fTextDirection && this->fTextAlign == rhs.fTextAlign &&
159 this->fDefaultTextStyle == rhs.fDefaultTextStyle &&159 this->fDefaultTextStyle == rhs.fDefaultTextStyle &&
160 this->fEllipsisModal == rhs.fEllipsisModal &&160 this->fEllipsisModal == rhs.fEllipsisModal &&
161 this->fTextOverflower == rhs.fTextOverflower &&161 this->fTextOverflower == rhs.fTextOverflower &&
162 this->fReplaceTabCharacters == rhs.fReplaceTabCharacters &&162 this->fReplaceTabCharacters == rhs.fReplaceTabCharacters &&
163- this->fTextTab == rhs.fTextTab && this->fParagraphSpacing == rhs.fParagraphSpacing &&163+ this->fTextTab == rhs.fTextTab && nearlyEqual(this->fParagraphSpacing, rhs.fParagraphSpacing) &&
164 this->fIsEndAddParagraphSpacing == rhs.fIsEndAddParagraphSpacing &&164 this->fIsEndAddParagraphSpacing == rhs.fIsEndAddParagraphSpacing &&
165 this->fIsTrailingSpaceOptimized == rhs.fIsTrailingSpaceOptimized &&165 this->fIsTrailingSpaceOptimized == rhs.fIsTrailingSpaceOptimized &&
166 this->fEnableAutoSpace == rhs.fEnableAutoSpace &&166 this->fEnableAutoSpace == rhs.fEnableAutoSpace &&
167 this->fVerticalAlignment == rhs.fVerticalAlignment &&167 this->fVerticalAlignment == rhs.fVerticalAlignment &&
168+ nearlyEqual(this->fLineSpacing, rhs.fLineSpacing) &&
liumingxiang
liumingxiangliumingxiang2025年8月26日

nearlyEqual

likedislike
168 nearlyEqual(this->fTextSplitRatio, rhs.fTextSplitRatio);169 nearlyEqual(this->fTextSplitRatio, rhs.fTextSplitRatio);
169#else170#else
170 return this->fHeight == rhs.fHeight &&171 return this->fHeight == rhs.fHeight &&
@@ -249,6 +250,8 @@ struct ParagraphStyle {
249 {250 {
250 fEnableAutoSpace = enableAutoSpace;251 fEnableAutoSpace = enableAutoSpace;
251 }252 }
253+ SkScalar getLineSpacing() const { return fLineSpacing; }
254+ void setLineSpacing(SkScalar lineSpacing) { fLineSpacing = lineSpacing; }
252#endif255#endif
253 bool getApplyRoundingHack() const { return fApplyRoundingHack; }256 bool getApplyRoundingHack() const { return fApplyRoundingHack; }
254 void setApplyRoundingHack(bool value) { fApplyRoundingHack = value; }257 void setApplyRoundingHack(bool value) { fApplyRoundingHack = value; }
@@ -276,6 +279,7 @@ private:
276 bool fIsTrailingSpaceOptimized{false};279 bool fIsTrailingSpaceOptimized{false};
277 bool fEnableAutoSpace{false};280 bool fEnableAutoSpace{false};
278 TextVerticalAlign fVerticalAlignment{TextVerticalAlign::BASELINE};281 TextVerticalAlign fVerticalAlignment{TextVerticalAlign::BASELINE};
282+ SkScalar fLineSpacing{0.0f};
279#endif283#endif
280};284};
281} // namespace textlayout285} // namespace textlayout
Mm133/modules/skparagraph/include/TextStyle.h+28-0
@@ -51,6 +51,13 @@ static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_S
51 return x == y;51 return x == y;
52}52}
53 53 
54+#ifdef ENABLE_TEXT_ENHANCE
55+enum class LineHeightStyle {
56+ kFontSize,
57+ kFontHeight
58+};
59+#endif
60+ 
54// Multiple decorations can be applied at once. Ex: Underline and overline is61// Multiple decorations can be applied at once. Ex: Underline and overline is
55// (0x1 | 0x2)62// (0x1 | 0x2)
56enum TextDecoration {63enum TextDecoration {
@@ -383,6 +390,24 @@ public:
383 SkScalar getBadgeBaseLineShift() const;390 SkScalar getBadgeBaseLineShift() const;
384 391 
385 SkScalar getCorrectFontSize() const;392 SkScalar getCorrectFontSize() const;
393+ 
394+ SkScalar getMaxLineHeight() const { return fMaxLineHeight; }
395+ 
396+ void setMaxLineHeight(SkScalar maxLineHeight) { fMaxLineHeight = maxLineHeight; }
397+ 
398+ SkScalar getMinLineHeight() const { return fMinLineHeight; }
399+ 
400+ void setMinLineHeight(SkScalar minLineHeight) { fMinLineHeight = minLineHeight; }
401+ 
402+ LineHeightStyle getLineHeightStyle() const { return fLineHeightStyle; }
403+ 
404+ void setLineHeightStyle(LineHeightStyle lineHeightStyle) { fLineHeightStyle = lineHeightStyle; }
405+ 
406+ bool equalsByTextShadow(const TextStyle& other) const;
407+ 
408+ bool equalsByFontFeatures(const TextStyle& other) const;
409+ 
410+ bool equalsByShape(const TextStyle& other) const;
386#endif411#endif
387private:412private:
388 static const std::vector<SkString>* kDefaultFontFamilies;413 static const std::vector<SkString>* kDefaultFontFamilies;
@@ -424,6 +449,9 @@ private:
424 SkColor fStyleId = {0};449 SkColor fStyleId = {0};
425 size_t fTextStyleUid{0};450 size_t fTextStyleUid{0};
426 SkScalar fVerticalAlignShift{0.0f};451 SkScalar fVerticalAlignShift{0.0f};
452+ SkScalar fMaxLineHeight{std::numeric_limits<float>::max()};
453+ SkScalar fMinLineHeight{0.0f};
454+ LineHeightStyle fLineHeightStyle{LineHeightStyle::kFontSize};
427#endif455#endif
428 456 
429 TextBaseline fTextBaseline = TextBaseline::kAlphabetic;457 TextBaseline fTextBaseline = TextBaseline::kAlphabetic;
Mm133/modules/skparagraph/src/ParagraphCache.cpp+4-0
@@ -153,6 +153,7 @@ void ParagraphCacheKey::computeHashMix(uint32_t& hash) const {
153 hash = mix(hash, SkGoodHash()(fParagraphStyle.getIsEndAddParagraphSpacing()));153 hash = mix(hash, SkGoodHash()(fParagraphStyle.getIsEndAddParagraphSpacing()));
154 hash = mix(hash, SkGoodHash()(fParagraphStyle.getEnableAutoSpace()));154 hash = mix(hash, SkGoodHash()(fParagraphStyle.getEnableAutoSpace()));
155 hash = mix(hash, SkGoodHash()(fParagraphStyle.getVerticalAlignment()));155 hash = mix(hash, SkGoodHash()(fParagraphStyle.getVerticalAlignment()));
156+ hash = mix(hash, SkGoodHash()(relax(fParagraphStyle.getLineSpacing())));
156 157 
157 auto& strutStyle = fParagraphStyle.getStrutStyle();158 auto& strutStyle = fParagraphStyle.getStrutStyle();
158 if (strutStyle.getStrutEnabled()) {159 if (strutStyle.getStrutEnabled()) {
@@ -211,6 +212,9 @@ uint32_t ParagraphCacheKey::computeHash() const {
211 hash = mix(hash, SkGoodHash()(ts.fRange));212 hash = mix(hash, SkGoodHash()(ts.fRange));
212 hash = mix(hash, SkGoodHash()(ts.fStyle.getTextBadgeType()));213 hash = mix(hash, SkGoodHash()(ts.fStyle.getTextBadgeType()));
213 hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getTotalVerticalShift())));214 hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getTotalVerticalShift())));
215+ hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getMaxLineHeight())));
216+ hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getMinLineHeight())));
217+ hash = mix(hash, SkGoodHash()(ts.fStyle.getLineHeightStyle()));
214 }218 }
215 219 
216 computeHashMix(hash);220 computeHashMix(hash);
Mm133/modules/skparagraph/src/ParagraphImpl.cpp+3-0
@@ -1277,6 +1277,9 @@ void ParagraphImpl::positionShapedTextIntoLine(SkScalar maxWidth) {
1277 } while (trailingSpaces != 0);1277 } while (trailingSpaces != 0);
1278 1278 
1279 advance.fY = metrics.height();1279 advance.fY = metrics.height();
1280+ if (this->paragraphStyle().getLineSpacing() > 0 && !disableLastDescent) {
1281+ advance.fY += this->paragraphStyle().getLineSpacing();
1282+ }
1280 SkScalar heightWithParagraphSpacing = advance.fY;1283 SkScalar heightWithParagraphSpacing = advance.fY;
FTL1ghtliumingxiang
FTL1ghtFTL1ght2025年8月28日

clone是不是忘记加了

paragraph 才有 cloneSelf

likedislike
liumingxiangliumingxiang2025年8月28日

clone是不是忘记加了

likedislike
1281 if (this->paragraphStyle().getIsEndAddParagraphSpacing() &&1284 if (this->paragraphStyle().getIsEndAddParagraphSpacing() &&
1282 this->paragraphStyle().getParagraphSpacing() > 0) {1285 this->paragraphStyle().getParagraphSpacing() > 0) {
Mm133/modules/skparagraph/src/Run.cpp+51-6
@@ -200,6 +200,7 @@ Run::Run(ParagraphImpl* owner,
200 metricsIncludeFontPadding(&fFontMetrics, decompressFont);200 metricsIncludeFontPadding(&fFontMetrics, decompressFont);
201 auto config = findCompressionConfigWithFont(decompressFont);201 auto config = findCompressionConfigWithFont(decompressFont);
202 fCompressionBaselineShift = (fFontMetrics.fDescent - fFontMetrics.fAscent) * config.baselineShiftScale;202 fCompressionBaselineShift = (fFontMetrics.fDescent - fFontMetrics.fAscent) * config.baselineShiftScale;
203+ initLimitHeightParam();
203#endif204#endif
204 205 
205 this->calculateMetrics();206 this->calculateMetrics();
@@ -222,21 +223,65 @@ Run::Run(ParagraphImpl* owner,
222 fPlaceholderIndex = std::numeric_limits<size_t>::max();223 fPlaceholderIndex = std::numeric_limits<size_t>::max();
223}224}
224 225 
226+#ifdef ENABLE_TEXT_ENHANCE
227+void Run::initLimitHeightParam() {
228+ if (fOwner == nullptr) {
229+ return;
230+ }
231+ 
232+ BlockRange blockRange = fOwner->findAllBlocks(fTextRange);
233+ const SkSpan<Block>& blocks = fOwner->blocks(blockRange);
234+ // Preprocessing has been completed, and within the same run,
235+ // all textstyle's minLineHeight, maxLineHeight, and lineHeightStyle are equal.
236+ if (!blocks.empty()) {
237+ const TextStyle& style = blocks.front().fStyle;
238+ setLineHeightStyle(style.getLineHeightStyle());
239+ style.getMaxLineHeight() > 0 ?
240+ setMaxLineHeight(style.getMaxLineHeight()) : setMaxLineHeight(std::numeric_limits<float>::max());
241+ setMinLineHeight(style.getMinLineHeight());
242+ }
243+}
244+ 
245+void Run::calculateMetricsWithoutHeightScale() {
246+ if (nearlyZero(fFont.GetSize())) {
247+ return;
248+ }
249+ SkScalar originRunHeight = fCorrectDescent - fCorrectAscent;
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

getMaxLineHeight按理不应返回小于0的情况,直接在set函数里限制小于0的修改就行

likedislike
FTL1ghtFTL1ght2025年8月27日

getMaxLineHeight按理不应返回小于0的情况,直接在set函数里限制小于0的修改就行

开发者设定值理论不应该改变,由对外 get 接口需要返回该值

likedislike
250+ SkScalar runHeight = std::min(std::max(originRunHeight, getMinLineHeight()), getMaxLineHeight());
251+ const auto multiplier = nearlyZero(originRunHeight) ? 0 : runHeight / originRunHeight;
252+ fCorrectAscent *= multiplier;
253+ fCorrectDescent *= multiplier;
254+}
255+#endif
256+ 
225void Run::calculateMetrics() {257void Run::calculateMetrics() {
226 fCorrectAscent = fFontMetrics.fAscent - fFontMetrics.fLeading * 0.5;258 fCorrectAscent = fFontMetrics.fAscent - fFontMetrics.fLeading * 0.5;
227 fCorrectDescent = fFontMetrics.fDescent + fFontMetrics.fLeading * 0.5;259 fCorrectDescent = fFontMetrics.fDescent + fFontMetrics.fLeading * 0.5;
228 fCorrectLeading = 0;260 fCorrectLeading = 0;
261+#ifdef ENABLE_TEXT_ENHANCE
262+ if (SkScalarNearlyZero(fHeightMultiplier)) {
263+ calculateMetricsWithoutHeightScale();
264+ return;
265+ }
266+ auto decompressFont = fFont;
267+ scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
268+ const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;
269+ if (nearlyZero(fontIntrinsicHeight)) {
270+ return;
271+ }
272+ SkScalar runHeight = fLineHeightStyle == LineHeightStyle::kFontSize ?
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

runHeight 什么场景会小于0?

那小于0时,就不需要满足在getMinLineHeight~getMaxLineHeight的范围了吗

likedislike
FTL1ghtFTL1ght2025年8月27日

runHeight 什么场景会小于0?

follow 以前逻辑,如果不做特别处理,会产生变更

likedislike
273+ fHeightMultiplier * decompressFont.GetSize() : fHeightMultiplier * fontIntrinsicHeight;
274+ // If the maxLineHeight is less than 0, it is meaningless and the it is set to max of type float
liumingxiang
liumingxiangliumingxiang2025年8月26日

特殊处理加个注释

likedislike
275+ if (runHeight >= 0) {
276+ runHeight = std::min(std::max(runHeight, getMinLineHeight()), getMaxLineHeight());
277+ }
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

runHeight 什么场景会小于0?

likedislike
FTL1ghtFTL1ght2025年8月27日

runHeight 什么场景会小于0?

heightScale < 0

likedislike
278+#else
229 if (SkScalarNearlyZero(fHeightMultiplier)) {279 if (SkScalarNearlyZero(fHeightMultiplier)) {
230 return;280 return;
231 }281 }
232-#ifdef ENABLE_TEXT_ENHANCE
233- auto decompressFont = fFont;
234- scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
235- const auto runHeight = fHeightMultiplier * decompressFont.GetSize();
236-#else
237 const auto runHeight = fHeightMultiplier * fFont.getSize();282 const auto runHeight = fHeightMultiplier * fFont.getSize();
238-#endif
239 const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;283 const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;
284+#endif
240 if (fUseHalfLeading) {285 if (fUseHalfLeading) {
241 const auto extraLeading = (runHeight - fontIntrinsicHeight) / 2;286 const auto extraLeading = (runHeight - fontIntrinsicHeight) / 2;
242 fCorrectAscent -= extraLeading;287 fCorrectAscent -= extraLeading;
Mm133/modules/skparagraph/src/Run.h+11-0
@@ -149,6 +149,8 @@ public:
149 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }149 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
150#ifdef ENABLE_TEXT_ENHANCE150#ifdef ENABLE_TEXT_ENHANCE
151 size_t globalClusterIndex(size_t pos) const;151 size_t globalClusterIndex(size_t pos) const;
152+ void initLimitHeightParam();
153+ void calculateMetricsWithoutHeightScale();
152#else154#else
153 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }155 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }
154#endif156#endif
@@ -268,6 +270,12 @@ public:
268 void setIndexInLine(size_t index) { indexInLine = index; }270 void setIndexInLine(size_t index) { indexInLine = index; }
269 SkScalar getVerticalAlignShift() const { return fVerticalAlignShift; }271 SkScalar getVerticalAlignShift() const { return fVerticalAlignShift; }
270 void setVerticalAlignShift(SkScalar verticalAlignShift) { fVerticalAlignShift = verticalAlignShift; }272 void setVerticalAlignShift(SkScalar verticalAlignShift) { fVerticalAlignShift = verticalAlignShift; }
273+ SkScalar getMaxLineHeight() const { return fMaxLineHeight; }
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

这几个属性值为什么要放run对象里,block的style拿不到吗

likedislike
FTL1ghtFTL1ght2025年8月27日

这几个属性值为什么要放run对象里,block的style拿不到吗

多个函数中使用,如果每次都在 textStyle 中取会比较麻烦

likedislike
274+ void setMaxLineHeight(SkScalar maxLineHeight) { fMaxLineHeight = maxLineHeight; }
275+ SkScalar getMinLineHeight() const { return fMinLineHeight; }
276+ void setMinLineHeight(SkScalar minLineHeight) { fMinLineHeight = minLineHeight; }
277+ LineHeightStyle getLineHeightStyle() const { return fLineHeightStyle; }
278+ void setLineHeightStyle(LineHeightStyle lineHeightStyle) { fLineHeightStyle = lineHeightStyle; }
271#endif279#endif
272private:280private:
273 friend class ParagraphImpl;281 friend class ParagraphImpl;
@@ -336,6 +344,9 @@ private:
336 size_t indexInLine;344 size_t indexInLine;
337 SkScalar fCompressionBaselineShift{0.0f};345 SkScalar fCompressionBaselineShift{0.0f};
338 SkScalar fVerticalAlignShift{0.0f};346 SkScalar fVerticalAlignShift{0.0f};
347+ SkScalar fMaxLineHeight{std::numeric_limits<float>::max()};
348+ SkScalar fMinLineHeight{0.0f};
349+ LineHeightStyle fLineHeightStyle{LineHeightStyle::kFontSize};
339#endif350#endif
340};351};
341 352 
Mm133/modules/skparagraph/src/TextStyle.cpp+91-15
@@ -56,6 +56,68 @@ TextStyle TextStyle::cloneForPlaceholder() {
56 return result;56 return result;
57}57}
58 58 
59+#ifdef ENABLE_TEXT_ENHANCE
60+bool TextStyle::equalsByTextShadow(const TextStyle& other) const {
61+ if (fTextShadows.size() != other.fTextShadows.size()) {
62+ return false;
63+ }
64+ for (size_t i = 0; i < fTextShadows.size(); ++i) {
65+ if (fTextShadows[i] != other.fTextShadows[i]) {
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

fTextShadows和下面的fFontFeatures均是vector,equal判断是否需要包序?比如:featuresA为 [{A,1},{B,1}]与featuresB为[{B,1},{A,1}],两个应用返回true还是false

likedislike
FTL1ghtFTL1ght2025年8月27日

fTextShadows和下面的fFontFeatures均是vector,equal判断是否需要包序?比如:featuresA为 [{A,1},{B,1}]与featuresB为[{B,1},{A,1}],两个应用返回true还是false

fTextShadows vector 内元素顺序决定了绘制顺序, features 顺序不影响效果 此处只是移动代码, 未修改原始逻辑, 建议后续统一整改

likedislike
66+ return false;
67+ }
68+ }
69+ return true;
70+}
71+ 
72+bool TextStyle::equalsByFontFeatures(const TextStyle& other) const {
73+ if (fFontFeatures.size() != other.fFontFeatures.size()) {
74+ return false;
75+ }
76+ for (size_t i = 0; i < fFontFeatures.size(); ++i) {
77+ if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
liumingxiangFTL1ght
liumingxiangliumingxiang2025年8月26日

fFontFeatures[i] != other.fFontFeatures[i]

likedislike
FTL1ghtFTL1ght2025年8月27日

fFontFeatures[i] != other.fFontFeatures[i]

fFontFeatures[i] 是结构体,没有重载 !=

likedislike
78+ return false;
79+ }
80+ }
81+ return true;
82+}
83+ 
84+bool TextStyle::equalsByShape(const TextStyle& other) const {
85+ return fFontStyle == other.fFontStyle &&
86+ fLocale == other.fLocale &&
87+ fFontFamilies == other.fFontFamilies &&
88+ getCorrectFontSize() == other.getCorrectFontSize() &&
89+ fHeightOverride == other.fHeightOverride &&
90+ fHeight == other.fHeight &&
91+ fHalfLeading == other.fHalfLeading &&
92+ nearlyEqual(getTotalVerticalShift(), other.getTotalVerticalShift()) &&
93+ fFontArguments == other.fFontArguments &&
94+ fStyleId == other.fStyleId &&
95+ fBackgroundRect == other.fBackgroundRect &&
96+ nearlyEqual(fBaselineShift, other.fBaselineShift) &&
97+ nearlyEqual(fMaxLineHeight, other.fMaxLineHeight) &&
98+ nearlyEqual(fMinLineHeight, other.fMinLineHeight) &&
99+ fLineHeightStyle == other.fLineHeightStyle &&
100+ fBadgeType == other.fBadgeType;
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

跟塑形相关的还有字体特征,是否需要添加

likedislike
FTL1ghtFTL1ght2025年8月27日

跟塑形相关的还有字体特征,是否需要添加

原有逻辑未添加, 建议后续酌情添加

likedislike
101+}
102+ 
103+bool TextStyle::equals(const TextStyle& other) const {
104+ if (fIsPlaceholder || other.fIsPlaceholder) {
GMiao522FTL1ght
GMiao522GMiao5222025年8月27日

占位符为什么就不参与textstyle的对比了?如果需要排除,在函数命名中体现出来

likedislike
FTL1ghtFTL1ght2025年8月27日

占位符为什么就不参与textstyle的对比了?如果需要排除,在函数命名中体现出来

原有逻辑

likedislike
105+ return false;
106+ }
107+ 
108+ return fColor == other.fColor &&
109+ fDecoration == other.fDecoration &&
110+ nearlyEqual(fLetterSpacing, other.fLetterSpacing) &&
111+ nearlyEqual(fWordSpacing, other.fWordSpacing) &&
112+ fHasForeground == other.fHasForeground &&
113+ fForeground == other.fForeground &&
114+ fHasBackground == other.fHasBackground &&
115+ fBackground == other.fBackground &&
116+ equalsByFontFeatures(other) &&
117+ equalsByTextShadow(other) &&
118+ equalsByShape(other);
119+}
120+#else
59bool TextStyle::equals(const TextStyle& other) const {121bool TextStyle::equals(const TextStyle& other) const {
60 122 
61 if (fIsPlaceholder || other.fIsPlaceholder) {123 if (fIsPlaceholder || other.fIsPlaceholder) {
@@ -123,13 +185,9 @@ bool TextStyle::equals(const TextStyle& other) const {
123 if (fFontArguments != other.fFontArguments) {185 if (fFontArguments != other.fFontArguments) {
124 return false;186 return false;
125 }187 }
126-#ifdef ENABLE_TEXT_ENHANCE
127- if (fStyleId != other.fStyleId || fBackgroundRect != other.fBackgroundRect) {
128- return false;
129- }
130-#endif
131 return true;188 return true;
132}189}
190+#endif
133 191 
134bool TextStyle::equalsByFonts(const TextStyle& that) const {192bool TextStyle::equalsByFonts(const TextStyle& that) const {
135 193 
@@ -152,6 +210,33 @@ bool TextStyle::equalsByFonts(const TextStyle& that) const {
152#endif210#endif
153}211}
154 212 
213+#ifdef ENABLE_TEXT_ENHANCE
214+bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
215+ switch (styleType) {
216+ case kForeground:
217+ return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
218+ (fHasForeground && other.fHasForeground && fForeground == other.fForeground);
liumingxiangFTL1ght
liumingxiangliumingxiang2025年8月26日

(后面的空格去掉

likedislike
FTL1ghtFTL1ght2025年8月27日

(后面的空格去掉

原生代码

likedislike
219+ case kBackground:
220+ return (!fHasBackground && !other.fHasBackground) ||
221+ (fHasBackground && other.fHasBackground && fBackground == other.fBackground);
liumingxiang
liumingxiangliumingxiang2025年8月26日

(后面的空格去掉

likedislike
222+ case kShadow:
223+ return equalsByTextShadow(other);
224+ case kDecorations:
225+ return this->fDecoration == other.fDecoration;
226+ case kLetterSpacing:
227+ return fLetterSpacing == other.fLetterSpacing;
228+ case kWordSpacing:
229+ return fWordSpacing == other.fWordSpacing;
230+ case kAllAttributes:
231+ return this->equals(other);
232+ case kFont:
233+ return equalsByShape(other);
234+ default:
235+ SkASSERT(false);
236+ return false;
237+ }
238+}
239+#else
155bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {240bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
156 switch (styleType) {241 switch (styleType) {
157 case kForeground:242 case kForeground:
@@ -191,26 +276,17 @@ bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) c
191 return fFontStyle == other.fFontStyle &&276 return fFontStyle == other.fFontStyle &&
192 fLocale == other.fLocale &&277 fLocale == other.fLocale &&
193 fFontFamilies == other.fFontFamilies &&278 fFontFamilies == other.fFontFamilies &&
194-#ifdef ENABLE_TEXT_ENHANCE
195- getCorrectFontSize() == other.getCorrectFontSize() &&
196- fHeight == other.fHeight &&
197- fHalfLeading == other.fHalfLeading &&
198- getTotalVerticalShift() == other.getTotalVerticalShift() &&
199- fFontArguments == other.fFontArguments &&
200- fStyleId == other.fStyleId &&
201- fBackgroundRect == other.fBackgroundRect;
202-#else
203 fFontSize == other.fFontSize &&279 fFontSize == other.fFontSize &&
204 fHeight == other.fHeight &&280 fHeight == other.fHeight &&
205 fHalfLeading == other.fHalfLeading &&281 fHalfLeading == other.fHalfLeading &&
206 fBaselineShift == other.fBaselineShift &&282 fBaselineShift == other.fBaselineShift &&
207 fFontArguments == other.fFontArguments;283 fFontArguments == other.fFontArguments;
208-#endif
209 default:284 default:
210 SkASSERT(false);285 SkASSERT(false);
211 return false;286 return false;
212 }287 }
213}288}
289+#endif
214 290 
215#ifdef ENABLE_TEXT_ENHANCE291#ifdef ENABLE_TEXT_ENHANCE
216void TextStyle::getFontMetrics(RSFontMetrics* metrics) const {292void TextStyle::getFontMetrics(RSFontMetrics* metrics) const {
Mm133/modules/skparagraph/src/TextWrapper.cpp+20-9
@@ -955,6 +955,8 @@ void TextWrapper::layoutLinesSimple(ParagraphImpl* parent,
955 auto disableFirstAscent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent;955 auto disableFirstAscent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent;
956 auto disableLastDescent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent;956 auto disableLastDescent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent;
957 bool firstLine = true; // We only interested in fist line if we have to disable the first ascent957 bool firstLine = true; // We only interested in fist line if we have to disable the first ascent
958+ SkScalar lineSpacing = parent->paragraphStyle().getLineSpacing();
959+ bool needLineSpacing = lineSpacing > 0;
958 960 
959 // Resolve balanced line widths961 // Resolve balanced line widths
960 std::vector<SkScalar> balancedWidths;962 std::vector<SkScalar> balancedWidths;
@@ -1050,6 +1052,7 @@ void TextWrapper::layoutLinesSimple(ParagraphImpl* parent,
1050 }1052 }
1051 if (disableLastDescent && (lastLine || (startLine == end && !fHardLineBreak))) {1053 if (disableLastDescent && (lastLine || (startLine == end && !fHardLineBreak))) {
1052 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;1054 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;
1055+ needLineSpacing = false;
1053 }1056 }
1054 1057 
1055 if (parent->strutEnabled()) {1058 if (parent->strutEnabled()) {
@@ -1058,6 +1061,9 @@ void TextWrapper::layoutLinesSimple(ParagraphImpl* parent,
1058 }1061 }
1059 1062 
1060 SkScalar lineHeight = fEndLine.metrics().height();1063 SkScalar lineHeight = fEndLine.metrics().height();
1064+ if (needLineSpacing) {
1065+ lineHeight += lineSpacing;
1066+ }
1061 if (fHardLineBreak && !lastLine && parent->paragraphStyle().getParagraphSpacing() > 0) {1067 if (fHardLineBreak && !lastLine && parent->paragraphStyle().getParagraphSpacing() > 0) {
1062 lineHeight += parent->paragraphStyle().getParagraphSpacing();1068 lineHeight += parent->paragraphStyle().getParagraphSpacing();
1063 }1069 }
@@ -1494,7 +1500,9 @@ void TextWrapper::initializeFormattingState(SkScalar maxWidth, const SkSpan<Clus
1494 style.getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent,1500 style.getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent,
1495 style.getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent,1501 style.getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent,
1496 style.getMaxLines(),1502 style.getMaxLines(),
1497- style.effective_align()};1503+ style.effective_align(),
1504+ fParent->paragraphStyle().getLineSpacing() > 0,
1505+ fParent->paragraphStyle().getLineSpacing()};
1498 1506 
1499 fFirstLine = true;1507 fFirstLine = true;
1500 fSoftLineMaxIntrinsicWidth = 0;1508 fSoftLineMaxIntrinsicWidth = 0;
@@ -1517,14 +1525,13 @@ void TextWrapper::processLineStretches(SkScalar maxWidth, const AddLineToParagra
1517}1525}
1518 1526 
1519void TextWrapper::finalizeTextLayout(const AddLineToParagraph& addLine) {1527void TextWrapper::finalizeTextLayout(const AddLineToParagraph& addLine) {
1520- processRemainingClusters();
1521- addFinalLineBreakIfNeeded(addLine);
1522- adjustFirstLastLineMetrics();
1523- 
1524 if (fParent->paragraphStyle().getIsEndAddParagraphSpacing() &&1528 if (fParent->paragraphStyle().getIsEndAddParagraphSpacing() &&
1525 fParent->paragraphStyle().getParagraphSpacing() > 0) {1529 fParent->paragraphStyle().getParagraphSpacing() > 0) {
1526 fHeight += fParent->paragraphStyle().getParagraphSpacing();1530 fHeight += fParent->paragraphStyle().getParagraphSpacing();
1527 }1531 }
1532+ processRemainingClusters();
1533+ addFinalLineBreakIfNeeded(addLine);
1534+ adjustFirstLastLineMetrics();
1528}1535}
1529 1536 
1530void TextWrapper::prepareLineForFormatting(TextStretch& line) {1537void TextWrapper::prepareLineForFormatting(TextStretch& line) {
@@ -1541,10 +1548,10 @@ void TextWrapper::formatCurrentLine(const AddLineToParagraph& addLine) {
1541}1548}
1542 1549 
1543bool TextWrapper::determineIfEllipsisNeeded() {1550bool TextWrapper::determineIfEllipsisNeeded() {
1544- bool lastLine = (fFormattingContext.hasEllipsis && fFormattingContext.unlimitedLines) ||1551+ fIsLastLine = (fFormattingContext.hasEllipsis && fFormattingContext.unlimitedLines) ||
1545 fLineNumber >= fFormattingContext.maxLines;1552 fLineNumber >= fFormattingContext.maxLines;
1546 bool needEllipsis =1553 bool needEllipsis =
1547- fFormattingContext.hasEllipsis && !fFormattingContext.endlessLine && lastLine;1554+ fFormattingContext.hasEllipsis && !fFormattingContext.endlessLine && fIsLastLine;
1548 1555 
1549 if (fParent->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD &&1556 if (fParent->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD &&
1550 fFormattingContext.hasEllipsis) {1557 fFormattingContext.hasEllipsis) {
@@ -1593,8 +1600,9 @@ void TextWrapper::adjustLineMetricsForFirstLastLine() {
1593 if (fFormattingContext.disableFirstAscent && fFirstLine) {1600 if (fFormattingContext.disableFirstAscent && fFirstLine) {
1594 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;1601 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;
1595 }1602 }
1596- if (fFormattingContext.disableLastDescent && isLastLine()) {1603+ if (fFormattingContext.disableLastDescent && (fIsLastLine || (fCurrentStartLine == fEnd && !fHardLineBreak))) {
liumingxiang
liumingxiangliumingxiang2025年8月28日

||(之间加空格

likedislike
1597 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;1604 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;
1605+ fFormattingContext.needLineSpacing = false;
1598 }1606 }
1599}1607}
1600 1608 
@@ -1639,6 +1647,9 @@ TextWrapper::LineTextRanges TextWrapper::calculateLineTextRanges() {
1639 1647 
1640SkScalar TextWrapper::calculateLineHeight() {1648SkScalar TextWrapper::calculateLineHeight() {
1641 SkScalar height = fEndLine.metrics().height();1649 SkScalar height = fEndLine.metrics().height();
1650+ if (fFormattingContext.needLineSpacing) {
1651+ height += fFormattingContext.lineSpacing;
1652+ }
1642 if (fHardLineBreak && !isLastLine() && fParent->paragraphStyle().getParagraphSpacing() > 0) {1653 if (fHardLineBreak && !isLastLine() && fParent->paragraphStyle().getParagraphSpacing() > 0) {
1643 height += fParent->paragraphStyle().getParagraphSpacing();1654 height += fParent->paragraphStyle().getParagraphSpacing();
1644 }1655 }
@@ -1768,7 +1779,7 @@ void TextWrapper::adjustMetricsForEmptyParagraph() {
1768 if (fFormattingContext.disableFirstAscent) {1779 if (fFormattingContext.disableFirstAscent) {
1769 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;1780 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;
1770 }1781 }
1771- if (fFormattingContext.disableLastDescent && !fHardLineBreak) {1782+ if (fFormattingContext.disableLastDescent && (fIsLastLine || (fEndLine.endCluster() == fEnd && !fHardLineBreak))) {
1772 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;1783 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;
1773 }1784 }
1774}1785}
Mm133/modules/skparagraph/src/TextWrapper.h+3-0
@@ -265,6 +265,8 @@ private:
265 bool disableLastDescent{false};265 bool disableLastDescent{false};
266 size_t maxLines{0};266 size_t maxLines{0};
267 TextAlign align{TextAlign::kLeft};267 TextAlign align{TextAlign::kLeft};
268+ bool needLineSpacing{false};
269+ SkScalar lineSpacing{0.0f};
268 };270 };
269 271 
270 struct LineTextRanges {272 struct LineTextRanges {
@@ -407,6 +409,7 @@ private:
407 size_t fCurrentStartPos{0};409 size_t fCurrentStartPos{0};
408 Cluster* fStart{nullptr};410 Cluster* fStart{nullptr};
409 Cluster* fEnd{nullptr};411 Cluster* fEnd{nullptr};
412+ bool fIsLastLine{false};
410#endif413#endif
411};414};
412} // namespace textlayout415} // namespace textlayout
Mmodules/skparagraph/include/ParagraphStyle.h+4-0
@@ -152,6 +152,7 @@ struct ParagraphStyle {
152 this->fIsTrailingSpaceOptimized == rhs.fIsTrailingSpaceOptimized &&152 this->fIsTrailingSpaceOptimized == rhs.fIsTrailingSpaceOptimized &&
153 this->fEnableAutoSpace == rhs.fEnableAutoSpace &&153 this->fEnableAutoSpace == rhs.fEnableAutoSpace &&
154 this->fVerticalAlignment == rhs.fVerticalAlignment &&154 this->fVerticalAlignment == rhs.fVerticalAlignment &&
155+ this->fLineSpacing == rhs.fLineSpacing &&
155#endif156#endif
156 nearlyEqual(this->fTextSplitRatio, rhs.fTextSplitRatio);157 nearlyEqual(this->fTextSplitRatio, rhs.fTextSplitRatio);
157 }158 }
@@ -231,6 +232,8 @@ struct ParagraphStyle {
231 {232 {
232 fEnableAutoSpace = enableAutoSpace;233 fEnableAutoSpace = enableAutoSpace;
233 }234 }
235+ SkScalar getLineSpacing() const { return fLineSpacing; }
236+ void setLineSpacing(SkScalar lineSpacing) { fLineSpacing = lineSpacing; }
234#endif237#endif
235private:238private:
236 StrutStyle fStrutStyle;239 StrutStyle fStrutStyle;
@@ -254,6 +257,7 @@ private:
254 bool fIsTrailingSpaceOptimized{false};257 bool fIsTrailingSpaceOptimized{false};
255 bool fEnableAutoSpace{false};258 bool fEnableAutoSpace{false};
256 TextVerticalAlign fVerticalAlignment{TextVerticalAlign::BASELINE};259 TextVerticalAlign fVerticalAlignment{TextVerticalAlign::BASELINE};
260+ SkScalar fLineSpacing{0.0f};
257#endif261#endif
258};262};
259} // namespace textlayout263} // namespace textlayout
Mmodules/skparagraph/include/TextStyle.h+28-0
@@ -48,6 +48,13 @@ static inline bool nearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance = SK_S
48 return x == y;48 return x == y;
49}49}
50 50 
51+#ifdef OHOS_SUPPORT
52+enum class LineHeightStyle {
53+ kFontSize,
54+ kFontHeight
55+};
56+#endif
57+ 
51// Multiple decorations can be applied at once. Ex: Underline and overline is58// Multiple decorations can be applied at once. Ex: Underline and overline is
52// (0x1 | 0x2)59// (0x1 | 0x2)
53enum TextDecoration {60enum TextDecoration {
@@ -385,6 +392,24 @@ public:
385 SkScalar getBadgeBaseLineShift() const;392 SkScalar getBadgeBaseLineShift() const;
386 393 
387 SkScalar getCorrectFontSize() const;394 SkScalar getCorrectFontSize() const;
395+ 
396+ SkScalar getMaxLineHeight() const { return fMaxLineHeight; }
397+ 
398+ void setMaxLineHeight(SkScalar maxLineHeight) { fMaxLineHeight = maxLineHeight; }
399+ 
400+ SkScalar getMinLineHeight() const { return fMinLineHeight; }
401+ 
402+ void setMinLineHeight(SkScalar minLineHeight) { fMinLineHeight = minLineHeight; }
403+ 
404+ LineHeightStyle getLineHeightStyle() const { return fLineHeightStyle; }
405+ 
406+ void setLineHeightStyle(LineHeightStyle lineHeightStyle) { fLineHeightStyle = lineHeightStyle; }
407+ 
408+ bool equalsByTextShadow(const TextStyle& other) const;
409+ 
410+ bool equalsByFontFeatures(const TextStyle& other) const;
411+ 
412+ bool equalsByShape(const TextStyle& other) const;
388#endif413#endif
389 414 
390private:415private:
@@ -421,6 +446,9 @@ private:
421#ifdef OHOS_SUPPORT446#ifdef OHOS_SUPPORT
422 size_t fTextStyleUid{0};447 size_t fTextStyleUid{0};
423 SkScalar fVerticalAlignShift{0.0f};448 SkScalar fVerticalAlignShift{0.0f};
449+ SkScalar fMaxLineHeight{std::numeric_limits<float>::max()};
450+ SkScalar fMinLineHeight{0.0f};
451+ LineHeightStyle fLineHeightStyle{LineHeightStyle::kFontSize};
424#endif452#endif
425 SkScalar fLetterSpacing = 0.0;453 SkScalar fLetterSpacing = 0.0;
426 SkScalar fWordSpacing = 0.0;454 SkScalar fWordSpacing = 0.0;
Mmodules/skparagraph/src/ParagraphCache.cpp+4-0
@@ -175,11 +175,15 @@ uint32_t hash = 0;
175#ifdef OHOS_SUPPORT175#ifdef OHOS_SUPPORT
176 hash = mix(hash, SkGoodHash()(ts.fStyle.getTextBadgeType()));176 hash = mix(hash, SkGoodHash()(ts.fStyle.getTextBadgeType()));
177 hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getTotalVerticalShift())));177 hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getTotalVerticalShift())));
178+ hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getMaxLineHeight())));
179+ hash = mix(hash, SkGoodHash()(relax(ts.fStyle.getMinLineHeight())));
180+ hash = mix(hash, SkGoodHash()(ts.fStyle.getLineHeightStyle()));
178#endif181#endif
179 }182 }
180 183 
181#ifdef OHOS_SUPPORT184#ifdef OHOS_SUPPORT
182 hash = mix(hash, SkGoodHash()(fParagraphStyle.getVerticalAlignment()));185 hash = mix(hash, SkGoodHash()(fParagraphStyle.getVerticalAlignment()));
186+ hash = mix(hash, SkGoodHash()(relax(fParagraphStyle.getLineSpacing())));
183#endif187#endif
184 hash = mix(hash, SkGoodHash()(relax(fParagraphStyle.getHeight())));188 hash = mix(hash, SkGoodHash()(relax(fParagraphStyle.getHeight())));
185 hash = mix(hash, SkGoodHash()(fParagraphStyle.getTextDirection()));189 hash = mix(hash, SkGoodHash()(fParagraphStyle.getTextDirection()));
Mmodules/skparagraph/src/ParagraphImpl.cpp+3-0
@@ -1197,6 +1197,9 @@ void ParagraphImpl::positionShapedTextIntoLine(SkScalar maxWidth) {
1197 } while (trailingSpaces != 0);1197 } while (trailingSpaces != 0);
1198 1198 
1199 advance.fY = metrics.height();1199 advance.fY = metrics.height();
1200+ if (this->paragraphStyle().getLineSpacing() > 0 && !disableLastDescent) {
1201+ advance.fY += this->paragraphStyle().getLineSpacing();
1202+ }
1200 SkScalar heightWithParagraphSpacing = advance.fY;1203 SkScalar heightWithParagraphSpacing = advance.fY;
1201 if (this->paragraphStyle().getIsEndAddParagraphSpacing() &&1204 if (this->paragraphStyle().getIsEndAddParagraphSpacing() &&
1202 this->paragraphStyle().getParagraphSpacing() > 0) {1205 this->paragraphStyle().getParagraphSpacing() > 0) {
Mmodules/skparagraph/src/Run.cpp+46-2
@@ -248,6 +248,7 @@ Run::Run(ParagraphImpl* owner,
248 metricsIncludeFontPadding(&fFontMetrics, decompressFont);248 metricsIncludeFontPadding(&fFontMetrics, decompressFont);
249 auto config = findCompressionConfigWithFont(decompressFont);249 auto config = findCompressionConfigWithFont(decompressFont);
250 fCompressionBaselineShift = (fFontMetrics.fDescent - fFontMetrics.fAscent) * config.baselineShiftScale;250 fCompressionBaselineShift = (fFontMetrics.fDescent - fFontMetrics.fAscent) * config.baselineShiftScale;
251+ initLimitHeightParam();
251#endif252#endif
252 253 
253 this->calculateMetrics();254 this->calculateMetrics();
@@ -270,6 +271,37 @@ Run::Run(ParagraphImpl* owner,
270 fPlaceholderIndex = std::numeric_limits<size_t>::max();271 fPlaceholderIndex = std::numeric_limits<size_t>::max();
271}272}
272 273 
274+#ifdef OHOS_SUPPORT
275+void Run::initLimitHeightParam() {
276+ if (fOwner == nullptr) {
277+ return;
278+ }
279+ 
280+ BlockRange blockRange = fOwner->findAllBlocks(fTextRange);
281+ const SkSpan<Block>& blocks = fOwner->blocks(blockRange);
282+ // Preprocessing has been completed, and within the same run,
283+ // all textstyle's minLineHeight, maxLineHeight, and lineHeightStyle are equal.
284+ if (!blocks.empty()) {
285+ const TextStyle& style = blocks.front().fStyle;
286+ setLineHeightStyle(style.getLineHeightStyle());
287+ style.getMaxLineHeight() > 0 ?
288+ setMaxLineHeight(style.getMaxLineHeight()) : setMaxLineHeight(std::numeric_limits<float>::max());
289+ setMinLineHeight(style.getMinLineHeight());
290+ }
291+}
292+ 
293+void Run::calculateMetricsWithoutHeightScale() {
294+ if (nearlyZero(fFont.GetSize())) {
295+ return;
296+ }
297+ SkScalar originRunHeight = fCorrectDescent - fCorrectAscent;
298+ SkScalar runHeight = std::min(std::max(originRunHeight, getMinLineHeight()), getMaxLineHeight());
299+ const auto multiplier = nearlyZero(originRunHeight) ? 0 : runHeight / originRunHeight;
liumingxiang
liumingxiangliumingxiang2025年8月28日

可能是0吗?

likedislike
300+ fCorrectAscent *= multiplier;
301+ fCorrectDescent *= multiplier;
302+}
303+#endif
304+ 
273void Run::calculateMetrics() {305void Run::calculateMetrics() {
274 fCorrectAscent = fFontMetrics.fAscent - fFontMetrics.fLeading * 0.5;306 fCorrectAscent = fFontMetrics.fAscent - fFontMetrics.fLeading * 0.5;
275 fCorrectDescent = fFontMetrics.fDescent + fFontMetrics.fLeading * 0.5;307 fCorrectDescent = fFontMetrics.fDescent + fFontMetrics.fLeading * 0.5;
@@ -279,12 +311,24 @@ void Run::calculateMetrics() {
279 }311 }
280#ifndef USE_SKIA_TXT312#ifndef USE_SKIA_TXT
281 const auto runHeight = fHeightMultiplier * fFont.getSize();313 const auto runHeight = fHeightMultiplier * fFont.getSize();
314+ const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;
282#else315#else
316+ if (SkScalarNearlyZero(fHeightMultiplier)) {
317+ calculateMetricsWithoutHeightScale();
318+ return;
319+ }
283 auto decompressFont = fFont;320 auto decompressFont = fFont;
284 scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);321 scaleFontWithCompressionConfig(decompressFont, ScaleOP::DECOMPRESS);
285- const auto runHeight = fHeightMultiplier * decompressFont.GetSize();
286-#endif
287 const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;322 const auto fontIntrinsicHeight = fCorrectDescent - fCorrectAscent;
323+ if (nearlyZero(fontIntrinsicHeight)) {
324+ return;
325+ }
326+ SkScalar runHeight = fLineHeightStyle == LineHeightStyle::kFontSize ?
327+ fHeightMultiplier * decompressFont.GetSize() : fHeightMultiplier * fontIntrinsicHeight;
328+ if (runHeight >= 0) {
329+ runHeight = std::min(std::max(runHeight, getMinLineHeight()), getMaxLineHeight());
330+ }
331+#endif
288 if (fUseHalfLeading) {332 if (fUseHalfLeading) {
289 const auto extraLeading = (runHeight - fontIntrinsicHeight) / 2;333 const auto extraLeading = (runHeight - fontIntrinsicHeight) / 2;
290 fCorrectAscent -= extraLeading;334 fCorrectAscent -= extraLeading;
Mmodules/skparagraph/src/Run.h+12-1
@@ -150,6 +150,8 @@ public:
150 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }150 size_t clusterIndex(size_t pos) const { return fClusterIndexes[pos]; }
151#ifdef OHOS_SUPPORT151#ifdef OHOS_SUPPORT
152 size_t globalClusterIndex(size_t pos) const;152 size_t globalClusterIndex(size_t pos) const;
153+ void initLimitHeightParam();
154+ void calculateMetricsWithoutHeightScale();
153#else155#else
154 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }156 size_t globalClusterIndex(size_t pos) const { return fClusterStart + fClusterIndexes[pos]; }
155#endif157#endif
@@ -218,6 +220,12 @@ public:
218 void iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor);220 void iterateGlyphRangeInTextOrder(const GlyphRange& glyphRange, Visitor visitor);
219 SkScalar getVerticalAlignShift() const { return fVerticalAlignShift; }221 SkScalar getVerticalAlignShift() const { return fVerticalAlignShift; }
220 void setVerticalAlignShift(SkScalar verticalAlignShift) { fVerticalAlignShift = verticalAlignShift; }222 void setVerticalAlignShift(SkScalar verticalAlignShift) { fVerticalAlignShift = verticalAlignShift; }
223+ SkScalar getMaxLineHeight() const { return fMaxLineHeight; }
224+ void setMaxLineHeight(SkScalar maxLineHeight) { fMaxLineHeight = maxLineHeight; }
225+ SkScalar getMinLineHeight() const { return fMinLineHeight; }
226+ void setMinLineHeight(SkScalar minLineHeight) { fMinLineHeight = minLineHeight; }
227+ LineHeightStyle getLineHeightStyle() const { return fLineHeightStyle; }
228+ void setLineHeightStyle(LineHeightStyle lineHeightStyle) { fLineHeightStyle = lineHeightStyle; }
221#endif229#endif
222 230 
223 using ClusterVisitor = std::function<void(Cluster* cluster)>;231 using ClusterVisitor = std::function<void(Cluster* cluster)>;
@@ -318,7 +326,7 @@ private:
318#else326#else
319 RSFontMetrics fFontMetrics;327 RSFontMetrics fFontMetrics;
320#endif328#endif
321- const SkScalar fHeightMultiplier;329+ SkScalar fHeightMultiplier;
322 const bool fUseHalfLeading;330 const bool fUseHalfLeading;
323 const SkScalar fBaselineShift;331 const SkScalar fBaselineShift;
324 SkScalar fCorrectAscent;332 SkScalar fCorrectAscent;
@@ -335,6 +343,9 @@ private:
335#ifdef OHOS_SUPPORT343#ifdef OHOS_SUPPORT
336 SkScalar fCompressionBaselineShift{0.0f};344 SkScalar fCompressionBaselineShift{0.0f};
337 SkScalar fVerticalAlignShift{0.0f};345 SkScalar fVerticalAlignShift{0.0f};
346+ SkScalar fMaxLineHeight{std::numeric_limits<float>::max()};
347+ SkScalar fMinLineHeight{0.0f};
348+ LineHeightStyle fLineHeightStyle{LineHeightStyle::kFontSize};
338#endif349#endif
339};350};
340 351 
Mmodules/skparagraph/src/TextStyle.cpp+91-11
@@ -52,6 +52,68 @@ TextStyle TextStyle::cloneForPlaceholder() {
52 return result;52 return result;
53}53}
54 54 
55+#ifdef OHOS_SUPPORT
56+bool TextStyle::equalsByTextShadow(const TextStyle& other) const {
57+ if (fTextShadows.size() != other.fTextShadows.size()) {
58+ return false;
59+ }
60+ for (size_t i = 0; i < fTextShadows.size(); ++i) {
61+ if (fTextShadows[i] != other.fTextShadows[i]) {
62+ return false;
63+ }
64+ }
65+ return true;
66+}
67+ 
68+bool TextStyle::equalsByFontFeatures(const TextStyle& other) const {
69+ if (fFontFeatures.size() != other.fFontFeatures.size()) {
70+ return false;
71+ }
72+ for (size_t i = 0; i < fFontFeatures.size(); ++i) {
73+ if (!(fFontFeatures[i] == other.fFontFeatures[i])) {
74+ return false;
75+ }
76+ }
77+ return true;
78+}
79+ 
80+bool TextStyle::equalsByShape(const TextStyle& other) const {
81+ return fFontStyle == other.fFontStyle &&
82+ fLocale == other.fLocale &&
83+ fFontFamilies == other.fFontFamilies &&
84+ getCorrectFontSize() == other.getCorrectFontSize() &&
85+ fHeightOverride == other.fHeightOverride &&
86+ fHeight == other.fHeight &&
87+ fHalfLeading == other.fHalfLeading &&
88+ nearlyEqual(getTotalVerticalShift(), other.getTotalVerticalShift()) &&
89+ fFontArguments == other.fFontArguments &&
90+ fStyleId == other.fStyleId &&
91+ fBackgroundRect == other.fBackgroundRect &&
92+ nearlyEqual(fBaselineShift, other.fBaselineShift) &&
93+ nearlyEqual(fMaxLineHeight, other.fMaxLineHeight) &&
94+ nearlyEqual(fMinLineHeight, other.fMinLineHeight) &&
95+ fLineHeightStyle == other.fLineHeightStyle &&
96+ fBadgeType == other.fBadgeType;
97+}
98+ 
99+bool TextStyle::equals(const TextStyle& other) const {
100+ if (fIsPlaceholder || other.fIsPlaceholder) {
101+ return false;
102+ }
103+ 
104+ return fColor == other.fColor &&
105+ fDecoration == other.fDecoration &&
106+ nearlyEqual(fLetterSpacing, other.fLetterSpacing) &&
107+ nearlyEqual(fWordSpacing, other.fWordSpacing) &&
108+ fHasForeground == other.fHasForeground &&
109+ fForeground == other.fForeground &&
110+ fHasBackground == other.fHasBackground &&
111+ fBackground == other.fBackground &&
112+ equalsByFontFeatures(other) &&
113+ equalsByTextShadow(other) &&
114+ equalsByShape(other);
115+}
116+#else
55bool TextStyle::equals(const TextStyle& other) const {117bool TextStyle::equals(const TextStyle& other) const {
56 118 
57 if (fIsPlaceholder || other.fIsPlaceholder) {119 if (fIsPlaceholder || other.fIsPlaceholder) {
@@ -119,12 +181,9 @@ bool TextStyle::equals(const TextStyle& other) const {
119 if (fFontArguments != other.fFontArguments) {181 if (fFontArguments != other.fFontArguments) {
120 return false;182 return false;
121 }183 }
122- if (fStyleId != other.fStyleId || fBackgroundRect != other.fBackgroundRect) {
123- return false;
124- }
125- 
126 return true;184 return true;
127}185}
186+#endif
128 187 
129bool TextStyle::equalsByFonts(const TextStyle& that) const {188bool TextStyle::equalsByFonts(const TextStyle& that) const {
130 189 
@@ -143,6 +202,33 @@ bool TextStyle::equalsByFonts(const TextStyle& that) const {
143 fBackgroundRect == that.fBackgroundRect;202 fBackgroundRect == that.fBackgroundRect;
144}203}
145 204 
205+#ifdef OHOS_SUPPORT
206+bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
207+ switch (styleType) {
208+ case kForeground:
209+ return (!fHasForeground && !other.fHasForeground && fColor == other.fColor) ||
210+ ( fHasForeground && other.fHasForeground && fForeground == other.fForeground);
211+ case kBackground:
212+ return (!fHasBackground && !other.fHasBackground) ||
213+ ( fHasBackground && other.fHasBackground && fBackground == other.fBackground);
214+ case kShadow:
215+ return equalsByTextShadow(other);
216+ case kDecorations:
217+ return this->fDecoration == other.fDecoration;
218+ case kLetterSpacing:
219+ return fLetterSpacing == other.fLetterSpacing;
220+ case kWordSpacing:
221+ return fWordSpacing == other.fWordSpacing;
222+ case kAllAttributes:
223+ return this->equals(other);
224+ case kFont:
225+ return equalsByShape(other);
226+ default:
227+ SkASSERT(false);
228+ return false;
229+ }
230+}
231+#else
146bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {232bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) const {
147 switch (styleType) {233 switch (styleType) {
148 case kForeground:234 case kForeground:
@@ -182,17 +268,10 @@ bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) c
182 return fFontStyle == other.fFontStyle &&268 return fFontStyle == other.fFontStyle &&
183 fLocale == other.fLocale &&269 fLocale == other.fLocale &&
184 fFontFamilies == other.fFontFamilies &&270 fFontFamilies == other.fFontFamilies &&
185-#ifdef OHOS_SUPPORT
186- getCorrectFontSize() == other.getCorrectFontSize() &&
187- fHeight == other.fHeight &&
188- fHalfLeading == other.fHalfLeading &&
189- getTotalVerticalShift() == other.getTotalVerticalShift() &&
190-#else
191 fFontSize == other.fFontSize &&271 fFontSize == other.fFontSize &&
192 fHeight == other.fHeight &&272 fHeight == other.fHeight &&
193 fHalfLeading == other.fHalfLeading &&273 fHalfLeading == other.fHalfLeading &&
194 fBaselineShift == other.fBaselineShift &&274 fBaselineShift == other.fBaselineShift &&
195-#endif
196 fFontArguments == other.fFontArguments &&275 fFontArguments == other.fFontArguments &&
197 fStyleId == other.fStyleId &&276 fStyleId == other.fStyleId &&
198 fBackgroundRect == other.fBackgroundRect;277 fBackgroundRect == other.fBackgroundRect;
@@ -201,6 +280,7 @@ bool TextStyle::matchOneAttribute(StyleType styleType, const TextStyle& other) c
201 return false;280 return false;
202 }281 }
203}282}
283+#endif
204 284 
205#ifndef USE_SKIA_TXT285#ifndef USE_SKIA_TXT
206void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {286void TextStyle::getFontMetrics(SkFontMetrics* metrics) const {
Mmodules/skparagraph/src/TextWrapper.cpp+20-9
@@ -954,6 +954,8 @@ void TextWrapper::layoutLinesSimple(ParagraphImpl* parent,
954 auto disableFirstAscent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent;954 auto disableFirstAscent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent;
955 auto disableLastDescent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent;955 auto disableLastDescent = parent->paragraphStyle().getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent;
956 bool firstLine = true; // We only interested in fist line if we have to disable the first ascent956 bool firstLine = true; // We only interested in fist line if we have to disable the first ascent
957+ SkScalar lineSpacing = parent->paragraphStyle().getLineSpacing();
958+ bool needLineSpacing = lineSpacing > 0;
957 959 
958 // Resolve balanced line widths960 // Resolve balanced line widths
959 std::vector<SkScalar> balancedWidths;961 std::vector<SkScalar> balancedWidths;
@@ -1049,6 +1051,7 @@ void TextWrapper::layoutLinesSimple(ParagraphImpl* parent,
1049 }1051 }
1050 if (disableLastDescent && (lastLine || (startLine == end && !fHardLineBreak))) {1052 if (disableLastDescent && (lastLine || (startLine == end && !fHardLineBreak))) {
1051 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;1053 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;
1054+ needLineSpacing = false;
1052 }1055 }
1053 1056 
1054 if (parent->strutEnabled()) {1057 if (parent->strutEnabled()) {
@@ -1057,6 +1060,9 @@ void TextWrapper::layoutLinesSimple(ParagraphImpl* parent,
1057 }1060 }
1058 1061 
1059 SkScalar lineHeight = fEndLine.metrics().height();1062 SkScalar lineHeight = fEndLine.metrics().height();
1063+ if (needLineSpacing) {
1064+ lineHeight += lineSpacing;
1065+ }
1060 if (fHardLineBreak && !lastLine && parent->paragraphStyle().getParagraphSpacing() > 0) {1066 if (fHardLineBreak && !lastLine && parent->paragraphStyle().getParagraphSpacing() > 0) {
1061 lineHeight += parent->paragraphStyle().getParagraphSpacing();1067 lineHeight += parent->paragraphStyle().getParagraphSpacing();
1062 }1068 }
@@ -1493,7 +1499,9 @@ void TextWrapper::initializeFormattingState(SkScalar maxWidth, const SkSpan<Clus
1493 style.getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent,1499 style.getTextHeightBehavior() & TextHeightBehavior::kDisableFirstAscent,
1494 style.getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent,1500 style.getTextHeightBehavior() & TextHeightBehavior::kDisableLastDescent,
1495 style.getMaxLines(),1501 style.getMaxLines(),
1496- style.effective_align()};1502+ style.effective_align(),
1503+ fParent->paragraphStyle().getLineSpacing() > 0,
1504+ fParent->paragraphStyle().getLineSpacing()};
1497 1505 
1498 fFirstLine = true;1506 fFirstLine = true;
1499 fSoftLineMaxIntrinsicWidth = 0;1507 fSoftLineMaxIntrinsicWidth = 0;
@@ -1516,14 +1524,13 @@ void TextWrapper::processLineStretches(SkScalar maxWidth, const AddLineToParagra
1516}1524}
1517 1525 
1518void TextWrapper::finalizeTextLayout(const AddLineToParagraph& addLine) {1526void TextWrapper::finalizeTextLayout(const AddLineToParagraph& addLine) {
1519- processRemainingClusters();
1520- addFinalLineBreakIfNeeded(addLine);
1521- adjustFirstLastLineMetrics();
1522- 
1523 if (fParent->paragraphStyle().getIsEndAddParagraphSpacing() &&1527 if (fParent->paragraphStyle().getIsEndAddParagraphSpacing() &&
1524 fParent->paragraphStyle().getParagraphSpacing() > 0) {1528 fParent->paragraphStyle().getParagraphSpacing() > 0) {
1525 fHeight += fParent->paragraphStyle().getParagraphSpacing();1529 fHeight += fParent->paragraphStyle().getParagraphSpacing();
1526 }1530 }
1531+ processRemainingClusters();
1532+ addFinalLineBreakIfNeeded(addLine);
1533+ adjustFirstLastLineMetrics();
1527}1534}
1528 1535 
1529void TextWrapper::prepareLineForFormatting(TextStretch& line) {1536void TextWrapper::prepareLineForFormatting(TextStretch& line) {
@@ -1540,10 +1547,10 @@ void TextWrapper::formatCurrentLine(const AddLineToParagraph& addLine) {
1540}1547}
1541 1548 
1542bool TextWrapper::determineIfEllipsisNeeded() {1549bool TextWrapper::determineIfEllipsisNeeded() {
1543- bool lastLine = (fFormattingContext.hasEllipsis && fFormattingContext.unlimitedLines) ||1550+ fIsLastLine = (fFormattingContext.hasEllipsis && fFormattingContext.unlimitedLines) ||
1544 fLineNumber >= fFormattingContext.maxLines;1551 fLineNumber >= fFormattingContext.maxLines;
1545 bool needEllipsis =1552 bool needEllipsis =
1546- fFormattingContext.hasEllipsis && !fFormattingContext.endlessLine && lastLine;1553+ fFormattingContext.hasEllipsis && !fFormattingContext.endlessLine && fIsLastLine;
1547 1554 
1548 if (fParent->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD &&1555 if (fParent->paragraphStyle().getEllipsisMod() == EllipsisModal::HEAD &&
1549 fFormattingContext.hasEllipsis) {1556 fFormattingContext.hasEllipsis) {
@@ -1592,8 +1599,9 @@ void TextWrapper::adjustLineMetricsForFirstLastLine() {
1592 if (fFormattingContext.disableFirstAscent && fFirstLine) {1599 if (fFormattingContext.disableFirstAscent && fFirstLine) {
1593 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;1600 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;
1594 }1601 }
1595- if (fFormattingContext.disableLastDescent && isLastLine()) {1602+ if (fFormattingContext.disableLastDescent && (fIsLastLine ||(fCurrentStartLine == fEnd && !fHardLineBreak))) {
1596 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;1603 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;
1604+ fFormattingContext.needLineSpacing = false;
1597 }1605 }
1598}1606}
1599 1607 
@@ -1638,6 +1646,9 @@ TextWrapper::LineTextRanges TextWrapper::calculateLineTextRanges() {
1638 1646 
1639SkScalar TextWrapper::calculateLineHeight() {1647SkScalar TextWrapper::calculateLineHeight() {
1640 SkScalar height = fEndLine.metrics().height();1648 SkScalar height = fEndLine.metrics().height();
1649+ if (fFormattingContext.needLineSpacing) {
1650+ height += fFormattingContext.lineSpacing;
1651+ }
1641 if (fHardLineBreak && !isLastLine() && fParent->paragraphStyle().getParagraphSpacing() > 0) {1652 if (fHardLineBreak && !isLastLine() && fParent->paragraphStyle().getParagraphSpacing() > 0) {
1642 height += fParent->paragraphStyle().getParagraphSpacing();1653 height += fParent->paragraphStyle().getParagraphSpacing();
1643 }1654 }
@@ -1767,7 +1778,7 @@ void TextWrapper::adjustMetricsForEmptyParagraph() {
1767 if (fFormattingContext.disableFirstAscent) {1778 if (fFormattingContext.disableFirstAscent) {
1768 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;1779 fEndLine.metrics().fAscent = fEndLine.metrics().fRawAscent;
1769 }1780 }
1770- if (fFormattingContext.disableLastDescent && !fHardLineBreak) {1781+ if (fFormattingContext.disableLastDescent && (fIsLastLine || (fEndLine.endCluster() == fEnd && !fHardLineBreak))) {
1771 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;1782 fEndLine.metrics().fDescent = fEndLine.metrics().fRawDescent;
1772 }1783 }
1773}1784}
Mmodules/skparagraph/src/TextWrapper.h+3-0
@@ -260,6 +260,8 @@ private:
260 bool disableLastDescent{false};260 bool disableLastDescent{false};
261 size_t maxLines{0};261 size_t maxLines{0};
262 TextAlign align{TextAlign::kLeft};262 TextAlign align{TextAlign::kLeft};
263+ bool needLineSpacing{false};
264+ SkScalar lineSpacing{0.0f};
263 };265 };
264 266 
265 struct LineTextRanges {267 struct LineTextRanges {
@@ -402,6 +404,7 @@ private:
402 size_t fCurrentStartPos{0};404 size_t fCurrentStartPos{0};
403 Cluster* fStart{nullptr};405 Cluster* fStart{nullptr};
404 Cluster* fEnd{nullptr};406 Cluster* fEnd{nullptr};
407+ bool fIsLastLine{false};
405#endif408#endif
406};409};
407} // namespace textlayout410} // namespace textlayout
liumingxiangFTL1ght
liumingxiangliumingxiang2025年8月26日

结构体拷贝以及快速重排版的地方没看到处理新增字段呢?

likedislike
FTL1ghtFTL1ght2025年8月27日

结构体拷贝以及快速重排版的地方没看到处理新增字段呢?

2d 层

likedislike