From 32ac61f890235d2d505dcc76c75cfefbc7a545cb Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Tue, 31 May 2022 12:31:28 +0300 Subject: [PATCH] Developing --- DesktopEditor/doctrenderer/doctrenderer.pro | 12 +- .../doctrenderer/embed/PointerEmbed.cpp | 32 + .../doctrenderer/embed/PointerEmbed.h | 35 + .../doctrenderer/embed/TextMeasurerEmbed.cpp | 85 +++ .../doctrenderer/embed/TextMeasurerEmbed.h | 42 ++ .../doctrenderer/embed/jsc/jsc_Pointer.mm | 31 + .../doctrenderer/embed/v8/v8_Pointer.cpp | 32 + .../doctrenderer/embed/v8/v8_Zip.cpp | 2 + .../doctrenderer/js_internal/js_base.h | 17 +- .../doctrenderer/js_internal/v8/v8_base.h | 51 ++ DesktopEditor/fontengine/TextShaper.cpp | 619 ++++++++++++++++++ DesktopEditor/fontengine/TextShaper.h | 82 +++ DesktopEditor/graphics/pro/graphics.pro | 7 + 13 files changed, 1042 insertions(+), 5 deletions(-) create mode 100644 DesktopEditor/doctrenderer/embed/PointerEmbed.cpp create mode 100644 DesktopEditor/doctrenderer/embed/PointerEmbed.h create mode 100644 DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp create mode 100644 DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.h create mode 100644 DesktopEditor/doctrenderer/embed/jsc/jsc_Pointer.mm create mode 100644 DesktopEditor/doctrenderer/embed/v8/v8_Pointer.cpp create mode 100644 DesktopEditor/fontengine/TextShaper.cpp create mode 100644 DesktopEditor/fontengine/TextShaper.h diff --git a/DesktopEditor/doctrenderer/doctrenderer.pro b/DesktopEditor/doctrenderer/doctrenderer.pro index 3923fbe3f6..634fdf2e51 100644 --- a/DesktopEditor/doctrenderer/doctrenderer.pro +++ b/DesktopEditor/doctrenderer/doctrenderer.pro @@ -53,19 +53,23 @@ HEADERS += \ graphics.h HEADERS += \ + embed/PointerEmbed.h \ embed/ZipEmbed.h \ embed/GraphicsEmbed.h \ embed/MemoryStreamEmbed.h \ embed/NativeControlEmbed.h \ embed/NativeBuilderEmbed.h \ + embed/TextMeasurerEmbed.h \ js_internal/js_base.h SOURCES += \ + embed/PointerEmbed.cpp \ embed/ZipEmbed.cpp \ embed/GraphicsEmbed.cpp \ embed/MemoryStreamEmbed.cpp \ embed/NativeControlEmbed.cpp \ - embed/NativeBuilderEmbed.cpp + embed/NativeBuilderEmbed.cpp \ + embed/TextMeasurerEmbed.cpp core_mac { !use_v8:CONFIG += use_javascript_core @@ -80,7 +84,8 @@ include($$PWD/js_internal/js_base.pri) embed/v8/v8_NativeControl.cpp \ embed/v8/v8_NativeBuilder.cpp \ embed/v8/v8_Graphics.cpp \ - embed/v8/v8_Zip.cpp + embed/v8/v8_Zip.cpp \ + embed/v8/v8_Pointer.cpp build_xp:DESTDIR=$$DESTDIR/xp } else { @@ -90,7 +95,8 @@ include($$PWD/js_internal/js_base.pri) embed/jsc/jsc_MemoryStream.mm \ embed/jsc/jsc_NativeControl.mm \ embed/jsc/jsc_NativeBuilder.mm \ - embed/jsc/jsc_Zip.mm + embed/jsc/jsc_Zip.mm \ + embed/v8/jsc_Pointer.cpp LIBS += -framework Foundation } diff --git a/DesktopEditor/doctrenderer/embed/PointerEmbed.cpp b/DesktopEditor/doctrenderer/embed/PointerEmbed.cpp new file mode 100644 index 0000000000..8270721a46 --- /dev/null +++ b/DesktopEditor/doctrenderer/embed/PointerEmbed.cpp @@ -0,0 +1,32 @@ +#include "PointerEmbed.h" +#include + +namespace NSPointerObjectDeleters +{ + void EmptyDeleter(void* data) + { + // nothing + } + void FreeDeleter(void* data) + { + free(data); + } +} + +CPointerEmbedObject::CPointerEmbedObject(void* data, NSPointerObjectDeleters::PointerObjectDeleter deleter) +{ + Data = data; + Deleter = deleter; +} + +void CPointerEmbedObject::Free() +{ + if (Data && Deleter) + Deleter(Data); + Data = nullptr; +} + +CPointerEmbedObject::~CPointerEmbedObject() +{ + Free(); +} diff --git a/DesktopEditor/doctrenderer/embed/PointerEmbed.h b/DesktopEditor/doctrenderer/embed/PointerEmbed.h new file mode 100644 index 0000000000..610ce4a8bb --- /dev/null +++ b/DesktopEditor/doctrenderer/embed/PointerEmbed.h @@ -0,0 +1,35 @@ +#ifndef _BUILD_NATIVE_POINTER_EMBED_H_ +#define _BUILD_NATIVE_POINTER_EMBED_H_ + +#include "../js_internal/js_base.h" + +namespace NSPointerObjectDeleters +{ + using PointerObjectDeleter = void (*)(void* data); + + void EmptyDeleter(void* data); + void FreeDeleter(void* data); +} + +#define POINTER_DELETER(CLASS_NAME, NAME) void NAME(void* data) { CLASS_NAME* p = (CLASS_NAME*)data; delete data; } + +using namespace NSJSBase; +class CPointerEmbedObject : public CJSEmbedObject +{ +public: + void* Data; + +private: + NSPointerObjectDeleters::PointerObjectDeleter Deleter; + +public: + CPointerEmbedObject(void* data, NSPointerObjectDeleters::PointerObjectDeleter = nullptr); + void Free(); + virtual ~CPointerEmbedObject(); + + virtual void* getObject() { return Data; } + + JSSmart createObject(); +}; + +#endif // _BUILD_NATIVE_POINTER_EMBED_H_ diff --git a/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp b/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp new file mode 100644 index 0000000000..beeb3d382c --- /dev/null +++ b/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.cpp @@ -0,0 +1,85 @@ +#include "./TextMeasurerEmbed.h" + +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(); + pData = malloc((size_t)len); + } + else + { + CJSDataBuffer pBuffer = typed_array_or_len->toTypedArray()->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() +{ + +} +JSSmart CTextMeasurerEmbed::FT_Set_TrueType_HintProp(JSSmart library, JSSmart tt_interpreter) +{ + +} + +JSSmart CTextMeasurerEmbed::FT_Open_Face(JSSmart library, JSSmart memory, JSSmart size, JSSmart face_index) +{ + +} +JSSmart CTextMeasurerEmbed::FT_GetFaceInfo(JSSmart face) +{ + +} + +JSSmart CTextMeasurerEmbed::FT_Load_Glyph(JSSmart face, JSSmart gid, JSSmart mode) +{ + +} +JSSmart CTextMeasurerEmbed::FT_Get_Glyph_Measure_Params(JSSmart face, JSSmart is_vector) +{ + +} +JSSmart CTextMeasurerEmbed::FT_Get_Glyph_Render_Params(JSSmart face, JSSmart render_mode) +{ + +} +JSSmart CTextMeasurerEmbed::FT_Get_Glyph_Render_Buffer(JSSmart face) +{ + +} + +JSSmart CTextMeasurerEmbed::FT_Set_Transform(JSSmart face, JSSmart xx, JSSmart yx, JSSmart xy, JSSmart yy) +{ + +} +JSSmart CTextMeasurerEmbed::FT_Set_Char_Size(JSSmart face, JSSmart char_width, JSSmart char_height, JSSmart hres, JSSmart vres) +{ + +} +JSSmart CTextMeasurerEmbed::FT_SetCMapForCharCode(JSSmart face, JSSmart unicode) +{ + +} +JSSmart CTextMeasurerEmbed::FT_GetKerningX(JSSmart face, JSSmart gid1, JSSmart gid2) +{ + +} +JSSmart CTextMeasurerEmbed::FT_GetFaceMaxAdvanceX(JSSmart face) +{ + +} diff --git a/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.h b/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.h new file mode 100644 index 0000000000..e97cf45818 --- /dev/null +++ b/DesktopEditor/doctrenderer/embed/TextMeasurerEmbed.h @@ -0,0 +1,42 @@ +#ifndef _BUILD_NATIVE_TEXT_MEASURER_EMBED_H_ +#define _BUILD_NATIVE_TEXT_MEASURER_EMBED_H_ + +#include "../js_internal/js_base.h" +#include "./PointerEmbed.h" + +using namespace NSJSBase; +class CTextMeasurerEmbed : public CJSEmbedObject +{ +public: + CTextMeasurerEmbed() + { + } + ~CTextMeasurerEmbed() + { + } + +public: + JSSmart FT_Malloc(JSSmart typed_array_or_len); + JSSmart FT_Free(JSSmart pointer); + + JSSmart FT_Init(); + JSSmart FT_Set_TrueType_HintProp(JSSmart library, JSSmart tt_interpreter); + + JSSmart FT_Open_Face(JSSmart library, JSSmart memory, JSSmart size, JSSmart face_index); + JSSmart FT_GetFaceInfo(JSSmart face); + + JSSmart FT_Load_Glyph(JSSmart face, JSSmart gid, JSSmart mode); + JSSmart FT_Get_Glyph_Measure_Params(JSSmart face, JSSmart is_vector); + JSSmart FT_Get_Glyph_Render_Params(JSSmart face, JSSmart render_mode); + JSSmart FT_Get_Glyph_Render_Buffer(JSSmart face); + + JSSmart FT_Set_Transform(JSSmart face, JSSmart xx, JSSmart yx, JSSmart xy, JSSmart yy); + JSSmart FT_Set_Char_Size(JSSmart face, JSSmart char_width, JSSmart char_height, JSSmart hres, JSSmart vres); + JSSmart FT_SetCMapForCharCode(JSSmart face, JSSmart unicode); + JSSmart FT_GetKerningX(JSSmart face, JSSmart gid1, JSSmart gid2); + JSSmart FT_GetFaceMaxAdvanceX(JSSmart face); + + static void CreateObjectInContext(const std::string& name, JSSmart context); +}; + +#endif // _BUILD_NATIVE_TEXT_MEASURER_EMBED_H_ diff --git a/DesktopEditor/doctrenderer/embed/jsc/jsc_Pointer.mm b/DesktopEditor/doctrenderer/embed/jsc/jsc_Pointer.mm new file mode 100644 index 0000000000..36c62c653c --- /dev/null +++ b/DesktopEditor/doctrenderer/embed/jsc/jsc_Pointer.mm @@ -0,0 +1,31 @@ +#include "../PointerEmbed.h" +#include "../../js_internal/jsc/jsc_base.h" + +@protocol IJSCPointer +@end + +@interface CJSCPointer : NSObject +{ +@public + CPointerEmbedObject* m_internal; +} +@end + +@implementation CJSCPointer + +EMBED_OBJECT_WRAPPER_METHODS(CPointerEmbedObject) + +-(id) initWithPointer:(CPointerEmbedObject*) pointer +{ + self = [super init]; + if (self) + m_internal = pointer; + return self; +} + +@end + +JSSmart CPointerEmbedObject::createObject() +{ + return [[CJSCPointer alloc] initWithPointer:this]; +} diff --git a/DesktopEditor/doctrenderer/embed/v8/v8_Pointer.cpp b/DesktopEditor/doctrenderer/embed/v8/v8_Pointer.cpp new file mode 100644 index 0000000000..b9b7277ae5 --- /dev/null +++ b/DesktopEditor/doctrenderer/embed/v8/v8_Pointer.cpp @@ -0,0 +1,32 @@ +#include "../PointerEmbed.h" +#include "../../js_internal/v8/v8_base.h" + +v8::Handle CreatePointerTemplate(v8::Isolate* isolate) +{ + v8::EscapableHandleScope handle_scope(isolate); + + v8::Local result = v8::ObjectTemplate::New(isolate); + result->SetInternalFieldCount(1); + + return handle_scope.Escape(result); +} + +JSSmart CPointerEmbedObject::createObject() +{ + v8::Isolate* isolate = CV8Worker::GetCurrent(); + v8::HandleScope scope(isolate); + + v8::Handle pointerTemplate = v8::ObjectTemplate::New(isolate); + pointerTemplate->SetInternalFieldCount(1); + + v8::Local obj = pointerTemplate->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); + obj->SetInternalField(0, v8::External::New(CV8Worker::GetCurrent(), this)); + + NSJSBase::CJSEmbedObjectPrivate::CreateWeaker(obj); + + CJSValueV8* returnValue = new CJSValueV8(); + returnValue->value = obj; + + JSSmart ret = returnValue; + return ret; +} diff --git a/DesktopEditor/doctrenderer/embed/v8/v8_Zip.cpp b/DesktopEditor/doctrenderer/embed/v8/v8_Zip.cpp index c81ffde182..31155e64c8 100644 --- a/DesktopEditor/doctrenderer/embed/v8/v8_Zip.cpp +++ b/DesktopEditor/doctrenderer/embed/v8/v8_Zip.cpp @@ -43,6 +43,8 @@ namespace NSZip v8::Local obj = ZipTemplate->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); obj->SetInternalField(0, v8::External::New(CV8Worker::GetCurrent(), pZip)); + NSJSBase::CJSEmbedObjectPrivate::CreateWeaker(obj); + args.GetReturnValue().Set(obj); } } diff --git a/DesktopEditor/doctrenderer/js_internal/js_base.h b/DesktopEditor/doctrenderer/js_internal/js_base.h index cb74e86a3d..44519e7836 100644 --- a/DesktopEditor/doctrenderer/js_internal/js_base.h +++ b/DesktopEditor/doctrenderer/js_internal/js_base.h @@ -50,14 +50,27 @@ namespace NSJSBase virtual CJSFunction* toFunction() = 0; }; + class CJSEmbedObjectPrivateBase + { + public: + CJSEmbedObjectPrivateBase() {} + virtual ~CJSEmbedObjectPrivateBase() {} + }; + class CJSEmbedObject { public: - CJSEmbedObject() {} - virtual ~CJSEmbedObject() {} + CJSEmbedObject() { embed_native_internal = NULL; } + virtual ~CJSEmbedObject() { RELEASEOBJECT(embed_native_internal); } public: virtual void* getObject() { return NULL; } + + protected: + CJSEmbedObjectPrivateBase* embed_native_internal; + + friend class CJSEmbedObjectPrivateBase; + friend class CJSEmbedObjectPrivate; }; class CJSObject : public CJSValue diff --git a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h index 787a3aff37..3d01558e4d 100644 --- a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h +++ b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h @@ -745,6 +745,57 @@ namespace NSJSBase }; } +namespace NSJSBase +{ + class CJSEmbedObjectPrivate : public CJSEmbedObjectPrivateBase + { + public: + v8::Persistent handle; + + CJSEmbedObjectPrivate(v8::Local obj) + { + SetWeak(obj); + } + virtual ~CJSEmbedObjectPrivate() + { + ClearWeak(); + } + + public: + void SetWeak(v8::Local obj) + { + v8::Handle field = v8::Handle::Cast(obj->GetInternalField(0)); + CJSEmbedObject* pEmbedObject = (NSJSBase::CJSEmbedObject*)field->Value(); + + handle.Reset(CV8Worker::GetCurrent(), obj); + handle.SetWeak(pEmbedObject, EmbedObjectWeakCallback, v8::WeakCallbackType::kParameter); + + pEmbedObject->embed_native_internal = this; + } + void ClearWeak() + { + if (handle.IsEmpty()) + return; + handle.ClearWeak(); + handle.Reset(); + } + + static void EmbedObjectWeakCallback(const v8::WeakCallbackInfo& data) + { + v8::Isolate* isolate = data.GetIsolate(); + v8::HandleScope scope(isolate); + CJSEmbedObject* wrap = data.GetParameter(); + ((CJSEmbedObjectPrivate*)wrap->embed_native_internal)->handle.Reset(); + delete wrap; + } + + static void CreateWeaker(v8::Local obj) + { + new CJSEmbedObjectPrivate(obj); + } + }; +} + namespace NSV8Objects { static void Template_Set(v8::Local& obj, const char* name, v8::FunctionCallback callback) diff --git a/DesktopEditor/fontengine/TextShaper.cpp b/DesktopEditor/fontengine/TextShaper.cpp new file mode 100644 index 0000000000..26b937b199 --- /dev/null +++ b/DesktopEditor/fontengine/TextShaper.cpp @@ -0,0 +1,619 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ + +#include "./TextShaper.h" + +#include +#include "ftsnames.h" +#include FT_OUTLINE_H +#include FT_SIZES_H +#include FT_GLYPH_H +#include FT_TRUETYPE_IDS_H +#include FT_TRUETYPE_TABLES_H +#include FT_XFREE86_H +#include FT_ADVANCES_H +#include FT_LCD_FILTER_H +#include FT_DRIVER_H +#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 + + CExternalPointer::CExternalPointer() + { + Data = NULL; + Len = 0; + } + CExternalPointer::~CExternalPointer() + { + } + + void CExternalPointer::WriteInt(unsigned char* data, const int& value) + { + WriteUInt(data, (unsigned int)value); + } + void CExternalPointer::WriteUInt(unsigned char* data, const unsigned int& value) + { + data[0] = (value & 0xFF); + data[1] = ((value >> 8) & 0xFF); + data[2] = ((value >> 16) & 0xFF); + data[3] = ((value >> 24) & 0xFF); + } + + void CExternalPointer::Alloc(const unsigned int& len) + { + Len = len; + Data = new unsigned char[Len]; + } + void CExternalPointer::Free() + { + if (Data) + delete [] Data; + } + + // outline + #define FT_DECOMPOSE_OUTLINE_BUFFER_INIT_SIZE 200 + typedef struct FT_Decompose_Outline_Buffer_ + { + FT_Pos* buffer; + FT_Int size; + FT_Int pos; + } FT_Decompose_Outline_Buffer; + + void FT_Decompose_Outline_Buffer_Init(FT_Decompose_Outline_Buffer* buffer) + { + buffer->buffer = NULL; + buffer->size = 0; + buffer->pos = 0; + } + + void FT_Decompose_Outline_Buffer_Destroy(FT_Decompose_Outline_Buffer* buffer) + { + ft_sfree(buffer->buffer); + } + + void FT_Decompose_Outline_Buffer_Check(FT_Decompose_Outline_Buffer* buffer, FT_Int add) + { + if ((buffer->pos + add) < buffer->size) + return; + + if (NULL == buffer->buffer) + { + buffer->buffer = (FT_Pos*)ft_smalloc(FT_DECOMPOSE_OUTLINE_BUFFER_INIT_SIZE * sizeof(FT_Pos)); + buffer->size = FT_DECOMPOSE_OUTLINE_BUFFER_INIT_SIZE; + buffer->pos = 0; + return; + } + + FT_Int sizeNew = 2 * buffer->size; + FT_Pos* bufferNew = (FT_Pos*)ft_smalloc((size_t)sizeNew * sizeof(FT_Pos)); + memcpy(bufferNew, buffer->buffer, (size_t)buffer->pos * sizeof(FT_Pos)); + ft_sfree(buffer->buffer); + buffer->buffer = bufferNew; + buffer->size = sizeNew; + // pos + } + + int GlyphPathMoveTo(const FT_Vector *point, void *user) + { + FT_Decompose_Outline_Buffer* buffer = (FT_Decompose_Outline_Buffer*)user; + FT_Decompose_Outline_Buffer_Check(buffer, 3); + buffer->buffer[buffer->pos++] = 0; + buffer->buffer[buffer->pos++] = point->x; + buffer->buffer[buffer->pos++] = point->y; + return 0; + } + + int GlyphPathLineTo(const FT_Vector *point, void *user) + { + FT_Decompose_Outline_Buffer* buffer = (FT_Decompose_Outline_Buffer*)user; + FT_Decompose_Outline_Buffer_Check(buffer, 3); + buffer->buffer[buffer->pos++] = 1; + buffer->buffer[buffer->pos++] = point->x; + buffer->buffer[buffer->pos++] = point->y; + return 0; + } + + int GlyphPathConicTo(const FT_Vector *pControlPoint, const FT_Vector *pEndPoint, void *user) + { + FT_Decompose_Outline_Buffer* buffer = (FT_Decompose_Outline_Buffer*)user; + FT_Decompose_Outline_Buffer_Check(buffer, 5); + buffer->buffer[buffer->pos++] = 2; + buffer->buffer[buffer->pos++] = pControlPoint->x; + buffer->buffer[buffer->pos++] = pControlPoint->y; + buffer->buffer[buffer->pos++] = pEndPoint->x; + buffer->buffer[buffer->pos++] = pEndPoint->y; + return 0; + } + + int GlyphPathCubicTo(const FT_Vector *pFirstControlPoint, const FT_Vector *pSecondControlPoint, const FT_Vector *pEndPoint, void *user) + { + FT_Decompose_Outline_Buffer* buffer = (FT_Decompose_Outline_Buffer*)user; + FT_Decompose_Outline_Buffer_Check(buffer, 7); + buffer->buffer[buffer->pos++] = 3; + buffer->buffer[buffer->pos++] = pFirstControlPoint->x; + buffer->buffer[buffer->pos++] = pFirstControlPoint->y; + buffer->buffer[buffer->pos++] = pSecondControlPoint->x; + buffer->buffer[buffer->pos++] = pSecondControlPoint->y; + buffer->buffer[buffer->pos++] = pEndPoint->x; + buffer->buffer[buffer->pos++] = pEndPoint->y; + return 0; + } + ///////////////////////////////////////////////////////////////////// + + void FT_Free(void* data) + { + ft_sfree(data); + } + + void* FT_Library_Init() + { + FT_Library library = NULL; + FT_Init_FreeType(&library); + FT_Library_SetLcdFilter(library, FT_LCD_FILTER_DEFAULT); + return library; + } + void FT_Library_Destroy(void* library) + { + FT_Library_Destroy(library); + } + + int FT_Set_TrueType_HintProp(void* library, unsigned int interpreter_version) + { + FT_UInt ft_interpreter_version = interpreter_version; + return FT_Property_Set((FT_Library)library, "truetype", "interpreter-version", &ft_interpreter_version); + } + + void* FT_Open_Face(void* library, unsigned char* memory, unsigned int size, int face_index) + { + FT_Open_Args oOpenArgs; + oOpenArgs.flags = FT_OPEN_MEMORY | FT_OPEN_PARAMS; + oOpenArgs.memory_base = memory; + oOpenArgs.memory_size = (FT_Long)size; + + FT_Parameter *pParams = (FT_Parameter *)ft_smalloc( sizeof(FT_Parameter) * 4 ); + pParams[0].tag = FT_MAKE_TAG( 'i', 'g', 'p', 'f' ); + pParams[0].data = NULL; + pParams[1].tag = FT_MAKE_TAG( 'i', 'g', 'p', 's' ); + pParams[1].data = NULL; + pParams[2].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY; + pParams[2].data = NULL; + pParams[3].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY; + pParams[3].data = NULL; + + oOpenArgs.params = pParams; + oOpenArgs.num_params = 4; + + FT_Face face; + int error = ::FT_Open_Face( (FT_Library)library, &oOpenArgs, face_index, &face ); + + ft_sfree(pParams); + + if (error) + return NULL; + + return face; + } + + void FT_Done_Face(void* face) + { + ::FT_Done_Face((FT_Face)face); + } + + unsigned int FT_SetCMapForCharCode(void* face_pointer, unsigned int unicode) + { + if (!face_pointer) + return 0; + + FT_Face face = (FT_Face)face_pointer; + + if ( 0 == face->num_charmaps ) + return unicode; + + unsigned int nCharIndex = 0; + + for ( int nIndex = 0; nIndex < face->num_charmaps; ++nIndex ) + { + FT_CharMap pCharMap = face->charmaps[nIndex]; + + if ( FT_Set_Charmap( face, pCharMap ) ) + continue; + + FT_Encoding pEncoding = pCharMap->encoding; + + if ( FT_ENCODING_UNICODE == pEncoding ) + { + nCharIndex = FT_Get_Char_Index( face, unicode ); + if ( nCharIndex ) + { + return nCharIndex; + } + } + else if ( FT_ENCODING_NONE == pEncoding || FT_ENCODING_MS_SYMBOL == pEncoding || FT_ENCODING_APPLE_ROMAN == pEncoding ) + { + #if 0 + FT_ULong charcode; + FT_UInt gindex; + + charcode = FT_Get_First_Char( face, &gindex ); + while ( gindex != 0 ) + { + charcode = FT_Get_Next_Char( face, charcode, &gindex ); + if ( charcode == unicode ) + { + nCharIndex = gindex; + break; + } + } + #endif + + nCharIndex = FT_Get_Char_Index( face, unicode ); + } + } + + return nCharIndex; + } + + int FT_GetFaceMaxAdvanceX(void* face_pointer) + { + if (!face_pointer) + return 0; + + FT_Face face = (FT_Face)face_pointer; + if (!face->size) + return 0; + + return (int)face->size->metrics.max_advance; + } + + int FT_GetKerningX(void* face, unsigned int prev_gid, unsigned int gid) + { + FT_Vector vec; + vec.x = 0; + vec.y = 0; + FT_Get_Kerning((FT_Face)face, prev_gid, gid, 0, &vec); + return vec.x; + } + + void FT_Set_Transform(void* face, int xx, int yx, int xy, int yy) + { + FT_Matrix m; + m.xx = xx; + m.yx = yx; + m.xy = xy; + m.yy = yy; + ::FT_Set_Transform((FT_Face)face, &m, NULL); + } + + int FT_Load_Glyph(void* face, unsigned int glyph_index, int load_flags) + { + return ::FT_Load_Glyph((FT_Face)face, glyph_index, load_flags); + } + + int FT_Set_Char_Size(void* face, int char_width, int char_height, unsigned int hres, unsigned int vres) + { + return ::FT_Set_Char_Size((FT_Face)face, char_width, char_height, hres, vres); + } + + void FT_Glyph_Get_CBox(void* glyph, unsigned int bbox_mode, CExternalPointer* result) + { + FT_BBox bbox; + FT_Glyph_Get_CBox((FT_Glyph)glyph, bbox_mode, &bbox); + ALLOC_WRITER(4 * 4); + WRITE_INT(bbox.xMin); + WRITE_INT(bbox.yMin); + WRITE_INT(bbox.xMax); + WRITE_INT(bbox.yMax); + } + + unsigned char* FT_Get_Glyph_Render_Buffer(void* face) + { + return ((FT_Face)face)->glyph->bitmap.buffer; + } + + bool FT_Get_Glyph_Render_Params(void* face, int render_mode, CExternalPointer* result) + { + FT_GlyphSlot slot = ((FT_Face)face)->glyph; + if (FT_Render_Glyph(slot, (FT_Render_Mode)render_mode)) + return false; + + ALLOC_WRITER(6 * 4); + WRITE_INT(slot->bitmap_left); + WRITE_INT(slot->bitmap_top); + WRITE_UINT(slot->bitmap.width); + WRITE_UINT(slot->bitmap.rows); + WRITE_INT(slot->bitmap.pitch); + WRITE_INT(slot->bitmap.pixel_mode); + return true; + } + + bool FT_GetFaceInfo(void* face_pointer, CExternalPointer* result) + { + if (!face_pointer) + return false; + + FT_Face face = (FT_Face)face_pointer; + + //face->units_per_EM + //face->ascender + //face->descender + //face->height + //face->face_flags + //face->num_faces + //face->num_glyphs + //face->num_charmaps + //face->style_flags + //face->face_index + //face->family_name + //face->style_name + + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, ft_sfnt_os2 ); + //os2->version + //os2->usWeightClass + //os2->fsSelection + //os2->usWinAscent + //os2->usWinDescent + //os2->usDefaultChar + //os2->sTypoAscender; + //os2->sTypoDescender; + //os2->sTypoLineGap; + + //os2->ulUnicodeRange1 + //os2->ulUnicodeRange2 + //os2->ulUnicodeRange3 + //os2->ulUnicodeRange4 + //os2->ulCodePageRange1 + //os2->ulCodePageRange2 + + int isSymbolic = -1; + if (os2 && 0xFFFF != os2->version) + { + FT_ULong ulCodePageRange1 = os2->ulCodePageRange1; + FT_ULong ulCodePageRange2 = os2->ulCodePageRange2; + + if ((ulCodePageRange1 & 0x80000000) || (ulCodePageRange1 == 0 && ulCodePageRange2 == 0)) + { + for( int nIndex = 0; nIndex < face->num_charmaps; nIndex++ ) + { + if (0 == face->charmaps[nIndex]->encoding_id && 3 == face->charmaps[nIndex]->platform_id) + { + isSymbolic = nIndex; + break; + } + } + } + } + + int nHeader_yMin = face->descender; + int nHeader_yMax = face->ascender; + if (face && FT_IS_SFNT(face)) + { + TT_Face ttface = (TT_Face)face; + nHeader_yMin = ttface->header.yMin; + nHeader_yMax = ttface->header.yMax; + } + + //isSymbolic + + unsigned int nLen1 = (unsigned int)strlen(face->family_name); + unsigned int nLen2 = (unsigned int)strlen(face->style_name); + + unsigned int nLen = 28 + nLen1 + 1 + nLen2 + 1 + 1 + (int)face->num_fixed_sizes; + + ALLOC_WRITER(nLen * 4); + WRITE_INT((int)face->units_per_EM); + WRITE_INT((int)face->ascender); + WRITE_INT((int)face->descender); + WRITE_INT((int)face->height); + WRITE_INT((int)face->face_flags); + WRITE_INT((int)face->num_faces); + WRITE_INT((int)face->num_glyphs); + WRITE_INT((int)face->num_charmaps); + WRITE_INT((int)face->style_flags); + WRITE_INT((int)face->face_index); + + for (unsigned int i = 0; i < nLen1; ++i) + WRITE_INT(face->family_name[i]); + WRITE_INT(0); + + for (unsigned int i = 0; i < nLen2; ++i) + WRITE_INT(face->style_name[i]); + WRITE_INT(0); + + if (os2) + { + WRITE_INT((int)os2->version); + WRITE_INT((int)os2->usWeightClass); + WRITE_INT((int)os2->fsSelection); + WRITE_INT((int)os2->usWinAscent); + WRITE_INT((int)os2->usWinDescent); + WRITE_INT((int)os2->usDefaultChar); + WRITE_INT((int)os2->sTypoAscender); + WRITE_INT((int)os2->sTypoDescender); + WRITE_INT((int)os2->sTypoLineGap); + + WRITE_INT((int)os2->ulUnicodeRange1); + WRITE_INT((int)os2->ulUnicodeRange2); + WRITE_INT((int)os2->ulUnicodeRange3); + WRITE_INT((int)os2->ulUnicodeRange4); + WRITE_INT((int)os2->ulCodePageRange1); + WRITE_INT((int)os2->ulCodePageRange2); + } + else + { + WRITE_INT((int)0xFFFF); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + WRITE_INT((int)0); + } + + WRITE_INT((int)isSymbolic); + WRITE_INT((int)nHeader_yMin); + WRITE_INT((int)nHeader_yMax); + + WRITE_INT((int)face->num_fixed_sizes); + + for (int i = 0; i < face->num_fixed_sizes; ++i) + WRITE_INT((int)face->available_sizes[i].size); + + return true; + } + + bool FT_Get_Glyph_Measure_Params(void* face, bool isVector, CExternalPointer* result) + { + FT_GlyphSlot slot = ((FT_Face)face)->glyph; + + if (!isVector && slot->bitmap.buffer != NULL && slot->format == FT_GLYPH_FORMAT_BITMAP) + { + ALLOC_WRITER(15 * 4); + WRITE_INT(15); + WRITE_INT(0); + WRITE_INT(0); + WRITE_INT(slot->metrics.width); + WRITE_INT(slot->metrics.height); + + WRITE_INT(slot->metrics.width); + WRITE_INT(slot->metrics.height); + + WRITE_INT(slot->metrics.horiAdvance); + WRITE_INT(slot->metrics.horiBearingX); + WRITE_INT(slot->metrics.horiBearingY); + + WRITE_INT(slot->metrics.vertAdvance); + WRITE_INT(slot->metrics.vertBearingX); + WRITE_INT(slot->metrics.vertBearingY); + + WRITE_INT(slot->linearHoriAdvance); + WRITE_INT(slot->linearVertAdvance); + return true; + } + + FT_Glyph glyph; + FT_Get_Glyph(slot, &glyph); + if (!glyph) + return false; + + FT_BBox bbox; + FT_Glyph_Get_CBox(glyph, 1, &bbox); + + if (isVector) + { + FT_Decompose_Outline_Buffer buffer; + FT_Decompose_Outline_Buffer_Init(&buffer); + + static FT_Outline_Funcs pOutlineFuncs = + { + &GlyphPathMoveTo, + &GlyphPathLineTo, + &GlyphPathConicTo, + &GlyphPathCubicTo, + 0, 0 + }; + + FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, &pOutlineFuncs, &buffer); + + int nCount = buffer.pos; + + ALLOC_WRITER((nCount + 15) * 4); + WRITE_INT((nCount + 15)); + WRITE_INT(bbox.xMin); + WRITE_INT(bbox.yMin); + WRITE_INT(bbox.xMax); + WRITE_INT(bbox.yMax); + + WRITE_INT(slot->metrics.width); + WRITE_INT(slot->metrics.height); + + WRITE_INT(slot->metrics.horiAdvance); + WRITE_INT(slot->metrics.horiBearingX); + WRITE_INT(slot->metrics.horiBearingY); + + WRITE_INT(slot->metrics.vertAdvance); + WRITE_INT(slot->metrics.vertBearingX); + WRITE_INT(slot->metrics.vertBearingY); + + WRITE_INT(slot->linearHoriAdvance); + WRITE_INT(slot->linearVertAdvance); + + for (int i = 0; i < nCount; i++) + WRITE_INT(buffer.buffer[i]); + + FT_Decompose_Outline_Buffer_Destroy(&buffer); + } + else + { + ALLOC_WRITER(15 * 4); + WRITE_INT(15); + WRITE_INT(bbox.xMin); + WRITE_INT(bbox.yMin); + WRITE_INT(bbox.xMax); + WRITE_INT(bbox.yMax); + + WRITE_INT(slot->metrics.width); + WRITE_INT(slot->metrics.height); + + WRITE_INT(slot->metrics.horiAdvance); + WRITE_INT(slot->metrics.horiBearingX); + WRITE_INT(slot->metrics.horiBearingY); + + WRITE_INT(slot->metrics.vertAdvance); + WRITE_INT(slot->metrics.vertBearingX); + WRITE_INT(slot->metrics.vertBearingY); + + WRITE_INT(slot->linearHoriAdvance); + WRITE_INT(slot->linearVertAdvance); + } + + FT_Done_Glyph(glyph); + return true; + } +} diff --git a/DesktopEditor/fontengine/TextShaper.h b/DesktopEditor/fontengine/TextShaper.h new file mode 100644 index 0000000000..60efde8ba9 --- /dev/null +++ b/DesktopEditor/fontengine/TextShaper.h @@ -0,0 +1,82 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ +#ifndef _BUILD_TEXT_MANAGER_FONTMANAGER_H_ +#define _BUILD_TEXT_MANAGER_FONTMANAGER_H_ + +#include "../graphics/pro/Fonts.h" + +namespace NSShaper +{ + class GRAPHICS_DECL CExternalPointer + { + public: + unsigned char* Data; + unsigned int Len; + + public: + CExternalPointer(); + virtual ~CExternalPointer(); + + public: + virtual void WriteInt(unsigned char* data, const int& value); + virtual void WriteUInt(unsigned char* data, const unsigned int& value); + + virtual void Alloc(const unsigned int& len); + virtual void Free(); + }; + + GRAPHICS_DECL void* FT_Library_Init(); + GRAPHICS_DECL void FT_Library_Destroy(void* library); + + GRAPHICS_DECL int FT_Set_TrueType_HintProp(void* library, unsigned int interpreter_version); + + GRAPHICS_DECL void* FT_Open_Face(void* library, unsigned char* memory, unsigned int size, int face_index); + GRAPHICS_DECL void FT_Done_Face(void* face); + + GRAPHICS_DECL bool FT_GetFaceInfo(void* face, CExternalPointer* result); + GRAPHICS_DECL bool FT_Get_Glyph_Measure_Params(void* face, bool is_vector, CExternalPointer* result); + + GRAPHICS_DECL bool FT_Get_Glyph_Render_Params(void* face, int render_mode, CExternalPointer* result); + GRAPHICS_DECL unsigned char* FT_Get_Glyph_Render_Buffer(void* face); + + GRAPHICS_DECL void FT_Glyph_Get_CBox(void* glyph, unsigned int bbox_mode, CExternalPointer* result); + + GRAPHICS_DECL int FT_Load_Glyph(void* face, unsigned int glyph_index, int load_flags); + GRAPHICS_DECL void FT_Set_Transform(void* face, int xx, int yx, int xy, int yy); + GRAPHICS_DECL int FT_Set_Char_Size(void* face, int char_width, int char_height, unsigned int hres, unsigned int vres); + + 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); +} + +#endif // _BUILD_TEXT_MANAGER_FONTMANAGER_H_ diff --git a/DesktopEditor/graphics/pro/graphics.pro b/DesktopEditor/graphics/pro/graphics.pro index 6d746cd554..d62dbfc760 100644 --- a/DesktopEditor/graphics/pro/graphics.pro +++ b/DesktopEditor/graphics/pro/graphics.pro @@ -489,6 +489,13 @@ HEADERS += ./../../fontengine/FontsAssistant.h SOURCES += ./../../fontengine/FontsAssistant.cpp # ------------------------------------------------- +# ------------------- shaper ---------------------- +HEADERS += ./../../fontengine/TextShaper.h +SOURCES += ./../../fontengine/TextShaper.cpp + +include(./../../fontengine/js/common/graphics_shaper.pri) +# ------------------------------------------------- + core_ios { OBJECTIVE_SOURCES += \