mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
renderer: introduce a ThorVG Text interface.
Introduced New APIs under the experimental tags. - Result Text::font(const char* name, float size, const char* style = nullptr); - Result Text::text(const char* text); - Result Text::fill(uint8_t r, uint8_t g, uint8_t b); - static Result Text::load(const std::string& path); - static Result Text::unload(const std::string& path); - static Text::std::unique_ptr<Text> gen(); - static Text::uint32_t identifier() @Issue: https://github.com/thorvg/thorvg/issues/969
This commit is contained in:
parent
061222bb59
commit
0f69eef8ed
8 changed files with 439 additions and 1 deletions
132
inc/thorvg.h
132
inc/thorvg.h
|
@ -1429,6 +1429,138 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class Text
|
||||
*
|
||||
* @brief A class to represent text objects in a graphical context, allowing for rendering and manipulation of unicode text.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
class TVG_API Text final : public Paint
|
||||
{
|
||||
public:
|
||||
~Text();
|
||||
|
||||
/**
|
||||
* @brief Sets the font properties for the text.
|
||||
*
|
||||
* This function allows you to define the font characteristics used for text rendering.
|
||||
* It sets the font name, size and optionally the style.
|
||||
*
|
||||
* @param[in] name The name of the font. This should correspond to a font available in the canvas.
|
||||
* @param[in] size The size of the font in points. This determines how large the text will appear.
|
||||
* @param[in] style The style of the font. It can be used to set the font to 'italic'.
|
||||
* If not specified, the default style is used. Only 'italic' style is supported currently.
|
||||
*
|
||||
* @retval Result::Success when the font properties are set successfully.
|
||||
* @retval Result::InsufficientCondition when the specified @p name cannot be found.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result font(const char* name, float size, const char* style = nullptr) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Assigns the given unicode text to be rendered.
|
||||
*
|
||||
* This function sets the unicode string that will be displayed by the rendering system.
|
||||
* The text is set according to the specified UTF encoding method, which defaults to UTF-8.
|
||||
*
|
||||
* @param[in] text The multi-byte text encoded with utf8 string to be rendered.
|
||||
*
|
||||
* @retval Result::Success when succeed.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result text(const char* text) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the text color.
|
||||
*
|
||||
* @param[in] r The red color channel value in the range [0 ~ 255]. The default value is 0.
|
||||
* @param[in] g The green color channel value in the range [0 ~ 255]. The default value is 0.
|
||||
* @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0.
|
||||
*
|
||||
* @retval Result::Success when succeed.
|
||||
* @retval Result::InsufficientCondition when the font has not been set up prior to this operation.
|
||||
*
|
||||
* @see Text::font()
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
Result fill(uint8_t r, uint8_t g, uint8_t b) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the gradient fill for all of the figures from the text.
|
||||
*
|
||||
* The parts of the text defined as inner are filled.
|
||||
*
|
||||
* @param[in] f The unique pointer to the gradient fill.
|
||||
*
|
||||
* @retval Result::Success when succeed, Result::MemoryCorruption otherwise.
|
||||
* @retval Result::InsufficientCondition when the font has not been set up prior to this operation.
|
||||
*
|
||||
* @note Either a solid color or a gradient fill is applied, depending on what was set as last.
|
||||
* @note Experimental API
|
||||
*
|
||||
* @see Text::font()
|
||||
*/
|
||||
Result fill(std::unique_ptr<Fill> f) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Loads a scalable font data(ttf) from a file.
|
||||
*
|
||||
* @param[in] path The path to the font file.
|
||||
*
|
||||
* @retval Result::Success When succeed.
|
||||
* @retval Result::InvalidArguments In case the @p path is invalid.
|
||||
* @retval Result::NonSupport When trying to load a file with an unknown extension.
|
||||
* @retval Result::Unknown If an error occurs at a later stage.
|
||||
*
|
||||
* @note Experimental API
|
||||
*
|
||||
* @see Text::unload(const std::string& path)
|
||||
*/
|
||||
static Result load(const std::string& path) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Unloads the specified scalable font data (TTF) that was previously loaded.
|
||||
*
|
||||
* This function is used to release resources associated with a font file that has been loaded into memory.
|
||||
*
|
||||
* @param[in] path The file path of the loaded font.
|
||||
*
|
||||
* @retval Result::Success Successfully unloads the font data.
|
||||
* @retval Result::InsufficientCondition Fails if the loader is not initialized.
|
||||
*
|
||||
* @note If the font data is currently in use, it will not be immediately unloaded.
|
||||
* @note Experimental API
|
||||
*
|
||||
* @see Text::load(const std::string& path)
|
||||
*/
|
||||
static Result unload(const std::string& path) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Creates a new Text object.
|
||||
*
|
||||
* @return A new Text object.
|
||||
*
|
||||
* @note Experimental API
|
||||
*/
|
||||
static std::unique_ptr<Text> gen() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Return the unique id value of this class.
|
||||
*
|
||||
* This method can be referred for identifying the Text class type.
|
||||
*
|
||||
* @return The type id of the Text class.
|
||||
*/
|
||||
static uint32_t identifier() noexcept;
|
||||
|
||||
_TVG_DECLARE_PRIVATE(Text);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class SwCanvas
|
||||
*
|
||||
|
|
|
@ -171,7 +171,7 @@ bool TtfLoader::resize(Paint* paint, float sx, TVG_UNUSED float sy)
|
|||
if (!paint) return false;
|
||||
auto shift = 0.0f;
|
||||
auto dpi = 96.0f / 72.0f; //dpi base?
|
||||
auto scale = sx * dpi / reader.metrics.unitsPerEm;
|
||||
scale = sx * dpi / reader.metrics.unitsPerEm;
|
||||
if (italic) shift = -scale * 0.18f; //experimental decision.
|
||||
Matrix m = {scale, shift, -(shift * reader.metrics.minw), 0, scale, 0, 0, 0, 1};
|
||||
paint->transform(m);
|
||||
|
|
|
@ -26,6 +26,7 @@ source_file = [
|
|||
'tvgScene.h',
|
||||
'tvgShape.h',
|
||||
'tvgTaskScheduler.h',
|
||||
'tvgText.h',
|
||||
'tvgAccessor.cpp',
|
||||
'tvgAnimation.cpp',
|
||||
'tvgCanvas.cpp',
|
||||
|
@ -41,6 +42,7 @@ source_file = [
|
|||
'tvgShape.cpp',
|
||||
'tvgSwCanvas.cpp',
|
||||
'tvgTaskScheduler.cpp',
|
||||
'tvgText.cpp'
|
||||
]
|
||||
|
||||
common_dep = declare_dependency(
|
||||
|
|
|
@ -61,6 +61,7 @@ using namespace tvg;
|
|||
#define TVG_CLASS_ID_PICTURE 3
|
||||
#define TVG_CLASS_ID_LINEAR 4
|
||||
#define TVG_CLASS_ID_RADIAL 5
|
||||
#define TVG_CLASS_ID_TEXT 6
|
||||
|
||||
enum class FileType { Tvg = 0, Svg, Ttf, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown };
|
||||
|
||||
|
|
|
@ -81,6 +81,8 @@ struct ImageLoader : LoadModule
|
|||
|
||||
struct FontLoader : LoadModule
|
||||
{
|
||||
float scale = 1.0f;
|
||||
|
||||
FontLoader(FileType type) : LoadModule(type) {}
|
||||
|
||||
virtual bool request(Shape* shape, char* text, bool italic = false) = 0;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "tvgShape.h"
|
||||
#include "tvgPicture.h"
|
||||
#include "tvgScene.h"
|
||||
#include "tvgText.h"
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
|
@ -35,6 +36,7 @@
|
|||
case TVG_CLASS_ID_SHAPE: ret = P((Shape*)paint)->METHOD; break; \
|
||||
case TVG_CLASS_ID_SCENE: ret = P((Scene*)paint)->METHOD; break; \
|
||||
case TVG_CLASS_ID_PICTURE: ret = P((Picture*)paint)->METHOD; break; \
|
||||
case TVG_CLASS_ID_TEXT: ret = P((Text*)paint)->METHOD; break; \
|
||||
default: ret = {}; \
|
||||
}
|
||||
|
||||
|
|
109
src/renderer/tvgText.cpp
Normal file
109
src/renderer/tvgText.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "tvgText.h"
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
Text::Text() : pImpl(new Impl)
|
||||
{
|
||||
Paint::pImpl->id = TVG_CLASS_ID_TEXT;
|
||||
}
|
||||
|
||||
|
||||
Text::~Text()
|
||||
{
|
||||
delete(pImpl);
|
||||
}
|
||||
|
||||
|
||||
Result Text::text(const char* text) noexcept
|
||||
{
|
||||
return pImpl->text(text);
|
||||
}
|
||||
|
||||
|
||||
Result Text::font(const char* name, float size, const char* style) noexcept
|
||||
{
|
||||
return pImpl->font(name, size, style);
|
||||
}
|
||||
|
||||
|
||||
Result Text::load(const std::string& path) noexcept
|
||||
{
|
||||
bool invalid; //invalid path
|
||||
if (!LoaderMgr::loader(path, &invalid)) {
|
||||
if (invalid) return Result::InvalidArguments;
|
||||
else return Result::NonSupport;
|
||||
}
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Text::unload(const std::string& path) noexcept
|
||||
{
|
||||
if (LoaderMgr::retrieve(path)) return Result::Success;
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
|
||||
Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept
|
||||
{
|
||||
if (!pImpl->paint) return Result::InsufficientCondition;
|
||||
|
||||
return pImpl->fill(r, g, b);
|
||||
}
|
||||
|
||||
|
||||
Result Text::fill(unique_ptr<Fill> f) noexcept
|
||||
{
|
||||
if (!pImpl->paint) return Result::InsufficientCondition;
|
||||
|
||||
auto p = f.release();
|
||||
if (!p) return Result::MemoryCorruption;
|
||||
|
||||
return pImpl->fill(p);
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<Text> Text::gen() noexcept
|
||||
{
|
||||
return unique_ptr<Text>(new Text);
|
||||
}
|
||||
|
||||
|
||||
uint32_t Text::identifier() noexcept
|
||||
{
|
||||
return TVG_CLASS_ID_TEXT;
|
||||
}
|
190
src/renderer/tvgText.h
Normal file
190
src/renderer/tvgText.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _TVG_TEXT_H
|
||||
#define _TVG_TEXT_H
|
||||
|
||||
#include <cstring>
|
||||
#include "tvgShape.h"
|
||||
#include "tvgFill.h"
|
||||
|
||||
#ifdef THORVG_TTF_LOADER_SUPPORT
|
||||
#include "tvgTtfLoader.h"
|
||||
#else
|
||||
#include "tvgLoader.h"
|
||||
#endif
|
||||
|
||||
struct Text::Impl
|
||||
{
|
||||
RenderData rd = nullptr;
|
||||
FontLoader* loader = nullptr;
|
||||
Shape* paint = nullptr;
|
||||
char* utf8 = nullptr;
|
||||
float fontSize;
|
||||
bool italic = false;
|
||||
bool changed = false;
|
||||
|
||||
~Impl()
|
||||
{
|
||||
LoaderMgr::retrieve(loader);
|
||||
delete(paint);
|
||||
}
|
||||
|
||||
Result fill(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return paint->fill(r, g, b);
|
||||
}
|
||||
|
||||
Result fill(Fill* f)
|
||||
{
|
||||
return paint->fill(cast<Fill>(f));
|
||||
}
|
||||
|
||||
Result text(const char* utf8)
|
||||
{
|
||||
free(this->utf8);
|
||||
if (utf8) this->utf8 = strdup(utf8);
|
||||
else this->utf8 = nullptr;
|
||||
changed = true;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
Result font(const char* name, float size, const char* style)
|
||||
{
|
||||
auto loader = LoaderMgr::loader(name);
|
||||
if (!loader) return Result::InsufficientCondition;
|
||||
|
||||
//Same resource has been loaded.
|
||||
if (this->loader == loader) {
|
||||
this->loader->sharing--; //make it sure the reference counting.
|
||||
return Result::Success;
|
||||
} else if (this->loader) {
|
||||
LoaderMgr::retrieve(this->loader);
|
||||
}
|
||||
this->loader = static_cast<FontLoader*>(loader);
|
||||
|
||||
if (!paint) paint = Shape::gen().release();
|
||||
|
||||
fontSize = size;
|
||||
if (style && strstr(style, "italic")) italic = true;
|
||||
changed = true;
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
RenderRegion bounds(RenderMethod& renderer)
|
||||
{
|
||||
return renderer.region(rd);
|
||||
}
|
||||
|
||||
bool render(RenderMethod& renderer)
|
||||
{
|
||||
if (paint) return PP(paint)->render(renderer);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load()
|
||||
{
|
||||
if (!loader) return false;
|
||||
|
||||
//reload
|
||||
if (changed) {
|
||||
loader->request(paint, utf8, italic);
|
||||
loader->read();
|
||||
changed = false;
|
||||
}
|
||||
if (paint) {
|
||||
loader->resize(paint, fontSize, fontSize);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
|
||||
{
|
||||
if (!load()) return nullptr;
|
||||
|
||||
//transform the gradient coordinates based on the final scaled font.
|
||||
if (P(paint)->flag & RenderUpdateFlag::Gradient) {
|
||||
auto fill = P(paint)->rs.fill;
|
||||
auto scale = 1.0f / loader->scale;
|
||||
if (fill->identifier() == TVG_CLASS_ID_LINEAR) {
|
||||
P(static_cast<LinearGradient*>(fill))->x1 *= scale;
|
||||
P(static_cast<LinearGradient*>(fill))->y1 *= scale;
|
||||
P(static_cast<LinearGradient*>(fill))->x2 *= scale;
|
||||
P(static_cast<LinearGradient*>(fill))->y2 *= scale;
|
||||
} else {
|
||||
P(static_cast<RadialGradient*>(fill))->cx *= scale;
|
||||
P(static_cast<RadialGradient*>(fill))->cy *= scale;
|
||||
P(static_cast<RadialGradient*>(fill))->r *= scale;
|
||||
P(static_cast<RadialGradient*>(fill))->fx *= scale;
|
||||
P(static_cast<RadialGradient*>(fill))->fy *= scale;
|
||||
P(static_cast<RadialGradient*>(fill))->fr *= scale;
|
||||
}
|
||||
}
|
||||
rd = PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper);
|
||||
return rd;
|
||||
}
|
||||
|
||||
bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking)
|
||||
{
|
||||
if (!load() || !paint) return false;
|
||||
paint->bounds(x, y, w, h, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dispose(RenderMethod& renderer)
|
||||
{
|
||||
renderer.dispose(rd);
|
||||
this->rd = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
Paint* duplicate()
|
||||
{
|
||||
load();
|
||||
|
||||
auto ret = Text::gen().release();
|
||||
auto dup = ret->pImpl;
|
||||
if (paint) dup->paint = static_cast<Shape*>(paint->duplicate());
|
||||
|
||||
if (loader) {
|
||||
dup->loader = loader;
|
||||
++dup->loader->sharing;
|
||||
}
|
||||
|
||||
dup->utf8 = strdup(utf8);
|
||||
dup->italic = italic;
|
||||
dup->fontSize = fontSize;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Iterator* iterator()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //_TVG_TEXT_H
|
Loading…
Add table
Reference in a new issue