Files
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

275 lines
9.6 KiB
C++

#include "./TextMeasurerEmbed.h"
#include "./PointerEmbed.h"
#include "./../../fontengine/TextShaper.h"
#include "./../../fontengine/TextHyphen.h"
#define RAW_POINTER(value) ((CPointerEmbedObject*)value->toObject()->getNative())->Data
#define POINTER_OBJECT(value) ((CPointerEmbedObject*)value->toObject()->getNative())
// в js не хотим следить, чтобы в каждом face была ссылка на library - т.е. чтобы
// сначала удалились все face, а потом library - поэтому делаем свой счетчик ссылок
// и следим за library сами. Т.е. используем FT_Library_Reference/FT_Library_UnReference
class CExternalPointerJS : public NSShaper::CExternalPointer
{
public:
CExternalPointerJS() : NSShaper::CExternalPointer() {}
virtual ~CExternalPointerJS() {}
public:
virtual void Alloc(const unsigned int& len)
{
Len = len;
Data = NSAllocator::Alloc((size_t)Len);
}
virtual void Free()
{
if (Data)
NSAllocator::Free(Data, (size_t)Len);
}
};
CTextMeasurerEmbed::CTextMeasurerEmbed()
{
m_hyphen_engine = new NSHyphen::CEngine();
}
CTextMeasurerEmbed::~CTextMeasurerEmbed()
{
NSHyphen::CEngine* tmp = (NSHyphen::CEngine*)m_hyphen_engine;
delete tmp;
m_hyphen_engine = NULL;
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Malloc(JSSmart<CJSValue> typed_array_or_len)
{
void* pData = NULL;
size_t len = 0;
if (typed_array_or_len->isNumber())
{
len = (size_t)typed_array_or_len->toInt32();
if (0 != len)
pData = malloc((size_t)len);
}
else
{
JSSmart<CJSTypedArray> typedArray = typed_array_or_len->toTypedArray();
CJSDataBuffer pBuffer = typedArray->getData();
pData = malloc(pBuffer.Len);
memcpy(pData, pBuffer.Data, pBuffer.Len);
if (pBuffer.IsExternalize)
pBuffer.Free();
}
CPointerEmbedObject* pObject = new CPointerEmbedObject(pData, NSPointerObjectDeleters::FreeDeleter);
return pObject->createObject();
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Free(JSSmart<CJSValue> pointer)
{
CPointerEmbedObject* pEmbed = (CPointerEmbedObject*)pointer->toObject()->getNative();
pEmbed->Free();
return CJSContext::createUndefined();
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Init()
{
CPointerEmbedObject* pointer = new CPointerEmbedObject(NSShaper::FT_Library_Init(), [](void* data) { NSShaper::FT_Library_UnReference(data); });
return pointer->createObject();
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Set_TrueType_HintProp(JSSmart<CJSValue> library, JSSmart<CJSValue> tt_interpreter)
{
return CJSContext::createInt(NSShaper::FT_Set_TrueType_HintProp(RAW_POINTER(library), tt_interpreter->toUInt32()));
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Open_Face(JSSmart<CJSValue> library, JSSmart<CJSValue> memory, JSSmart<CJSValue> size, JSSmart<CJSValue> face_index)
{
void* ftlibrary = RAW_POINTER(library);
void* face = NSShaper::FT_Open_Face(ftlibrary, (unsigned char*)RAW_POINTER(memory), size->toUInt32(), face_index->toInt32());
if (NULL != face)
NSShaper::FT_Library_Reference(ftlibrary);
CPointerEmbedObject* pointer = new CPointerEmbedObject(face, [](void* data) { NSShaper::FT_Done_Face_With_Library(data); });
return pointer->createObject();
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Open_Face2(JSSmart<CJSValue> library, JSSmart<CJSValue> array, JSSmart<CJSValue> face_index)
{
void* ftlibrary = RAW_POINTER(library);
JSSmart<CJSTypedArray> typedArray = array->toTypedArray();
CJSDataBuffer buffer = typedArray->getData();
void* face = NSShaper::FT_Open_Face(ftlibrary, (unsigned char*)buffer.Data, (unsigned int)buffer.Len, face_index->toInt32());
if (NULL != face)
NSShaper::FT_Library_Reference(ftlibrary);
CPointerEmbedObject* pointer = new CPointerEmbedObject(face, [](void* data) { NSShaper::FT_Done_Face_With_Library(data); });
return pointer->createObject();
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_GetFaceInfo(JSSmart<CJSValue> face)
{
CExternalPointerJS result;
if (!NSShaper::FT_GetFaceInfo(RAW_POINTER(face), &result))
return CJSContext::createNull();
return CJSContext::createUint8Array(result.Data, result.Len, false);
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Load_Glyph(JSSmart<CJSValue> face, JSSmart<CJSValue> gid, JSSmart<CJSValue> mode)
{
return CJSContext::createInt(NSShaper::FT_Load_Glyph(RAW_POINTER(face), gid->toUInt32(), mode->toInt32()));
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Get_Glyph_Measure_Params(JSSmart<CJSValue> face, JSSmart<CJSValue> is_vector)
{
CExternalPointerJS result;
if (!NSShaper::FT_Get_Glyph_Measure_Params(RAW_POINTER(face), is_vector->toBool(), &result))
return CJSContext::createNull();
return CJSContext::createUint8Array(result.Data, result.Len, false);
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Get_Glyph_Render_Params(JSSmart<CJSValue> face, JSSmart<CJSValue> render_mode)
{
CExternalPointerJS result;
if (!NSShaper::FT_Get_Glyph_Render_Params(RAW_POINTER(face), render_mode->toInt32(), &result))
return CJSContext::createNull();
return CJSContext::createUint8Array(result.Data, result.Len, false);
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Get_Glyph_Render_Buffer(JSSmart<CJSValue> face, JSSmart<CJSValue> size)
{
void* Data = NSShaper::FT_Get_Glyph_Render_Buffer(RAW_POINTER(face));
int nSize = size->toInt32();
int nSizeMax = NSShaper::FT_Get_Glyph_Render_BufferSize(RAW_POINTER(face));
if (nSize > nSizeMax)
nSize = nSizeMax;
return CJSContext::createUint8Array((unsigned char*)Data, nSize, true);
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Set_Transform(JSSmart<CJSValue> face, JSSmart<CJSValue> xx, JSSmart<CJSValue> yx, JSSmart<CJSValue> xy, JSSmart<CJSValue> yy)
{
NSShaper::FT_Set_Transform(RAW_POINTER(face), xx->toInt32(), yx->toInt32(), xy->toInt32(), yy->toInt32());
return CJSContext::createUndefined();
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_Set_Char_Size(JSSmart<CJSValue> face, JSSmart<CJSValue> char_width, JSSmart<CJSValue> char_height, JSSmart<CJSValue> hres, JSSmart<CJSValue> vres)
{
return CJSContext::createInt(NSShaper::FT_Set_Char_Size(RAW_POINTER(face), char_width->toInt32(), char_height->toInt32(), hres->toUInt32(), vres->toUInt32()));
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_SetCMapForCharCode(JSSmart<CJSValue> face, JSSmart<CJSValue> unicode)
{
return CJSContext::createUInt(NSShaper::FT_SetCMapForCharCode(RAW_POINTER(face), unicode->toUInt32()));
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_GetKerningX(JSSmart<CJSValue> face, JSSmart<CJSValue> gid1, JSSmart<CJSValue> gid2)
{
return CJSContext::createInt(NSShaper::FT_GetKerningX(RAW_POINTER(face), gid1->toUInt32(), gid2->toUInt32()));
}
JSSmart<CJSValue> CTextMeasurerEmbed::FT_GetFaceMaxAdvanceX(JSSmart<CJSValue> face)
{
return CJSContext::createInt(NSShaper::FT_GetFaceMaxAdvanceX(RAW_POINTER(face)));
}
#ifdef SUPPORT_HARFBUZZ_SHAPER
JSSmart<CJSValue> CTextMeasurerEmbed::HB_LanguageFromString(JSSmart<CJSValue> language_bcp_47)
{
void* Data = NSShaper::HB_LanguageFromString(language_bcp_47->toStringA());
CPointerEmbedObject* pObject = new CPointerEmbedObject(Data, NSPointerObjectDeleters::EmptyDeleter);
return pObject->createObject();
}
JSSmart<CJSValue> CTextMeasurerEmbed::HB_ShapeText(JSSmart<CJSValue> face, JSSmart<CJSValue> font, JSSmart<CJSValue> text,
JSSmart<CJSValue> nFeatures, JSSmart<CJSValue> nScript, JSSmart<CJSValue> nDirection, JSSmart<CJSValue> nLanguage)
{
CPointerEmbedObject* pFont = POINTER_OBJECT(font);
CExternalPointerJS result;
JSSmart<CJSTypedArray> typedArray = text->toTypedArray();
CJSDataBuffer buffer = typedArray->getData();
char* pText = (char*)buffer.Data;
NSShaper::HB_ShapeText(RAW_POINTER(face), pFont->Data, pText,
nFeatures->toUInt32(), nScript->toUInt32(), nDirection->toUInt32(), RAW_POINTER(nLanguage),
&result, true);
if (buffer.IsExternalize)
buffer.Free();
if (NULL == result.Data)
return CJSContext::createNull();
return CJSContext::createUint8Array(result.Data, result.Len, false);
}
JSSmart<CJSValue> CTextMeasurerEmbed::HB_FontMalloc()
{
CPointerEmbedObject* pObject = new CPointerEmbedObject(NULL, [](void* data) { NSShaper::HB_FontFree(data); });
return pObject->createObject();
}
JSSmart<CJSValue> CTextMeasurerEmbed::HB_FontFree(JSSmart<CJSValue> font)
{
CPointerEmbedObject* pFont = POINTER_OBJECT(font);
pFont->Free();
return CJSContext::createUndefined();
}
#endif
JSSmart<CJSValue> CTextMeasurerEmbed::Hyphen_SetCacheSize(JSSmart<CJSValue> size)
{
((NSHyphen::CEngine*)m_hyphen_engine)->SetCacheSize(size->toInt32());
return CJSContext::createUndefined();
}
inline int GetUtf8SymbolLen(const unsigned char& c)
{
if (0x00 == (c & 0x80))
return 1;
else if (0x00 == (c & 0x20))
return 2;
else if (0x00 == (c & 0x10))
return 3;
else if (0x00 == (c & 0x0F))
return 4;
else if (0x00 == (c & 0x08))
return 4;
else if (0x00 == (c & 0x04))
return 5;
return 6;
}
JSSmart<CJSValue> CTextMeasurerEmbed::Hyphen_Word(JSSmart<CJSValue> lang, JSSmart<CJSValue> word)
{
std::string sWord = word->toStringA();
const char* curUnicode = sWord.c_str();
char* result = ((NSHyphen::CEngine*)m_hyphen_engine)->Process(lang->toInt32(), curUnicode, (int)sWord.length());
if (!result)
return CJSContext::createNull();
int count = 0;
int pos = 0;
while (result[pos] != 0)
{
if (1 == (result[pos] & 1))
++count;
++pos;
}
if (0 == count)
return CJSContext::createNull();
CJSArray* ret = CJSContext::createArray(count);
pos = 0;
count = 0;
while (result[pos] != 0)
{
if (1 == (result[pos] & 1))
ret->set(count++, CJSContext::createInt(pos + 1));
pos++;
}
return ret;
}
JSSmart<CJSValue> CTextMeasurerEmbed::Hyphen_IsDictionaryExist(JSSmart<CJSValue> lang)
{
return CJSContext::createBool(((NSHyphen::CEngine*)m_hyphen_engine)->IsDictionaryExist(lang->toInt32()));
}