Core.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019-2023 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "../../Include/RmlUi/Core/Core.h"
  29. #include "../../Include/RmlUi/Core/Context.h"
  30. #include "../../Include/RmlUi/Core/Element.h"
  31. #include "../../Include/RmlUi/Core/ElementInstancer.h"
  32. #include "../../Include/RmlUi/Core/Factory.h"
  33. #include "../../Include/RmlUi/Core/FileInterface.h"
  34. #include "../../Include/RmlUi/Core/FontEngineInterface.h"
  35. #include "../../Include/RmlUi/Core/Plugin.h"
  36. #include "../../Include/RmlUi/Core/RenderInterface.h"
  37. #include "../../Include/RmlUi/Core/RenderManager.h"
  38. #include "../../Include/RmlUi/Core/StyleSheetSpecification.h"
  39. #include "../../Include/RmlUi/Core/SystemInterface.h"
  40. #include "../../Include/RmlUi/Core/TextInputHandler.h"
  41. #include "../../Include/RmlUi/Core/Types.h"
  42. #include "BoxShadowCache.h"
  43. #include "ComputeProperty.h"
  44. #include "ControlledLifetimeResource.h"
  45. #include "ElementMeta.h"
  46. #include "EventSpecification.h"
  47. #include "FileInterfaceDefault.h"
  48. #include "Layout/LayoutPools.h"
  49. #include "PluginRegistry.h"
  50. #include "RenderManagerAccess.h"
  51. #include "StyleSheetFactory.h"
  52. #include "StyleSheetParser.h"
  53. #include "TemplateCache.h"
  54. #ifdef RMLUI_FONT_ENGINE_FREETYPE
  55. #include "FontEngineDefault/FontEngineInterfaceDefault.h"
  56. #endif
  57. #ifdef RMLUI_LOTTIE_PLUGIN
  58. #include "../Lottie/LottiePlugin.h"
  59. #endif
  60. #ifdef RMLUI_SVG_PLUGIN
  61. #include "../SVG/SVGPlugin.h"
  62. #endif
  63. #include <algorithm>
  64. namespace Rml {
  65. static RenderInterface* render_interface = nullptr;
  66. static SystemInterface* system_interface = nullptr;
  67. static FileInterface* file_interface = nullptr;
  68. static FontEngineInterface* font_interface = nullptr;
  69. static TextInputHandler* text_input_handler = nullptr;
  70. struct CoreData {
  71. // Default interfaces should be created and destroyed on Initialise and Shutdown, respectively.
  72. UniquePtr<SystemInterface> default_system_interface;
  73. UniquePtr<FileInterface> default_file_interface;
  74. UniquePtr<FontEngineInterface> default_font_interface;
  75. UniquePtr<TextInputHandler> default_text_input_handler;
  76. SmallUnorderedMap<RenderInterface*, UniquePtr<RenderManager>> render_managers;
  77. UnorderedMap<String, ContextPtr> contexts;
  78. };
  79. static ControlledLifetimeResource<CoreData> core_data;
  80. static bool initialised = false;
  81. static void InitializeMemoryPools()
  82. {
  83. Detail::InitializeElementInstancerPools();
  84. ElementMetaPool::Initialize();
  85. LayoutPools::Initialize();
  86. }
  87. static void ReleaseMemoryPools()
  88. {
  89. LayoutPools::Shutdown();
  90. ElementMetaPool::Shutdown();
  91. Detail::ShutdownElementInstancerPools();
  92. }
  93. #ifndef RMLUI_VERSION
  94. #define RMLUI_VERSION "custom"
  95. #endif
  96. bool Initialise()
  97. {
  98. RMLUI_ASSERTMSG(!initialised, "Rml::Initialise() called, but RmlUi is already initialised!");
  99. InitializeMemoryPools();
  100. InitializeComputeProperty();
  101. core_data.Initialize();
  102. // Install default interfaces as appropriate.
  103. if (!system_interface)
  104. {
  105. core_data->default_system_interface = MakeUnique<SystemInterface>();
  106. system_interface = core_data->default_system_interface.get();
  107. }
  108. if (!file_interface)
  109. {
  110. #ifndef RMLUI_NO_FILE_INTERFACE_DEFAULT
  111. core_data->default_file_interface = MakeUnique<FileInterfaceDefault>();
  112. file_interface = core_data->default_file_interface.get();
  113. #else
  114. Log::Message(Log::LT_ERROR, "No file interface set!");
  115. return false;
  116. #endif
  117. }
  118. if (!font_interface)
  119. {
  120. #ifdef RMLUI_FONT_ENGINE_FREETYPE
  121. core_data->default_font_interface = MakeUnique<FontEngineInterfaceDefault>();
  122. font_interface = core_data->default_font_interface.get();
  123. #else
  124. Log::Message(Log::LT_ERROR, "No font engine interface set!");
  125. return false;
  126. #endif
  127. }
  128. if (!text_input_handler)
  129. {
  130. core_data->default_text_input_handler = MakeUnique<TextInputHandler>();
  131. text_input_handler = core_data->default_text_input_handler.get();
  132. }
  133. EventSpecificationInterface::Initialize();
  134. Detail::InitializeObserverPtrPool();
  135. if (render_interface)
  136. core_data->render_managers[render_interface] = MakeUnique<RenderManager>(render_interface);
  137. font_interface->Initialize();
  138. StyleSheetSpecification::Initialise();
  139. StyleSheetParser::Initialise();
  140. StyleSheetFactory::Initialise();
  141. TemplateCache::Initialise();
  142. Factory::Initialise();
  143. // Initialise plugins integrated with Core.
  144. #ifdef RMLUI_LOTTIE_PLUGIN
  145. Lottie::Initialise();
  146. #endif
  147. #ifdef RMLUI_SVG_PLUGIN
  148. SVG::Initialise();
  149. #endif
  150. BoxShadowCache::Initialize();
  151. // Notify all plugins we're starting up.
  152. PluginRegistry::NotifyInitialise();
  153. initialised = true;
  154. return true;
  155. }
  156. void Shutdown()
  157. {
  158. RMLUI_ASSERTMSG(initialised, "Rml::Shutdown() called, but RmlUi is not initialised!");
  159. // Clear out all contexts, which should also clean up all attached elements.
  160. core_data->contexts.clear();
  161. // Notify all plugins we're being shutdown.
  162. PluginRegistry::NotifyShutdown();
  163. BoxShadowCache::Shutdown();
  164. Factory::Shutdown();
  165. TemplateCache::Shutdown();
  166. StyleSheetFactory::Shutdown();
  167. StyleSheetParser::Shutdown();
  168. StyleSheetSpecification::Shutdown();
  169. font_interface->Shutdown();
  170. core_data->render_managers.clear();
  171. Detail::ShutdownObserverPtrPool();
  172. initialised = false;
  173. text_input_handler = nullptr;
  174. font_interface = nullptr;
  175. render_interface = nullptr;
  176. file_interface = nullptr;
  177. system_interface = nullptr;
  178. core_data.Shutdown();
  179. EventSpecificationInterface::Shutdown();
  180. ShutdownComputeProperty();
  181. ReleaseMemoryPools();
  182. }
  183. String GetVersion()
  184. {
  185. return RMLUI_VERSION;
  186. }
  187. void SetSystemInterface(SystemInterface* _system_interface)
  188. {
  189. system_interface = _system_interface;
  190. }
  191. SystemInterface* GetSystemInterface()
  192. {
  193. return system_interface;
  194. }
  195. void SetRenderInterface(RenderInterface* _render_interface)
  196. {
  197. render_interface = _render_interface;
  198. }
  199. RenderInterface* GetRenderInterface()
  200. {
  201. return render_interface;
  202. }
  203. void SetFileInterface(FileInterface* _file_interface)
  204. {
  205. file_interface = _file_interface;
  206. }
  207. FileInterface* GetFileInterface()
  208. {
  209. return file_interface;
  210. }
  211. void SetFontEngineInterface(FontEngineInterface* _font_interface)
  212. {
  213. font_interface = _font_interface;
  214. }
  215. FontEngineInterface* GetFontEngineInterface()
  216. {
  217. return font_interface;
  218. }
  219. void SetTextInputHandler(TextInputHandler* _text_input_handler)
  220. {
  221. text_input_handler = _text_input_handler;
  222. }
  223. TextInputHandler* GetTextInputHandler()
  224. {
  225. return text_input_handler;
  226. }
  227. Context* CreateContext(const String& name, const Vector2i dimensions, RenderInterface* render_interface_for_context,
  228. TextInputHandler* text_input_handler_for_context)
  229. {
  230. if (!initialised)
  231. return nullptr;
  232. if (!render_interface_for_context)
  233. render_interface_for_context = render_interface;
  234. if (!text_input_handler_for_context)
  235. text_input_handler_for_context = text_input_handler;
  236. if (!render_interface_for_context)
  237. {
  238. Log::Message(Log::LT_WARNING, "Failed to create context '%s', no render interface specified and no default render interface exists.",
  239. name.c_str());
  240. return nullptr;
  241. }
  242. if (GetContext(name))
  243. {
  244. Log::Message(Log::LT_WARNING, "Failed to create context '%s', context already exists.", name.c_str());
  245. return nullptr;
  246. }
  247. // Each unique render interface gets its own render manager.
  248. auto& render_manager = core_data->render_managers[render_interface_for_context];
  249. if (!render_manager)
  250. render_manager = MakeUnique<RenderManager>(render_interface_for_context);
  251. ContextPtr new_context = Factory::InstanceContext(name, render_manager.get(), text_input_handler_for_context);
  252. if (!new_context)
  253. {
  254. Log::Message(Log::LT_WARNING, "Failed to instance context '%s', instancer returned nullptr.", name.c_str());
  255. return nullptr;
  256. }
  257. new_context->SetDimensions(dimensions);
  258. Context* new_context_raw = new_context.get();
  259. core_data->contexts[name] = std::move(new_context);
  260. PluginRegistry::NotifyContextCreate(new_context_raw);
  261. return new_context_raw;
  262. }
  263. bool RemoveContext(const String& name)
  264. {
  265. return core_data->contexts.erase(name) != 0;
  266. }
  267. Context* GetContext(const String& name)
  268. {
  269. auto it = core_data->contexts.find(name);
  270. if (it == core_data->contexts.end())
  271. return nullptr;
  272. return it->second.get();
  273. }
  274. Context* GetContext(int index)
  275. {
  276. if (index < 0 || index >= GetNumContexts())
  277. return nullptr;
  278. auto it = core_data->contexts.begin();
  279. std::advance(it, index);
  280. if (it == core_data->contexts.end())
  281. return nullptr;
  282. return it->second.get();
  283. }
  284. int GetNumContexts()
  285. {
  286. return (int)core_data->contexts.size();
  287. }
  288. bool LoadFontFace(const String& file_path, bool fallback_face, Style::FontWeight weight, int face_index)
  289. {
  290. return font_interface->LoadFontFace(file_path, face_index, fallback_face, weight);
  291. }
  292. bool LoadFontFace(Span<const byte> data, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face, int face_index)
  293. {
  294. return font_interface->LoadFontFace(data, face_index, family, style, weight, fallback_face);
  295. }
  296. void RegisterPlugin(Plugin* plugin)
  297. {
  298. if (initialised)
  299. plugin->OnInitialise();
  300. PluginRegistry::RegisterPlugin(plugin);
  301. }
  302. void UnregisterPlugin(Plugin* plugin)
  303. {
  304. PluginRegistry::UnregisterPlugin(plugin);
  305. if (initialised)
  306. plugin->OnShutdown();
  307. }
  308. EventId RegisterEventType(const String& type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase)
  309. {
  310. return EventSpecificationInterface::InsertOrReplaceCustom(type, interruptible, bubbles, default_action_phase);
  311. }
  312. StringList GetTextureSourceList()
  313. {
  314. StringList result;
  315. if (!core_data)
  316. return result;
  317. for (const auto& render_manager : core_data->render_managers)
  318. {
  319. RenderManagerAccess::GetTextureSourceList(render_manager.second.get(), result);
  320. }
  321. return result;
  322. }
  323. void ReleaseTextures(RenderInterface* match_render_interface)
  324. {
  325. if (!core_data)
  326. return;
  327. for (auto& render_manager : core_data->render_managers)
  328. {
  329. if (!match_render_interface || render_manager.first == match_render_interface)
  330. RenderManagerAccess::ReleaseAllTextures(render_manager.second.get());
  331. }
  332. }
  333. bool ReleaseTexture(const String& source, RenderInterface* match_render_interface)
  334. {
  335. bool result = false;
  336. if (!core_data)
  337. return result;
  338. for (auto& render_manager : core_data->render_managers)
  339. {
  340. if (!match_render_interface || render_manager.first == match_render_interface)
  341. {
  342. if (RenderManagerAccess::ReleaseTexture(render_manager.second.get(), source))
  343. result = true;
  344. }
  345. }
  346. return result;
  347. }
  348. void ReleaseCompiledGeometry(RenderInterface* match_render_interface)
  349. {
  350. if (!core_data)
  351. return;
  352. for (auto& render_manager : core_data->render_managers)
  353. {
  354. if (!match_render_interface || render_manager.first == match_render_interface)
  355. RenderManagerAccess::ReleaseAllCompiledGeometry(render_manager.second.get());
  356. }
  357. }
  358. void ReleaseFontResources()
  359. {
  360. if (!font_interface)
  361. return;
  362. for (const auto& name_context : core_data->contexts)
  363. name_context.second->GetRootElement()->DirtyFontFaceRecursive();
  364. font_interface->ReleaseFontResources();
  365. for (const auto& name_context : core_data->contexts)
  366. name_context.second->Update();
  367. }
  368. void ReleaseRenderManagers()
  369. {
  370. auto& contexts = core_data->contexts;
  371. auto& render_managers = core_data->render_managers;
  372. ReleaseFontResources();
  373. for (auto it = render_managers.begin(); it != render_managers.end();)
  374. {
  375. RenderManager* render_manager = it->second.get();
  376. const auto num_contexts_using_manager = std::count_if(contexts.begin(), contexts.end(),
  377. [&](const auto& context_pair) { return &context_pair.second->GetRenderManager() == render_manager; });
  378. if (num_contexts_using_manager == 0)
  379. it = render_managers.erase(it);
  380. else
  381. ++it;
  382. }
  383. }
  384. // Functions that need to be accessible within the Core library, but not publicly.
  385. namespace CoreInternal {
  386. bool HasRenderManager(RenderInterface* match_render_interface)
  387. {
  388. return core_data && core_data->render_managers.find(match_render_interface) != core_data->render_managers.end();
  389. }
  390. } // namespace CoreInternal
  391. } // namespace Rml