1 /* 2 * Copyright (c) 2023 - 2024 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 #include "../../lv_conf_internal.h" 24 #if LV_USE_THORVG_INTERNAL 25 26 #ifndef _TVG_TEXT_H 27 #define _TVG_TEXT_H 28 29 #include <cstring> 30 #include "tvgShape.h" 31 #include "tvgFill.h" 32 #include "tvgLoader.h" 33 34 struct Text::Impl 35 { 36 FontLoader* loader = nullptr; 37 Text* paint; 38 Shape* shape; 39 char* utf8 = nullptr; 40 float fontSize; 41 bool italic = false; 42 bool changed = false; 43 ImplImpl44 Impl(Text* p) : paint(p), shape(Shape::gen().release()) 45 { 46 } 47 ~ImplImpl48 ~Impl() 49 { 50 free(utf8); 51 LoaderMgr::retrieve(loader); 52 delete(shape); 53 } 54 textImpl55 Result text(const char* utf8) 56 { 57 free(this->utf8); 58 if (utf8) this->utf8 = strdup(utf8); 59 else this->utf8 = nullptr; 60 changed = true; 61 62 return Result::Success; 63 } 64 fontImpl65 Result font(const char* name, float size, const char* style) 66 { 67 auto loader = LoaderMgr::loader(name); 68 if (!loader) return Result::InsufficientCondition; 69 70 if (style && strstr(style, "italic")) italic = true; 71 else italic = false; 72 73 fontSize = size; 74 75 //Same resource has been loaded. 76 if (this->loader == loader) { 77 this->loader->sharing--; //make it sure the reference counting. 78 return Result::Success; 79 } else if (this->loader) { 80 LoaderMgr::retrieve(this->loader); 81 } 82 this->loader = static_cast<FontLoader*>(loader); 83 84 changed = true; 85 return Result::Success; 86 } 87 boundsImpl88 RenderRegion bounds(RenderMethod* renderer) 89 { 90 return P(shape)->bounds(renderer); 91 } 92 renderImpl93 bool render(RenderMethod* renderer) 94 { 95 if (!loader) return true; 96 renderer->blend(PP(paint)->blendMethod); 97 return PP(shape)->render(renderer); 98 } 99 loadImpl100 bool load() 101 { 102 if (!loader) return false; 103 104 loader->request(shape, utf8); 105 //reload 106 if (changed) { 107 loader->read(); 108 changed = false; 109 } 110 return loader->transform(shape, fontSize, italic); 111 } 112 updateImpl113 RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper) 114 { 115 if (!load()) return nullptr; 116 117 //transform the gradient coordinates based on the final scaled font. 118 auto fill = P(shape)->rs.fill; 119 if (fill && P(shape)->flag & RenderUpdateFlag::Gradient) { 120 auto scale = 1.0f / loader->scale; 121 if (fill->type() == Type::LinearGradient) { 122 P(static_cast<LinearGradient*>(fill))->x1 *= scale; 123 P(static_cast<LinearGradient*>(fill))->y1 *= scale; 124 P(static_cast<LinearGradient*>(fill))->x2 *= scale; 125 P(static_cast<LinearGradient*>(fill))->y2 *= scale; 126 } else { 127 P(static_cast<RadialGradient*>(fill))->cx *= scale; 128 P(static_cast<RadialGradient*>(fill))->cy *= scale; 129 P(static_cast<RadialGradient*>(fill))->r *= scale; 130 P(static_cast<RadialGradient*>(fill))->fx *= scale; 131 P(static_cast<RadialGradient*>(fill))->fy *= scale; 132 P(static_cast<RadialGradient*>(fill))->fr *= scale; 133 } 134 } 135 return PP(shape)->update(renderer, transform, clips, opacity, pFlag, false); 136 } 137 boundsImpl138 bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking) 139 { 140 if (!load()) return false; 141 PP(shape)->bounds(x, y, w, h, true, true, false); 142 return true; 143 } 144 duplicateImpl145 Paint* duplicate(Paint* ret) 146 { 147 if (ret) TVGERR("RENDERER", "TODO: duplicate()"); 148 149 load(); 150 151 auto text = Text::gen().release(); 152 auto dup = text->pImpl; 153 P(shape)->duplicate(dup->shape); 154 155 if (loader) { 156 dup->loader = loader; 157 ++dup->loader->sharing; 158 } 159 160 dup->utf8 = strdup(utf8); 161 dup->italic = italic; 162 dup->fontSize = fontSize; 163 164 return text; 165 } 166 iteratorImpl167 Iterator* iterator() 168 { 169 return nullptr; 170 } 171 }; 172 173 174 175 #endif //_TVG_TEXT_H 176 177 #endif /* LV_USE_THORVG_INTERNAL */ 178 179