• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }