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
32struct 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