1 /*
2  * Copyright (c) 2022 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 
16 #ifndef GRAPHIC_LTE_GEOMERTY_PATH_STORAGE_H
17 #define GRAPHIC_LTE_GEOMERTY_PATH_STORAGE_H
18 
19 #include "geometry_bezier_arc.h"
20 #include "gfx_utils/diagram/common/common_math.h"
21 #include "gfx_utils/diagram/vertexprimitive/geometry_plaindata_array.h"
22 
23 namespace OHOS {
24 /**
25  * @brief Vertex source data block
26  * @since 1.0
27  * @version 1.0
28  */
29 class VertexBlockStorage {
30 public:
31     enum BlockScale {
32         BLOCK_SCALE_SHIFT = THIRTY_TWO_COLOR_NUM,
33         BLOCK_SCALE_SIZE = 1 << BLOCK_SCALE_SHIFT,
34         BLOCK_SCALE_MASK = BLOCK_SCALE_SIZE - 1,
35         BLOCK_SCALE_POOL = MAX_COLOR_SIZE
36     };
37 
~VertexBlockStorage()38     ~VertexBlockStorage()
39     {
40         FreeAll();
41     }
42 
VertexBlockStorage()43     VertexBlockStorage() : totalVertices_(0), totalBlocks_(0), maxBlocks_(0), croodBlocks_(0), cmdBlocks_(0) {}
44 
45     const VertexBlockStorage& operator=(const VertexBlockStorage& vertexBlockStorage)
46     {
47         RemoveAll();
48         for (uint32_t iIndex = 0; iIndex < vertexBlockStorage.GetTotalVertices(); iIndex++) {
49             float x;
50             float y;
51             uint32_t cmd = vertexBlockStorage.GenerateVertex(iIndex, &x, &y);
52             AddVertex(x, y, cmd);
53         }
54         this->totalBlocks_ = vertexBlockStorage.totalBlocks_;
55         maxBlocks_ = vertexBlockStorage.maxBlocks_;
56         croodBlocks_ = vertexBlockStorage.croodBlocks_;
57         cmdBlocks_ = vertexBlockStorage.cmdBlocks_;
58         return *this;
59     }
60 
VertexBlockStorage(const VertexBlockStorage & vertexBlockStorage)61     VertexBlockStorage(const VertexBlockStorage& vertexBlockStorage)
62     {
63         *this = vertexBlockStorage;
64     }
65 
66     /**
67      * @brief Remove all vertices.
68      *
69      * @since 1.0
70      * @version 1.0
71      */
RemoveAll()72     void RemoveAll()
73     {
74         totalVertices_ = 0;
75     }
76     /**
77      * @brief Free up space
78      * @since 1.0
79      * @version 1.0
80      */
FreeAll()81     void FreeAll()
82     {
83         if (totalBlocks_ > 0) {
84             float** coordBLK = croodBlocks_ + totalBlocks_ - 1;
85             for (; totalBlocks_ > 0; totalBlocks_--) {
86                 GeometryArrayAllocator<float>::Deallocate(
87                     *coordBLK, BLOCK_SCALE_SIZE * TWO_TIMES + BLOCK_SCALE_SIZE / (sizeof(float) / sizeof(uint8_t)));
88                 --coordBLK;
89             }
90             GeometryArrayAllocator<float*>::Deallocate(croodBlocks_, maxBlocks_ * TWO_TIMES);
91             totalBlocks_ = 0;
92             maxBlocks_ = 0;
93             croodBlocks_ = 0;
94             cmdBlocks_ = 0;
95             totalVertices_ = 0;
96         }
97     }
98     /**
99      * @brief add vertex.
100      *
101      * @param x Vertex X-axis coordinates.
102      * @param y Vertex Y-axis coordinates.
103      * @param cmd Instruction type.
104      * @since 1.0
105      * @version 1.0
106      */
AddVertex(float x,float y,uint32_t cmd)107     void AddVertex(float x, float y, uint32_t cmd)
108     {
109         float* coordPtr = 0;
110         *StoragePtrs(&coordPtr) = static_cast<uint8_t>(cmd);
111         coordPtr[0] = float(x);
112         coordPtr[1] = float(y);
113         totalVertices_++;
114     }
115     /**
116      * @brief Returns the last instruction.
117      * @return Returns the last instruction type.
118      * @since 1.0
119      * @version 1.0
120      */
LastCommand()121     uint32_t LastCommand() const
122     {
123         if (totalVertices_) {
124             return Command(totalVertices_ - 1);
125         }
126         return PATH_CMD_STOP;
127     }
128     /**
129      * @brief Returns the coordinates of the last vertex.
130      * @param x Used to obtain the x-axis coordinates of the last vertex.
131      * @param y Used to obtain the y-axis coordinates of the last vertex.
132      * @return Returns the instruction type corresponding to the vertex.
133      * @since 1.0
134      * @version 1.0
135      */
LastVertex(float * x,float * y)136     uint32_t LastVertex(float* x, float* y) const
137     {
138         if (totalVertices_) {
139             return GenerateVertex(totalVertices_ - 1, x, y);
140         }
141         return PATH_CMD_STOP;
142     }
143     /**
144      * @brief Returns the number of vertices.
145      * @return Returns the number of vertices.
146      * @since 1.0
147      * @version 1.0
148      */
GetTotalVertices()149     uint32_t GetTotalVertices() const
150     {
151         return totalVertices_;
152     }
153     /**
154      * @brief Gets the coordinates of a particular vertex.
155      * @param idx Vertex subscript.
156      * @param x Used to obtain the x-axis coordinates of vertices.
157      * @param y Used to obtain the y-axis coordinates of vertices.
158      * @return Returns the instruction type corresponding to the vertex.
159      * @since 1.0
160      * @version 1.0
161      */
GenerateVertex(uint32_t idx,float * x,float * y)162     uint32_t GenerateVertex(uint32_t idx, float* x, float* y) const
163     {
164         uint32_t nb = idx >> BLOCK_SCALE_SHIFT;
165         const float* pv = croodBlocks_[nb] + ((idx & BLOCK_SCALE_MASK) << 1);
166         *x = pv[0];
167         *y = pv[1];
168         return cmdBlocks_[nb][idx & BLOCK_SCALE_MASK];
169     }
170     /**
171      * @brief ets the instruction type corresponding to a specific vertex.
172      * @param index Vertex subscript.
173      * @return Returns the instruction type corresponding to the vertex.
174      * @since 1.0
175      * @version 1.0
176      */
Command(uint32_t index)177     uint32_t Command(uint32_t index) const
178     {
179         return cmdBlocks_[index >> BLOCK_SCALE_SHIFT][index & BLOCK_SCALE_MASK];
180     }
181 
182 private:
AllocateBlock(uint32_t nb)183     void AllocateBlock(uint32_t nb)
184     {
185         if (nb >= maxBlocks_) {
186             float** new_coords = GeometryArrayAllocator<float*>::Allocate((maxBlocks_ + BLOCK_SCALE_POOL) * TWO_TIMES);
187             if (new_coords == nullptr) {
188                 return;
189             }
190 
191             uint8_t** new_cmds = (uint8_t**)(new_coords + maxBlocks_ + BLOCK_SCALE_POOL);
192             if (new_cmds == nullptr) {
193                 return;
194             }
195 
196             if (croodBlocks_) {
197                 if (memcpy_s(new_coords, maxBlocks_ * sizeof(float*),
198                              croodBlocks_, maxBlocks_ * sizeof(float*)) != EOK) {
199                 }
200                 if (memcpy_s(new_cmds, maxBlocks_ * sizeof(float*),
201                              cmdBlocks_, maxBlocks_ * sizeof(uint8_t*)) != EOK) {
202                 }
203                 GeometryArrayAllocator<float*>::Deallocate(croodBlocks_, maxBlocks_ * TWO_TIMES);
204             }
205             croodBlocks_ = new_coords;
206             cmdBlocks_ = new_cmds;
207             maxBlocks_ += BLOCK_SCALE_POOL;
208         }
209         croodBlocks_[nb] = GeometryArrayAllocator<float>::Allocate(
210             BLOCK_SCALE_SIZE * TWO_TIMES + BLOCK_SCALE_SIZE / (sizeof(float) / sizeof(uint8_t)));
211 
212         cmdBlocks_[nb] = (uint8_t*)(croodBlocks_[nb] + BLOCK_SCALE_SIZE * TWO_TIMES);
213 
214         totalBlocks_++;
215     }
StoragePtrs(float ** xy_ptr)216     uint8_t* StoragePtrs(float** xy_ptr)
217     {
218         uint32_t nb = totalVertices_ >> BLOCK_SCALE_SHIFT;
219         if (nb >= totalBlocks_) {
220             AllocateBlock(nb);
221         }
222         *xy_ptr = croodBlocks_[nb] + ((totalVertices_ & BLOCK_SCALE_MASK) << 1);
223         return cmdBlocks_[nb] + (totalVertices_ & BLOCK_SCALE_MASK);
224     }
225 
226 private:
227     uint32_t totalVertices_;
228     uint32_t totalBlocks_;
229     uint32_t maxBlocks_;
230     float** croodBlocks_; // Input points
231     uint8_t** cmdBlocks_; // Mark point status
232 };
233 
234 class UICanvasVertices : public HeapBase {
235 public:
UICanvasVertices()236     UICanvasVertices() : vertices_(), iterator_(0) {}
237 
238     /**
239      * @brief Remove all vertices
240      *
241      * @since 1.0
242      * @version 1.0
243      */
RemoveAll()244     void RemoveAll()
245     {
246         vertices_.RemoveAll();
247         iterator_ = 0;
248     }
249     /**
250      * @brief Free up space
251      * @since 1.0
252      * @version 1.0
253      */
FreeAll()254     void FreeAll()
255     {
256         vertices_.FreeAll();
257         iterator_ = 0;
258     }
259 
260     /**
261      * @brief Move a point to the set coordinates
262      * @param x Vertex X-axis coordinates
263      * @param y Vertex Y-axis coordinates
264      * @since 1.0
265      * @version 1.0
266      */
MoveTo(float x,float y)267     void MoveTo(float x, float y)
268     {
269         vertices_.AddVertex(x, y, PATH_CMD_MOVE_TO);
270     }
271     /**
272      * @brief Connect the line to the entered coordinates
273      * @param x Vertex X-axis coordinates
274      * @param y Vertex Y-axis coordinates
275      * @since 1.0
276      * @version 1.0
277      */
LineTo(float x,float y)278     void LineTo(float x, float y)
279     {
280         vertices_.AddVertex(x, y, PATH_CMD_LINE_TO);
281     }
282 
CubicBezierCurve(double xCtrl1,double yCtrl1,double xCtrl2,double yCtrl2,double xEnd,double yEnd)283     void CubicBezierCurve(double xCtrl1, double yCtrl1,
284                           double xCtrl2, double yCtrl2,
285                           double xEnd,    double yEnd)
286     {
287         vertices_.AddVertex(xCtrl1, yCtrl1, PATH_CMD_CURVE4);
288         vertices_.AddVertex(xCtrl2, yCtrl2, PATH_CMD_CURVE4);
289         vertices_.AddVertex(xEnd, yEnd, PATH_CMD_CURVE4);
290     }
291 
292     /**
293      * @brief Draw an arc
294      * @param rx Long and short axle
295      * @param ry Long and short axle
296      * @param angle angle
297      * @param largeArcFlag Superior inferior arc
298      * @param sweepFlag Clockwise and counterclockwise
299      * @param x End X coordinate
300      * @param y End Y-axis coordinates
301      * @since 1.0
302      * @version 1.0
303      */
ArcTo(float rx,float ry,float angle,bool largeArcFlag,bool sweepFlag,float x,float y)304     void ArcTo(float rx, float ry,
305                float angle,
306                bool largeArcFlag,
307                bool sweepFlag,
308                float x, float y)
309     {
310         if (vertices_.GetTotalVertices() && IsVertex(vertices_.LastCommand())) {
311             const float epsilon = 1e-30;
312             float x0 = 0.0f;
313             float y0 = 0.0f;
314             vertices_.LastVertex(&x0, &y0);
315 
316             rx = MATH_ABS(rx);
317             ry = MATH_ABS(ry);
318             if (rx < epsilon || ry < epsilon) {
319                 LineTo(x, y);
320                 return;
321             }
322             if (CalcDistance(x0, y0, x, y) < epsilon) {
323                 return;
324             }
325 #if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG
326             BezierArcSvg bezierArcSvg(x0, y0, rx, ry, angle, largeArcFlag, sweepFlag, x, y);
327             if (bezierArcSvg.RadiiOK()) {
328                 JoinPath(bezierArcSvg);
329             } else {
330                 LineTo(x, y);
331             }
332 #else
333             LineTo(x, y);
334 #endif
335         } else {
336             MoveTo(x, y);
337         }
338     }
339 
340     void EndPoly(uint32_t flags = PATH_FLAGS_CLOSE)
341     {
342         if (IsVertex(vertices_.LastCommand())) {
343             vertices_.AddVertex(0.0f, 0.0f, PATH_CMD_END_POLY | flags);
344         }
345     }
346     /**
347      * @brief ClosePolygon Closed polygon path
348      * @param flags
349      */
350     void ClosePolygon(uint32_t flags = PATH_FLAGS_NONE)
351     {
352         EndPoly(PATH_FLAGS_CLOSE | flags);
353     }
354 
355     /**
356      * @brief Returns the number of vertices.
357      * @return Returns the number of vertices.
358      * @since 1.0
359      * @version 1.0
360      */
GetTotalVertices()361     uint32_t GetTotalVertices() const
362     {
363         return vertices_.GetTotalVertices();
364     }
365 
366     /**
367      * @brief Returns the coordinates of the last vertex.
368      * @param x Used to obtain the x-axis coordinates of the last vertex.
369      * @param y Used to obtain the y-axis coordinates of the last vertex.
370      * @return Returns the instruction type corresponding to the vertex.
371      * @since 1.0
372      * @version 1.0
373      */
LastVertex(float * x,float * y)374     uint32_t LastVertex(float* x, float* y) const
375     {
376         return vertices_.LastVertex(x, y);
377     }
378     /**
379      * @brief Gets the coordinates of a particular vertex.
380      * @param idx Vertex subscript.
381      * @param x Used to obtain the x-axis coordinates of vertices.
382      * @param y Used to obtain the y-axis coordinates of vertices.
383      * @return Returns the instruction type corresponding to the vertex.
384      * @since 1.0
385      * @version 1.0
386      */
387     uint32_t GenerateVertex(uint32_t idx, float* x, float* y) const;
388 
389     /**
390      * @brief Iterator fallback to a vertex。
391      * @param pathId The vertex sequence number of the fallback.
392      * @since 1.0
393      * @version 1.0
394      */
Rewind(uint32_t pathId)395     void Rewind(uint32_t pathId)
396     {
397         iterator_ = pathId;
398     }
399 
400     /**
401      * @brief Gets the coordinates of the next vertex.
402      * @param x Used to obtain the x-axis coordinates of vertices.
403      * @param y Used to obtain the y-axis coordinates of vertices.
404      * @return Returns the instruction type corresponding to the next vertex.
405      * @since 1.0
406      * @version 1.0
407      */
GenerateVertex(float * x,float * y)408     uint32_t GenerateVertex(float* x, float* y)
409     {
410         if (iterator_ >= vertices_.GetTotalVertices()) {
411             return PATH_CMD_STOP;
412         }
413         return vertices_.GenerateVertex(iterator_++, x, y);
414     }
415 #if defined(GRAPHIC_ENABLE_BEZIER_ARC_FLAG) && GRAPHIC_ENABLE_BEZIER_ARC_FLAG
416     /**
417      * @brief Connection path.
418      * @param vs Vertex source to connect.
419      * @param pathId Connection location.
420      * @since 1.0
421      * @version 1.0
422      */
423     void ConcatPath(BezierArc& path, uint32_t pathId = 0)
424     {
425         float x;
426         float y;
427         uint32_t cmd;
428         path.Rewind(pathId);
429         while (!IsStop(cmd = path.GenerateVertex(&x, &y))) {
430             vertices_.AddVertex(x, y, cmd);
431         }
432     }
433 
434     /**
435      * @brief Add vertex source to existing source.
436      * @param vs Vertex source to join.
437      * @param pathId Join location.
438      * @since 1.0
439      * @version 1.0
440      */
441     void JoinPath(BezierArcSvg& path, uint32_t pathId = 0)
442     {
443         float x;
444         float y;
445         uint32_t pathCommand;
446         path.Rewind(pathId);
447         pathCommand = path.GenerateVertex(&x, &y);
448         if (!IsStop(pathCommand)) {
449             if (IsVertex(pathCommand)) {
450                 float x0;
451                 float y0;
452                 uint32_t cmd0 = LastVertex(&x0, &y0);
453                 if (IsVertex(cmd0) && (CalcDistance(x, y, x0, y0) > VERTEX_DIST_EPSILON)) {
454                     if (IsMoveTo(pathCommand)) {
455                         pathCommand = PATH_CMD_LINE_TO;
456                     }
457                     vertices_.AddVertex(x, y, pathCommand);
458                 } else if (IsStop(cmd0)) {
459                     pathCommand = PATH_CMD_MOVE_TO;
460                     vertices_.AddVertex(x, y, pathCommand);
461                 } else {
462                     if (IsMoveTo(pathCommand)) {
463                         pathCommand = PATH_CMD_LINE_TO;
464                     }
465                     vertices_.AddVertex(x, y, pathCommand);
466                 }
467             }
468             for (; !IsStop(pathCommand = path.GenerateVertex(&x, &y));) {
469                 uint32_t pathCmd;
470                 if (IsMoveTo(pathCommand)) {
471                     pathCmd = uint32_t(PATH_CMD_LINE_TO);
472                 } else {
473                     pathCmd = pathCommand;
474                 }
475                 vertices_.AddVertex(x, y, pathCmd);
476             }
477         }
478     }
479 #endif
480 private:
481     VertexBlockStorage vertices_;
482     uint32_t iterator_;
483 };
484 } // namespace OHOS
485 #endif
486