1 | /* |
2 | * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. |
3 | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | * of this software and associated documentation files (the "Software"), to deal |
6 | * in the Software without restriction, including without limitation the rights |
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | * copies of the Software, and to permit persons to whom the Software is |
9 | * furnished to do so, subject to the following conditions: |
10 | |
11 | * The above copyright notice and this permission notice shall be included in all |
12 | * copies or substantial portions of the Software. |
13 | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
20 | * SOFTWARE. |
21 | */ |
22 | |
23 | #ifndef _TVG_CANVAS_IMPL_H_ |
24 | #define _TVG_CANVAS_IMPL_H_ |
25 | |
26 | #include "tvgPaint.h" |
27 | |
28 | /************************************************************************/ |
29 | /* Internal Class Implementation */ |
30 | /************************************************************************/ |
31 | |
32 | struct Canvas::Impl |
33 | { |
34 | list<Paint*> paints; |
35 | RenderMethod* renderer; |
36 | bool refresh = false; //if all paints should be updated by force. |
37 | bool drawing = false; //on drawing condition? |
38 | |
39 | Impl(RenderMethod* pRenderer):renderer(pRenderer) |
40 | { |
41 | } |
42 | |
43 | ~Impl() |
44 | { |
45 | clear(true); |
46 | delete(renderer); |
47 | } |
48 | |
49 | Result push(unique_ptr<Paint> paint) |
50 | { |
51 | //You can not push paints during rendering. |
52 | if (drawing) return Result::InsufficientCondition; |
53 | |
54 | auto p = paint.release(); |
55 | if (!p) return Result::MemoryCorruption; |
56 | paints.push_back(p); |
57 | |
58 | return update(p, true); |
59 | } |
60 | |
61 | Result clear(bool free) |
62 | { |
63 | //Clear render target before drawing |
64 | if (!renderer || !renderer->clear()) return Result::InsufficientCondition; |
65 | |
66 | //Free paints |
67 | for (auto paint : paints) { |
68 | paint->pImpl->dispose(*renderer); |
69 | if (free) delete(paint); |
70 | } |
71 | |
72 | paints.clear(); |
73 | |
74 | drawing = false; |
75 | |
76 | return Result::Success; |
77 | } |
78 | |
79 | void needRefresh() |
80 | { |
81 | refresh = true; |
82 | } |
83 | |
84 | Result update(Paint* paint, bool force) |
85 | { |
86 | if (paints.empty() || drawing || !renderer) return Result::InsufficientCondition; |
87 | |
88 | Array<RenderData> clips; |
89 | auto flag = RenderUpdateFlag::None; |
90 | if (refresh || force) flag = RenderUpdateFlag::All; |
91 | |
92 | //Update single paint node |
93 | if (paint) { |
94 | //Optimize Me: Can we skip the searching? |
95 | for (auto paint2 : paints) { |
96 | if (paint2 == paint) { |
97 | paint->pImpl->update(*renderer, nullptr, clips, 255, flag); |
98 | return Result::Success; |
99 | } |
100 | } |
101 | return Result::InvalidArguments; |
102 | //Update all retained paint nodes |
103 | } else { |
104 | for (auto paint : paints) { |
105 | paint->pImpl->update(*renderer, nullptr, clips, 255, flag); |
106 | } |
107 | } |
108 | |
109 | refresh = false; |
110 | |
111 | return Result::Success; |
112 | } |
113 | |
114 | Result draw() |
115 | { |
116 | if (drawing || paints.empty() || !renderer || !renderer->preRender()) return Result::InsufficientCondition; |
117 | |
118 | bool rendered = false; |
119 | for (auto paint : paints) { |
120 | if (paint->pImpl->render(*renderer)) rendered = true; |
121 | } |
122 | |
123 | if (!rendered || !renderer->postRender()) return Result::InsufficientCondition; |
124 | |
125 | drawing = true; |
126 | |
127 | return Result::Success; |
128 | } |
129 | |
130 | Result sync() |
131 | { |
132 | if (!drawing) return Result::InsufficientCondition; |
133 | |
134 | if (renderer->sync()) { |
135 | drawing = false; |
136 | return Result::Success; |
137 | } |
138 | |
139 | return Result::InsufficientCondition; |
140 | } |
141 | }; |
142 | |
143 | #endif /* _TVG_CANVAS_IMPL_H_ */ |
144 | |