#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 CTextMeasurerEmbed::FT_Malloc(JSSmart 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 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 CTextMeasurerEmbed::FT_Free(JSSmart pointer) { CPointerEmbedObject* pEmbed = (CPointerEmbedObject*)pointer->toObject()->getNative(); pEmbed->Free(); return CJSContext::createUndefined(); } JSSmart CTextMeasurerEmbed::FT_Init() { CPointerEmbedObject* pointer = new CPointerEmbedObject(NSShaper::FT_Library_Init(), [](void* data) { NSShaper::FT_Library_UnReference(data); }); return pointer->createObject(); } JSSmart CTextMeasurerEmbed::FT_Set_TrueType_HintProp(JSSmart library, JSSmart tt_interpreter) { return CJSContext::createInt(NSShaper::FT_Set_TrueType_HintProp(RAW_POINTER(library), tt_interpreter->toUInt32())); } JSSmart CTextMeasurerEmbed::FT_Open_Face(JSSmart library, JSSmart memory, JSSmart size, JSSmart 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 CTextMeasurerEmbed::FT_Open_Face2(JSSmart library, JSSmart array, JSSmart face_index) { void* ftlibrary = RAW_POINTER(library); JSSmart 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 CTextMeasurerEmbed::FT_GetFaceInfo(JSSmart face) { CExternalPointerJS result; if (!NSShaper::FT_GetFaceInfo(RAW_POINTER(face), &result)) return CJSContext::createNull(); return CJSContext::createUint8Array(result.Data, result.Len, false); } JSSmart CTextMeasurerEmbed::FT_Load_Glyph(JSSmart face, JSSmart gid, JSSmart mode) { return CJSContext::createInt(NSShaper::FT_Load_Glyph(RAW_POINTER(face), gid->toUInt32(), mode->toInt32())); } JSSmart CTextMeasurerEmbed::FT_Get_Glyph_Measure_Params(JSSmart face, JSSmart 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 CTextMeasurerEmbed::FT_Get_Glyph_Render_Params(JSSmart face, JSSmart 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 CTextMeasurerEmbed::FT_Get_Glyph_Render_Buffer(JSSmart face, JSSmart 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 CTextMeasurerEmbed::FT_Set_Transform(JSSmart face, JSSmart xx, JSSmart yx, JSSmart xy, JSSmart yy) { NSShaper::FT_Set_Transform(RAW_POINTER(face), xx->toInt32(), yx->toInt32(), xy->toInt32(), yy->toInt32()); return CJSContext::createUndefined(); } JSSmart CTextMeasurerEmbed::FT_Set_Char_Size(JSSmart face, JSSmart char_width, JSSmart char_height, JSSmart hres, JSSmart vres) { return CJSContext::createInt(NSShaper::FT_Set_Char_Size(RAW_POINTER(face), char_width->toInt32(), char_height->toInt32(), hres->toUInt32(), vres->toUInt32())); } JSSmart CTextMeasurerEmbed::FT_SetCMapForCharCode(JSSmart face, JSSmart unicode) { return CJSContext::createUInt(NSShaper::FT_SetCMapForCharCode(RAW_POINTER(face), unicode->toUInt32())); } JSSmart CTextMeasurerEmbed::FT_GetKerningX(JSSmart face, JSSmart gid1, JSSmart gid2) { return CJSContext::createInt(NSShaper::FT_GetKerningX(RAW_POINTER(face), gid1->toUInt32(), gid2->toUInt32())); } JSSmart CTextMeasurerEmbed::FT_GetFaceMaxAdvanceX(JSSmart face) { return CJSContext::createInt(NSShaper::FT_GetFaceMaxAdvanceX(RAW_POINTER(face))); } #ifdef SUPPORT_HARFBUZZ_SHAPER JSSmart CTextMeasurerEmbed::HB_LanguageFromString(JSSmart language_bcp_47) { void* Data = NSShaper::HB_LanguageFromString(language_bcp_47->toStringA()); CPointerEmbedObject* pObject = new CPointerEmbedObject(Data, NSPointerObjectDeleters::EmptyDeleter); return pObject->createObject(); } JSSmart CTextMeasurerEmbed::HB_ShapeText(JSSmart face, JSSmart font, JSSmart text, JSSmart nFeatures, JSSmart nScript, JSSmart nDirection, JSSmart nLanguage) { CPointerEmbedObject* pFont = POINTER_OBJECT(font); CExternalPointerJS result; JSSmart 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 CTextMeasurerEmbed::HB_FontMalloc() { CPointerEmbedObject* pObject = new CPointerEmbedObject(NULL, [](void* data) { NSShaper::HB_FontFree(data); }); return pObject->createObject(); } JSSmart CTextMeasurerEmbed::HB_FontFree(JSSmart font) { CPointerEmbedObject* pFont = POINTER_OBJECT(font); pFont->Free(); return CJSContext::createUndefined(); } #endif JSSmart CTextMeasurerEmbed::Hyphen_SetCacheSize(JSSmart 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 CTextMeasurerEmbed::Hyphen_Word(JSSmart lang, JSSmart 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 CTextMeasurerEmbed::Hyphen_IsDictionaryExist(JSSmart lang) { return CJSContext::createBool(((NSHyphen::CEngine*)m_hyphen_engine)->IsDictionaryExist(lang->toInt32())); }