1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved.
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 #include "hm_symbol_run.h"
17 #include "custom_symbol_config.h"
18 #include "draw/path.h"
19 #include "hm_symbol_node_build.h"
20 #include "include/pathops/SkPathOps.h"
21 #include "utils/text_log.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 namespace SPText {
26 static const std::vector<RSEffectStrategy> COMMON_ANIMATION_TYPES = {
27 RSEffectStrategy::SCALE, RSEffectStrategy::APPEAR, RSEffectStrategy::DISAPPEAR,
28 RSEffectStrategy::BOUNCE, RSEffectStrategy::REPLACE_APPEAR};
29
HMSymbolRun(uint64_t symbolId,const HMSymbolTxt & symbolTxt,const std::shared_ptr<RSTextBlob> & textBlob,std::function<bool (const std::shared_ptr<TextEngine::SymbolAnimationConfig> &)> & animationFunc)30 HMSymbolRun::HMSymbolRun(uint64_t symbolId,
31 const HMSymbolTxt& symbolTxt,
32 const std::shared_ptr<RSTextBlob>& textBlob,
33 std::function<bool(const std::shared_ptr<TextEngine::SymbolAnimationConfig>&)>& animationFunc)
34 : symbolTxt_(symbolTxt), symbolId_(symbolId)
35 {
36 if (textBlob) {
37 textBlob_ = textBlob;
38 } else {
39 TEXT_LOGD("Null text blob");
40 }
41 if (animationFunc) {
42 animationFunc_ = animationFunc;
43 } else {
44 TEXT_LOGD("Null animation func");
45 }
46 }
47
GetSymbolLayers(uint16_t glyphId,const HMSymbolTxt & symbolText)48 RSSymbolLayers HMSymbolRun::GetSymbolLayers(uint16_t glyphId, const HMSymbolTxt& symbolText)
49 {
50 RSSymbolLayers symbolInfo;
51 symbolInfo.symbolGlyphId = glyphId;
52 auto& symbolInfoOrign = symbolLayersGroups_;
53 if (symbolInfoOrign.renderModeGroups.empty() || symbolInfoOrign.symbolGlyphId == 0) {
54 TEXT_LOGD("Invalid symbol layer groups, glyph id %{public}hu.", glyphId);
55 return symbolInfo;
56 }
57
58 RSSymbolRenderingStrategy renderMode = symbolText.GetRenderMode();
59 if (symbolInfoOrign.renderModeGroups.find(renderMode) == symbolInfoOrign.renderModeGroups.end()) {
60 renderMode = RSSymbolRenderingStrategy::SINGLE;
61 }
62
63 symbolInfo.layers = symbolInfoOrign.layers;
64 if (symbolInfoOrign.renderModeGroups.find(renderMode) != symbolInfoOrign.renderModeGroups.end()) {
65 symbolInfo.renderGroups = symbolInfoOrign.renderModeGroups[renderMode];
66 symbolInfo.symbolGlyphId = symbolInfoOrign.symbolGlyphId;
67 }
68
69 std::vector<RSSColor> colorList = symbolText.GetRenderColor();
70 if (!colorList.empty()) {
71 SetSymbolRenderColor(renderMode, colorList, symbolInfo);
72 }
73 return symbolInfo;
74 }
75
SetSymbolRenderColor(const RSSymbolRenderingStrategy & renderMode,const std::vector<RSSColor> & colors,RSSymbolLayers & symbolInfo)76 void HMSymbolRun::SetSymbolRenderColor(const RSSymbolRenderingStrategy& renderMode,
77 const std::vector<RSSColor>& colors, RSSymbolLayers& symbolInfo)
78 {
79 if (colors.empty()) {
80 return;
81 }
82 switch (renderMode) {
83 // SINGLE and HIERARCHICAL: Supports single color setting
84 case RSSymbolRenderingStrategy::SINGLE:
85 for (size_t i = 0; i < symbolInfo.renderGroups.size(); ++i) {
86 symbolInfo.renderGroups[i].color = colors[0]; // the 0 indicates the the first color is used
87 }
88 break;
89 // MULTIPLE_OPACITY: Supports rgb replace and alphia overlay setting by the first color
90 case RSSymbolRenderingStrategy::MULTIPLE_OPACITY:
91 for (size_t i = 0; i < symbolInfo.renderGroups.size(); ++i) {
92 float colorAlphia = symbolInfo.renderGroups[i].color.a * colors[0].a;
93 symbolInfo.renderGroups[i].color.a = std::clamp(colorAlphia, 0.0f, 1.0f); // 0.0: min, 1.0: max
94 symbolInfo.renderGroups[i].color.r = colors[0].r; // the 0 indicates the the first color is used
95 symbolInfo.renderGroups[i].color.g = colors[0].g; // the 0 indicates the the first color is used
96 symbolInfo.renderGroups[i].color.b = colors[0].b; // the 0 indicates the the first color is used
97 }
98 break;
99 // MULTIPLE_COLOR: Supports mutiple color setting
100 case RSSymbolRenderingStrategy::MULTIPLE_COLOR:
101 for (size_t i = 0; i < symbolInfo.renderGroups.size() && i < colors.size(); ++i) {
102 symbolInfo.renderGroups[i].color = colors[i];
103 }
104 break;
105 default:
106 break;
107 }
108 }
109
UpdateSymbolLayersGroups(uint16_t glyphId)110 void HMSymbolRun::UpdateSymbolLayersGroups(uint16_t glyphId)
111 {
112 symbolLayersGroups_.symbolGlyphId = glyphId;
113 // Obtaining Symbol Preset LayerGroups Parameters
114 if (symbolTxt_.GetSymbolType() == SymbolType::SYSTEM) {
115 auto groups = RSHmSymbolConfig_OHOS::GetSymbolLayersGroups(glyphId);
116 if (groups.renderModeGroups.empty()) {
117 TEXT_LOGD("Failed to get system symbol layer groups, glyph id %{public}hu", glyphId);
118 symbolLayersGroups_.renderModeGroups = {};
119 return;
120 }
121 symbolLayersGroups_ = groups;
122 } else {
123 auto groups = CustomSymbolConfig::GetInstance()->GetSymbolLayersGroups(symbolTxt_.familyName_, glyphId);
124 if (!groups.has_value()) {
125 TEXT_LOGD("Failed to get custom symbol layer groups, glyph id %{public}hu", glyphId);
126 symbolLayersGroups_.renderModeGroups = {};
127 return;
128 }
129 symbolLayersGroups_ = groups.value();
130 }
131 }
132
DrawSymbol(RSCanvas * canvas,const RSPoint & offset)133 void HMSymbolRun::DrawSymbol(RSCanvas* canvas, const RSPoint& offset)
134 {
135 if (!textBlob_) {
136 TEXT_LOGD("Null text blob");
137 return;
138 }
139
140 if (!canvas) {
141 TEXT_LOGD("Null canvas");
142 return;
143 }
144
145 std::vector<uint16_t> glyphIds;
146 RSTextBlob::GetDrawingGlyphIDforTextBlob(textBlob_.get(), glyphIds);
147 if (glyphIds.size() != 1) {
148 TEXT_LOGD("Glyph isn't unique");
149 canvas->DrawTextBlob(textBlob_.get(), offset.GetX(), offset.GetY());
150 return;
151 }
152 TEXT_LOGD("HmSymbol: DrawSymbol");
153 uint16_t glyphId = glyphIds[0];
154 OHOS::Rosen::Drawing::Path path = RSTextBlob::GetDrawingPathforTextBlob(glyphId, textBlob_.get());
155 RSHMSymbolData symbolData;
156
157 UpdateSymbolLayersGroups(glyphId);
158 symbolData.symbolInfo_ = GetSymbolLayers(glyphId, symbolTxt_);
159 if (symbolData.symbolInfo_.symbolGlyphId != glyphId) {
160 path = RSTextBlob::GetDrawingPathforTextBlob(symbolData.symbolInfo_.symbolGlyphId, textBlob_.get());
161 }
162 symbolData.path_ = path;
163 symbolData.symbolId = symbolId_; // symbolspan Id in paragraph
164 RSEffectStrategy symbolEffect = symbolTxt_.GetEffectStrategy();
165 std::pair<float, float> offsetXY(offset.GetX(), offset.GetY());
166 if (symbolEffect > 0 && symbolTxt_.GetAnimationStart()) { // 0 > has animation
167 if (SymbolAnimation(symbolData, offsetXY)) {
168 currentAnimationHasPlayed_ = true;
169 return;
170 }
171 }
172 ClearSymbolAnimation(symbolData, offsetXY);
173 OnDrawSymbol(canvas, symbolData, offset);
174 currentAnimationHasPlayed_ = false;
175 }
176
SetRenderColor(const std::vector<RSSColor> & colorList)177 void HMSymbolRun::SetRenderColor(const std::vector<RSSColor>& colorList)
178 {
179 symbolTxt_.SetRenderColor(colorList);
180 }
181
SetRenderMode(RSSymbolRenderingStrategy renderMode)182 void HMSymbolRun::SetRenderMode(RSSymbolRenderingStrategy renderMode)
183 {
184 symbolTxt_.SetRenderMode(renderMode);
185 }
186
SetSymbolEffect(const RSEffectStrategy & effectStrategy)187 void HMSymbolRun::SetSymbolEffect(const RSEffectStrategy& effectStrategy)
188 {
189 symbolTxt_.SetSymbolEffect(effectStrategy);
190 currentAnimationHasPlayed_ = false;
191 }
192
SetAnimationMode(uint16_t animationMode)193 void HMSymbolRun::SetAnimationMode(uint16_t animationMode)
194 {
195 symbolTxt_.SetAnimationMode(animationMode);
196 currentAnimationHasPlayed_ = false;
197 }
198
SetAnimationStart(bool animationStart)199 void HMSymbolRun::SetAnimationStart(bool animationStart)
200 {
201 symbolTxt_.SetAnimationStart(animationStart);
202 }
203
SetCommonSubType(Drawing::DrawingCommonSubType commonSubType)204 void HMSymbolRun::SetCommonSubType(Drawing::DrawingCommonSubType commonSubType)
205 {
206 symbolTxt_.SetCommonSubType(commonSubType);
207 currentAnimationHasPlayed_ = false;
208 }
209
SetAnimation(const std::function<bool (const std::shared_ptr<OHOS::Rosen::TextEngine::SymbolAnimationConfig> &)> & animationFunc)210 void HMSymbolRun::SetAnimation(
211 const std::function<bool(const std::shared_ptr<OHOS::Rosen::TextEngine::SymbolAnimationConfig>&)>&
212 animationFunc)
213 {
214 if (animationFunc) {
215 animationFunc_ = animationFunc;
216 }
217 }
218
SetTextBlob(const std::shared_ptr<RSTextBlob> & textBlob)219 void HMSymbolRun::SetTextBlob(const std::shared_ptr<RSTextBlob>& textBlob)
220 {
221 if (textBlob) {
222 std::vector<uint16_t> glyphId1;
223 std::vector<uint16_t> glyphId2;
224 RSTextBlob::GetDrawingGlyphIDforTextBlob(textBlob_.get(), glyphId1);
225 RSTextBlob::GetDrawingGlyphIDforTextBlob(textBlob.get(), glyphId2);
226 // 1 mean the textBlob has one symbol
227 if (!(glyphId1.size() == 1 && glyphId2.size() == 1 && glyphId1[0] == glyphId2[0])) {
228 currentAnimationHasPlayed_ = false;
229 }
230 textBlob_ = textBlob;
231 }
232 }
233
OnDrawSymbol(RSCanvas * canvas,const RSHMSymbolData & symbolData,RSPoint locate)234 void HMSymbolRun::OnDrawSymbol(RSCanvas* canvas, const RSHMSymbolData& symbolData, RSPoint locate)
235 {
236 RSPath path(symbolData.path_);
237
238 // 1.0 move path
239 path.Offset(locate.GetX(), locate.GetY());
240 if (symbolData.symbolInfo_.renderGroups.empty()) {
241 TEXT_LOGD("Empty render groups");
242 canvas->DrawPath(path);
243 return;
244 }
245
246 // 2.0 split path
247 std::vector<RSPath> paths;
248 RSHMSymbol::PathOutlineDecompose(path, paths);
249 std::vector<RSPath> pathLayers;
250 RSHMSymbol::MultilayerPath(symbolData.symbolInfo_.layers, paths, pathLayers);
251
252 // 3.0 set paint
253 Drawing::Brush brush;
254 Drawing::Pen pen;
255 brush.SetAntiAlias(true);
256 pen.SetAntiAlias(true);
257
258 // draw path
259 std::vector<RSRenderGroup> groups = symbolData.symbolInfo_.renderGroups;
260 TEXT_LOGD("RenderGroup size %{public}zu", groups.size());
261 RSColor color;
262 for (auto group : groups) {
263 RSPath multPath;
264 SymbolNodeBuild::MergeDrawingPath(multPath, group, pathLayers);
265 // set color
266 color.SetRgb(group.color.r, group.color.g, group.color.b);
267 color.SetAlphaF(group.color.a);
268 brush.SetColor(color);
269 pen.SetColor(color);
270 canvas->AttachPen(pen);
271 canvas->AttachBrush(brush);
272 canvas->DrawPath(multPath);
273 canvas->DetachPen();
274 canvas->DetachBrush();
275 }
276 }
277
SymbolAnimation(const RSHMSymbolData & symbol,const std::pair<float,float> & offset)278 bool HMSymbolRun::SymbolAnimation(const RSHMSymbolData& symbol, const std::pair<float, float>& offset)
279 {
280 RSEffectStrategy effectMode = symbolTxt_.GetEffectStrategy();
281 uint16_t animationMode = symbolTxt_.GetAnimationMode();
282 if (effectMode == RSEffectStrategy::NONE) {
283 TEXT_LOGD("Invalid effect mode");
284 return false;
285 }
286 RSAnimationSetting animationSetting;
287 if (animationMode == 0 || effectMode == RSEffectStrategy::VARIABLE_COLOR) {
288 if (!GetAnimationGroups(effectMode, animationSetting)) {
289 TEXT_LOGD("Invalid animation setting");
290 return false;
291 }
292
293 if (std::find(COMMON_ANIMATION_TYPES.begin(), COMMON_ANIMATION_TYPES.end(), effectMode) !=
294 COMMON_ANIMATION_TYPES.end() && animationSetting.groupSettings.size() == 1) {
295 animationMode = 1; // the 1 is wholeSymbol effect
296 }
297 }
298 SymbolNodeBuild symbolNode = SymbolNodeBuild(animationSetting, symbol, effectMode, offset);
299 symbolNode.SetAnimation(animationFunc_);
300 symbolNode.SetSymbolId(symbolId_);
301 symbolNode.SetAnimationMode(animationMode);
302 symbolNode.SetRepeatCount(symbolTxt_.GetRepeatCount());
303 symbolNode.SetAnimationStart(symbolTxt_.GetAnimationStart());
304 symbolNode.SetCommonSubType(symbolTxt_.GetCommonSubType());
305 symbolNode.SetCurrentAnimationHasPlayed(currentAnimationHasPlayed_);
306 return symbolNode.DecomposeSymbolAndDraw();
307 }
308
ClearSymbolAnimation(const RSHMSymbolData & symbol,const std::pair<float,float> & offset)309 void HMSymbolRun::ClearSymbolAnimation(const RSHMSymbolData& symbol, const std::pair<float, float>& offset)
310 {
311 auto effectMode = RSEffectStrategy::NONE;
312 RSAnimationSetting animationSetting;
313
314 SymbolNodeBuild symbolNode = SymbolNodeBuild(animationSetting, symbol, effectMode, offset);
315 symbolNode.SetAnimation(animationFunc_);
316 symbolNode.SetSymbolId(symbolId_);
317 symbolNode.ClearAnimation();
318 }
319
GetAnimationGroups(const RSEffectStrategy effectStrategy,RSAnimationSetting & animationOut)320 bool HMSymbolRun::GetAnimationGroups(const RSEffectStrategy effectStrategy,
321 RSAnimationSetting& animationOut)
322 {
323 RSAnimationType animationType = static_cast<RSAnimationType>(effectStrategy);
324
325 for (const auto& animationSetting : symbolLayersGroups_.animationSettings) {
326 if (std::find(animationSetting.animationTypes.begin(), animationSetting.animationTypes.end(),
327 animationType) == animationSetting.animationTypes.end()) {
328 continue;
329 }
330 if (!animationSetting.groupSettings.empty()) {
331 animationOut = animationSetting;
332 return true;
333 }
334 }
335 return false;
336 }
337 }
338 }
339 }