• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "hm_symbol_node_build.h"
16 
17 #include "common/rs_common_def.h"
18 #include "include/pathops/SkPathOps.h"
19 #include "utils/text_log.h"
20 
21 namespace OHOS {
22 namespace Rosen {
23 namespace SPText {
24 
25 /**
26  * @brief  Obtain the group id to layer
27  * @param groupIds (output paramer) the index of groupIds if layer index, the groupIds[index] is the group index
28  * @param renderGroup the renderGroup info of symbol
29  * @param index the renderGroup index
30  */
GetLayersGroupId(std::vector<size_t> & groupIds,const RSRenderGroup & renderGroup,size_t index)31 static void GetLayersGroupId(std::vector<size_t>& groupIds, const RSRenderGroup& renderGroup, size_t index)
32 {
33     for (const auto& groupInfo : renderGroup.groupInfos) {
34         for (size_t j : groupInfo.layerIndexes) {
35             if (j < groupIds.size()) {
36                 groupIds[j] = index;
37             }
38         }
39         for (size_t j : groupInfo.maskIndexes) {
40             if (j < groupIds.size()) {
41                 groupIds[j] = index;
42             }
43         }
44     }
45 }
46 
47 /**
48  * @brief Merge the mask paths.
49  * @param maskIndexes the indexes of maskLayer of group informations
50  * @param pathLayers the path data of layers on symbol, the value of maskIndexes < pathLayers.size
51  * @param pathsColorIndex the start pathsColor position for merging mask pathh
52  * @param pathsColor (output paramer) the result of the merge
53  */
MergeMaskPath(const std::vector<size_t> & maskIndexes,std::vector<RSPath> & pathLayers,size_t pathsColorIndex,std::vector<TextEngine::NodeLayerInfo> & pathsColor)54 static void MergeMaskPath(const std::vector<size_t>& maskIndexes, std::vector<RSPath>& pathLayers,
55     size_t pathsColorIndex, std::vector<TextEngine::NodeLayerInfo>& pathsColor)
56 {
57     RSPath maskPath;
58     for (size_t maskIndex : maskIndexes) {
59         if (maskIndex < pathLayers.size()) {
60             maskPath.AddPath(pathLayers[maskIndex]);
61         }
62     }
63     if (!maskPath.IsValid()) {
64         return;
65     }
66 
67     for (size_t j = pathsColorIndex; j < pathsColor.size(); j++) {
68         Drawing::Path outPath;
69         bool isOk = outPath.Op(pathsColor[j].path, maskPath, Drawing::PathOp::DIFFERENCE);
70         pathsColor[j].path = isOk ? outPath : pathsColor[j].path;
71     }
72 }
73 
74 /**
75  * @brief Merge the paths of Group by layer color.
76  * @param groupInfos a group informations of dynamic drawing
77  * @param pathLayers the path data of layers on symbol
78  * @param groupIndexes the indexes list of groups on colorGroups, the groupIndexes.size == pathLayers.size, \n
79  * groupIndexes.size == pathLayers.size, groupIndexes[groupIndexes.size - 1] < colorGroups.size
80  * @param pathsColor (output paramer) the result of the merge, where each merged path corresponds to a specific color
81  * @param colorGroups the groups informations of static drawing, include color data
82  */
MergePathByLayerColor(const std::vector<RSGroupInfo> & groupInfos,std::vector<RSPath> & pathLayers,const std::vector<size_t> & groupIndexes,std::vector<TextEngine::NodeLayerInfo> & pathsColor,std::vector<std::shared_ptr<SymbolGradient>> & colorGroups)83 static void MergePathByLayerColor(const std::vector<RSGroupInfo>& groupInfos,
84     std::vector<RSPath>& pathLayers, const std::vector<size_t>& groupIndexes,
85     std::vector<TextEngine::NodeLayerInfo>& pathsColor,
86     std::vector<std::shared_ptr<SymbolGradient>>& colorGroups)
87 {
88     size_t pathsColorIndex = 0;
89     std::shared_ptr<SymbolGradient> color = nullptr;
90     for (const auto& groupInfo : groupInfos) {
91         TextEngine::NodeLayerInfo tempLayer;
92         size_t currentIndex = 0; // the current layerindex, that effective index of tempLayer
93         bool isFirst = true;
94         for (size_t layerIndex: groupInfo.layerIndexes) {
95             if (layerIndex >= pathLayers.size() || layerIndex >= groupIndexes.size()) {
96                 continue;
97             }
98             if (isFirst) { // initialize tempLayer
99                 auto groupIndex = groupIndexes[layerIndex];
100                 tempLayer.color = groupIndex < colorGroups.size() ? colorGroups[groupIndex] : color;
101                 tempLayer.path.AddPath(pathLayers[layerIndex]);
102                 currentIndex = layerIndex;
103                 isFirst = false;
104                 continue;
105             }
106             // If the groupIndex of two paths is different, update pathsColor and tempLayer
107             if (groupIndexes[currentIndex] != groupIndexes[layerIndex]) {
108                 pathsColor.push_back(tempLayer);
109                 tempLayer.path.Reset();
110                 auto groupIndex = groupIndexes[layerIndex];
111                 tempLayer.color = groupIndex < colorGroups.size() ? colorGroups[groupIndex] : color;
112                 currentIndex = layerIndex;
113             }
114             tempLayer.path.AddPath(pathLayers[layerIndex]);
115         }
116         pathsColor.push_back(tempLayer);
117         if (!groupInfo.maskIndexes.empty()) {
118             MergeMaskPath(groupInfo.maskIndexes, pathLayers, pathsColorIndex, pathsColor);
119         }
120         pathsColorIndex = pathsColor.size();
121     }
122 }
123 
124 /**
125  * @brief check if the symbol group is a mask layer, that it has only mask indexes
126  * @param multPath (output paramer) combine all paths of mask indexes in groupInfos
127  * @param groupInfos the groupsInfos of symbol
128  * @param pathLayers the all paths of symbol
129  * @return true if the group is a mask layer
130  */
IsMaskLayer(RSPath & multPath,const std::vector<RSGroupInfo> & groupInfos,std::vector<RSPath> & pathLayers)131 static bool IsMaskLayer(RSPath& multPath, const std::vector<RSGroupInfo>& groupInfos, std::vector<RSPath>& pathLayers)
132 {
133     for (const auto& groupInfo : groupInfos) {
134         RSPath pathTemp;
135         if (groupInfo.layerIndexes.size() > 0) {
136             return false;
137         }
138         for (auto k : groupInfo.maskIndexes) {
139             if (k >= pathLayers.size()) {
140                 continue;
141             }
142             pathTemp.AddPath(pathLayers[k]);
143         }
144         multPath.AddPath(pathTemp);
145     }
146     return true;
147 }
148 
MergeDrawingPath(RSPath & multPath,const RSRenderGroup & group,std::vector<RSPath> & pathLayers)149 void SymbolNodeBuild::MergeDrawingPath(RSPath& multPath, const RSRenderGroup& group, std::vector<RSPath>& pathLayers)
150 {
151     for (const auto& groupInfo : group.groupInfos) {
152         RSPath pathTemp;
153         for (auto i : groupInfo.layerIndexes) {
154             if (i < pathLayers.size()) {
155                 pathTemp.AddPath(pathLayers[i]);
156             }
157         }
158         RSPath maskPath;
159         for (auto j : groupInfo.maskIndexes) {
160             if (j < pathLayers.size()) {
161                 maskPath.AddPath(pathLayers[j]);
162             }
163         }
164         if (maskPath.IsValid()) {
165             Drawing::Path outPath;
166             auto isOk = outPath.Op(pathTemp, maskPath, Drawing::PathOp::DIFFERENCE);
167             pathTemp = isOk ? outPath : pathTemp;
168             multPath.SetFillStyle(pathTemp.GetFillStyle());
169         }
170         multPath.AddPath(pathTemp);
171     }
172 }
173 
SymbolNodeBuild(const RSAnimationSetting & animationSetting,const RSHMSymbolData & symbolData,const RSEffectStrategy & effectStrategy,const std::pair<float,float> & offset)174 SymbolNodeBuild::SymbolNodeBuild(const RSAnimationSetting &animationSetting, const RSHMSymbolData &symbolData,
175     const RSEffectStrategy &effectStrategy,
176     const std::pair<float, float> &offset) : animationSetting_(animationSetting),
177     symbolData_(symbolData), effectStrategy_(effectStrategy),
178     offsetX_(offset.first), offsetY_(offset.second) {}
179 
AddWholeAnimation(const RSHMSymbolData & symbolData,const Vector4f & nodeBounds,std::shared_ptr<TextEngine::SymbolAnimationConfig> symbolAnimationConfig)180 void SymbolNodeBuild::AddWholeAnimation(const RSHMSymbolData &symbolData, const Vector4f &nodeBounds,
181     std::shared_ptr<TextEngine::SymbolAnimationConfig> symbolAnimationConfig)
182 {
183     TextEngine::SymbolNode symbolNode;
184     symbolNode.symbolData = symbolData;
185     symbolNode.nodeBoundary = nodeBounds;
186 
187     std::vector<RSPath> paths;
188     RSHMSymbol::PathOutlineDecompose(symbolData.path_, paths);
189     std::vector<RSPath> pathLayers;
190     RSHMSymbol::MultilayerPath(symbolData.symbolInfo_.layers, paths, pathLayers);
191     std::vector<RSRenderGroup> groups = symbolData.symbolInfo_.renderGroups;
192     UpdateGradient(groups, pathLayers, symbolData.path_);
193     TEXT_LOGD("Render group size %{public}zu", groups.size());
194     for (size_t i = 0; i < groups.size(); i++) {
195         RSPath multPath;
196         MergeDrawingPath(multPath, groups[i], pathLayers);
197         TextEngine::NodeLayerInfo pathInfo;
198         pathInfo.path = multPath;
199         bool isValid = i < gradients_.size() && gradients_[i] != nullptr;
200         if (isValid) {
201             pathInfo.color = gradients_[i];
202         }
203         symbolNode.pathsInfo.push_back(pathInfo);
204     }
205 
206     symbolAnimationConfig->symbolNodes.push_back(symbolNode);
207     symbolAnimationConfig->numNodes = symbolAnimationConfig->symbolNodes.size();
208 }
209 
SetSymbolNodeColors(const TextEngine::SymbolNode & symbolNode,TextEngine::SymbolNode & outSymbolNode)210 void SymbolNodeBuild::SetSymbolNodeColors(const TextEngine::SymbolNode& symbolNode,
211     TextEngine::SymbolNode& outSymbolNode)
212 {
213     bool isNoNeed = symbolNode.pathsInfo.empty() || outSymbolNode.pathsInfo.empty() ||
214         outSymbolNode.pathsInfo[0].color; // If color != nullptr is no need to set
215     if (isNoNeed) {
216         return;
217     }
218 
219     std::shared_ptr<SymbolGradient> color;
220     if (disableSlashColor_ != nullptr) {
221         disableSlashColor_->Make(outSymbolNode.pathsInfo[0].path.GetBounds());
222         color = disableSlashColor_;
223     } else {
224         color = symbolNode.pathsInfo[0].color;
225     }
226     for (auto& pathInfo: outSymbolNode.pathsInfo) {
227         pathInfo.color = color;
228     }
229 }
230 
AddHierarchicalAnimation(const RSHMSymbolData & symbolData,const Vector4f & nodeBounds,const std::vector<RSGroupSetting> & groupSettings,std::shared_ptr<TextEngine::SymbolAnimationConfig> symbolAnimationConfig)231 void SymbolNodeBuild::AddHierarchicalAnimation(const RSHMSymbolData &symbolData, const Vector4f &nodeBounds,
232     const std::vector<RSGroupSetting> &groupSettings,
233     std::shared_ptr<TextEngine::SymbolAnimationConfig> symbolAnimationConfig)
234 {
235     if (symbolAnimationConfig == nullptr) {
236         symbolAnimationConfig = std::make_shared<TextEngine::SymbolAnimationConfig>();
237     }
238     std::vector<RSPath> paths;
239     RSHMSymbol::PathOutlineDecompose(symbolData.path_, paths);
240     std::vector<RSPath> pathLayers;
241     RSHMSymbol::MultilayerPath(symbolData.symbolInfo_.layers, paths, pathLayers);
242     UpdateGradient(symbolData.symbolInfo_.renderGroups, pathLayers, symbolData.path_);
243 
244     // Obtain the group id of layer
245     std::vector<size_t> groupIds(pathLayers.size(), pathLayers.size());
246     for (size_t idx = 0; idx < symbolData.symbolInfo_.renderGroups.size(); idx++) {
247         GetLayersGroupId(groupIds, symbolData.symbolInfo_.renderGroups[idx], idx);
248     }
249 
250     // Splitting animation nodes information
251     for (const auto& groupSetting: groupSettings) {
252         TextEngine::SymbolNode symbolNode;
253         TextEngine::NodeLayerInfo maskPath;
254         bool isMask = IsMaskLayer(maskPath.path, groupSetting.groupInfos, pathLayers);
255         if (!isMask) {
256             MergePathByLayerColor(groupSetting.groupInfos, pathLayers, groupIds, symbolNode.pathsInfo,
257                 gradients_);
258         } else {
259             symbolNode.pathsInfo.push_back(maskPath);
260         }
261         symbolNode.nodeBoundary = nodeBounds;
262         symbolNode.symbolData = symbolData;
263         symbolNode.animationIndex = groupSetting.animationIndex;
264         symbolNode.isMask = isMask;
265         symbolAnimationConfig->symbolNodes.push_back(symbolNode);
266     }
267     bool isDisableType = (effectStrategy_ == RSEffectStrategy::DISABLE) && (
268         symbolAnimationConfig->symbolNodes.size() > 2); // 2: disableType symbol nodes size must be greater than 2
269     if (isDisableType) {
270         uint32_t last = symbolAnimationConfig->symbolNodes.size() - 1; // the last
271         uint32_t last3 = symbolAnimationConfig->symbolNodes.size() - 3; // 3: the third from the bottom
272         SetSymbolNodeColors(symbolAnimationConfig->symbolNodes[last3], symbolAnimationConfig->symbolNodes[last]);
273     }
274     symbolAnimationConfig->numNodes = symbolAnimationConfig->symbolNodes.size();
275 }
276 
CreateGradient(const std::shared_ptr<SymbolGradient> & gradient)277 std::shared_ptr<SymbolGradient> SymbolNodeBuild::CreateGradient(
278     const std::shared_ptr<SymbolGradient>& gradient)
279 {
280     if (gradient == nullptr) {
281         return nullptr;
282     }
283 
284     std::shared_ptr<SymbolGradient> outGradient = nullptr;
285     if (gradient->GetGradientType() == GradientType::LINE_GRADIENT) {
286         auto lineGradient = std::static_pointer_cast<SymbolLineGradient>(gradient);
287         outGradient = std::make_shared<SymbolLineGradient>(lineGradient->GetAngle());
288     } else if (gradient->GetGradientType() == GradientType::RADIAL_GRADIENT) {
289         auto radiaGradient = std::static_pointer_cast<SymbolRadialGradient>(gradient);
290         auto newRadiaGradient = std::make_shared<SymbolRadialGradient>(radiaGradient->GetCenterPoint(),
291             radiaGradient->GetRadiusRatio());
292         if (!radiaGradient->IsRadiusRatio()) {
293             newRadiaGradient->SetRadius(radiaGradient->GetRadius());
294         }
295         outGradient = newRadiaGradient;
296     } else {
297         outGradient = std::make_shared<SymbolGradient>();
298     }
299 
300     outGradient->SetTileMode(gradient->GetTileMode());
301     outGradient->SetColors(gradient->GetColors());
302     outGradient->SetPositions(gradient->GetPositions());
303 
304     return outGradient;
305 }
306 
UpdateGradient(const std::vector<RSRenderGroup> & groups,std::vector<RSPath> & pathLayers,const RSPath & path)307 void SymbolNodeBuild::UpdateGradient(const std::vector<RSRenderGroup>& groups,
308     std::vector<RSPath>& pathLayers, const RSPath& path)
309 {
310     if (gradients_.empty()) {
311         return;
312     }
313 
314     std::vector<std::shared_ptr<SymbolGradient>> gradients;
315     if (renderMode_ == RSSymbolRenderingStrategy::SINGLE) {
316         if (gradients_[0] != nullptr) {
317             gradients_[0]->Make(path.GetBounds());
318         }
319         for (size_t i = 0; i < groups.size(); i++) {
320             gradients.push_back(gradients_[0]);
321         }
322         gradients_ = gradients;
323         return;
324     }
325 
326     for (size_t i = 0; i < groups.size() && i < gradients_.size(); i++) {
327         RSPath multPath;
328         MergeDrawingPath(multPath, groups[i], pathLayers);
329         auto gradient = gradients_[i];
330         if (gradient != nullptr) {
331             gradient->Make(multPath.GetBounds());
332             gradients.push_back(gradient);
333         }
334     }
335     gradients_ = gradients;
336 }
337 
ClearAnimation()338 void SymbolNodeBuild::ClearAnimation()
339 {
340     if (animationFunc_ == nullptr) {
341         return;
342     }
343     auto symbolAnimationConfig = std::make_shared<TextEngine::SymbolAnimationConfig>();
344     if (symbolAnimationConfig == nullptr) {
345         return;
346     }
347     symbolAnimationConfig->effectStrategy = Drawing::DrawingEffectStrategy::NONE;
348     symbolAnimationConfig->symbolSpanId = symblSpanId_;
349     animationFunc_(symbolAnimationConfig);
350 }
351 
DecomposeSymbolAndDraw()352 bool SymbolNodeBuild::DecomposeSymbolAndDraw()
353 {
354     if (symbolData_.symbolInfo_.renderGroups.empty()) {
355         TEXT_LOGD("Render group is empty");
356         return false;
357     }
358     if (animationFunc_ == nullptr) {
359         TEXT_LOGD("Null animation func");
360         return false;
361     }
362     auto symbolAnimationConfig = std::make_shared<TextEngine::SymbolAnimationConfig>();
363     if (symbolAnimationConfig == nullptr) {
364         return false;
365     }
366     auto rect = symbolData_.path_.GetBounds();
367     float nodeWidth = rect.GetWidth();
368     float nodeHeight = rect.GetHeight();
369     Vector4f nodeBounds = Vector4f(offsetX_, offsetY_, nodeWidth, nodeHeight);
370 
371     if (effectStrategy_ == RSEffectStrategy::VARIABLE_COLOR || animationMode_ == 0) {
372         AddHierarchicalAnimation(symbolData_, nodeBounds, animationSetting_.groupSettings, symbolAnimationConfig);
373     } else {
374         AddWholeAnimation(symbolData_, nodeBounds, symbolAnimationConfig);
375     }
376 
377     symbolAnimationConfig->effectStrategy = effectStrategy_;
378     symbolAnimationConfig->repeatCount = repeatCount_;
379     symbolAnimationConfig->animationMode = animationMode_;
380     symbolAnimationConfig->animationStart = animationStart_;
381     symbolAnimationConfig->symbolSpanId = symblSpanId_;
382     symbolAnimationConfig->commonSubType = commonSubType_;
383     symbolAnimationConfig->currentAnimationHasPlayed = currentAnimationHasPlayed_;
384     symbolAnimationConfig->slope = slope_;
385     symbolAnimationConfig->symbolShadow = symbolShadow_;
386     return animationFunc_(symbolAnimationConfig);
387 }
388 }
389 }
390 }