mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
ttf: ++thread safety
Properly allow the ttf loader sharable among threads. issue: https://github.com/thorvg/thorvg/issues/3165
This commit is contained in:
parent
756f866d54
commit
bd520c1c69
7 changed files with 58 additions and 51 deletions
|
@ -221,17 +221,16 @@ void TtfLoader::clear()
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
bool TtfLoader::transform(Paint* paint, float fontSize, bool italic)
|
float TtfLoader::transform(Paint* paint, FontMetrics& metrics, float fontSize, bool italic)
|
||||||
{
|
{
|
||||||
if (!paint) return false;
|
|
||||||
auto shift = 0.0f;
|
auto shift = 0.0f;
|
||||||
auto dpi = 96.0f / 72.0f; //dpi base?
|
auto dpi = 96.0f / 72.0f; //dpi base?
|
||||||
scale = fontSize * dpi / reader.metrics.unitsPerEm;
|
auto scale = fontSize * dpi / reader.metrics.unitsPerEm;
|
||||||
if (italic) shift = -scale * 0.18f; //experimental decision.
|
if (italic) shift = -scale * 0.18f; //experimental decision.
|
||||||
Matrix m = {scale, shift, -(shift * reader.metrics.minw), 0, scale, 0, 0, 0, 1};
|
Matrix m = {scale, shift, -(shift * metrics.minw), 0, scale, 0, 0, 0, 1};
|
||||||
paint->transform(m);
|
paint->transform(m);
|
||||||
|
|
||||||
return true;
|
return scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,21 +276,11 @@ bool TtfLoader::open(const char* data, uint32_t size, TVG_UNUSED const char* rpa
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TtfLoader::request(Shape* shape, char* text)
|
bool TtfLoader::read(Shape* shape, char* text, FontMetrics& out)
|
||||||
{
|
|
||||||
this->shape = shape;
|
|
||||||
this->text = text;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TtfLoader::read()
|
|
||||||
{
|
{
|
||||||
if (!text) return false;
|
if (!text) return false;
|
||||||
|
|
||||||
shape->reset();
|
shape->reset();
|
||||||
shape->fill(FillRule::EvenOdd);
|
|
||||||
|
|
||||||
auto n = strlen(text);
|
auto n = strlen(text);
|
||||||
auto code = _codepoints(text, n);
|
auto code = _codepoints(text, n);
|
||||||
|
@ -313,7 +302,7 @@ bool TtfLoader::read()
|
||||||
lglyph = rglyph;
|
lglyph = rglyph;
|
||||||
//store the first glyph with outline min size for italic transform.
|
//store the first glyph with outline min size for italic transform.
|
||||||
if (loadMinw && gmetrics.outline) {
|
if (loadMinw && gmetrics.outline) {
|
||||||
reader.metrics.minw = gmetrics.minw;
|
out.minw = gmetrics.minw;
|
||||||
loadMinw = false;
|
loadMinw = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,12 @@ struct TtfLoader : public FontLoader
|
||||||
~TtfLoader();
|
~TtfLoader();
|
||||||
|
|
||||||
using FontLoader::open;
|
using FontLoader::open;
|
||||||
|
using FontLoader::read;
|
||||||
|
|
||||||
bool open(const char* path) override;
|
bool open(const char* path) override;
|
||||||
bool open(const char *data, uint32_t size, const char* rpath, bool copy) override;
|
bool open(const char *data, uint32_t size, const char* rpath, bool copy) override;
|
||||||
bool transform(Paint* paint, float fontSize, bool italic) override;
|
float transform(Paint* paint, FontMetrics& metrices, float fontSize, bool italic) override;
|
||||||
bool request(Shape* shape, char* text) override;
|
bool read(Shape* shape, char* text, FontMetrics& out) override;
|
||||||
bool read() override;
|
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -63,12 +63,10 @@ static int _cmpu32(const void *a, const void *b)
|
||||||
|
|
||||||
bool TtfReader::validate(uint32_t offset, uint32_t margin) const
|
bool TtfReader::validate(uint32_t offset, uint32_t margin) const
|
||||||
{
|
{
|
||||||
#if 1
|
|
||||||
if ((offset > size) || (size - offset < margin)) {
|
if ((offset > size) || (size - offset < margin)) {
|
||||||
TVGERR("TTF", "Invalidate data");
|
TVGERR("TTF", "Invalidate data");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +193,11 @@ uint32_t TtfReader::outlineOffset(uint32_t glyph)
|
||||||
{
|
{
|
||||||
uint32_t cur, next;
|
uint32_t cur, next;
|
||||||
|
|
||||||
if (!loca) loca = table("loca");
|
auto loca = this->loca.load();
|
||||||
if (!glyf) glyf = table("glyf");
|
if (loca == 0) this->loca = loca = table("loca");
|
||||||
|
|
||||||
|
auto glyf = this->glyf.load();
|
||||||
|
if (glyf == 0) this->glyf = glyf = table("glyf");
|
||||||
|
|
||||||
if (metrics.locaFormat == 0) {
|
if (metrics.locaFormat == 0) {
|
||||||
auto base = loca + 2 * glyph;
|
auto base = loca + 2 * glyph;
|
||||||
|
@ -318,8 +319,8 @@ bool TtfReader::header()
|
||||||
metrics.numHmtx = _u16(data, hhea + 34);
|
metrics.numHmtx = _u16(data, hhea + 34);
|
||||||
|
|
||||||
//kerning
|
//kerning
|
||||||
this->kern = table("kern");
|
auto kern = this->kern = table("kern");
|
||||||
if (this->kern) {
|
if (kern) {
|
||||||
if (!validate(kern, 4)) return false;
|
if (!validate(kern, 4)) return false;
|
||||||
if (_u16(data, kern) != 0) return false;
|
if (_u16(data, kern) != 0) return false;
|
||||||
}
|
}
|
||||||
|
@ -330,8 +331,9 @@ bool TtfReader::header()
|
||||||
|
|
||||||
uint32_t TtfReader::glyph(uint32_t codepoint)
|
uint32_t TtfReader::glyph(uint32_t codepoint)
|
||||||
{
|
{
|
||||||
|
auto cmap = this->cmap.load();
|
||||||
if (cmap == 0) {
|
if (cmap == 0) {
|
||||||
cmap = table("cmap");
|
this->cmap = cmap = table("cmap");
|
||||||
if (!validate(cmap, 4)) return -1;
|
if (!validate(cmap, 4)) return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +390,8 @@ uint32_t TtfReader::glyph(uint32_t codepoint, TtfGlyphMetrics& gmetrics)
|
||||||
bool TtfReader::glyphMetrics(uint32_t glyphIndex, TtfGlyphMetrics& gmetrics)
|
bool TtfReader::glyphMetrics(uint32_t glyphIndex, TtfGlyphMetrics& gmetrics)
|
||||||
{
|
{
|
||||||
//horizontal metrics
|
//horizontal metrics
|
||||||
if (!hmtx) hmtx = table("hmtx");
|
auto hmtx = this->hmtx.load();
|
||||||
|
if (hmtx == 0) this->hmtx = hmtx = table("hmtx");
|
||||||
|
|
||||||
//glyph is inside long metrics segment.
|
//glyph is inside long metrics segment.
|
||||||
if (glyphIndex < metrics.numHmtx) {
|
if (glyphIndex < metrics.numHmtx) {
|
||||||
|
@ -442,7 +445,8 @@ bool TtfReader::convert(Shape* shape, TtfGlyphMetrics& gmetrics, const Point& of
|
||||||
if (outlineCnt == 0) return false;
|
if (outlineCnt == 0) return false;
|
||||||
if (outlineCnt < 0) {
|
if (outlineCnt < 0) {
|
||||||
uint16_t maxComponentDepth = 1U;
|
uint16_t maxComponentDepth = 1U;
|
||||||
if (!maxp) maxp = table("maxp");
|
auto maxp = this->maxp.load();
|
||||||
|
if (maxp == 0) this->maxp = maxp = table("maxp");
|
||||||
if (validate(maxp, 32) && _u32(data, maxp) >= 0x00010000U) { // >= version 1.0
|
if (validate(maxp, 32) && _u32(data, maxp) >= 0x00010000U) { // >= version 1.0
|
||||||
maxComponentDepth = _u16(data, maxp + 30);
|
maxComponentDepth = _u16(data, maxp + 30);
|
||||||
}
|
}
|
||||||
|
@ -598,7 +602,7 @@ void TtfReader::kerning(uint32_t lglyph, uint32_t rglyph, Point& out)
|
||||||
|
|
||||||
if (!kern) return;
|
if (!kern) return;
|
||||||
|
|
||||||
auto kern = this->kern;
|
auto kern = this->kern.load();
|
||||||
|
|
||||||
out.x = out.y = 0.0f;
|
out.x = out.y = 0.0f;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#ifndef _TVG_TTF_READER_H
|
#ifndef _TVG_TTF_READER_H
|
||||||
#define _TVG_TTF_READER_H
|
#define _TVG_TTF_READER_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
#include "tvgArray.h"
|
#include "tvgArray.h"
|
||||||
|
|
||||||
|
@ -55,7 +56,6 @@ public:
|
||||||
float lineGap;
|
float lineGap;
|
||||||
} hhea;
|
} hhea;
|
||||||
|
|
||||||
float minw; //first glyph width (used for italic)
|
|
||||||
uint16_t unitsPerEm;
|
uint16_t unitsPerEm;
|
||||||
uint16_t numHmtx; //the number of Horizontal metrics table
|
uint16_t numHmtx; //the number of Horizontal metrics table
|
||||||
uint8_t locaFormat; //0 for short offsets, 1 for long
|
uint8_t locaFormat; //0 for short offsets, 1 for long
|
||||||
|
@ -68,12 +68,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//table offsets
|
//table offsets
|
||||||
uint32_t cmap = 0;
|
atomic<uint32_t> cmap{};
|
||||||
uint32_t hmtx = 0;
|
atomic<uint32_t> hmtx{};
|
||||||
uint32_t loca = 0;
|
atomic<uint32_t> loca{};
|
||||||
uint32_t glyf = 0;
|
atomic<uint32_t> glyf{};
|
||||||
uint32_t kern = 0;
|
atomic<uint32_t> kern{};
|
||||||
uint32_t maxp = 0;
|
atomic<uint32_t> maxp{};
|
||||||
|
|
||||||
uint32_t cmap_12_13(uint32_t table, uint32_t codepoint, int which) const;
|
uint32_t cmap_12_13(uint32_t table, uint32_t codepoint, int which) const;
|
||||||
uint32_t cmap_4(uint32_t table, uint32_t codepoint) const;
|
uint32_t cmap_4(uint32_t table, uint32_t codepoint) const;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#ifndef _TVG_LOAD_MODULE_H_
|
#ifndef _TVG_LOAD_MODULE_H_
|
||||||
#define _TVG_LOAD_MODULE_H_
|
#define _TVG_LOAD_MODULE_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include "tvgCommon.h"
|
#include "tvgCommon.h"
|
||||||
#include "tvgRender.h"
|
#include "tvgRender.h"
|
||||||
#include "tvgInlist.h"
|
#include "tvgInlist.h"
|
||||||
|
@ -37,7 +38,7 @@ struct LoadModule
|
||||||
char* hashpath = nullptr;
|
char* hashpath = nullptr;
|
||||||
|
|
||||||
FileType type; //current loader file type
|
FileType type; //current loader file type
|
||||||
uint16_t sharing = 0; //reference count
|
atomic<uint16_t> sharing{}; //reference count
|
||||||
bool readied = false; //read done already.
|
bool readied = false; //read done already.
|
||||||
bool cached = false; //cached for sharing
|
bool cached = false; //cached for sharing
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ struct LoadModule
|
||||||
|
|
||||||
struct ImageLoader : LoadModule
|
struct ImageLoader : LoadModule
|
||||||
{
|
{
|
||||||
static ColorSpace cs; //desired value
|
static atomic<ColorSpace> cs; //desired value
|
||||||
|
|
||||||
float w = 0, h = 0; //default image size
|
float w = 0, h = 0; //default image size
|
||||||
RenderSurface surface;
|
RenderSurface surface;
|
||||||
|
@ -100,15 +101,23 @@ struct ImageLoader : LoadModule
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct FontMetrics
|
||||||
|
{
|
||||||
|
//TODO: add necessary metrics
|
||||||
|
float minw;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct FontLoader : LoadModule
|
struct FontLoader : LoadModule
|
||||||
{
|
{
|
||||||
float scale = 1.0f;
|
|
||||||
char* name = nullptr;
|
char* name = nullptr;
|
||||||
|
|
||||||
FontLoader(FileType type) : LoadModule(type) {}
|
FontLoader(FileType type) : LoadModule(type) {}
|
||||||
|
|
||||||
virtual bool request(Shape* shape, char* text) = 0;
|
using LoadModule::read;
|
||||||
virtual bool transform(Paint* paint, float fontSize, bool italic) = 0;
|
|
||||||
|
virtual bool read(Shape* shape, char* text, FontMetrics& out) = 0;
|
||||||
|
virtual float transform(Paint* paint, FontMetrics& mertrics, float fontSize, bool italic) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_TVG_LOAD_MODULE_H_
|
#endif //_TVG_LOAD_MODULE_H_
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include "tvgInlist.h"
|
#include "tvgInlist.h"
|
||||||
#include "tvgStr.h"
|
#include "tvgStr.h"
|
||||||
#include "tvgLoader.h"
|
#include "tvgLoader.h"
|
||||||
|
@ -61,7 +62,8 @@ uintptr_t HASH_KEY(const char* data)
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
ColorSpace ImageLoader::cs = ColorSpace::ARGB8888;
|
//TODO: remove it.
|
||||||
|
atomic<ColorSpace> ImageLoader::cs{ColorSpace::ARGB8888};
|
||||||
|
|
||||||
static Key _key;
|
static Key _key;
|
||||||
static Inlist<LoadModule> _activeLoaders;
|
static Inlist<LoadModule> _activeLoaders;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define _TVG_TEXT_H
|
#define _TVG_TEXT_H
|
||||||
|
|
||||||
#include "tvgStr.h"
|
#include "tvgStr.h"
|
||||||
|
#include "tvgMath.h"
|
||||||
#include "tvgShape.h"
|
#include "tvgShape.h"
|
||||||
#include "tvgFill.h"
|
#include "tvgFill.h"
|
||||||
#include "tvgLoader.h"
|
#include "tvgLoader.h"
|
||||||
|
@ -34,6 +35,7 @@ struct Text::Impl : Paint::Impl
|
||||||
{
|
{
|
||||||
Shape* shape; //text shape
|
Shape* shape; //text shape
|
||||||
FontLoader* loader = nullptr;
|
FontLoader* loader = nullptr;
|
||||||
|
FontMetrics metrics;
|
||||||
char* utf8 = nullptr;
|
char* utf8 = nullptr;
|
||||||
float fontSize;
|
float fontSize;
|
||||||
bool italic = false;
|
bool italic = false;
|
||||||
|
@ -42,6 +44,7 @@ struct Text::Impl : Paint::Impl
|
||||||
Impl(Text* p) : Paint::Impl(p), shape(Shape::gen())
|
Impl(Text* p) : Paint::Impl(p), shape(Shape::gen())
|
||||||
{
|
{
|
||||||
PAINT(shape)->parent = p;
|
PAINT(shape)->parent = p;
|
||||||
|
shape->fill(FillRule::EvenOdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Impl()
|
~Impl()
|
||||||
|
@ -96,27 +99,26 @@ struct Text::Impl : Paint::Impl
|
||||||
return PAINT(shape)->render(renderer);
|
return PAINT(shape)->render(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load()
|
float load()
|
||||||
{
|
{
|
||||||
if (!loader) return false;
|
if (!loader) return 0.0f;
|
||||||
|
|
||||||
loader->request(shape, utf8);
|
|
||||||
//reload
|
//reload
|
||||||
if (changed) {
|
if (changed) {
|
||||||
loader->read();
|
loader->read(shape, utf8, metrics);
|
||||||
changed = false;
|
changed = false;
|
||||||
}
|
}
|
||||||
return loader->transform(shape, fontSize, italic);
|
return loader->transform(shape, metrics, fontSize, italic);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper)
|
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper)
|
||||||
{
|
{
|
||||||
if (!load()) return nullptr;
|
auto scale = 1.0f / load();
|
||||||
|
if (tvg::zero(scale)) return nullptr;
|
||||||
|
|
||||||
//transform the gradient coordinates based on the final scaled font.
|
//transform the gradient coordinates based on the final scaled font.
|
||||||
auto fill = SHAPE(shape)->rs.fill;
|
auto fill = SHAPE(shape)->rs.fill;
|
||||||
if (fill && SHAPE(shape)->renderFlag & RenderUpdateFlag::Gradient) {
|
if (fill && SHAPE(shape)->renderFlag & RenderUpdateFlag::Gradient) {
|
||||||
auto scale = 1.0f / loader->scale;
|
|
||||||
if (fill->type() == Type::LinearGradient) {
|
if (fill->type() == Type::LinearGradient) {
|
||||||
LINEAR(fill)->x1 *= scale;
|
LINEAR(fill)->x1 *= scale;
|
||||||
LINEAR(fill)->y1 *= scale;
|
LINEAR(fill)->y1 *= scale;
|
||||||
|
@ -137,7 +139,7 @@ struct Text::Impl : Paint::Impl
|
||||||
|
|
||||||
Result bounds(Point* pt4, Matrix& m, bool obb, TVG_UNUSED bool stroking)
|
Result bounds(Point* pt4, Matrix& m, bool obb, TVG_UNUSED bool stroking)
|
||||||
{
|
{
|
||||||
if (!load()) return Result::InsufficientCondition;
|
if (load() == 0.0f) return Result::InsufficientCondition;
|
||||||
return PAINT(shape)->bounds(pt4, &m, obb, true);
|
return PAINT(shape)->bounds(pt4, &m, obb, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue