diff --git a/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp b/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp index beeb3d382c..bac9f57d90 100644 --- a/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp +++ b/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp @@ -1,4 +1,26 @@ #include "./TextMeasurerEmbed.h" +#include "./../../fontengine/TextShaper.h" + +#define RAW_POINTER(value) ((CPointerEmbedObject*)value->toObject()->getNative())->Data + +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); + } +}; JSSmart CTextMeasurerEmbed::FT_Malloc(JSSmart typed_array_or_len) { @@ -30,56 +52,74 @@ JSSmart CTextMeasurerEmbed::FT_Free(JSSmart pointer) JSSmart CTextMeasurerEmbed::FT_Init() { - + CPointerEmbedObject* pointer = new CPointerEmbedObject(NSShaper::FT_Library_Init(), [](void* data) { NSShaper::FT_Library_Destroy(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* face = NSShaper::FT_Open_Face(RAW_POINTER(library), (unsigned char*)RAW_POINTER(memory), size->toUInt32(), face_index->toInt32()); + CPointerEmbedObject* pointer = new CPointerEmbedObject(face, [](void* data) { NSShaper::FT_Done_Face(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) { - + void* Data = NSShaper::FT_Get_Glyph_Render_Buffer(RAW_POINTER(face)); + CPointerEmbedObject* pObject = new CPointerEmbedObject(Data, NSPointerObjectDeleters::EmptyDeleter); + return pObject->createObject(); } 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))); } diff --git a/DesktopEditor/doctrenderer/embed/ZipEmbed.cpp b/DesktopEditor/doctrenderer/embed/ZipEmbed.cpp index 122ab6f200..dff096270a 100644 --- a/DesktopEditor/doctrenderer/embed/ZipEmbed.cpp +++ b/DesktopEditor/doctrenderer/embed/ZipEmbed.cpp @@ -51,7 +51,7 @@ JSSmart CZipEmbed::getFile(JSSmart filePath) std::wstring sFilePath = filePath->toStringW(); IFolder::CBuffer* pBuffer; - if (m_pFolder->read(sFilePath, pBuffer)) + if (!m_pFolder->read(sFilePath, pBuffer)) return CJSContext::createNull(); size_t nBufferSize = (size_t)pBuffer->Size; diff --git a/DesktopEditor/doctrenderer/js_internal/js_base.h b/DesktopEditor/doctrenderer/js_internal/js_base.h index 44519e7836..ea39a7f5d9 100644 --- a/DesktopEditor/doctrenderer/js_internal/js_base.h +++ b/DesktopEditor/doctrenderer/js_internal/js_base.h @@ -40,6 +40,7 @@ namespace NSJSBase virtual bool toBool() = 0; virtual int toInt32() = 0; + virtual unsigned int toUInt32() = 0; virtual double toDouble() = 0; virtual std::string toStringA() = 0; virtual std::wstring toStringW() = 0; @@ -250,6 +251,7 @@ namespace NSJSBase static CJSValue* createNull(); static CJSValue* createBool(const bool& value); static CJSValue* createInt(const int& value); + static CJSValue* createUInt(const unsigned int& value); static CJSValue* createDouble(const double& value); static CJSValue* createString(const char* value, const int& length = -1); static CJSValue* createString(const std::string& value); diff --git a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.cpp b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.cpp index 7ecb408857..f07652453a 100644 --- a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.cpp +++ b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.cpp @@ -221,6 +221,13 @@ namespace NSJSBase return _value; } + CJSValue* CJSContext::createUInt(const unsigned int& value) + { + CJSValueV8* _value = new CJSValueV8(); + _value->value = v8::Integer::NewFromUnsigned(CV8Worker::GetCurrent(), value); + return _value; + } + CJSValue* CJSContext::createDouble(const double& value) { CJSValueV8* _value = new CJSValueV8(); diff --git a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h index 3d01558e4d..9000afa8d8 100644 --- a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h +++ b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h @@ -282,6 +282,11 @@ namespace NSJSBase return 0; } + virtual unsigned int toUInt32() + { + return 0; + } + virtual double toDouble() { return 0; @@ -342,6 +347,11 @@ namespace NSJSBase return value.IsEmpty() ? 0 : value->Int32Value(V8ContextOneArg).V8ToChecked(); } + virtual unsigned int toUInt32() + { + return value.IsEmpty() ? 0 : value->Uint32Value(V8ContextOneArg).V8ToChecked(); + } + virtual double toDouble() { return value.IsEmpty() ? 0 : value->NumberValue(V8ContextOneArg).V8ToChecked(); diff --git a/DesktopEditor/fontengine/TextShaper.cpp b/DesktopEditor/fontengine/TextShaper.cpp index 26b937b199..b021a3b101 100644 --- a/DesktopEditor/fontengine/TextShaper.cpp +++ b/DesktopEditor/fontengine/TextShaper.cpp @@ -46,15 +46,12 @@ #include #include "ftmodapi.h" -#include -#include -#include - namespace NSShaper { #define ALLOC_WRITER(size) result->Alloc((size)); unsigned char* pCurData = result->Data #define WRITE_INT(value) result->WriteInt(pCurData, value); pCurData += 4 #define WRITE_UINT(value) result->WriteUInt(pCurData, value); pCurData += 4 + #define WRITE_UCHAR(value) *pCurData++ = value CExternalPointer::CExternalPointer() { @@ -617,3 +614,115 @@ namespace NSShaper return true; } } + +#ifdef SUPPORT_HARFBUZZ_SHAPER + +#include +#include +#include + +namespace NSShaper +{ + #define g_userfeatures_count 5 + hb_feature_t g_userfeatures[g_userfeatures_count]; + bool g_userfeatures_init = false; + + void* HB_LanguageFromString(const std::string language_bcp_47) + { + return (void*)hb_language_from_string(language_bcp_47.c_str(), language_bcp_47.length()); + } + void HB_free(void* data) + { + HB_free(data); + } + + void HB_ShapeText(void* face, void* font, char* text, + unsigned int nFeatures, unsigned int nScript, unsigned int nDirection, void* nLanguage, CExternalPointer* result) + { + // init features + if (!g_userfeatures_init) + { + hb_tag_t tags[] = { + HB_TAG('l','i','g','a'), + HB_TAG('c','l','i','g'), + HB_TAG('h','l','i','g'), + HB_TAG('d','l','i','g'), + HB_TAG('k','e','r','n') + }; + for (int nTag = 0; nTag < g_userfeatures_count; ++nTag) + { + g_userfeatures[nTag].tag = tags[nTag]; + g_userfeatures[nTag].value = 0; + g_userfeatures[nTag].start = HB_FEATURE_GLOBAL_START; + g_userfeatures[nTag].end = HB_FEATURE_GLOBAL_END; + } + g_userfeatures_init = true; + } + + // font + hb_font_t* pFont; + if (NULL == font) + { + pFont = hb_ft_font_create((FT_Face)face, NULL); + hb_ft_font_set_funcs(pFont); + } + else + pFont = (hb_font_t*)font; + + // features + for (int nTag = 0; nTag < g_userfeatures_count; ++nTag) + g_userfeatures[nTag].value = (nFeatures & (1 << nTag)) ? 1 : 0; + + // buffer + hb_buffer_t* hbBuffer = hb_buffer_create(); + hb_buffer_set_direction(hbBuffer, (hb_direction_t)nDirection); + hb_buffer_set_script(hbBuffer, (hb_script_t)nScript); + hb_buffer_set_language(hbBuffer, (hb_language_t)nLanguage); + hb_buffer_set_cluster_level(hbBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES); + int text_len = (int)strlen(text); + hb_buffer_add_utf8(hbBuffer, text, text_len, 0, text_len); + hb_buffer_guess_segment_properties(hbBuffer); + + // shape + hb_shape(pFont, hbBuffer, g_userfeatures, g_userfeatures_count); + + unsigned int glyph_count; + hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos(hbBuffer, &glyph_count); + hb_glyph_position_t* glyph_pos = hb_buffer_get_glyph_positions(hbBuffer, &glyph_count); + + int nSize = 4 + 8 + glyph_count * (1 + 1 + 4 * 6); + + ALLOC_WRITER(nSize); + + WRITE_UINT(nSize); + + uint64_t pFontPointer = (uint64_t)pFont; + WRITE_UINT(pFontPointer & 0xFFFFFFFF); + WRITE_UINT((pFontPointer >> 32) & 0xFFFFFFFF); + + for (unsigned i = 0; i < glyph_count; ++i) + { + unsigned char nGlyphType = (unsigned char)hb_ot_layout_get_glyph_class(hb_font_get_face(pFont), glyph_info[i].codepoint); + unsigned char nGlyphFlags = (unsigned char)hb_glyph_info_get_glyph_flags(&glyph_info[i]); + + WRITE_UCHAR(nGlyphType); + WRITE_UCHAR(nGlyphFlags); + + WRITE_UINT(glyph_info[i].codepoint); + WRITE_UINT(glyph_info[i].cluster); + + WRITE_INT(glyph_pos[i].x_advance); + WRITE_INT(glyph_pos[i].y_advance); + WRITE_INT(glyph_pos[i].x_offset); + WRITE_INT(glyph_pos[i].y_offset); + } + + hb_buffer_destroy(hbBuffer); + } + + void HB_FontFree(void* font) + { + hb_font_destroy((hb_font_t*)font); + } +} +#endif diff --git a/DesktopEditor/fontengine/TextShaper.h b/DesktopEditor/fontengine/TextShaper.h index 60efde8ba9..e0212bc388 100644 --- a/DesktopEditor/fontengine/TextShaper.h +++ b/DesktopEditor/fontengine/TextShaper.h @@ -77,6 +77,16 @@ namespace NSShaper GRAPHICS_DECL unsigned int FT_SetCMapForCharCode(void* face, unsigned int unicode); GRAPHICS_DECL int FT_GetKerningX(void* face, unsigned int prev_gid, unsigned int gid); GRAPHICS_DECL int FT_GetFaceMaxAdvanceX(void* face); + +#ifdef SUPPORT_HARFBUZZ_SHAPER + GRAPHICS_DECL void* HB_LanguageFromString(const std::string language_bcp_47); + GRAPHICS_DECL void HB_free(void* data); + + GRAPHICS_DECL void HB_ShapeText(void* face, void* font, char* text, + unsigned int nFeatures, unsigned int nScript, unsigned int nDirection, void* nLanguage, CExternalPointer* result); + + GRAPHICS_DECL void HB_FontFree(void* font); +#endif } #endif // _BUILD_TEXT_MANAGER_FONTMANAGER_H_ diff --git a/DesktopEditor/graphics/pro/graphics.pro b/DesktopEditor/graphics/pro/graphics.pro index d62dbfc760..5fa0026adc 100644 --- a/DesktopEditor/graphics/pro/graphics.pro +++ b/DesktopEditor/graphics/pro/graphics.pro @@ -493,7 +493,20 @@ SOURCES += ./../../fontengine/FontsAssistant.cpp HEADERS += ./../../fontengine/TextShaper.h SOURCES += ./../../fontengine/TextShaper.cpp -include(./../../fontengine/js/common/graphics_shaper.pri) +CONFIG += enable_support_shaper + +core_windows { + MSVC_VERSION_DETECT = $$(VisualStudioVersion) + + lessThan(MSVC_VERSION_DETECT, 16.0) { + CONFIG -= enable_support_shaper + } +} + +enable_support_shaper { + DEFINES += SUPPORT_HARFBUZZ_SHAPER + include(./../../fontengine/js/common/graphics_shaper.pri) +} # ------------------------------------------------- core_ios {