From 87d9ad5b88616bdae3ecbec5f81d8e01c5cf1ef2 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 10 Nov 2023 15:36:11 +0400 Subject: [PATCH 01/54] Basic functionality --- DesktopEditor/doctrenderer/doctrenderer.pro | 6 +- DesktopEditor/doctrenderer/json/json.cpp | 193 ++++++++++++++++++ DesktopEditor/doctrenderer/json/json.h | 81 ++++++++ DesktopEditor/doctrenderer/test/json/main.cpp | 114 +++++++++++ DesktopEditor/doctrenderer/test/json/test.pro | 31 +++ 5 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 DesktopEditor/doctrenderer/json/json.cpp create mode 100644 DesktopEditor/doctrenderer/json/json.h create mode 100644 DesktopEditor/doctrenderer/test/json/main.cpp create mode 100644 DesktopEditor/doctrenderer/test/json/test.pro diff --git a/DesktopEditor/doctrenderer/doctrenderer.pro b/DesktopEditor/doctrenderer/doctrenderer.pro index 17a3ff8cff..d0d5848372 100644 --- a/DesktopEditor/doctrenderer/doctrenderer.pro +++ b/DesktopEditor/doctrenderer/doctrenderer.pro @@ -23,7 +23,7 @@ core_android:DEFINES += DISABLE_MEMORY_LIMITATION HEADERS += \ config.h \ doctrenderer.h \ - docbuilder.h + docbuilder.h SOURCES += \ nativecontrol.cpp \ @@ -69,6 +69,10 @@ SOURCES += \ embed/HashEmbed.cpp \ embed/Default.cpp +# Serialize objects to JS +HEADERS += json/json.h +SOURCES += json/json.cpp + include($$PWD/js_internal/js_base.pri) !use_javascript_core { diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp new file mode 100644 index 0000000000..ce82061203 --- /dev/null +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -0,0 +1,193 @@ +#include "json.h" + +namespace NSJSON +{ + CValue::CValue() : m_type(vtUndefined) + { + } + + CValue::CValue(const CValue& other) : m_type(other.m_type) + { + *this = other; + } + + CValue::~CValue() + { + clear(); + } + + CValue& CValue::operator=(const CValue& other) + { + clear(); + switch (m_type) + { + case vtBoolean: + m_bool = other.m_bool; + break; + case vtInteger: + m_int = other.m_int; + break; + case vtDouble: + m_double = other.m_double; + break; + case vtStringA: + new (&m_string) std::string(other.m_string); + break; + case vtStringW: + new (&m_wstring) std::wstring(other.m_wstring); + break; + default: + break; + } + return *this; + } + + CValue& CValue::operator=(const bool& value) + { + clear(); + m_type = vtBoolean; + m_bool = value; + return *this; + } + + CValue& CValue::operator=(const int& value) + { + clear(); + m_type = vtInteger; + m_int = value; + return *this; + } + + CValue& CValue::operator=(const double& value) + { + clear(); + m_type = vtDouble; + m_double = value; + return *this; + } + + CValue& CValue::operator=(const std::string& str) + { + clear(); + m_type = vtStringA; + new (&m_string) std::string(str); + return *this; + } + + CValue& CValue::operator=(const std::wstring& wstr) + { + clear(); + m_type = vtStringW; + new (&m_wstring) std::wstring(wstr); + return *this; + } + + void CValue::setUndefined() + { + clear(); + m_type = vtUndefined; + } + + void CValue::setNull() + { + clear(); + m_type = vtNull; + } + + bool CValue::isUndefined() const + { + return m_type == vtUndefined; + } + + bool CValue::isNull() const + { + return m_type == vtNull; + } + + JSSmart CValue::toJS() const + { + JSSmart ret; + switch (m_type) { + case vtUndefined: + ret = NSJSBase::CJSContext::createUndefined(); + break; + case vtNull: + ret = NSJSBase::CJSContext::createNull(); + break; + case vtBoolean: + ret = NSJSBase::CJSContext::createBool(m_bool); + break; + case vtInteger: + ret = NSJSBase::CJSContext::createInt(m_int); + break; + case vtDouble: + ret = NSJSBase::CJSContext::createDouble(m_double); + break; + case vtStringA: + ret = NSJSBase::CJSContext::createString(m_string); + break; + case vtStringW: + ret = NSJSBase::CJSContext::createString(m_wstring); + break; + } + return ret; + } + + void CValue::clear() + { + switch (m_type) + { + case vtBoolean: + m_bool = false; + break; + case vtInteger: + m_int = 0; + break; + case vtDouble: + m_double = 0.0; + break; + case vtStringA: + m_string.~basic_string(); + break; + case vtStringW: + m_wstring.~basic_string(); + break; + default: + break; + } + } + + void CObject::addMember(const CValue* pValue, const std::string& name) + { + m_values[name] = pValue; + } + + void CObject::addMember(const CObject* pObject, const std::string& name) + { + m_objects[name] = pObject; + } + + JSSmart CObject::toJS() const + { + JSSmart ret = NSJSBase::CJSContext::createObject(); + // set values + for (const auto& entry : m_values) + { + if (entry.second) + { + JSSmart jsValue = entry.second->toJS(); + ret->set(entry.first.c_str(), jsValue); + } + } + // set inner objects + for (const auto& entry : m_objects) + { + if (entry.second) + { + JSSmart jsObject = entry.second->toJS(); + ret->set(entry.first.c_str(), jsObject); + } + } + return ret; + } +} diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h new file mode 100644 index 0000000000..dcdb55a982 --- /dev/null +++ b/DesktopEditor/doctrenderer/json/json.h @@ -0,0 +1,81 @@ +#ifndef JSON_H_ +#define JSON_H_ + +#include "../js_internal/js_base.h" + +#include +#include + +namespace NSJSON +{ + class CObject; + class JS_DECL CValue + { + private: + enum ValueType + { + vtUndefined, + vtNull, + vtBoolean, + vtInteger, + vtDouble, + vtStringA, + vtStringW, + }; + + public: + CValue(); + CValue(const CValue& other); + CValue(CValue&& other) = delete; + // TODO: move constructor and assignment operator ??? + // TODO: constructors from value ??? + ~CValue(); + + CValue& operator=(const CValue& other); + CValue& operator=(CValue&& other) = delete; + CValue& operator=(const bool& value); + CValue& operator=(const int& value); + CValue& operator=(const double& value); + CValue& operator=(const std::string& str); + CValue& operator=(const std::wstring& wstr); + + // TODO: type cast operators ??? + + public: + void setUndefined(); + void setNull(); + bool isUndefined() const; + bool isNull() const; + // Transform C++ value to JS value + JSSmart toJS() const; + + private: + void clear(); + + private: + ValueType m_type; + union + { + bool m_bool; + int m_int; + double m_double; + std::string m_string; + std::wstring m_wstring; + }; + }; + + class JS_DECL CObject + { + public: + void addMember(const CValue* pValue, const std::string& name); + void addMember(const CObject* pObject, const std::string& name); + // Transform C++ object to JS object + JSSmart toJS() const; + + private: + std::unordered_map m_values; + std::unordered_map m_objects; + }; +} + +#endif // JSON_H_ diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp new file mode 100644 index 0000000000..4eff027a07 --- /dev/null +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -0,0 +1,114 @@ +//#include "gtest/gtest.h" +#include "js_internal/js_base.h" +#include "json/json.h" + +#include +#include + +using namespace NSJSBase; + +/* +class CJSONTest : public testing::Test +{ +public: + void SetUp() override + { + // create and enter context + m_pContext = new CJSContext(); + m_pContext->Enter(); + } + + void TearDown() override + { + m_pContext->Exit(); + } + +public: + JSSmart m_pContext; +}; + +TEST_F(..., ...) +{ + ... +} +*/ + +class CColorRGB : public NSJSON::CObject +{ +public: + NSJSON::CValue m_nR; + NSJSON::CValue m_nG; + NSJSON::CValue m_nB; + +public: + CColorRGB() + { + addMember(&m_nR, "r"); + addMember(&m_nG, "g"); + addMember(&m_nB, "b"); + } +}; + +class CColorRGBA : public NSJSON::CObject +{ +public: + NSJSON::CObject m_oRGB; + NSJSON::CValue m_nAlpha; + +public: + CColorRGBA() + { + addMember(&m_oRGB, "rgb"); + addMember(&m_nAlpha, "alpha"); + } +}; + +class CTextParameters : public NSJSON::CObject +{ +public: + NSJSON::CValue m_nSize; + NSJSON::CValue m_bBold; + NSJSON::CValue m_sFontName; + NSJSON::CObject m_oColor; + +public: + CTextParameters() + { + addMember(&m_nSize, "size"); + addMember(&m_bBold, "bold"); + addMember(&m_sFontName, "fontName"); + addMember(&m_oColor, "color"); + } +}; + +int main() +{ + JSSmart pContext = new CJSContext(); + CJSContextScope scope(pContext); + + CColorRGB oColorRGB; + oColorRGB.m_nR = 12; + oColorRGB.m_nG = 34; + oColorRGB.m_nB = 56; + + CColorRGBA oColorRGBA; + oColorRGBA.m_oRGB = oColorRGB; + oColorRGBA.m_nAlpha = 80; + + CTextParameters oTextPr; + oTextPr.m_nSize = 42.0; + oTextPr.m_bBold = true; + oTextPr.m_sFontName = std::string("Times New Roman"); + oTextPr.m_oColor = oColorRGBA; + + JSSmart jsObj = oTextPr.toJS(); + JSSmart global = pContext->GetGlobal(); + global->set("textPr", jsObj); + JSSmart ret = pContext->runScript("(function () { return JSON.stringify(textPr); })();"); + if (ret.IsInit()) + { + std::cout << ret->toStringA() << std::endl; + } + + return 0; +} diff --git a/DesktopEditor/doctrenderer/test/json/test.pro b/DesktopEditor/doctrenderer/test/json/test.pro new file mode 100644 index 0000000000..2669f84897 --- /dev/null +++ b/DesktopEditor/doctrenderer/test/json/test.pro @@ -0,0 +1,31 @@ +QT -= core +QT -= gui + +TARGET = test +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +CONFIG += core_static_link_libstd + +CORE_ROOT_DIR = $$PWD/../../../../../core +CORE_3DPARTY_DIR = $$CORE_ROOT_DIR/Common/3dParty +PWD_ROOT_DIR = $$PWD + +include($$CORE_ROOT_DIR/Common/base.pri) +#include($$CORE_3DPARTY_DIR/googletest/googletest.pri) + +DESTDIR = $$PWD/build + +INCLUDEPATH += ../.. + +ADD_DEPENDENCY(doctrenderer) + +core_linux { + LIBS += -Wl,-unresolved-symbols=ignore-in-shared-libs + LIBS += -ldl +} + +SOURCES += \ + main.cpp From dddd37af126e5fb08b48d4d4a12e70b11eab8a50 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 10 Nov 2023 19:20:51 +0400 Subject: [PATCH 02/54] Refactoring: added base class --- DesktopEditor/doctrenderer/json/json.cpp | 74 +++++++++---------- DesktopEditor/doctrenderer/json/json.h | 42 +++++++---- DesktopEditor/doctrenderer/test/json/main.cpp | 9 ++- 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index ce82061203..28ca3f419f 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -2,11 +2,30 @@ namespace NSJSON { - CValue::CValue() : m_type(vtUndefined) + IBaseValue::IBaseValue() : m_type(vtUndefined) { } - CValue::CValue(const CValue& other) : m_type(other.m_type) + void IBaseValue::setNull() + { + m_type = vtNull; + } + + bool IBaseValue::isUndefined() const + { + return m_type == vtUndefined; + } + + bool IBaseValue::isNull() const + { + return m_type == vtNull; + } + + CValue::CValue() + { + } + + CValue::CValue(const CValue& other) { *this = other; } @@ -19,6 +38,7 @@ namespace NSJSON CValue& CValue::operator=(const CValue& other) { clear(); + m_type = other.m_type; switch (m_type) { case vtBoolean: @@ -82,28 +102,12 @@ namespace NSJSON return *this; } - void CValue::setUndefined() - { - clear(); - m_type = vtUndefined; - } - void CValue::setNull() { clear(); m_type = vtNull; } - bool CValue::isUndefined() const - { - return m_type == vtUndefined; - } - - bool CValue::isNull() const - { - return m_type == vtNull; - } - JSSmart CValue::toJS() const { JSSmart ret; @@ -157,37 +161,27 @@ namespace NSJSON } } - void CObject::addMember(const CValue* pValue, const std::string& name) + void CObject::addMember(const IBaseValue* pValue, const std::string& name) { + if (m_type != vtObject) + m_type = vtObject; m_values[name] = pValue; } - void CObject::addMember(const CObject* pObject, const std::string& name) + JSSmart CObject::toJS() const { - m_objects[name] = pObject; - } + if (m_type == vtUndefined) + return NSJSBase::CJSContext::createUndefined(); + if (m_type == vtNull) + return NSJSBase::CJSContext::createNull(); - JSSmart CObject::toJS() const - { JSSmart ret = NSJSBase::CJSContext::createObject(); - // set values for (const auto& entry : m_values) { - if (entry.second) - { - JSSmart jsValue = entry.second->toJS(); - ret->set(entry.first.c_str(), jsValue); - } + JSSmart jsValue = entry.second->toJS(); + ret->set(entry.first.c_str(), jsValue); } - // set inner objects - for (const auto& entry : m_objects) - { - if (entry.second) - { - JSSmart jsObject = entry.second->toJS(); - ret->set(entry.first.c_str(), jsObject); - } - } - return ret; + + return ret->toValue(); } } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index dcdb55a982..05399a00cc 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -8,10 +8,9 @@ namespace NSJSON { - class CObject; - class JS_DECL CValue + class JS_DECL IBaseValue { - private: + protected: enum ValueType { vtUndefined, @@ -21,8 +20,25 @@ namespace NSJSON vtDouble, vtStringA, vtStringW, + vtObject }; + public: + IBaseValue(); + + protected: + ValueType m_type; + + public: + virtual void setNull(); + virtual bool isUndefined() const; + virtual bool isNull() const; + // Transform C++ value to JS value + virtual JSSmart toJS() const = 0; + }; + + class JS_DECL CValue : public IBaseValue + { public: CValue(); CValue(const CValue& other); @@ -42,18 +58,14 @@ namespace NSJSON // TODO: type cast operators ??? public: - void setUndefined(); - void setNull(); - bool isUndefined() const; - bool isNull() const; + virtual void setNull() override; // Transform C++ value to JS value - JSSmart toJS() const; + virtual JSSmart toJS() const override; private: void clear(); private: - ValueType m_type; union { bool m_bool; @@ -64,17 +76,17 @@ namespace NSJSON }; }; - class JS_DECL CObject + // extend this class to make custom objects serializable to JS + class JS_DECL CObject : public IBaseValue { public: - void addMember(const CValue* pValue, const std::string& name); - void addMember(const CObject* pObject, const std::string& name); + // Add member to JS object when it will be serialized + void addMember(const IBaseValue* pValue, const std::string& name); // Transform C++ object to JS object - JSSmart toJS() const; + virtual JSSmart toJS() const override; private: - std::unordered_map m_values; - std::unordered_map m_objects; + std::unordered_map m_values; }; } diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 4eff027a07..fd4c9cb3dd 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -70,6 +70,7 @@ public: NSJSON::CValue m_bBold; NSJSON::CValue m_sFontName; NSJSON::CObject m_oColor; + NSJSON::CObject m_oExtras; public: CTextParameters() @@ -78,6 +79,7 @@ public: addMember(&m_bBold, "bold"); addMember(&m_sFontName, "fontName"); addMember(&m_oColor, "color"); + addMember(&m_oExtras, "extras"); } }; @@ -96,15 +98,16 @@ int main() oColorRGBA.m_nAlpha = 80; CTextParameters oTextPr; - oTextPr.m_nSize = 42.0; + oTextPr.m_nSize = 4.2; oTextPr.m_bBold = true; oTextPr.m_sFontName = std::string("Times New Roman"); oTextPr.m_oColor = oColorRGBA; + oTextPr.m_oExtras.setNull(); - JSSmart jsObj = oTextPr.toJS(); + JSSmart jsObj = oTextPr.toJS()->toObject(); JSSmart global = pContext->GetGlobal(); global->set("textPr", jsObj); - JSSmart ret = pContext->runScript("(function () { return JSON.stringify(textPr); })();"); + JSSmart ret = pContext->runScript("(function () { return JSON.stringify(textPr, null, 4); })();"); if (ret.IsInit()) { std::cout << ret->toStringA() << std::endl; From 20e782bf5bc45174e4a655e4e2d9d45f1be68b50 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 10 Nov 2023 20:51:40 +0400 Subject: [PATCH 03/54] Test example improvements --- DesktopEditor/doctrenderer/test/json/main.cpp | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index fd4c9cb3dd..68a4ac148b 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -52,7 +52,7 @@ public: class CColorRGBA : public NSJSON::CObject { public: - NSJSON::CObject m_oRGB; + CColorRGB m_oRGB; NSJSON::CValue m_nAlpha; public: @@ -63,21 +63,35 @@ public: } }; +class CFontFamily : public NSJSON::CObject +{ +public: + NSJSON::CValue m_sFontName; + NSJSON::CValue m_bBold; + NSJSON::CValue m_bItalic; + +public: + CFontFamily() + { + addMember(&m_sFontName, "fontName"); + addMember(&m_bBold, "bold"); + addMember(&m_bItalic, "italic"); + } +}; + class CTextParameters : public NSJSON::CObject { public: NSJSON::CValue m_nSize; - NSJSON::CValue m_bBold; - NSJSON::CValue m_sFontName; - NSJSON::CObject m_oColor; + CFontFamily m_oFont; + CColorRGBA m_oColor; NSJSON::CObject m_oExtras; public: CTextParameters() { addMember(&m_nSize, "size"); - addMember(&m_bBold, "bold"); - addMember(&m_sFontName, "fontName"); + addMember(&m_oFont, "font"); addMember(&m_oColor, "color"); addMember(&m_oExtras, "extras"); } @@ -99,9 +113,11 @@ int main() CTextParameters oTextPr; oTextPr.m_nSize = 4.2; - oTextPr.m_bBold = true; - oTextPr.m_sFontName = std::string("Times New Roman"); oTextPr.m_oColor = oColorRGBA; + oTextPr.m_oFont.m_sFontName = std::wstring(L"Times New Roman"); + oTextPr.m_oFont.m_bBold = true; + // undefined member: +// oTextPr.m_oFont.m_bItalic = true; oTextPr.m_oExtras.setNull(); JSSmart jsObj = oTextPr.toJS()->toObject(); From a4ac108c7c86a043f17d3bfb182a572e816df905 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 10 Nov 2023 20:59:34 +0400 Subject: [PATCH 04/54] Some minor improvements --- DesktopEditor/doctrenderer/json/json.cpp | 12 +++--------- DesktopEditor/doctrenderer/test/json/main.cpp | 1 + 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 28ca3f419f..ff5e5cb600 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -133,6 +133,9 @@ namespace NSJSON case vtStringW: ret = NSJSBase::CJSContext::createString(m_wstring); break; + default: + // this will never happen + break; } return ret; } @@ -141,15 +144,6 @@ namespace NSJSON { switch (m_type) { - case vtBoolean: - m_bool = false; - break; - case vtInteger: - m_int = 0; - break; - case vtDouble: - m_double = 0.0; - break; case vtStringA: m_string.~basic_string(); break; diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 68a4ac148b..717915c668 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -118,6 +118,7 @@ int main() oTextPr.m_oFont.m_bBold = true; // undefined member: // oTextPr.m_oFont.m_bItalic = true; + // null member: oTextPr.m_oExtras.setNull(); JSSmart jsObj = oTextPr.toJS()->toObject(); From 6bafc84285a38e658cc2071e8c685d0b2dac3c18 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 10 Nov 2023 21:02:35 +0400 Subject: [PATCH 05/54] Made destructors virtual --- DesktopEditor/doctrenderer/json/json.cpp | 12 ++++++++++++ DesktopEditor/doctrenderer/json/json.h | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index ff5e5cb600..8537d6c94b 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -6,6 +6,10 @@ namespace NSJSON { } + IBaseValue::~IBaseValue() + { + } + void IBaseValue::setNull() { m_type = vtNull; @@ -155,6 +159,14 @@ namespace NSJSON } } + CObject::CObject() + { + } + + CObject::~CObject() + { + } + void CObject::addMember(const IBaseValue* pValue, const std::string& name) { if (m_type != vtObject) diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 05399a00cc..8ab3e1cb01 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -25,6 +25,7 @@ namespace NSJSON public: IBaseValue(); + virtual ~IBaseValue(); protected: ValueType m_type; @@ -45,7 +46,7 @@ namespace NSJSON CValue(CValue&& other) = delete; // TODO: move constructor and assignment operator ??? // TODO: constructors from value ??? - ~CValue(); + virtual ~CValue(); CValue& operator=(const CValue& other); CValue& operator=(CValue&& other) = delete; @@ -79,6 +80,10 @@ namespace NSJSON // extend this class to make custom objects serializable to JS class JS_DECL CObject : public IBaseValue { + public: + CObject(); + virtual ~CObject(); + public: // Add member to JS object when it will be serialized void addMember(const IBaseValue* pValue, const std::string& name); From eecd9833779b44676afe770ae6dada89782bb6e7 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 13 Nov 2023 15:08:59 +0400 Subject: [PATCH 06/54] Rewrited toJS() as a static function --- DesktopEditor/doctrenderer/doctrenderer.pro | 5 +- DesktopEditor/doctrenderer/json/json.cpp | 49 ---------------- DesktopEditor/doctrenderer/json/json.h | 22 ++++--- .../doctrenderer/json/serialization.h | 57 +++++++++++++++++++ DesktopEditor/doctrenderer/test/json/main.cpp | 4 +- 5 files changed, 76 insertions(+), 61 deletions(-) create mode 100644 DesktopEditor/doctrenderer/json/serialization.h diff --git a/DesktopEditor/doctrenderer/doctrenderer.pro b/DesktopEditor/doctrenderer/doctrenderer.pro index d0d5848372..78a31255a5 100644 --- a/DesktopEditor/doctrenderer/doctrenderer.pro +++ b/DesktopEditor/doctrenderer/doctrenderer.pro @@ -70,7 +70,10 @@ SOURCES += \ embed/Default.cpp # Serialize objects to JS -HEADERS += json/json.h +HEADERS += \ + json/json.h \ + json/serialization.h + SOURCES += json/json.cpp include($$PWD/js_internal/js_base.pri) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 8537d6c94b..cf0c0a560a 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -112,38 +112,6 @@ namespace NSJSON m_type = vtNull; } - JSSmart CValue::toJS() const - { - JSSmart ret; - switch (m_type) { - case vtUndefined: - ret = NSJSBase::CJSContext::createUndefined(); - break; - case vtNull: - ret = NSJSBase::CJSContext::createNull(); - break; - case vtBoolean: - ret = NSJSBase::CJSContext::createBool(m_bool); - break; - case vtInteger: - ret = NSJSBase::CJSContext::createInt(m_int); - break; - case vtDouble: - ret = NSJSBase::CJSContext::createDouble(m_double); - break; - case vtStringA: - ret = NSJSBase::CJSContext::createString(m_string); - break; - case vtStringW: - ret = NSJSBase::CJSContext::createString(m_wstring); - break; - default: - // this will never happen - break; - } - return ret; - } - void CValue::clear() { switch (m_type) @@ -173,21 +141,4 @@ namespace NSJSON m_type = vtObject; m_values[name] = pValue; } - - JSSmart CObject::toJS() const - { - if (m_type == vtUndefined) - return NSJSBase::CJSContext::createUndefined(); - if (m_type == vtNull) - return NSJSBase::CJSContext::createNull(); - - JSSmart ret = NSJSBase::CJSContext::createObject(); - for (const auto& entry : m_values) - { - JSSmart jsValue = entry.second->toJS(); - ret->set(entry.first.c_str(), jsValue); - } - - return ret->toValue(); - } } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 8ab3e1cb01..ac58b59ce7 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -8,6 +8,10 @@ namespace NSJSON { + class IBaseValue; + // Transform C++ value to JS value + JSSmart toJS(const IBaseValue* pValue); + class JS_DECL IBaseValue { protected: @@ -27,15 +31,15 @@ namespace NSJSON IBaseValue(); virtual ~IBaseValue(); - protected: - ValueType m_type; - public: virtual void setNull(); virtual bool isUndefined() const; virtual bool isNull() const; - // Transform C++ value to JS value - virtual JSSmart toJS() const = 0; + + friend JSSmart toJS(const IBaseValue* pValue); + + protected: + ValueType m_type; }; class JS_DECL CValue : public IBaseValue @@ -60,12 +64,12 @@ namespace NSJSON public: virtual void setNull() override; - // Transform C++ value to JS value - virtual JSSmart toJS() const override; private: void clear(); + friend JSSmart toJS(const IBaseValue* pValue); + private: union { @@ -87,8 +91,8 @@ namespace NSJSON public: // Add member to JS object when it will be serialized void addMember(const IBaseValue* pValue, const std::string& name); - // Transform C++ object to JS object - virtual JSSmart toJS() const override; + + friend JSSmart toJS(const IBaseValue* pValue); private: std::unordered_map m_values; diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h new file mode 100644 index 0000000000..c88d0aeea1 --- /dev/null +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -0,0 +1,57 @@ +#ifndef SERIALIZATION_H_ +#define SERIALIZATION_H_ + +#include "json.h" + +namespace NSJSON +{ + static JSSmart toJS(const IBaseValue* pValue) + { + IBaseValue::ValueType type = pValue->m_type; + if (type == IBaseValue::vtUndefined) + return NSJSBase::CJSContext::createUndefined(); + if (type == IBaseValue::vtNull) + return NSJSBase::CJSContext::createNull(); + + JSSmart ret; + if (type == IBaseValue::vtObject) + { + const CObject* pObject = static_cast(pValue); + JSSmart jsObj = NSJSBase::CJSContext::createObject(); + for (const auto& entry : pObject->m_values) + { + JSSmart jsValue = toJS(entry.second); + jsObj->set(entry.first.c_str(), jsValue); + } + ret = jsObj->toValue(); + } + else + { + // primitive type + const CValue* pPrimitiveValue = static_cast(pValue); + switch (type) { + case IBaseValue::vtBoolean: + ret = NSJSBase::CJSContext::createBool(pPrimitiveValue->m_bool); + break; + case IBaseValue::vtInteger: + ret = NSJSBase::CJSContext::createInt(pPrimitiveValue->m_int); + break; + case IBaseValue::vtDouble: + ret = NSJSBase::CJSContext::createDouble(pPrimitiveValue->m_double); + break; + case IBaseValue::vtStringA: + ret = NSJSBase::CJSContext::createString(pPrimitiveValue->m_string); + break; + case IBaseValue::vtStringW: + ret = NSJSBase::CJSContext::createString(pPrimitiveValue->m_wstring); + break; + default: + break; + } + } + + return ret; + } +} + +#endif // SERIALIZATION_H_ diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 717915c668..266e34f134 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -1,6 +1,6 @@ //#include "gtest/gtest.h" #include "js_internal/js_base.h" -#include "json/json.h" +#include "json/serialization.h"" #include #include @@ -121,7 +121,7 @@ int main() // null member: oTextPr.m_oExtras.setNull(); - JSSmart jsObj = oTextPr.toJS()->toObject(); + JSSmart jsObj = toJS(&oTextPr)->toObject(); JSSmart global = pContext->GetGlobal(); global->set("textPr", jsObj); JSSmart ret = pContext->runScript("(function () { return JSON.stringify(textPr, null, 4); })();"); From 62f5b03bb4f21ba6dcaca6dea66c0cf8437711e3 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 13 Nov 2023 17:40:12 +0400 Subject: [PATCH 07/54] Added arrays --- DesktopEditor/doctrenderer/json/json.cpp | 70 ++++++++++++++++++- DesktopEditor/doctrenderer/json/json.h | 36 +++++++++- .../doctrenderer/json/serialization.h | 10 +++ DesktopEditor/doctrenderer/test/json/main.cpp | 10 +++ 4 files changed, 121 insertions(+), 5 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index cf0c0a560a..102c13005c 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -6,6 +6,10 @@ namespace NSJSON { } + IBaseValue::IBaseValue(ValueType type) : m_type(type) + { + } + IBaseValue::~IBaseValue() { } @@ -29,6 +33,31 @@ namespace NSJSON { } + CValue::CValue(const bool& value) : IBaseValue(vtBoolean) + { + m_bool = value; + } + + CValue::CValue(const int& value) : IBaseValue(vtInteger) + { + m_int = value; + } + + CValue::CValue(const double& value) : IBaseValue(vtDouble) + { + m_double = value; + } + + CValue::CValue(const std::string& str) : IBaseValue(vtStringA) + { + new (&m_string) std::string(str); + } + + CValue::CValue(const std::wstring& wstr) : IBaseValue(vtStringW) + { + new (&m_wstring) std::wstring(wstr); + } + CValue::CValue(const CValue& other) { *this = other; @@ -127,12 +156,49 @@ namespace NSJSON } } - CObject::CObject() + CArray::CArray() : IBaseValue(vtArray) { } - CObject::~CObject() + CArray::~CArray() { + for (IBaseValue* pValue : m_values) + { + delete pValue; + } + } + + void CArray::add(IBaseValue* value) + { + m_values.push_back(value); + } + + void CArray::addNull() + { + CValue* pValue = new CValue(); + pValue->setNull(); + m_values.push_back(pValue); + } + + void CArray::addUndefined() + { + CValue* pValue = new CValue(); + m_values.push_back(pValue); + } + + int CArray::getCount() const + { + return static_cast(m_values.size()); + } + + IBaseValue* CArray::operator[](int index) + { + return m_values[index]; + } + + const IBaseValue* CArray::operator[](int index) const + { + return m_values[index]; } void CObject::addMember(const IBaseValue* pValue, const std::string& name) diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index ac58b59ce7..c86482fd6e 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -5,6 +5,7 @@ #include #include +#include namespace NSJSON { @@ -24,11 +25,13 @@ namespace NSJSON vtDouble, vtStringA, vtStringW, + vtArray, vtObject }; public: IBaseValue(); + IBaseValue(ValueType type); virtual ~IBaseValue(); public: @@ -42,6 +45,7 @@ namespace NSJSON ValueType m_type; }; + // for primitive values class JS_DECL CValue : public IBaseValue { public: @@ -49,7 +53,11 @@ namespace NSJSON CValue(const CValue& other); CValue(CValue&& other) = delete; // TODO: move constructor and assignment operator ??? - // TODO: constructors from value ??? + CValue(const bool& value); + CValue(const int& value); + CValue(const double& value); + CValue(const std::string& str); + CValue(const std::wstring& wstr); virtual ~CValue(); CValue& operator=(const CValue& other); @@ -81,12 +89,34 @@ namespace NSJSON }; }; + class JS_DECL CArray : public IBaseValue + { + public: + CArray(); + // elements get deleted on array destruction + virtual ~CArray(); + + public: + void add(IBaseValue* value); + void addNull(); + void addUndefined(); + int getCount() const; + + IBaseValue* operator[](int index); + const IBaseValue* operator[](int index) const; + + friend JSSmart toJS(const IBaseValue* pValue); + + private: + std::vector m_values; + }; + // extend this class to make custom objects serializable to JS class JS_DECL CObject : public IBaseValue { public: - CObject(); - virtual ~CObject(); + CObject() = default; + virtual ~CObject() = default; public: // Add member to JS object when it will be serialized diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index c88d0aeea1..150c6fb36f 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -25,6 +25,16 @@ namespace NSJSON } ret = jsObj->toValue(); } + else if (type == IBaseValue::vtArray) + { + const CArray* pArray = static_cast(pValue); + JSSmart jsArr = NSJSBase::CJSContext::createArray(0); + for (const IBaseValue* pArrValue : pArray->m_values) + { + jsArr->add(toJS(pArrValue).GetPointer()); + } + ret = jsArr->toValue(); + } else { // primitive type diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 266e34f134..ef8ca15c2c 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -86,6 +86,7 @@ public: CFontFamily m_oFont; CColorRGBA m_oColor; NSJSON::CObject m_oExtras; + NSJSON::CArray m_arrNumbers; public: CTextParameters() @@ -94,6 +95,7 @@ public: addMember(&m_oFont, "font"); addMember(&m_oColor, "color"); addMember(&m_oExtras, "extras"); + addMember(&m_arrNumbers, "numbers"); } }; @@ -120,6 +122,14 @@ int main() // oTextPr.m_oFont.m_bItalic = true; // null member: oTextPr.m_oExtras.setNull(); + oTextPr.m_arrNumbers.add(new NSJSON::CValue(10000)); + oTextPr.m_arrNumbers.addNull(); + oTextPr.m_arrNumbers.add(new NSJSON::CValue(42)); + oTextPr.m_arrNumbers.add(new NSJSON::CValue(0)); + NSJSON::CArray* pArray = new NSJSON::CArray(); + pArray->add(new NSJSON::CValue(std::string("test!"))); + pArray->addNull(); + oTextPr.m_arrNumbers.add(pArray); JSSmart jsObj = toJS(&oTextPr)->toObject(); JSSmart global = pContext->GetGlobal(); From 85f86c2de6f6eab73cf5e29c027710b35be25d7c Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 13 Nov 2023 18:33:14 +0400 Subject: [PATCH 08/54] Added typed arrays --- DesktopEditor/doctrenderer/json/json.cpp | 24 +++++++++++++++++++ DesktopEditor/doctrenderer/json/json.h | 20 ++++++++++++++++ .../doctrenderer/json/serialization.h | 6 +++++ DesktopEditor/doctrenderer/test/json/main.cpp | 9 ++++++- 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 102c13005c..c15681ea51 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -201,6 +201,30 @@ namespace NSJSON return m_values[index]; } + CTypedArray::CTypedArray(BYTE* data, int len) : IBaseValue(vtTypedArray), m_data(data), m_len(len) + { + } + + CTypedArray::~CTypedArray() + { + delete[] m_data; + } + + BYTE* CTypedArray::getData() + { + return m_data; + } + + const BYTE* CTypedArray::getData() const + { + return m_data; + } + + int CTypedArray::getCount() const + { + return m_len; + } + void CObject::addMember(const IBaseValue* pValue, const std::string& name) { if (m_type != vtObject) diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index c86482fd6e..9f4431d679 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -26,6 +26,7 @@ namespace NSJSON vtStringA, vtStringW, vtArray, + vtTypedArray, vtObject }; @@ -111,6 +112,25 @@ namespace NSJSON std::vector m_values; }; + class JS_DECL CTypedArray : public IBaseValue + { + public: + CTypedArray(BYTE* data = nullptr, int len = 0); + // elements get deleted on typed array destruction + virtual ~CTypedArray(); + + public: + BYTE* getData(); + const BYTE* getData() const; + int getCount() const; + + friend JSSmart toJS(const IBaseValue* pValue); + + private: + BYTE* m_data; + int m_len; + }; + // extend this class to make custom objects serializable to JS class JS_DECL CObject : public IBaseValue { diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index 150c6fb36f..a32faf5978 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -35,6 +35,12 @@ namespace NSJSON } ret = jsArr->toValue(); } + else if (type == IBaseValue::vtTypedArray) + { + const CTypedArray* pTypedArray = static_cast(pValue); + JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(pTypedArray->m_data, pTypedArray->m_len); + ret = jsTypedArr->toValue(); + } else { // primitive type diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index ef8ca15c2c..cd4bfa7e3d 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -128,8 +128,15 @@ int main() oTextPr.m_arrNumbers.add(new NSJSON::CValue(0)); NSJSON::CArray* pArray = new NSJSON::CArray(); pArray->add(new NSJSON::CValue(std::string("test!"))); - pArray->addNull(); + pArray->add(new NSJSON::CValue(3.14)); oTextPr.m_arrNumbers.add(pArray); + BYTE* pData = new BYTE[4]; + pData[0] = 0x22; + pData[1] = 0x33; + pData[2] = 0xaa; + pData[3] = 0x45; + NSJSON::CTypedArray* pTypedArray = new NSJSON::CTypedArray(pData, 4); + oTextPr.m_arrNumbers.add(pTypedArray); JSSmart jsObj = toJS(&oTextPr)->toObject(); JSSmart global = pContext->GetGlobal(); From eecc623723646ede9958ca706c1b16f638b9b414 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Wed, 15 Nov 2023 18:51:31 +0400 Subject: [PATCH 09/54] Add some new functionality + Getters for CValue + Reworked CObject + Partly functioning fromJS() function + Changed test example --- DesktopEditor/doctrenderer/json/json.cpp | 77 +++++++++- DesktopEditor/doctrenderer/json/json.h | 42 ++++-- .../doctrenderer/json/serialization.h | 71 +++++++++ DesktopEditor/doctrenderer/test/json/main.cpp | 138 ++++++------------ 4 files changed, 220 insertions(+), 108 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index c15681ea51..0681ff15b8 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -135,6 +135,56 @@ namespace NSJSON return *this; } + bool CValue::toBool() const + { + if (m_type == vtBoolean) + return m_bool; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return false; + } + + int CValue::toInt() const + { + if (m_type == vtInteger) + return m_int; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return 0; + } + + double CValue::toDouble() const + { + if (m_type == vtDouble) + return m_double; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return 0.0; + } + + std::string CValue::toStringA() const + { + if (m_type == vtStringA) + return m_string; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return std::string(); + } + + std::wstring CValue::toStringW () const + { + if (m_type == vtStringW) + return m_wstring; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return std::wstring(); + } + void CValue::setNull() { clear(); @@ -225,10 +275,29 @@ namespace NSJSON return m_len; } - void CObject::addMember(const IBaseValue* pValue, const std::string& name) + CObject::CObject() : IBaseValue(vtObject) { - if (m_type != vtObject) - m_type = vtObject; - m_values[name] = pValue; + } + + CObject::~CObject() + { + } + + void CObject::set(const std::string& name, IBaseValue* pValue) + { + IBaseValue*& pMapValue = m_values[name]; + if (pMapValue) + delete pMapValue; + pMapValue = pValue; + } + + IBaseValue* CObject::get(const std::string& name) + { + return m_values[name]; + } + + IBaseValue* CObject::operator[](const std::string& name) + { + return m_values[name]; } } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 9f4431d679..57ec4c3990 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -7,11 +7,16 @@ #include #include +// enable to see debug output and exceptions +//#define JSON_DEBUG + namespace NSJSON { class IBaseValue; // Transform C++ value to JS value JSSmart toJS(const IBaseValue* pValue); + // Transform JS value to C++ value + IBaseValue* fromJS(JSSmart jsValue); class JS_DECL IBaseValue { @@ -41,6 +46,7 @@ namespace NSJSON virtual bool isNull() const; friend JSSmart toJS(const IBaseValue* pValue); + friend IBaseValue* fromJS(JSSmart jsValue); protected: ValueType m_type; @@ -57,10 +63,21 @@ namespace NSJSON CValue(const bool& value); CValue(const int& value); CValue(const double& value); + // TODO: constructor and assignment operator from (const char*/wchar_t*) CValue(const std::string& str); CValue(const std::wstring& wstr); virtual ~CValue(); + // getters + bool toBool() const; + // TODO: should cast to int handle the case when current value is double and vise-versa ? + // If so, then cast to bool can handle other values too ? + int toInt() const; + double toDouble() const; + std::string toStringA() const; + std::wstring toStringW() const; + + // TODO: setters CValue& operator=(const CValue& other); CValue& operator=(CValue&& other) = delete; CValue& operator=(const bool& value); @@ -69,8 +86,6 @@ namespace NSJSON CValue& operator=(const std::string& str); CValue& operator=(const std::wstring& wstr); - // TODO: type cast operators ??? - public: virtual void setNull() override; @@ -78,6 +93,7 @@ namespace NSJSON void clear(); friend JSSmart toJS(const IBaseValue* pValue); + friend IBaseValue* fromJS(JSSmart jsValue); private: union @@ -107,6 +123,7 @@ namespace NSJSON const IBaseValue* operator[](int index) const; friend JSSmart toJS(const IBaseValue* pValue); + friend IBaseValue* fromJS(JSSmart jsValue); private: std::vector m_values; @@ -125,27 +142,34 @@ namespace NSJSON int getCount() const; friend JSSmart toJS(const IBaseValue* pValue); + friend IBaseValue* fromJS(JSSmart jsValue); private: BYTE* m_data; int m_len; }; - // extend this class to make custom objects serializable to JS class JS_DECL CObject : public IBaseValue { - public: - CObject() = default; - virtual ~CObject() = default; + private: + // Need to store smart pointers to IBaseValue instead of raw pointers, because user can reset members with new values + using storage_t = std::unordered_map; public: - // Add member to JS object when it will be serialized - void addMember(const IBaseValue* pValue, const std::string& name); + CObject(); + virtual ~CObject(); + + public: + void set(const std::string& name, IBaseValue* pValue); + // TODO: implement getValue, getObject, getArray, getTypedArray so there is no need to cast to needed type explicitly + IBaseValue* get(const std::string& name); + IBaseValue* operator[](const std::string& name); friend JSSmart toJS(const IBaseValue* pValue); + friend IBaseValue* fromJS(JSSmart jsValue); private: - std::unordered_map m_values; + storage_t m_values; }; } diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index a32faf5978..1a122f7cdc 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -3,6 +3,8 @@ #include "json.h" +#include + namespace NSJSON { static JSSmart toJS(const IBaseValue* pValue) @@ -68,6 +70,75 @@ namespace NSJSON return ret; } + + static IBaseValue* fromJS(JSSmart jsValue) + { + if (jsValue->isUndefined()) + return new CValue(); + + if (jsValue->isNull()) + { + CValue* pValue = new CValue; + pValue->setNull(); + return pValue; + } + + IBaseValue* ret = nullptr; + if (jsValue->isObject()) + { + JSSmart jsObj = jsValue->toObject(); + CObject* pObject = new CObject; + // TODO: add CJSObject::getPropertyNames() + ret = pObject; + } + else if (jsValue->isArray()) + { + JSSmart jsArr = jsValue->toArray(); + const int len = jsArr->getCount(); + CArray* pArray = new CArray(); + for (int i = 0; i < len; i++) + { + JSSmart jsElement = jsArr->get(i); + pArray->add(fromJS(jsElement)); + } + ret = pArray; + } + else if (jsValue->isTypedArray()) + { + JSSmart jsTypedArr = jsValue->toTypedArray(); + const int len = jsTypedArr->getCount(); + BYTE* data = jsTypedArr->getData().Data; + ret = new CTypedArray(data, len); + } + // primitives + else if (jsValue->isBool()) + { + ret = new CValue(jsValue->toBool()); + } + else if (jsValue->isNumber()) + { + // TODO: this check seems redundant. Similiar to string (look further). + // check if number is an integer or double + double number = jsValue->toDouble(); + double integral; // integral part + double fractional = std::modf(number, &integral); // fractional part + if (fractional == 0.0 && integral >= INT_MIN && integral <= INT_MAX) + { + ret = new CValue(static_cast(integral)); + } + else + { + ret = new CValue(number); + } + } + else if (jsValue->isString()) + { + // TODO: how do we know whether string consist of char or wchar_t? Can we convert all strings to std::wstring? + } + // else ret is nullptr + + return ret; + } } #endif // SERIALIZATION_H_ diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index cd4bfa7e3d..9cd11af085 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -1,11 +1,12 @@ //#include "gtest/gtest.h" #include "js_internal/js_base.h" -#include "json/serialization.h"" +#include "json/serialization.h" #include #include using namespace NSJSBase; +using namespace NSJSON; /* class CJSONTest : public testing::Test @@ -33,110 +34,57 @@ TEST_F(..., ...) } */ -class CColorRGB : public NSJSON::CObject -{ -public: - NSJSON::CValue m_nR; - NSJSON::CValue m_nG; - NSJSON::CValue m_nB; - -public: - CColorRGB() - { - addMember(&m_nR, "r"); - addMember(&m_nG, "g"); - addMember(&m_nB, "b"); - } -}; - -class CColorRGBA : public NSJSON::CObject -{ -public: - CColorRGB m_oRGB; - NSJSON::CValue m_nAlpha; - -public: - CColorRGBA() - { - addMember(&m_oRGB, "rgb"); - addMember(&m_nAlpha, "alpha"); - } -}; - -class CFontFamily : public NSJSON::CObject -{ -public: - NSJSON::CValue m_sFontName; - NSJSON::CValue m_bBold; - NSJSON::CValue m_bItalic; - -public: - CFontFamily() - { - addMember(&m_sFontName, "fontName"); - addMember(&m_bBold, "bold"); - addMember(&m_bItalic, "italic"); - } -}; - -class CTextParameters : public NSJSON::CObject -{ -public: - NSJSON::CValue m_nSize; - CFontFamily m_oFont; - CColorRGBA m_oColor; - NSJSON::CObject m_oExtras; - NSJSON::CArray m_arrNumbers; - -public: - CTextParameters() - { - addMember(&m_nSize, "size"); - addMember(&m_oFont, "font"); - addMember(&m_oColor, "color"); - addMember(&m_oExtras, "extras"); - addMember(&m_arrNumbers, "numbers"); - } -}; - int main() { JSSmart pContext = new CJSContext(); CJSContextScope scope(pContext); - CColorRGB oColorRGB; - oColorRGB.m_nR = 12; - oColorRGB.m_nG = 34; - oColorRGB.m_nB = 56; + // top object (declared + CObject oTextPr; - CColorRGBA oColorRGBA; - oColorRGBA.m_oRGB = oColorRGB; - oColorRGBA.m_nAlpha = 80; + CObject* pColorRGB = new CObject; + pColorRGB->set("r", new CValue(12)); + pColorRGB->set("g", new CValue(34)); + pColorRGB->set("b", new CValue(56)); - CTextParameters oTextPr; - oTextPr.m_nSize = 4.2; - oTextPr.m_oColor = oColorRGBA; - oTextPr.m_oFont.m_sFontName = std::wstring(L"Times New Roman"); - oTextPr.m_oFont.m_bBold = true; + CObject* pColorRGBA = new CObject; + pColorRGBA->set("rgb", pColorRGB); + pColorRGBA->set("alpha", new CValue(80)); + + oTextPr.set("size", new CValue(4.2)); + oTextPr.set("color", pColorRGBA); + CObject* pFont = new CObject(); + oTextPr.set("font", pFont); + pFont->set("fontName", new CValue(std::wstring(L"Times New Roman"))); + pFont->set("bold", new CValue(true)); // undefined member: -// oTextPr.m_oFont.m_bItalic = true; + pFont->set("italic", new CValue()); // null member: - oTextPr.m_oExtras.setNull(); - oTextPr.m_arrNumbers.add(new NSJSON::CValue(10000)); - oTextPr.m_arrNumbers.addNull(); - oTextPr.m_arrNumbers.add(new NSJSON::CValue(42)); - oTextPr.m_arrNumbers.add(new NSJSON::CValue(0)); - NSJSON::CArray* pArray = new NSJSON::CArray(); - pArray->add(new NSJSON::CValue(std::string("test!"))); - pArray->add(new NSJSON::CValue(3.14)); - oTextPr.m_arrNumbers.add(pArray); + CObject* pExtras = new CObject(); + oTextPr.set("extras", pExtras); + pExtras->setNull(); + // array + CArray* pArrNumbers = new CArray(); + oTextPr.set("numbers", pArrNumbers); + pArrNumbers->add(new CValue(10000)); + // add new elements to array via object's get() + static_cast(oTextPr["numbers"])->addNull(); + static_cast(oTextPr["numbers"])->add(new CValue(42)); + static_cast(oTextPr["numbers"])->add(new CValue(0)); + // inner array + CArray* pArrInner = new CArray(); + pArrInner->add(new CValue(std::string("test!"))); + pArrInner->add(new CValue(3.14)); + pArrNumbers->add(pArrInner); + // typed array BYTE* pData = new BYTE[4]; - pData[0] = 0x22; - pData[1] = 0x33; - pData[2] = 0xaa; - pData[3] = 0x45; - NSJSON::CTypedArray* pTypedArray = new NSJSON::CTypedArray(pData, 4); - oTextPr.m_arrNumbers.add(pTypedArray); + pData[0] = 11; + pData[1] = 23; + pData[2] = 58; + pData[3] = 13; + // typed array + CTypedArray* pTypedArray = new CTypedArray(pData, 4); + pArrInner->add(pTypedArray); JSSmart jsObj = toJS(&oTextPr)->toObject(); JSSmart global = pContext->GetGlobal(); From 7eebede9a6a6178f7f3c2f04d63448a8ffc35169 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 16 Nov 2023 12:00:26 +0400 Subject: [PATCH 10/54] Tests rearrangement --- .../{internal => embed/external}/Embed.cpp | 0 .../test/{internal => embed/external}/Embed.h | 2 +- .../external}/jsc/jsc_Embed.mm | 0 .../{internal => embed/external}/main.cpp | 0 .../external/test.pro} | 4 +- .../external}/v8/v8_Embed.cpp | 0 .../{test.cpp => internal/hash/main.cpp} | 0 .../hash/test.pro} | 64 +++++++++---------- 8 files changed, 35 insertions(+), 35 deletions(-) rename DesktopEditor/doctrenderer/test/{internal => embed/external}/Embed.cpp (100%) rename DesktopEditor/doctrenderer/test/{internal => embed/external}/Embed.h (94%) rename DesktopEditor/doctrenderer/test/{internal => embed/external}/jsc/jsc_Embed.mm (100%) rename DesktopEditor/doctrenderer/test/{internal => embed/external}/main.cpp (100%) rename DesktopEditor/doctrenderer/test/{internal/test_internal.pro => embed/external/test.pro} (86%) rename DesktopEditor/doctrenderer/test/{internal => embed/external}/v8/v8_Embed.cpp (100%) rename DesktopEditor/doctrenderer/test/embed/{test.cpp => internal/hash/main.cpp} (100%) rename DesktopEditor/doctrenderer/test/embed/{test_embed.pro => internal/hash/test.pro} (76%) diff --git a/DesktopEditor/doctrenderer/test/internal/Embed.cpp b/DesktopEditor/doctrenderer/test/embed/external/Embed.cpp similarity index 100% rename from DesktopEditor/doctrenderer/test/internal/Embed.cpp rename to DesktopEditor/doctrenderer/test/embed/external/Embed.cpp diff --git a/DesktopEditor/doctrenderer/test/internal/Embed.h b/DesktopEditor/doctrenderer/test/embed/external/Embed.h similarity index 94% rename from DesktopEditor/doctrenderer/test/internal/Embed.h rename to DesktopEditor/doctrenderer/test/embed/external/Embed.h index 80f06776a7..2d67bf898a 100644 --- a/DesktopEditor/doctrenderer/test/internal/Embed.h +++ b/DesktopEditor/doctrenderer/test/embed/external/Embed.h @@ -1,7 +1,7 @@ #ifndef _BUILD_NATIVE_HASH_EMBED_H_ #define _BUILD_NATIVE_HASH_EMBED_H_ -#include "../../js_internal/js_base.h" +#include "js_internal/js_base.h" #define ENABLE_SUM_DEL #define ENABLE_GET diff --git a/DesktopEditor/doctrenderer/test/internal/jsc/jsc_Embed.mm b/DesktopEditor/doctrenderer/test/embed/external/jsc/jsc_Embed.mm similarity index 100% rename from DesktopEditor/doctrenderer/test/internal/jsc/jsc_Embed.mm rename to DesktopEditor/doctrenderer/test/embed/external/jsc/jsc_Embed.mm diff --git a/DesktopEditor/doctrenderer/test/internal/main.cpp b/DesktopEditor/doctrenderer/test/embed/external/main.cpp similarity index 100% rename from DesktopEditor/doctrenderer/test/internal/main.cpp rename to DesktopEditor/doctrenderer/test/embed/external/main.cpp diff --git a/DesktopEditor/doctrenderer/test/internal/test_internal.pro b/DesktopEditor/doctrenderer/test/embed/external/test.pro similarity index 86% rename from DesktopEditor/doctrenderer/test/internal/test_internal.pro rename to DesktopEditor/doctrenderer/test/embed/external/test.pro index aa25c41f1f..6d2b027065 100644 --- a/DesktopEditor/doctrenderer/test/internal/test_internal.pro +++ b/DesktopEditor/doctrenderer/test/embed/external/test.pro @@ -9,7 +9,7 @@ TEMPLATE = app CONFIG += core_static_link_libstd -CORE_ROOT_DIR = $$PWD/../../../../../core +CORE_ROOT_DIR = $$PWD/../../../../../../core PWD_ROOT_DIR = $$PWD include($$CORE_ROOT_DIR/Common/base.pri) @@ -18,7 +18,7 @@ include($$CORE_ROOT_DIR/DesktopEditor/doctrenderer/js_internal/js_base_embed.pri ############### destination path ############### DESTDIR = $$PWD/build ################################################ -INCLUDEPATH += ../.. +INCLUDEPATH += $$CORE_ROOT_DIR/DesktopEditor/doctrenderer DEFINES += CURR_DIR=\\\"$$PWD_ROOT_DIR\\\" diff --git a/DesktopEditor/doctrenderer/test/internal/v8/v8_Embed.cpp b/DesktopEditor/doctrenderer/test/embed/external/v8/v8_Embed.cpp similarity index 100% rename from DesktopEditor/doctrenderer/test/internal/v8/v8_Embed.cpp rename to DesktopEditor/doctrenderer/test/embed/external/v8/v8_Embed.cpp diff --git a/DesktopEditor/doctrenderer/test/embed/test.cpp b/DesktopEditor/doctrenderer/test/embed/internal/hash/main.cpp similarity index 100% rename from DesktopEditor/doctrenderer/test/embed/test.cpp rename to DesktopEditor/doctrenderer/test/embed/internal/hash/main.cpp diff --git a/DesktopEditor/doctrenderer/test/embed/test_embed.pro b/DesktopEditor/doctrenderer/test/embed/internal/hash/test.pro similarity index 76% rename from DesktopEditor/doctrenderer/test/embed/test_embed.pro rename to DesktopEditor/doctrenderer/test/embed/internal/hash/test.pro index b088bd08b7..9f1ad28169 100644 --- a/DesktopEditor/doctrenderer/test/embed/test_embed.pro +++ b/DesktopEditor/doctrenderer/test/embed/internal/hash/test.pro @@ -1,32 +1,32 @@ -QT -= core -QT -= gui - -TARGET = test -CONFIG += console -CONFIG -= app_bundle - -TEMPLATE = app - -CONFIG += core_static_link_libstd - -CORE_ROOT_DIR = $$PWD/../../../../../core -CORE_3DPARTY_DIR = $$CORE_ROOT_DIR/Common/3dParty -PWD_ROOT_DIR = $$PWD - -include($$CORE_ROOT_DIR/Common/base.pri) -include($$CORE_3DPARTY_DIR/googletest/googletest.pri) - -DESTDIR = $$PWD/build - -INCLUDEPATH += ../.. - -ADD_DEPENDENCY(doctrenderer) - -core_linux { - LIBS += -Wl,-unresolved-symbols=ignore-in-shared-libs - LIBS += -ldl -} - -SOURCES += \ - test.cpp - +QT -= core +QT -= gui + +TARGET = test +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +CONFIG += core_static_link_libstd + +CORE_ROOT_DIR = $$PWD/../../../../../../../core +CORE_3DPARTY_DIR = $$CORE_ROOT_DIR/Common/3dParty +PWD_ROOT_DIR = $$PWD + +include($$CORE_ROOT_DIR/Common/base.pri) +include($$CORE_3DPARTY_DIR/googletest/googletest.pri) + +DESTDIR = $$PWD/build + +INCLUDEPATH += $$CORE_ROOT_DIR/DesktopEditor/doctrenderer + +ADD_DEPENDENCY(doctrenderer) + +core_linux { + LIBS += -Wl,-unresolved-symbols=ignore-in-shared-libs + LIBS += -ldl +} + +SOURCES += \ + main.cpp + From 59806039ed1a552a0106de0f6e017af365305d33 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 16 Nov 2023 14:34:06 +0400 Subject: [PATCH 11/54] V8: Implemented CJSObject::getPropertyNames() --- .../doctrenderer/js_internal/js_base.h | 8 ++++++-- .../doctrenderer/js_internal/v8/v8_base.h | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/js_base.h b/DesktopEditor/doctrenderer/js_internal/js_base.h index 319308308d..ba61ce1a6b 100644 --- a/DesktopEditor/doctrenderer/js_internal/js_base.h +++ b/DesktopEditor/doctrenderer/js_internal/js_base.h @@ -215,7 +215,7 @@ namespace NSJSBase * Returns specified property of the object. * @param name The name of a property. */ - virtual JSSmart get(const char* name) = 0; + virtual JSSmart get(const char* name) = 0; /** * Sets a property of the object. * @param name The name of a property. @@ -228,6 +228,10 @@ namespace NSJSBase void set(const char* name, JSSmart value); void set(const char* name, JSSmart value); + /** + * Returns a vector containing the names of the properties of this object as strings, including properties from prototype objects. + */ + virtual std::vector getPropertyNames() = 0; /** * Returns a pointer to the native embedded object. */ @@ -673,7 +677,7 @@ namespace NSJSBase * * NOTE: If you don't want to export certain functions from your embedded class for some reason, * then add the inline comment "[noexport]" at the start of a function declaration. - * Also you can use `#ifdef ... #endif` blocks (see doctrenderer/test/internal/Embed.h for an example). + * Also you can use `#ifdef ... #endif` blocks (see doctrenderer/test/embed/external/Embed.h for an example). */ #endif // _CORE_EXT_JS_BASE_H_ diff --git a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h index c90f2966d4..35d072b21a 100644 --- a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h +++ b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h @@ -446,6 +446,23 @@ namespace NSJSBase value->Set(V8ContextFirstArg _name, v8::Number::New(isolate, _value)); } + virtual std::vector getPropertyNames() + { + v8::Local context = CV8Worker::GetCurrentContext(); + v8::Local names = value->GetPropertyNames(context).ToLocalChecked(); + uint32_t len = names->Length(); + + std::vector ret(len); + for (uint32_t i = 0; i < len; i++) + { + CJSValueV8 _value; + _value.value = names->Get(context, i).ToLocalChecked(); + ret[i] = _value.toStringA(); + } + + return ret; + } + virtual CJSEmbedObject* getNative() { v8::Handle field = v8::Handle::Cast(value->GetInternalField(0)); From 31f52731f6ad11eece896c323250142e7b746a80 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 16 Nov 2023 14:34:29 +0400 Subject: [PATCH 12/54] Added tests for CJSObject::getPropertyNames() --- .../doctrenderer/test/js_internal/main.cpp | 117 ++++++++++++++++++ .../doctrenderer/test/js_internal/test.pro | 32 +++++ 2 files changed, 149 insertions(+) create mode 100644 DesktopEditor/doctrenderer/test/js_internal/main.cpp create mode 100644 DesktopEditor/doctrenderer/test/js_internal/test.pro diff --git a/DesktopEditor/doctrenderer/test/js_internal/main.cpp b/DesktopEditor/doctrenderer/test/js_internal/main.cpp new file mode 100644 index 0000000000..cb496c62d9 --- /dev/null +++ b/DesktopEditor/doctrenderer/test/js_internal/main.cpp @@ -0,0 +1,117 @@ +#include "gtest/gtest.h" + +#include "js_internal/js_base.h" + +#include + +using namespace NSJSBase; + +class CGetPropertyNamesTest : public testing::Test +{ +public: + void SetUp() override + { + // create and enter context + m_pContext = new CJSContext(); + m_pContext->Enter(); + } + + void TearDown() override + { + m_pContext->Exit(); + } + + std::vector getObjectProperties(const std::string& objLiteral) + { + JSSmart obj = m_pContext->runScript("(() => { return " + objLiteral + ";})();")->toObject(); + return obj->getPropertyNames(); + } + + // The order of properties of object in JS is not always the same as insertion order. + // So this function sorts and compares two vectors with property names. + bool compare(std::vector& lhs, std::vector& rhs) + { + std::sort(lhs.begin(), lhs.end()); + std::sort(rhs.begin(), rhs.end()); + return lhs == rhs; + } + + std::string printInfo(const std::string& info, const std::vector& names) + { + std::string ret = info; + ret += '['; + const int lenResult = names.size(); + for (int i = 0; i < lenResult; i++) + { + ret += "\"" + names[i] + "\""; + if (i < lenResult - 1) + ret += ','; + } + ret += "]\n"; + return ret; + } + +public: + JSSmart m_pContext; +}; + + +TEST_F(CGetPropertyNamesTest, normal_object) +{ + std::vector result = getObjectProperties("{number: 42, name: 'foo', arr: [1, 'abc', 2, 3], func() { return 'bar'; }}"); + std::vector expected = {"number", "name", "arr", "func"}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, empty_object) +{ + std::vector result = getObjectProperties("{}"); + std::vector expected = {}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, only_one_function_in_object) +{ + std::vector result = getObjectProperties("{add(a, b) { return a + b; }}"); + std::vector expected = {"add"}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, inner_object) +{ + std::vector result = getObjectProperties("{inner: {number: 42, name: 'foo'}}"); + std::vector expected = {"inner"}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, object_with_null_and_undefined_properties) +{ + std::vector result = getObjectProperties("{number: null, name: undefined, func() { return 'bar'; }}"); + std::vector expected = {"number", "name", "func"}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, array_as_object) +{ + std::vector result = getObjectProperties("{0: 4, 1: 2, 2: undefined, 3: 'foo', 42: 'bar'}"); + std::vector expected = {"0", "1", "2", "3", "42"}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, object_with_prototype) +{ + m_pContext->runScript( + "var personPrototype = { greet() { return 'Hello, world!'; } };" + "function Person(name) { this.name = name; }" + ); + + JSSmart obj = m_pContext->runScript("new Person('Foo');")->toObject(); + std::vector result1 = obj->getPropertyNames(); + std::vector expected1 = {"name"}; + EXPECT_TRUE(compare(result1, expected1)) << printInfo("Actual: ", result1) << printInfo("Expected: ", expected1); + + m_pContext->runScript("Person.prototype.greet = personPrototype.greet;"); + std::vector result2 = obj->getPropertyNames(); + std::vector expected2 = {"name", "greet"}; + EXPECT_TRUE(compare(result2, expected2)) << printInfo("Actual: ", result2) << printInfo("Expected: ", expected2); +} diff --git a/DesktopEditor/doctrenderer/test/js_internal/test.pro b/DesktopEditor/doctrenderer/test/js_internal/test.pro new file mode 100644 index 0000000000..e8554bc81f --- /dev/null +++ b/DesktopEditor/doctrenderer/test/js_internal/test.pro @@ -0,0 +1,32 @@ +QT -= core +QT -= gui + +TARGET = test +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +CONFIG += core_static_link_libstd + +CORE_ROOT_DIR = $$PWD/../../../../../core +CORE_3DPARTY_DIR = $$CORE_ROOT_DIR/Common/3dParty +PWD_ROOT_DIR = $$PWD + +include($$CORE_ROOT_DIR/Common/base.pri) +include($$CORE_3DPARTY_DIR/googletest/googletest.pri) + +DESTDIR = $$PWD/build + +INCLUDEPATH += $$CORE_ROOT_DIR/DesktopEditor/doctrenderer + +ADD_DEPENDENCY(doctrenderer) + +core_linux { + LIBS += -Wl,-unresolved-symbols=ignore-in-shared-libs + LIBS += -ldl +} + +SOURCES += \ + main.cpp + From c23eece6ae966b363302ebc51096caf6f2de32ff Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 16 Nov 2023 18:07:59 +0400 Subject: [PATCH 13/54] JSC: Implemented CJSObject::getPropertyNames() --- .../doctrenderer/js_internal/jsc/jsc_base.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h index 1a82a4e0b1..547dcb0f3b 100644 --- a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h +++ b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h @@ -133,6 +133,21 @@ namespace NSJSBase [value setValue:[JSValue valueWithDouble:_value inContext: getContext()] forProperty:[[NSString alloc] initWithUTF8String:name]]; } + virtual std::vector getPropertyNames() + { + NSArray* names = [[value toObject] allKeys]; + uint32_t len = [names count]; + + std::vector ret(len); + for (uint32_t i = 0; i < len; i++) + { + NSString* name = [names objectAtIndex:i]; + ret[i] = [name stdstring]; + } + + return ret; + } + virtual CJSEmbedObject* getNative() { id _wrapper = [value toObject]; From 84c34eed65d9a9523e4a27cc4e6855fd2acea0d1 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 16 Nov 2023 18:19:43 +0400 Subject: [PATCH 14/54] Fixes + Fixed build for mac + Removed undefined properties from tests --- DesktopEditor/doctrenderer/json/json.h | 4 ++-- DesktopEditor/doctrenderer/test/js_internal/main.cpp | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 57ec4c3990..61bb287be3 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -14,9 +14,9 @@ namespace NSJSON { class IBaseValue; // Transform C++ value to JS value - JSSmart toJS(const IBaseValue* pValue); + static JSSmart toJS(const IBaseValue* pValue); // Transform JS value to C++ value - IBaseValue* fromJS(JSSmart jsValue); + static IBaseValue* fromJS(JSSmart jsValue); class JS_DECL IBaseValue { diff --git a/DesktopEditor/doctrenderer/test/js_internal/main.cpp b/DesktopEditor/doctrenderer/test/js_internal/main.cpp index cb496c62d9..5ebc571c58 100644 --- a/DesktopEditor/doctrenderer/test/js_internal/main.cpp +++ b/DesktopEditor/doctrenderer/test/js_internal/main.cpp @@ -87,14 +87,21 @@ TEST_F(CGetPropertyNamesTest, inner_object) TEST_F(CGetPropertyNamesTest, object_with_null_and_undefined_properties) { std::vector result = getObjectProperties("{number: null, name: undefined, func() { return 'bar'; }}"); - std::vector expected = {"number", "name", "func"}; + std::vector expected = {"number", "func"}; + EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); +} + +TEST_F(CGetPropertyNamesTest, object_with_only_undefined_properties) +{ + std::vector result = getObjectProperties("{foo: undefined, bar: undefined}"); + std::vector expected = {}; EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); } TEST_F(CGetPropertyNamesTest, array_as_object) { std::vector result = getObjectProperties("{0: 4, 1: 2, 2: undefined, 3: 'foo', 42: 'bar'}"); - std::vector expected = {"0", "1", "2", "3", "42"}; + std::vector expected = {"0", "1", "3", "42"}; EXPECT_TRUE(compare(result, expected)) << printInfo("Actual: ", result) << printInfo("Expected: ", expected); } From d64687634744032a2751fa5213250cf7d8ed24ee Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 16 Nov 2023 19:28:46 +0400 Subject: [PATCH 15/54] V8: Exclude undefined properties from result --- DesktopEditor/doctrenderer/js_internal/v8/v8_base.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h index 35d072b21a..8e0456e36e 100644 --- a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h +++ b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h @@ -452,12 +452,17 @@ namespace NSJSBase v8::Local names = value->GetPropertyNames(context).ToLocalChecked(); uint32_t len = names->Length(); - std::vector ret(len); + std::vector ret; for (uint32_t i = 0; i < len; i++) { + v8::Local propertyName = names->Get(context, i).ToLocalChecked(); + v8::Local propertyValue = value->Get(context, propertyName).ToLocalChecked(); + // skip undefined properties + if (propertyValue->IsUndefined()) + continue; CJSValueV8 _value; - _value.value = names->Get(context, i).ToLocalChecked(); - ret[i] = _value.toStringA(); + _value.value = propertyName; + ret.push_back(_value.toStringA()); } return ret; From f6c0ffc64400c0d33c180ff9cff920ce2e338bec Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Sat, 18 Nov 2023 00:56:32 +0400 Subject: [PATCH 16/54] CValue major rework --- DesktopEditor/doctrenderer/doctrenderer.pro | 6 +- DesktopEditor/doctrenderer/json/json.cpp | 429 ++++++++++-------- DesktopEditor/doctrenderer/json/json.h | 393 +++++++++------- DesktopEditor/doctrenderer/json/json_p.h | 34 ++ .../doctrenderer/json/json_values.cpp | 258 +++++++++++ DesktopEditor/doctrenderer/json/json_values.h | 128 ++++++ .../doctrenderer/json/serialization.h | 18 +- DesktopEditor/doctrenderer/test/json/main.cpp | 69 ++- 8 files changed, 920 insertions(+), 415 deletions(-) create mode 100644 DesktopEditor/doctrenderer/json/json_p.h create mode 100644 DesktopEditor/doctrenderer/json/json_values.cpp create mode 100644 DesktopEditor/doctrenderer/json/json_values.h diff --git a/DesktopEditor/doctrenderer/doctrenderer.pro b/DesktopEditor/doctrenderer/doctrenderer.pro index 78a31255a5..5404f5c1a0 100644 --- a/DesktopEditor/doctrenderer/doctrenderer.pro +++ b/DesktopEditor/doctrenderer/doctrenderer.pro @@ -72,9 +72,13 @@ SOURCES += \ # Serialize objects to JS HEADERS += \ json/json.h \ + json/json_p.h \ + json/json_values.h \ json/serialization.h -SOURCES += json/json.cpp +SOURCES += \ + json/json.cpp \ + json/json_values.cpp include($$PWD/js_internal/js_base.pri) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 0681ff15b8..82e03cd9db 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -1,303 +1,344 @@ #include "json.h" +#include "json_p.h" +#include "json_values.h" namespace NSJSON { - IBaseValue::IBaseValue() : m_type(vtUndefined) + CValueContainer::CValueContainer() : m_type(vtUndefined) { } - IBaseValue::IBaseValue(ValueType type) : m_type(type) + CValueContainer::CValueContainer(ValueType type, IBaseValue* pValue) : m_value(pValue), m_type(type) { } - IBaseValue::~IBaseValue() + CValueContainer CValueContainer::DeepCopy(const CValueContainer& other) { - } - - void IBaseValue::setNull() - { - m_type = vtNull; - } - - bool IBaseValue::isUndefined() const - { - return m_type == vtUndefined; - } - - bool IBaseValue::isNull() const - { - return m_type == vtNull; - } - - CValue::CValue() - { - } - - CValue::CValue(const bool& value) : IBaseValue(vtBoolean) - { - m_bool = value; - } - - CValue::CValue(const int& value) : IBaseValue(vtInteger) - { - m_int = value; - } - - CValue::CValue(const double& value) : IBaseValue(vtDouble) - { - m_double = value; - } - - CValue::CValue(const std::string& str) : IBaseValue(vtStringA) - { - new (&m_string) std::string(str); - } - - CValue::CValue(const std::wstring& wstr) : IBaseValue(vtStringW) - { - new (&m_wstring) std::wstring(wstr); - } - - CValue::CValue(const CValue& other) - { - *this = other; - } - - CValue::~CValue() - { - clear(); - } - - CValue& CValue::operator=(const CValue& other) - { - clear(); - m_type = other.m_type; - switch (m_type) + CValueContainer ret; + ValueType type = other.m_type; + ret.m_type = type; + switch (type) { - case vtBoolean: - m_bool = other.m_bool; + case vtPrimitive: + ret.m_value = std::make_shared(*static_cast(other.m_value.get())); break; - case vtInteger: - m_int = other.m_int; + case vtArray: + ret.m_value = std::make_shared(*static_cast(other.m_value.get())); break; - case vtDouble: - m_double = other.m_double; + case vtTypedArray: + ret.m_value = std::make_shared(*static_cast(other.m_value.get())); break; - case vtStringA: - new (&m_string) std::string(other.m_string); - break; - case vtStringW: - new (&m_wstring) std::wstring(other.m_wstring); + case vtObject: + ret.m_value = std::make_shared(*static_cast(other.m_value.get())); break; default: + // vtUndefined of vtNull break; } - return *this; + return ret; } - CValue& CValue::operator=(const bool& value) + CValue::CValue() : m_internal(new CValueContainer()) { - clear(); - m_type = vtBoolean; - m_bool = value; - return *this; } - CValue& CValue::operator=(const int& value) + bool CValue::IsUndefined() const { - clear(); - m_type = vtInteger; - m_int = value; - return *this; + return m_internal->m_type == CValueContainer::vtUndefined; } - CValue& CValue::operator=(const double& value) + bool CValue::IsNull() const { - clear(); - m_type = vtDouble; - m_double = value; - return *this; + return m_internal->m_type == CValueContainer::vtNull; } - CValue& CValue::operator=(const std::string& str) + bool CValue::IsBool() const { - clear(); - m_type = vtStringA; - new (&m_string) std::string(str); - return *this; + return (m_internal->m_type == CValueContainer::vtPrimitive && + static_cast(m_internal->m_value.get())->isBool()); } - CValue& CValue::operator=(const std::wstring& wstr) + bool CValue::IsInt() const { - clear(); - m_type = vtStringW; - new (&m_wstring) std::wstring(wstr); - return *this; + return (m_internal->m_type == CValueContainer::vtPrimitive && + static_cast(m_internal->m_value.get())->isInt()); } - bool CValue::toBool() const + bool CValue::IsDouble() const { - if (m_type == vtBoolean) - return m_bool; -#ifdef JSON_DEBUG - throw std::bad_cast(); -#endif - return false; + return (m_internal->m_type == CValueContainer::vtPrimitive && + static_cast(m_internal->m_value.get())->isDouble()); } - int CValue::toInt() const + bool CValue::IsStringA() const { - if (m_type == vtInteger) - return m_int; -#ifdef JSON_DEBUG - throw std::bad_cast(); -#endif - return 0; + return (m_internal->m_type == CValueContainer::vtPrimitive && + static_cast(m_internal->m_value.get())->isStringA()); } - double CValue::toDouble() const + bool CValue::IsStringW() const { - if (m_type == vtDouble) - return m_double; -#ifdef JSON_DEBUG - throw std::bad_cast(); -#endif - return 0.0; + return (m_internal->m_type == CValueContainer::vtPrimitive && + static_cast(m_internal->m_value.get())->isStringW()); } - std::string CValue::toStringA() const + bool CValue::IsArray() const { - if (m_type == vtStringA) - return m_string; -#ifdef JSON_DEBUG - throw std::bad_cast(); -#endif - return std::string(); + return m_internal->m_type == CValueContainer::vtArray; } - std::wstring CValue::toStringW () const + bool CValue::IsTypedArray() const { - if (m_type == vtStringW) - return m_wstring; -#ifdef JSON_DEBUG - throw std::bad_cast(); -#endif - return std::wstring(); + return m_internal->m_type == CValueContainer::vtTypedArray; } - void CValue::setNull() + bool CValue::IsObject() const { - clear(); - m_type = vtNull; + return m_internal->m_type == CValueContainer::vtObject; } - void CValue::clear() + bool CValue::ToBool() const { - switch (m_type) + return static_cast(m_internal->m_value.get())->toBool(); + } + + int CValue::ToInt() const + { + return static_cast(m_internal->m_value.get())->toInt(); + } + + double CValue::ToDouble() const + { + return static_cast(m_internal->m_value.get())->toDouble(); + } + + std::string CValue::ToStringA() const + { + return static_cast(m_internal->m_value.get())->toStringA(); + } + + std::wstring CValue::ToStringW() const + { + return static_cast(m_internal->m_value.get())->toStringW(); + } + + CValue::operator bool() const + { + return ToBool(); + } + + CValue::operator int() const + { + return ToInt(); + } + + CValue::operator double() const + { + return ToDouble(); + } + + CValue::operator std::string() const + { + return ToStringA(); + } + + CValue::operator std::wstring() const + { + return ToStringW(); + } + + CValue::CValue(bool value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + { + } + + CValue::CValue(int value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + { + } + + CValue::CValue(double value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + { + } + + CValue::CValue(const char* value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(std::string(value)))) + { + } + + CValue::CValue(const std::string& value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + { + } + + CValue::CValue(const wchar_t* value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(std::wstring(value)))) + { + } + + CValue::CValue(const std::wstring& value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + { + } + + // Helper function to reduce code duplication for further assignment operators + template + static inline void setPrimitive(const std::shared_ptr& value, T primitive) + { + if (value->m_type != CValueContainer::vtPrimitive) { - case vtStringA: - m_string.~basic_string(); - break; - case vtStringW: - m_wstring.~basic_string(); - break; - default: - break; + value->m_type = CValueContainer::vtPrimitive; + value->m_value = std::make_shared(primitive); } - } - - CArray::CArray() : IBaseValue(vtArray) - { - } - - CArray::~CArray() - { - for (IBaseValue* pValue : m_values) + else { - delete pValue; + static_cast(value->m_value.get())->set(primitive); } } - void CArray::add(IBaseValue* value) + CValue& CValue::operator=(bool value) { - m_values.push_back(value); + setPrimitive(m_internal, value); + return *this; } - void CArray::addNull() + CValue& CValue::operator=(int value) { - CValue* pValue = new CValue(); - pValue->setNull(); - m_values.push_back(pValue); + setPrimitive(m_internal, value); + return *this; } - void CArray::addUndefined() + CValue& CValue::operator=(double value) { - CValue* pValue = new CValue(); - m_values.push_back(pValue); + setPrimitive(m_internal, value); + return *this; } - int CArray::getCount() const + CValue& CValue::operator=(const char* value) { - return static_cast(m_values.size()); + setPrimitive(m_internal, value); + return *this; } - IBaseValue* CArray::operator[](int index) + CValue& CValue::operator=(const std::string& value) { - return m_values[index]; + setPrimitive(m_internal, value); + return *this; } - const IBaseValue* CArray::operator[](int index) const + CValue& CValue::operator=(const wchar_t* value) { - return m_values[index]; + setPrimitive(m_internal, value); + return *this; } - CTypedArray::CTypedArray(BYTE* data, int len) : IBaseValue(vtTypedArray), m_data(data), m_len(len) + CValue& CValue::operator=(const std::wstring& value) + { + setPrimitive(m_internal, value); + return *this; + } + + int CValue::GetCount() const + { + if (m_internal->m_type != CValueContainer::vtArray) + return 0; + return static_cast(m_internal->m_value.get())->getCount(); + } + + const CValue CValue::Get(int index) const + { + if (m_internal->m_type != CValueContainer::vtArray) + return CValue(); + return static_cast(m_internal->m_value.get())->get(index); + } + + CValue CValue::Get(int index) + { + return static_cast(*this).Get(index); + } + + const CValue CValue::operator[](int index) const + { + return Get(index); + } + + CValue CValue::operator[](int index) + { + return Get(index); + } + + CValue::CValue(std::initializer_list elements) : m_internal(new CValueContainer(CValueContainer::vtArray, new CArray(elements))) { } - CTypedArray::~CTypedArray() + CValue CValue::CreateArray(int count) { - delete[] m_data; + CValue ret; + ret.m_internal = std::make_shared(CValueContainer::vtArray, new CArray(count)); + return ret; } - BYTE* CTypedArray::getData() + const BYTE* CValue::GetData() const { - return m_data; + if (m_internal->m_type != CValueContainer::vtTypedArray) + return nullptr; + return static_cast(m_internal->m_value.get())->getData(); } - const BYTE* CTypedArray::getData() const + BYTE* CValue::GetData() { - return m_data; + return const_cast(static_cast(*this).GetData()); } - int CTypedArray::getCount() const + CValue CValue::CreateTypedArray(BYTE* data, int count, bool isExternalize) { - return m_len; + // TODO: + return CValue(); } - CObject::CObject() : IBaseValue(vtObject) + BYTE* CValue::AllocTypedArray(size_t size) { + // TODO: + return nullptr; } - CObject::~CObject() + void CValue::FreeTypedArray(BYTE* data, size_t size) { + // TODO: } - void CObject::set(const std::string& name, IBaseValue* pValue) + const CValue CValue::Get(const char* name) const { - IBaseValue*& pMapValue = m_values[name]; - if (pMapValue) - delete pMapValue; - pMapValue = pValue; + if (m_internal->m_type != CValueContainer::vtObject) + return CValue(); + return static_cast(m_internal->m_value.get())->get(name); } - IBaseValue* CObject::get(const std::string& name) + CValue CValue::Get(const char* name) { - return m_values[name]; + return static_cast(*this).Get(name); } - IBaseValue* CObject::operator[](const std::string& name) + CValue CValue::operator[](const char* name) { - return m_values[name]; + return Get(name); + } + + const CValue CValue::operator[](const char* name) const + { + return Get(name); + } + + CValue CValue::CreateObject() + { + CValue ret; + ret.m_internal = std::make_shared(CValueContainer::vtObject, new CObject()); + return ret; + } + + CValue CValue::CreateUndefined() + { + return CValue(); + } + + CValue CValue::CreateNull() + { + CValue ret; + ret.m_internal->m_type = CValueContainer::vtNull; + return ret; } } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 61bb287be3..f4793fbee6 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -1,176 +1,217 @@ -#ifndef JSON_H_ -#define JSON_H_ - -#include "../js_internal/js_base.h" - -#include -#include -#include - -// enable to see debug output and exceptions -//#define JSON_DEBUG - -namespace NSJSON -{ - class IBaseValue; - // Transform C++ value to JS value - static JSSmart toJS(const IBaseValue* pValue); - // Transform JS value to C++ value - static IBaseValue* fromJS(JSSmart jsValue); - - class JS_DECL IBaseValue - { - protected: - enum ValueType - { - vtUndefined, - vtNull, - vtBoolean, - vtInteger, - vtDouble, - vtStringA, - vtStringW, - vtArray, - vtTypedArray, - vtObject - }; - - public: - IBaseValue(); - IBaseValue(ValueType type); - virtual ~IBaseValue(); - - public: - virtual void setNull(); - virtual bool isUndefined() const; - virtual bool isNull() const; - - friend JSSmart toJS(const IBaseValue* pValue); - friend IBaseValue* fromJS(JSSmart jsValue); - - protected: - ValueType m_type; - }; - - // for primitive values - class JS_DECL CValue : public IBaseValue - { - public: - CValue(); - CValue(const CValue& other); - CValue(CValue&& other) = delete; - // TODO: move constructor and assignment operator ??? - CValue(const bool& value); - CValue(const int& value); - CValue(const double& value); - // TODO: constructor and assignment operator from (const char*/wchar_t*) - CValue(const std::string& str); - CValue(const std::wstring& wstr); - virtual ~CValue(); - - // getters - bool toBool() const; - // TODO: should cast to int handle the case when current value is double and vise-versa ? - // If so, then cast to bool can handle other values too ? - int toInt() const; - double toDouble() const; - std::string toStringA() const; - std::wstring toStringW() const; - - // TODO: setters - CValue& operator=(const CValue& other); - CValue& operator=(CValue&& other) = delete; - CValue& operator=(const bool& value); - CValue& operator=(const int& value); - CValue& operator=(const double& value); - CValue& operator=(const std::string& str); - CValue& operator=(const std::wstring& wstr); - - public: - virtual void setNull() override; - - private: - void clear(); - - friend JSSmart toJS(const IBaseValue* pValue); - friend IBaseValue* fromJS(JSSmart jsValue); - - private: - union - { - bool m_bool; - int m_int; - double m_double; - std::string m_string; - std::wstring m_wstring; - }; - }; - - class JS_DECL CArray : public IBaseValue - { - public: - CArray(); - // elements get deleted on array destruction - virtual ~CArray(); - - public: - void add(IBaseValue* value); - void addNull(); - void addUndefined(); - int getCount() const; - - IBaseValue* operator[](int index); - const IBaseValue* operator[](int index) const; - - friend JSSmart toJS(const IBaseValue* pValue); - friend IBaseValue* fromJS(JSSmart jsValue); - - private: - std::vector m_values; - }; - - class JS_DECL CTypedArray : public IBaseValue - { - public: - CTypedArray(BYTE* data = nullptr, int len = 0); - // elements get deleted on typed array destruction - virtual ~CTypedArray(); - - public: - BYTE* getData(); - const BYTE* getData() const; - int getCount() const; - - friend JSSmart toJS(const IBaseValue* pValue); - friend IBaseValue* fromJS(JSSmart jsValue); - - private: - BYTE* m_data; - int m_len; - }; - - class JS_DECL CObject : public IBaseValue - { - private: - // Need to store smart pointers to IBaseValue instead of raw pointers, because user can reset members with new values - using storage_t = std::unordered_map; - - public: - CObject(); - virtual ~CObject(); - - public: - void set(const std::string& name, IBaseValue* pValue); - // TODO: implement getValue, getObject, getArray, getTypedArray so there is no need to cast to needed type explicitly - IBaseValue* get(const std::string& name); - IBaseValue* operator[](const std::string& name); - - friend JSSmart toJS(const IBaseValue* pValue); - friend IBaseValue* fromJS(JSSmart jsValue); - - private: - storage_t m_values; - }; -} - -#endif // JSON_H_ +#ifndef JSON_H_ +#define JSON_H_ + +#include +#include +#include + +#ifdef JSBASE_NO_USE_DYNAMIC_LIBRARY +#define JSON_DECL +#else +#include "../../common/base_export.h" +#ifdef JSBASE_USE_DYNAMIC_LIBRARY_BUILDING +#define JSON_DECL Q_DECL_EXPORT +#else +#define JSON_DECL Q_DECL_IMPORT +#endif +#endif + +namespace NSJSON +{ + typedef unsigned char BYTE; + + class CValueContainer; + // Main class for storing values. + // This class provide interface to work with each type of values. + class JSON_DECL CValue + { + public: + CValue(); + + public: + // TYPE CHECKS + /** + * Returns true if the value is undefined. + */ + bool IsUndefined() const; + /** + * Returns true if the value is null. + */ + bool IsNull() const; + /** + * Returns true if the value is a boolean value. + */ + bool IsBool() const; + /** + * Returns true if the value is an integer. + */ + bool IsInt() const; + /** + * Returns true if the value is a double value. + */ + bool IsDouble() const; + /** + * Returns true if the value is a string. + */ + bool IsStringA() const; + /** + * Returns true if the value is a wstring. + */ + bool IsStringW() const; + /** + * Returns true if the value is an array. + */ + bool IsArray() const; + /** + * Returns true if the value is a typed array. + */ + bool IsTypedArray() const; + /** + * Returns true if the value is an object. + */ + bool IsObject() const; + + // FUNCTIONS FOR WORKING WITH PRIMITIVE VALUES + /** + * Converts this value to a boolean value. + * @returns Corresponding boolean value. If the value is not a boolean, returns false instead. + */ + bool ToBool() const; + /** + * Converts this value to an integer. + * @returns Corresponding integer value. If the value is not a number, returns 0 instead. + */ + int ToInt() const; + /** + * Converts this value to a double value. + * @returns Corresponding double value. If the value is not a number, returns 0.0 instead. + */ + double ToDouble() const; + /** + * Converts this value to a std::string. + * @returns Corresponding std::string. If the value is not a string, returns empty string instead. + */ + std::string ToStringA() const; + /** + * Converts this value to a wstring. + * @returns Corresponding std::wstring. If the value is not a string, returns empty string instead. + */ + std::wstring ToStringW() const; + + // Type cast operators work the same way as conversion functions + operator bool() const; + operator int() const; + operator double() const; + operator std::string() const; + operator std::wstring() const; + + // Creates a value from primitive types + CValue(bool value); + CValue(int value); + CValue(double value); + CValue(const char* value); + CValue(const std::string& value); + CValue(const wchar_t* value); + CValue(const std::wstring& value); + + // Assigns primitive + CValue& operator=(bool value); + CValue& operator=(int value); + CValue& operator=(double value); + CValue& operator=(const char* value); + CValue& operator=(const std::string& value); + CValue& operator=(const wchar_t* value); + CValue& operator=(const std::wstring& value); + + // FUNCTIONS FOR WORKING WITH ARRAYS + /** + * Gets lengths of the array/typed array. + * @returns Returns the number of elements in the array or number of bytes in typed array. If current value is not an array/typed array, returns 0. + */ + int GetCount() const; + + /** + * Gets an array value by its index. + * @param index The index of the array value. + * @returns the value in the array. If current value is not an array, returns undefined value. + */ + const CValue Get(int index) const; + CValue Get(int index); + + // operators [] works the same way as Get(index) + const CValue operator[](int index) const; + CValue operator[](int index); + + /** + * Creates an array with initializer list syntax (CValue arr = {1, 2, 3}). + * @param elements The elements of an array as an std::initializer_list. + */ + CValue(std::initializer_list elements); + /** + * Creates and returns new array. + * @param count The number of elements reserved for the array. + */ + static CValue CreateArray(int count); + + // FUNCTIONS FOR WORKING WITH TYPED ARRAYS + /** + * Gets data of typed array. + * @return the pointer to memory, allocated for this typed array. If current value is not a typed array, returns nullptr. + */ + const BYTE* GetData() const; + BYTE* GetData(); + + /** + * Creates and returns new typed array. + * @param data The pointer to binary data. The pointer should be acquired with AllocTypedArray()! + * @param count The length of an array in bytes. + * @param isExternalize If true the memory block will not be reclaimed when the created typed array is destroyed. + * If this parameter is false then the memory block will be released using FreeTypedArray() during the typed array destruction. + */ + static CValue CreateTypedArray(BYTE* data, int count, bool isExternalize = true); + /** + * Allocates the memory for a typed array by creating a buffer array of the specified size. + * @param size The buffer array size. + */ + static BYTE* AllocTypedArray(size_t size); + /** + * Frees the memory for a typed array. + * @param data The allocated memory to be released. + * @param size The buffer array size. + */ + static void FreeTypedArray(BYTE* data, size_t size); + + // FUNCTIONS FOR WORKING WITH OBJECTS + /** + * Gets a property of this object. + * @param name The name of the property. + * @returns the value of the object's property. If current value is not an object returns undefined value. + */ + const CValue Get(const char* name) const; + CValue Get(const char* name); + + // operators [] works the same way as Get(name) + const CValue operator[](const char* name) const; + CValue operator[](const char* name); + + /** + * Creates and returns empty object. + */ + static CValue CreateObject(); + + // OTHER FUNCTIONS + /** + * Creates and returns undefined value (the same as CValue()). + */ + static CValue CreateUndefined(); + /** + * Creates and returns null value. + */ + static CValue CreateNull(); + + private: + std::shared_ptr m_internal; + }; +} + +#endif // JSON_H_ diff --git a/DesktopEditor/doctrenderer/json/json_p.h b/DesktopEditor/doctrenderer/json/json_p.h new file mode 100644 index 0000000000..9f3be1ac0e --- /dev/null +++ b/DesktopEditor/doctrenderer/json/json_p.h @@ -0,0 +1,34 @@ +#ifndef JSON_PRIVATE_H_ +#define JSON_PRIVATE_H_ + +#include + +namespace NSJSON +{ + class IBaseValue; + class CValueContainer + { + public: + enum ValueType + { + vtUndefined, + vtNull, + vtPrimitive, + vtArray, + vtTypedArray, + vtObject + }; + + public: + CValueContainer(); + CValueContainer(ValueType type, IBaseValue* pValue); + + static CValueContainer DeepCopy(const CValueContainer& other); + + public: + std::shared_ptr m_value; + ValueType m_type; + }; +} + +#endif // JSON_PRIVATE_H_ diff --git a/DesktopEditor/doctrenderer/json/json_values.cpp b/DesktopEditor/doctrenderer/json/json_values.cpp new file mode 100644 index 0000000000..70414e0444 --- /dev/null +++ b/DesktopEditor/doctrenderer/json/json_values.cpp @@ -0,0 +1,258 @@ +#include "json_values.h" + +namespace NSJSON +{ + IBaseValue::IBaseValue() + { + } + + IBaseValue::~IBaseValue() + { + } + + CPrimitive::CPrimitive() + { + } + + CPrimitive::CPrimitive(bool value) : m_type(ptBoolean) + { + m_bool = value; + } + + CPrimitive::CPrimitive(int value) : m_type(ptInteger) + { + m_int = value; + } + + CPrimitive::CPrimitive(double value) : m_type(ptDouble) + { + m_double = value; + } + + CPrimitive::CPrimitive(const std::string& str) : m_type(ptStringA) + { + new (&m_string) std::string(str); + } + + CPrimitive::CPrimitive(const std::wstring& wstr) : m_type(ptStringW) + { + new (&m_wstring) std::wstring(wstr); + } + + CPrimitive::CPrimitive(const CPrimitive& other) + { + this->set(other); + } + + CPrimitive::~CPrimitive() + { + clear(); + } + + void CPrimitive::set(const CPrimitive& other) + { + clear(); + m_type = other.m_type; + switch (m_type) + { + case ptBoolean: + m_bool = other.m_bool; + break; + case ptInteger: + m_int = other.m_int; + break; + case ptDouble: + m_double = other.m_double; + break; + case ptStringA: + new (&m_string) std::string(other.m_string); + break; + case ptStringW: + new (&m_wstring) std::wstring(other.m_wstring); + break; + } + } + + bool CPrimitive::isBool() const + { + return m_type == ptBoolean; + } + + bool CPrimitive::isInt() const + { + return m_type == ptInteger; + } + + bool CPrimitive::isDouble() const + { + return m_type == ptDouble; + } + + bool CPrimitive::isStringA() const + { + return m_type == ptStringA; + } + + bool CPrimitive::isStringW() const + { + return m_type == ptStringW; + } + + bool CPrimitive::toBool() const + { + if (m_type == ptBoolean) + return m_bool; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return false; + } + + int CPrimitive::toInt() const + { + if (m_type == ptInteger) + return m_int; + if (m_type == ptDouble) + return (int)m_double; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return 0; + } + + double CPrimitive::toDouble() const + { + if (m_type == ptDouble) + return m_double; + if (m_type == ptInteger) + return (double)m_double; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return 0.0; + } + + std::string CPrimitive::toStringA() const + { + if (m_type == ptStringA) + return m_string; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return ""; + } + + std::wstring CPrimitive::toStringW() const + { + if (m_type == ptStringW) + return m_wstring; +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif + return L""; + } + + void CPrimitive::set(bool value) + { + clear(); + m_type = ptBoolean; + m_bool = value; + } + + void CPrimitive::set(int value) + { + clear(); + m_type = ptInteger; + m_int = value; + } + + void CPrimitive::set(double value) + { + clear(); + m_type = ptDouble; + m_double = value; + } + + void CPrimitive::set(const std::string& str) + { + clear(); + m_type = ptStringA; + new (&m_string) std::string(str); + } + + void CPrimitive::set(const std::wstring& wstr) + { + clear(); + m_type = ptStringW; + new (&m_wstring) std::wstring(wstr); + } + + void CPrimitive::clear() + { + switch (m_type) + { + case ptStringA: + m_string.~basic_string(); + break; + case ptStringW: + m_wstring.~basic_string(); + break; + default: + break; + } + } + + CArray::CArray(int count) : m_values(count) + { + } + + CArray::CArray(std::initializer_list elements) : m_values(elements) + { + } + + CArray::~CArray() + { + } + + int CArray::getCount() const + { + return static_cast(m_values.size()); + } + + CValue CArray::get(int index) + { + return m_values[index]; + } + + CTypedArray::CTypedArray(BYTE* data, int len) : m_data(data), m_len(len) + { + } + + CTypedArray::~CTypedArray() + { + // TODO: + } + + BYTE* CTypedArray::getData() + { + return m_data; + } + + int CTypedArray::getCount() const + { + return m_len; + } + + CObject::CObject() + { + } + + CObject::~CObject() + { + } + + CValue CObject::get(const std::string& name) + { + return m_values[name]; + } +} diff --git a/DesktopEditor/doctrenderer/json/json_values.h b/DesktopEditor/doctrenderer/json/json_values.h new file mode 100644 index 0000000000..43c5ec7618 --- /dev/null +++ b/DesktopEditor/doctrenderer/json/json_values.h @@ -0,0 +1,128 @@ +#ifndef JSON_VALUES_H_ +#define JSON_VALUES_H_ + +#include +#include +#include + +#include "json.h" + +// uncomment to see debug output and exceptions +//#define JSON_DEBUG + +namespace NSJSON +{ + class IBaseValue + { + public: + IBaseValue(); + virtual ~IBaseValue(); + }; + + class CPrimitive : public IBaseValue + { + private: + enum PrimitiveType + { + ptBoolean, + ptInteger, + ptDouble, + ptStringA, + ptStringW + }; + + public: + CPrimitive(); + CPrimitive(const CPrimitive& other); + CPrimitive(bool value); + CPrimitive(int value); + CPrimitive(double value); + CPrimitive(const std::string& str); + CPrimitive(const std::wstring& wstr); + ~CPrimitive(); + + // type check + bool isBool() const; + bool isInt() const; + bool isDouble() const; + bool isStringA() const; + bool isStringW() const; + + // getters + bool toBool() const; + int toInt() const; + double toDouble() const; + std::string toStringA() const; + std::wstring toStringW() const; + + // setters + void set(const CPrimitive& other); + void set(bool value); + void set(int value); + void set(double value); + void set(const std::string& str); + void set(const std::wstring& wstr); + + private: + void clear(); + + private: + union + { + bool m_bool; + int m_int; + double m_double; + std::string m_string; + std::wstring m_wstring; + }; + PrimitiveType m_type; + }; + + class CArray : public IBaseValue + { + public: + CArray(int count); + CArray(std::initializer_list elements); + ~CArray(); + + public: + int getCount() const; + CValue get(int index); + + private: + std::vector m_values; + }; + + class CTypedArray : public IBaseValue + { + public: + CTypedArray(BYTE* data = nullptr, int len = 0); + ~CTypedArray(); + + public: + BYTE* getData(); + int getCount() const; + + private: + BYTE* m_data; + int m_len; + }; + + class CObject : public IBaseValue + { + private: + using storage_t = std::unordered_map; + + public: + CObject(); + ~CObject(); + + public: + CValue get(const std::string& name); + + private: + storage_t m_values; + }; +} + +#endif // JSON_VALUES_H_ diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index 1a122f7cdc..10c4c5f721 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -2,12 +2,14 @@ #define SERIALIZATION_H_ #include "json.h" +#include "json_values.h" +#include "../js_internal/js_base.h" #include namespace NSJSON { - static JSSmart toJS(const IBaseValue* pValue) + static JSSmart toJS(const CValue& pValue) { IBaseValue::ValueType type = pValue->m_type; if (type == IBaseValue::vtUndefined) @@ -46,7 +48,7 @@ namespace NSJSON else { // primitive type - const CValue* pPrimitiveValue = static_cast(pValue); + const CPrimitive* pPrimitiveValue = static_cast(pValue); switch (type) { case IBaseValue::vtBoolean: ret = NSJSBase::CJSContext::createBool(pPrimitiveValue->m_bool); @@ -71,14 +73,14 @@ namespace NSJSON return ret; } - static IBaseValue* fromJS(JSSmart jsValue) + static CValue fromJS(JSSmart jsValue) { if (jsValue->isUndefined()) - return new CValue(); + return new CPrimitive(); if (jsValue->isNull()) { - CValue* pValue = new CValue; + CPrimitive* pValue = new CPrimitive; pValue->setNull(); return pValue; } @@ -113,7 +115,7 @@ namespace NSJSON // primitives else if (jsValue->isBool()) { - ret = new CValue(jsValue->toBool()); + ret = new CPrimitive(jsValue->toBool()); } else if (jsValue->isNumber()) { @@ -124,11 +126,11 @@ namespace NSJSON double fractional = std::modf(number, &integral); // fractional part if (fractional == 0.0 && integral >= INT_MIN && integral <= INT_MAX) { - ret = new CValue(static_cast(integral)); + ret = new CPrimitive(static_cast(integral)); } else { - ret = new CValue(number); + ret = new CPrimitive(number); } } else if (jsValue->isString()) diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 9cd11af085..edda7aa998 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -1,6 +1,7 @@ //#include "gtest/gtest.h" #include "js_internal/js_base.h" -#include "json/serialization.h" +//#include "json/serialization.h" +#include "json/json.h" #include #include @@ -39,54 +40,49 @@ int main() JSSmart pContext = new CJSContext(); CJSContextScope scope(pContext); - // top object (declared - CObject oTextPr; + // top object with text parameters + CValue textPr = CValue::CreateObject(); - CObject* pColorRGB = new CObject; - pColorRGB->set("r", new CValue(12)); - pColorRGB->set("g", new CValue(34)); - pColorRGB->set("b", new CValue(56)); + CValue colorRGB = CValue::CreateObject(); + colorRGB["r"] = 12; + colorRGB["g"] = 34; + colorRGB["b"] = 56; - CObject* pColorRGBA = new CObject; - pColorRGBA->set("rgb", pColorRGB); - pColorRGBA->set("alpha", new CValue(80)); + CValue colorRGBA = CValue::CreateObject(); + colorRGBA["rgb"] = colorRGB; + colorRGBA["alpha"] = 80; - oTextPr.set("size", new CValue(4.2)); - oTextPr.set("color", pColorRGBA); - CObject* pFont = new CObject(); - oTextPr.set("font", pFont); - pFont->set("fontName", new CValue(std::wstring(L"Times New Roman"))); - pFont->set("bold", new CValue(true)); + textPr["size"] = 4.2; + textPr["color"] = colorRGBA; + textPr["font"] = CValue::CreateObject(); + textPr["font"]["fontName"] = L"Times New Roman"; + textPr["font"]["bold"] = true; // undefined member: - pFont->set("italic", new CValue()); + textPr["font"]["italic"] = CValue::CreateUndefined(); + // or just +// textPr["font"]["italic"]; // null member: - CObject* pExtras = new CObject(); - oTextPr.set("extras", pExtras); - pExtras->setNull(); + textPr["extras"] = CValue::CreateNull(); // array - CArray* pArrNumbers = new CArray(); - oTextPr.set("numbers", pArrNumbers); - pArrNumbers->add(new CValue(10000)); - // add new elements to array via object's get() - static_cast(oTextPr["numbers"])->addNull(); - static_cast(oTextPr["numbers"])->add(new CValue(42)); - static_cast(oTextPr["numbers"])->add(new CValue(0)); + CValue numbers = {10000, 12, 42, 0, 147}; // inner array - CArray* pArrInner = new CArray(); - pArrInner->add(new CValue(std::string("test!"))); - pArrInner->add(new CValue(3.14)); - pArrNumbers->add(pArrInner); - // typed array + CValue innerArray = {true, "abc", 3.1415926535, L"ABC", 4}; + numbers[3] = innerArray; + textPr["numbers"] = numbers; + // create typed array + /* BYTE* pData = new BYTE[4]; pData[0] = 11; pData[1] = 23; pData[2] = 58; pData[3] = 13; - // typed array - CTypedArray* pTypedArray = new CTypedArray(pData, 4); - pArrInner->add(pTypedArray); + // add typed array + ... + */ - JSSmart jsObj = toJS(&oTextPr)->toObject(); + // convert to JS + /* + JSSmart jsObj = toJS(textPr)->toObject(); JSSmart global = pContext->GetGlobal(); global->set("textPr", jsObj); JSSmart ret = pContext->runScript("(function () { return JSON.stringify(textPr, null, 4); })();"); @@ -94,6 +90,7 @@ int main() { std::cout << ret->toStringA() << std::endl; } + */ return 0; } From a8f9ff175ecf9583a056afd54ffab7df0cf6aa93 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Mon, 20 Nov 2023 17:56:17 +0300 Subject: [PATCH 17/54] Create StartAP, AddLineToAP, EndAP --- .../graphics/commands/AnnotField.cpp | 9 +- PdfFile/PdfWriter.cpp | 187 ++++++++++++++- PdfFile/SrcWriter/Annotation.cpp | 212 +++++++++--------- PdfFile/SrcWriter/Annotation.h | 95 ++------ PdfFile/SrcWriter/Field.cpp | 184 ++++++++++----- PdfFile/SrcWriter/Field.h | 67 +++++- 6 files changed, 509 insertions(+), 245 deletions(-) diff --git a/DesktopEditor/graphics/commands/AnnotField.cpp b/DesktopEditor/graphics/commands/AnnotField.cpp index 9c3f6782e4..6035767f1f 100644 --- a/DesktopEditor/graphics/commands/AnnotField.cpp +++ b/DesktopEditor/graphics/commands/AnnotField.cpp @@ -457,9 +457,12 @@ bool CAnnotFieldInfo::Read(NSOnlineOfficeBinToPdf::CBufferReader* pReader, IMeta { m_oBorder.nType = pReader->ReadByte(); m_oBorder.dWidth = pReader->ReadDouble(); - int n = pReader->ReadInt(); - for (int i = 0; i < n; ++i) - m_oBorder.arrDash.push_back(pReader->ReadDouble()); + if (m_oBorder.nType == 2) + { + int n = pReader->ReadInt(); + for (int i = 0; i < n; ++i) + m_oBorder.arrDash.push_back(pReader->ReadDouble()); + } } if (nFlags & (1 << 5)) m_wsLM = pReader->ReadString(); diff --git a/PdfFile/PdfWriter.cpp b/PdfFile/PdfWriter.cpp index 450118984d..97aa3f940a 100644 --- a/PdfFile/PdfWriter.cpp +++ b/PdfFile/PdfWriter.cpp @@ -2017,20 +2017,22 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF PdfWriter::CWidgetAnnotation* pWidgetAnnot = (PdfWriter::CWidgetAnnotation*)pAnnot; put_FontName(pPr->GetFontName()); - put_FontStyle(pPr->GetFontStyle()); + int nStyle = pPr->GetFontStyle(); + double dFontSize = pPr->GetFontSizeAP(); + put_FontStyle(nStyle); if (m_bNeedUpdateTextFont) UpdateFont(); - // TODO почему важно добавить CFontTrueType, а не CFontCidTrueType PdfWriter::CFontTrueType* pFontTT = NULL; if (m_pFont) pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pWidgetAnnot->SetDocument(m_pDocument); - pWidgetAnnot->SetDA(pFontTT, pPr->GetFontSize(), pPr->GetFontSizeAP(), pPr->GetTC()); + pWidgetAnnot->SetDA(pFontTT, pPr->GetFontSize(), dFontSize, pPr->GetTC()); - pWidgetAnnot->SetQ(pPr->GetQ()); + BYTE nAlign = pPr->GetQ(); + pWidgetAnnot->SetQ(nAlign); int nWidgetFlag = pPr->GetFlag(); pWidgetAnnot->SetFlag(nWidgetFlag); @@ -2144,6 +2146,9 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF pWidgetAnnot->AddAction(pA); } + bool isBold = (nStyle & 1 ? true : false); + bool isItalic = (nStyle & 2 ? true : false); + if (oInfo.IsButtonWidget()) { CAnnotFieldInfo::CWidgetAnnotPr::CButtonWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetButtonWidgetPr(); @@ -2187,14 +2192,182 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF CAnnotFieldInfo::CWidgetAnnotPr::CTextWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetTextWidgetPr(); PdfWriter::CTextWidget* pTextWidget = (PdfWriter::CTextWidget*)pAnnot; + std::wstring wsValue; if (nFlags & (1 << 9)) - pTextWidget->SetV(pPr->GetV()); + { + wsValue = pPr->GetV(); + pTextWidget->SetV(wsValue); + } + unsigned int unMaxLen = 0; if (nFlags & (1 << 10)) - pTextWidget->SetMaxLen(pPr->GetMaxLen()); + { + unMaxLen = pPr->GetMaxLen(); + pTextWidget->SetMaxLen(unMaxLen); + } if (nWidgetFlag & (1 << 25)) pTextWidget->SetRV(pPr->GetRV()); - pTextWidget->CreateAP(); + // Коды, шрифты, количество + unsigned int unLen; + unsigned int* pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsValue, unLen); + if (!pUnicodes) + return S_FALSE; + unsigned short* pCodes = new unsigned short[unLen]; + if (!pCodes) + { + RELEASEARRAYOBJECTS(pUnicodes); + return S_FALSE; + } + PdfWriter::CFontCidTrueType** ppFonts = new PdfWriter::CFontCidTrueType*[unLen]; + if (!ppFonts) + { + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + return S_FALSE; + } + + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + unsigned int unUnicode = pUnicodes[unIndex]; + + if (!m_pFont->HaveChar(unUnicode)) + { + std::wstring wsFontFamily = pAppFonts->GetFontBySymbol(unUnicode); + PdfWriter::CFontCidTrueType* pTempFont = GetFont(wsFontFamily, isBold, isItalic); + if (pTempFont) + { + pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode); + ppFonts[unIndex] = pTempFont; + continue; + } + } + + pCodes[unIndex] = m_pFont->EncodeUnicode(unUnicode); + ppFonts[unIndex] = m_pFont; + } + + double _dY = pPage->GetHeight() - dY1; + double _dB = pPage->GetHeight() - dY2; + double dMargin = 2; // Отступ используемый в Adobe + double dBaseLine = dY2 - dY1; // TODO -BaseLineOffset + double dShiftX = dMargin; + + bool isComb = pTextWidget->IsCombFlag(); + + // TODO PlaceHolder заполнитель без значения + + if (!isComb && pTextWidget->IsMultiLine()) + { + unsigned short* pCodes2 = new unsigned short[unLen]; + unsigned int* pWidths = new unsigned int[unLen]; + + unsigned short ushSpaceCode = 0xFFFF; + unsigned short ushNewLineCode = 0xFFFE; + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + unsigned short ushCode = 0; + if (0x0020 == pUnicodes[unIndex]) + ushCode = ushSpaceCode; + else if (0x000D == pUnicodes[unIndex] || 0x000A == pUnicodes[unIndex]) + ushCode = ushNewLineCode; + + pCodes2[unIndex] = ushCode; + pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]); + } + + m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, ushNewLineCode, pFontTT->GetLineHeight(), pFontTT->GetAscent()); + + // TODO Автоподбор размера шрифта dFontSize + if (!dFontSize) + dFontSize = m_oLinesManager.ProcessAutoFit(dX2 - dX1, (dY2 - dY1 - 3 * dMargin)); + + double dLineHeight = pFontTT->GetLineHeight() * dFontSize / 1000.0; + + m_oLinesManager.CalculateLines(dFontSize, dX2 - dX1); + + pTextWidget->StartAP(m_pFont, dFontSize, 1.0); + + unsigned int unLinesCount = m_oLinesManager.GetLinesCount(); + double dLineShiftY = dY2 - dY1 - pFontTT->GetLineHeight() * dFontSize / 1000.0 - dMargin; + for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex) + { + unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex); + double dLineShiftX = dShiftX; + double dLineWidth = m_oLinesManager.GetLineWidth(unIndex, dFontSize); + if (0 == nAlign) + dLineShiftX += (dX2 - dX1 - dLineWidth); + else if (2 == nAlign) + dLineShiftX += (dX2 - dX1 - dLineWidth) / 2; + + int nInLineCount = m_oLinesManager.GetLineEndPos(unIndex) - m_oLinesManager.GetLineStartPos(unIndex); + if (nInLineCount > 0) + pTextWidget->AddLineToAP(dLineShiftX, dLineShiftY, pCodes + unLineStart, nInLineCount, ppFonts + unLineStart, NULL); + + dLineShiftY -= dLineHeight; + } + + pTextWidget->EndAP(); + + m_oLinesManager.Clear(); + + RELEASEARRAYOBJECTS(pCodes2); + RELEASEARRAYOBJECTS(pWidths); + } + else + { + double* pShifts = NULL; + unsigned int unShiftsCount = 0; + + if (isComb) + { + // TODO для безопасности перевыставить в Ff DoNotScroll=true, DoNotSpellCheck=true, Multiline=false + + unShiftsCount = unLen; + pShifts = new double[unShiftsCount]; + if (pShifts && unShiftsCount) + { + // Сдвиг нулевой для comb форм и не забываем, что мы к ширине добавили 2 * dMargin + dShiftX = 0; + unsigned int unCellsCount = std::max(unShiftsCount, unMaxLen); + double dPrevW = 0; + double dCellW = (dX2 - dX1 + 2 * dMargin) / unCellsCount; + + if (0 == nAlign && unShiftsCount) + dPrevW = (unCellsCount - unShiftsCount) * dCellW; + + for (unsigned int unIndex = 0; unIndex < unShiftsCount; ++unIndex) + { + unsigned short ushCode = pCodes[unIndex]; + double dGlyphWidth = ppFonts[unIndex]->GetGlyphWidth(ushCode) / 1000.0 * dFontSize; + double dTempShift = (dCellW - dGlyphWidth) / 2; + pShifts[unIndex] = dPrevW + dTempShift; + dPrevW = dCellW - dTempShift; + } + } + } + else if (0 == nAlign || 2 == nAlign) + { + double dSumWidth = 0; + for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) + { + unsigned short ushCode = pCodes[unIndex]; + double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize; + dSumWidth += dLetterWidth; + } + + if (0 == nAlign && dX2 - dX1 - dSumWidth > 0) + dShiftX += dX2 - dX1 - dSumWidth; + else if (2 == nAlign && (dX2 - dX1 - dSumWidth) / 2 > 0) + dShiftX += (dX2 - dX1 - dSumWidth) / 2; + } + + pTextWidget->SetAP(wsValue, pCodes, unLen, m_pFont, {}, 1.0, m_oFont.GetSize(), dShiftX, dBaseLine, ppFonts, pShifts); + RELEASEARRAYOBJECTS(pShifts); + } + + RELEASEARRAYOBJECTS(pUnicodes); + RELEASEARRAYOBJECTS(pCodes); + RELEASEARRAYOBJECTS(ppFonts); } else if (oInfo.IsChoiceWidget()) { diff --git a/PdfFile/SrcWriter/Annotation.cpp b/PdfFile/SrcWriter/Annotation.cpp index b537203f3f..93cdb5b905 100644 --- a/PdfFile/SrcWriter/Annotation.cpp +++ b/PdfFile/SrcWriter/Annotation.cpp @@ -123,6 +123,24 @@ namespace PdfWriter pArray->Add(dRD3); pArray->Add(dRD4); } + std::string GetColor(const std::vector& arr, bool bCaps) + { + std::string sDA; + for (double dColoc : arr) + { + sDA.append(std::to_string(dColoc)); + sDA.append(" "); + } + if (arr.size() == 3) + sDA.append(bCaps ? "RG" : "rg"); + else if (arr.size() == 4) + sDA.append(bCaps ? "K" : "k"); + else if (arr.size() == 1) + sDA.append(bCaps ? "G" : "g"); + else + sDA.append(bCaps ? "SC" : "sc"); + return sDA; + } //---------------------------------------------------------------------------------------- // CAnnotation @@ -137,6 +155,8 @@ namespace PdfWriter // Для PDFA нужно, чтобы 0, 1, 4 биты были выключены, а второй включен Add("F", 4); + + bHaveBorder = false; } void CAnnotation::SetRect(const TRect& oRect) { @@ -179,7 +199,7 @@ namespace PdfWriter EBorderSubtype eSubtype = EBorderSubtype(nType); if (border_subtype_Dashed == eSubtype) - AddToVectorD(this, "D", arrDash); + AddToVectorD(pBorderStyleDict, "D", arrDash); switch (eSubtype) { @@ -189,6 +209,9 @@ namespace PdfWriter case border_subtype_Inset: pBorderStyleDict->Add("S", "I"); break; case border_subtype_Underlined: pBorderStyleDict->Add("S", "U"); break; } + + bHaveBorder = true; + dBorderWidth = dWidth; } void CAnnotation::SetAnnotFlag(const int& nAnnotFlag) { @@ -249,10 +272,6 @@ namespace PdfWriter CDocument* CAnnotation::GetDocument() { return m_pDocument; - } - void CAnnotation::CreateAP() - { - } //---------------------------------------------------------------------------------------- // CMarkupAnnotation @@ -309,10 +328,6 @@ namespace PdfWriter void CMarkupAnnotation::SetIRTID(CAnnotation* pAnnot) { Add("IRT", pAnnot); - } - void CMarkupAnnotation::CreateAP() - { - } //---------------------------------------------------------------------------------------- // CLinkAnnotation @@ -412,13 +427,13 @@ namespace PdfWriter Add("StateModel", new CStringObject(sValue.c_str())); } - void CTextAnnotation::CreateAP() + void CTextAnnotation::SetAP() { switch (m_nName) { case 3: { - CAnnotationAppearance* pAP = new CAnnotationAppearance(m_pXref, this); + CAnnotAppearanceObject* pAP = new CAnnotAppearanceObject(m_pXref, this); Add("AP", pAP); pAP->DrawTextComment(); @@ -779,21 +794,7 @@ namespace PdfWriter CResourcesDict* pFieldsResources = m_pDocument->GetFieldsResources(); const char* sFontName = pFieldsResources->GetFontName(pFont); - std::string sDA; - for (double dColoc : arrTC) - { - sDA.append(std::to_string(dColoc)); - sDA.append(" "); - } - if (arrTC.size() == 3) - sDA.append("rg"); - else if (arrTC.size() == 4) - sDA.append("k"); - else if (arrTC.size() == 1) - sDA.append("g"); - else - sDA.append("sc"); - + std::string sDA = GetColor(arrTC, false); if (sFontName) { sDA.append(" /"); @@ -894,11 +895,13 @@ namespace PdfWriter { CheckMK(); AddToVectorD(m_pMK, "BC", arrBC); + m_arrBC = arrBC; } void CWidgetAnnotation::SetBG(const std::vector& arrBG) { CheckMK(); AddToVectorD(m_pMK, "BG", arrBG); + m_arrBG = arrBG; } void CWidgetAnnotation::AddAction(CAction* pAction) { @@ -928,6 +931,14 @@ namespace PdfWriter m_pAA->Add(pAction->m_sType.c_str(), pAction); } + std::string CWidgetAnnotation::GetBGforAP() + { + return GetColor(m_arrBG, false); + } + std::string CWidgetAnnotation::GetBCforAP() + { + return GetColor(m_arrBC, true); + } //---------------------------------------------------------------------------------------- // CButtonWidget //---------------------------------------------------------------------------------------- @@ -1108,16 +1119,75 @@ namespace PdfWriter std::string sValue = U_TO_UTF8(wsRV); Add("RV", new CStringObject(sValue.c_str())); } - void CTextWidget::CreateAP() + void CTextWidget::SetAP(const std::wstring& wsValue, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, const TRgb& oColor, const double& dAlpha, double dFontSize, double dX, double dY, CFontCidTrueType** ppFonts, double* pShifts) { - CAnnotationAppearance* pAPN = new CAnnotationAppearance(m_pXref, this); + m_pAppearance = new CAnnotAppearance(m_pXref, this); + if (!m_pAppearance) + return; + Add("AP", m_pAppearance); - CDictObject* pAP = new CDictObject(); - pAP->Add("N", pAPN); + CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); + CResourcesDict* pFieldsResources = m_pDocument->GetFieldsResources(); - Add("AP", pAP); + const char* sExtGrStateName = NULL; + if (fabs(dAlpha - 1.0) > 0.001) + { + CExtGrState* pExtGrState = m_pDocument->GetFillAlpha(dAlpha); + sExtGrStateName = pFieldsResources->GetExtGrStateName(pExtGrState); + } - pAPN->DrawTextWidget(); + pNormal->DrawSimpleText(wsValue, pCodes, unCount, pFont, dFontSize, dX, dY, oColor.r, oColor.g, oColor.b, sExtGrStateName, fabs(m_oRect.fRight - m_oRect.fLeft), fabs(m_oRect.fBottom - m_oRect.fTop), ppFonts, pShifts); + } + void CTextWidget::StartAP(CFontDict* pFont, const double& dFontSize, const double& dAlpha) + { + m_pAppearance = new CAnnotAppearance(m_pXref, this); + if (!m_pAppearance) + return; + + Add("AP", m_pAppearance); + + CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); + CResourcesDict* pFieldsResources = m_pDocument->GetFieldsResources(); + + const char* sExtGrStateName = NULL; + if (fabs(dAlpha - 1.0) > 0.001) + { + CExtGrState* pExtGrState = m_pDocument->GetFillAlpha(dAlpha); + sExtGrStateName = pFieldsResources->GetExtGrStateName(pExtGrState); + } + + pNormal->StartDrawText(pFont, dFontSize, 0, 0, 0, sExtGrStateName, fabs(m_oRect.fRight - m_oRect.fLeft), fabs(m_oRect.fBottom - m_oRect.fTop)); + } + void CTextWidget::AddLineToAP(const double& dX, const double& dY, unsigned short* pCodes, const unsigned int& unCodesCount, CFontCidTrueType** ppFonts, const double* pShifts) + { + if (!m_pAppearance) + return; + + CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); + pNormal->DrawTextLine(dX, dY, pCodes, unCodesCount, ppFonts, pShifts); + } + void CTextWidget::EndAP() + { + if (!m_pAppearance) + return; + + CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); + pNormal->EndDrawText(); + } + bool CTextWidget::IsCombFlag() + { + int nFlags = ((CNumberObject*)Get("Ff"))->Get(); + return (nFlags & (1 << 24)); + } + bool CTextWidget::IsMultiLine() + { + int nFlags = ((CNumberObject*)Get("Ff"))->Get(); + return (nFlags & (1 << 12)); + } + int CTextWidget::GetMaxLen() + { + CNumberObject* oMaxLen = m_pParent ? (CNumberObject*)m_pParent->Get("MaxLen") : (CNumberObject*)Get("MaxLen"); + return oMaxLen ? oMaxLen->Get() : 0; } //---------------------------------------------------------------------------------------- // CChoiceWidget @@ -1174,87 +1244,21 @@ namespace PdfWriter CSignatureWidget::CSignatureWidget(CXref* pXref) : CWidgetAnnotation(pXref, AnnotWidget) { } - //---------------------------------------------------------------------------------------- - // CAnnotationAppearance - //---------------------------------------------------------------------------------------- - CAnnotationAppearance::CAnnotationAppearance(CXref* pXref, CAnnotation* pAnnot) - { - m_pXref = pXref; - m_pStream = new CMemoryStream(); - m_pAnnot = pAnnot; - - SetStream(m_pXref, m_pStream); - - Add("Type", "XObject"); - Add("Subtype", "Form"); - - Add("Resources", pAnnot->GetDocument()->GetFieldsResources()); - } - void CAnnotationAppearance::DrawTextComment() - { - CArrayObject* pArray = new CArrayObject(); - if (!pArray) - return; - - Add("BBox", pArray); - pArray->Add(0); - pArray->Add(0); - pArray->Add(20); - pArray->Add(20); - - m_pStream->WriteStr(""); - } + /* void CAnnotationAppearance::DrawTextWidget() { - CArrayObject* pArray = new CArrayObject(); - if (!pArray) - return; - - TRect oRect = m_pAnnot->GetRect(); - - Add("BBox", pArray); - pArray->Add(0); - pArray->Add(0); - pArray->Add(oRect.fRight - oRect.fLeft); - pArray->Add(oRect.fTop - oRect.fBottom); - CTextWidget* pAnnot = (CTextWidget*)m_pAnnot; - m_pStream->WriteStr("Tx BMC\012"); - // TODO если имеется фоновый цвет - double dBorderSize = 0; - double dBorderSize2 = 0; - // TODO если имеется граница - m_pStream->WriteStr("q\012"); - m_pStream->WriteReal(dBorderSize); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(dBorderSize); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(std::max(oRect.fRight - oRect.fLeft - dBorderSize2, 0.0)); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(std::max(oRect.fTop - oRect.fBottom - dBorderSize2, 0.0)); - m_pStream->WriteStr(" re\012W\012n\012BT\012"); - std::string sFontInfo = pAnnot->GetDAforAP(); - if (sFontInfo.empty()) - { - CDictObject* pOwner = pAnnot->GetObjOwnValue("DA"); - if (pOwner) - { - CStringObject* pDA = dynamic_cast(pOwner->Get("DA")); - if (pDA) - sFontInfo = std::string((const char*)pDA->GetString()); - } - } - if (!sFontInfo.empty()) - m_pStream->WriteStr(sFontInfo.c_str()); // TODO потребуется смещение Y-координаты в зависимости от размеров области и размеров шрифта // TODO требуется запись юникод значений, т.е необходимо писать по глифам - m_pStream->WriteStr(" 2 6.548 Td ("); - m_pStream->WriteStr(pAnnot->GetV().c_str()); - m_pStream->WriteStr(") Tj ET\012Q\012EMC\012"); + m_pStream->WriteStr(" 2 6.548 Td\012"); + std::string sV = pAnnot->GetV(); + m_pStream->WriteEscapeText((BYTE*)sV.c_str(), sV.length()); + m_pStream->WriteStr(" Tj\012ET\012Q\012EMC\012"); } + */ //---------------------------------------------------------------------------------------- // CAction //---------------------------------------------------------------------------------------- diff --git a/PdfFile/SrcWriter/Annotation.h b/PdfFile/SrcWriter/Annotation.h index 7785659654..73df7c3a51 100644 --- a/PdfFile/SrcWriter/Annotation.h +++ b/PdfFile/SrcWriter/Annotation.h @@ -36,64 +36,12 @@ #include "Types.h" #include "Pages.h" #include "Document.h" +#include "Field.h" namespace PdfWriter { class CDestination; - enum EBorderSubtype - { - border_subtype_Solid, - border_subtype_Beveled, - border_subtype_Dashed, - border_subtype_Inset, - border_subtype_Underlined - }; - enum EAnnotType - { - AnnotUnknown = -1, - AnnotText = 0, - AnnotLink = 1, - AnnotSound = 2, - AnnotFreeText = 3, - AnnotStamp = 4, - AnnotSquare = 5, - AnnotCircle = 6, - AnnotStrikeOut = 7, - AnnotHighLight = 8, - AnnotUnderline = 9, - AnnotInk = 10, - AnnotFileAttachment = 11, - AnnotPopup = 12, - AnnotLine = 13, - AnnotSquiggly = 14, - AnnotPolygon = 15, - AnnotPolyLine = 16, - AnnotCaret = 17, - AnnotWidget = 18 - }; - enum EAnnotHighlightMode - { - AnnotNoHighlight = 0, - AnnotInvertBox, - AnnotInvertBorder, - AnnotDownAppearance, - AnnotHighlightModeEOF - }; - enum EAnnotIcon - { - AnnotIconComment = 0, - AnnotIconKey = 1, - AnnotIconNote = 2, - AnnotIconHelp = 3, - AnnotIconNewParagraph = 4, - AnnotIconParagraph = 5, - AnnotIconInsert = 6, - - AnnotIconMin = 0, - AnnotIconMax = 6 - }; - class CAction : public CDictObject { public: @@ -159,6 +107,9 @@ namespace PdfWriter double m_dPageHeight = 0; CDocument* m_pDocument; + bool bHaveBorder; + double dBorderWidth; + public: EDictType GetDictType() const { @@ -183,12 +134,13 @@ namespace PdfWriter void SetNM(const std::wstring& wsNM); void SetLM(const std::wstring& wsLM); void SetC(const std::vector& arrC); - // TODO AP Необходимо генерировать внешний вид аннотации как у Widget - virtual void CreateAP(); - TRect GetRect() { return m_oRect; } + + TRect& GetRect() { return m_oRect; } void SetXref(CXref* pXref) { m_pXref = pXref; } void SetDocument(CDocument* pDocument); CDocument* GetDocument(); + bool HaveBorder() { return bHaveBorder; } + double GetBorderWidth() { return dBorderWidth; } }; class CPopupAnnotation : public CAnnotation { @@ -223,7 +175,6 @@ namespace PdfWriter void SetIRTID(CAnnotation* pAnnot); CPopupAnnotation* CreatePopup(); - virtual void CreateAP() override; }; class CLinkAnnotation : public CAnnotation { @@ -252,7 +203,7 @@ namespace PdfWriter void SetState(BYTE nState); void SetStateModel(BYTE nStateModel); - void CreateAP() override; + void SetAP(); }; class CUriLinkAnnotation : public CAnnotation { @@ -377,6 +328,9 @@ namespace PdfWriter CDictObject* m_pA; std::string m_sDAforAP; + std::vector m_arrBC; + std::vector m_arrBG; + void CheckMK(); public: @@ -399,6 +353,8 @@ namespace PdfWriter void AddAction(CAction* pAction); std::string GetDAforAP() { return m_sDAforAP; } + std::string GetBGforAP(); + std::string GetBCforAP(); }; class CButtonWidget : public CWidgetAnnotation { @@ -434,6 +390,7 @@ namespace PdfWriter private: EAnnotType m_nSubtype; std::string m_sV; + CAnnotAppearance* m_pAppearance; public: CTextWidget(CXref* pXref); @@ -446,8 +403,14 @@ namespace PdfWriter void SetV (const std::wstring& wsV); void SetRV(const std::wstring& wsRV); - void CreateAP() override; + void SetAP(const std::wstring& wsValue, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, const TRgb& oColor, const double& dAlpha, double dFontSize, double dX, double dY, CFontCidTrueType** ppFonts, double* pShifts); + void StartAP(CFontDict* pFont, const double& dFontSize, const double& dAlpha); + void AddLineToAP(const double& dX, const double& dY, unsigned short* pCodes, const unsigned int& unCodesCount, CFontCidTrueType** ppFonts = NULL, const double* pShifts = NULL); + void EndAP(); std::string GetV() { return m_sV; } + bool IsCombFlag(); + bool IsMultiLine(); + int GetMaxLen(); }; class CChoiceWidget : public CWidgetAnnotation { @@ -477,19 +440,5 @@ namespace PdfWriter return m_nSubtype; } }; - - class CAnnotationAppearance : public CDictObject - { - public: - CAnnotationAppearance(CXref* pXref, CAnnotation* pAnnot); - - void DrawTextComment(); - void DrawTextWidget(); - - private: - CXref* m_pXref; - CStream* m_pStream; - CAnnotation* m_pAnnot; - }; } #endif // _PDF_WRITER_SRC_ANNOTATION_H diff --git a/PdfFile/SrcWriter/Field.cpp b/PdfFile/SrcWriter/Field.cpp index fc92c70f86..3664f99e9e 100644 --- a/PdfFile/SrcWriter/Field.cpp +++ b/PdfFile/SrcWriter/Field.cpp @@ -39,6 +39,7 @@ #include "Font.h" #include "Info.h" #include "EncryptDictionary.h" +#include "Annotation.h" #include #include @@ -1518,6 +1519,7 @@ namespace PdfWriter { m_pXref = pXref; m_pField = pField; + m_pAnnot = NULL; m_pNormal = new CAnnotAppearanceObject(pXref, pField); m_pRollover = NULL; @@ -1525,6 +1527,18 @@ namespace PdfWriter Add("N", m_pNormal); } + CAnnotAppearance::CAnnotAppearance(CXref* pXref, CAnnotation* pAnnot) + { + m_pXref = pXref; + m_pAnnot = pAnnot; + m_pField = NULL; + + m_pNormal = new CAnnotAppearanceObject(pXref, pAnnot); + m_pRollover = NULL; + m_pDown = NULL; + + Add("N", m_pNormal); + } CAnnotAppearanceObject* CAnnotAppearance::GetNormal() { return m_pNormal; @@ -1533,7 +1547,10 @@ namespace PdfWriter { if (!m_pRollover) { - m_pRollover = new CAnnotAppearanceObject(m_pXref, m_pField); + if (m_pField) + m_pRollover = new CAnnotAppearanceObject(m_pXref, m_pField); + else if (m_pAnnot) + m_pRollover = new CAnnotAppearanceObject(m_pXref, m_pAnnot); Add("R", m_pRollover); } @@ -1543,7 +1560,10 @@ namespace PdfWriter { if (!m_pDown) { - m_pDown = new CAnnotAppearanceObject(m_pXref, m_pField); + if (m_pField) + m_pDown = new CAnnotAppearanceObject(m_pXref, m_pField); + else if (m_pAnnot) + m_pDown = new CAnnotAppearanceObject(m_pXref, m_pAnnot); Add("D", m_pDown); } @@ -1591,11 +1611,10 @@ namespace PdfWriter //---------------------------------------------------------------------------------------- // CAnnotAppearanceObject //---------------------------------------------------------------------------------------- - CAnnotAppearanceObject::CAnnotAppearanceObject(CXref* pXref, CFieldBase* pField) + void CAnnotAppearanceObject::Init(CXref* pXref, CResourcesDict* pResources, TRect* pRect) { m_pXref = pXref; m_pStream = new CMemoryStream(); - m_pField = pField; m_pFont = NULL; m_dFontSize = 10.0; @@ -1603,8 +1622,7 @@ namespace PdfWriter Add("Type", "XObject"); Add("Subtype", "Form"); - - TRect oRect = pField->GetRect(); + Add("Resources", pResources); CArrayObject* pArray = new CArrayObject(); if (!pArray) @@ -1613,14 +1631,20 @@ namespace PdfWriter Add("BBox", pArray); pArray->Add(0); pArray->Add(0); - pArray->Add(oRect.fRight - oRect.fLeft); - pArray->Add(oRect.fBottom - oRect.fTop); - - Add("Resources", pField->GetResourcesDict()); - -#ifndef FILTER_FLATE_DECODE_DISABLED - //SetFilter(STREAM_FILTER_FLATE_DECODE); -#endif + pArray->Add(pRect->fRight - pRect->fLeft); + pArray->Add(pRect->fBottom - pRect->fTop); + } + CAnnotAppearanceObject::CAnnotAppearanceObject(CXref* pXref, CFieldBase* pField) + { + Init(pXref, pField->GetResourcesDict(), &pField->GetRect()); + m_pField = pField; + m_pAnnot = NULL; + } + CAnnotAppearanceObject::CAnnotAppearanceObject(CXref* pXRef, CAnnotation* pAnnot) + { + Init(pXRef, pAnnot->GetDocument()->GetFieldsResources(), &pAnnot->GetRect()); + m_pAnnot = pAnnot; + m_pField = NULL; } void CAnnotAppearanceObject::DrawSimpleText(const std::wstring& wsText, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, double dFontSize, double dX, double dY, double dR, double dG, double dB, const char* sExtGStateName, double dWidth, double dHeight, CFontCidTrueType** ppFonts, double* pShifts) { @@ -1746,23 +1770,31 @@ namespace PdfWriter } void CAnnotAppearanceObject::StartDrawText(CFontDict* pFont, const double& dFontSize, const double& dR, const double& dG, const double& dB, const char* sExtGStateName, const double& dWidth, const double& dHeight) { - CResourcesDict* pResources = m_pField->GetResourcesDict(); + CResourcesDict* pResources = dynamic_cast(Get("Resources")); if (!m_pStream || !pFont || !pResources) return; m_pStream->WriteEscapeName("Tx"); m_pStream->WriteStr(" BMC\012"); - if (m_pField->HaveShd()) + if ((m_pField && m_pField->HaveShd()) || (m_pAnnot && m_pAnnot->Get("BG"))) { m_pStream->WriteStr("q\012"); - TRgb oColor = m_pField->GetShdColor(); - m_pStream->WriteReal(oColor.r); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.g); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.b); - m_pStream->WriteStr(" rg\012"); + if (m_pField) + { + TRgb oColor = m_pField->GetShdColor(); + m_pStream->WriteReal(oColor.r); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.g); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.b); + m_pStream->WriteStr(" rg\012"); + } + else + { + CWidgetAnnotation* pAnnot = (CWidgetAnnotation*)m_pAnnot; + m_pStream->WriteStr(pAnnot->GetBGforAP().c_str()); + } m_pStream->WriteStr("1 0 0 1 0 0 cm\012"); m_pStream->WriteStr("0 0 "); @@ -1776,19 +1808,27 @@ namespace PdfWriter double dBorderSize = 0; double dBorderSize_2 = 0; double dBorderSize2 = 0; - if (m_pField && m_pField->HaveBorder()) + if ((m_pField && m_pField->HaveBorder()) || (m_pAnnot && m_pAnnot->HaveBorder())) { - TRgb oColor = m_pField->GetBorderColor(); m_pStream->WriteStr("q\012"); - m_pStream->WriteReal(oColor.r); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.g); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.b); - m_pStream->WriteStr(" RG\012"); + if (m_pField) + { + TRgb oColor = m_pField->GetBorderColor(); + m_pStream->WriteReal(oColor.r); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.g); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.b); + m_pStream->WriteStr(" RG\012"); + } + else + { + CWidgetAnnotation* pAnnot = (CWidgetAnnotation*)m_pAnnot; + m_pStream->WriteStr(pAnnot->GetBCforAP().c_str()); + } - dBorderSize = m_pField->GetBorderSize(); + dBorderSize = m_pField ? m_pField->GetBorderSize() : m_pAnnot->GetBorderWidth(); dBorderSize_2 = dBorderSize / 2; dBorderSize2 = dBorderSize * 2; m_pStream->WriteReal(dBorderSize); @@ -1804,9 +1844,10 @@ namespace PdfWriter m_pStream->WriteStr(" re\012S\012"); CTextField* pTextField = dynamic_cast(m_pField); - if (pTextField && pTextField->IsCombFlag()) + CTextWidget* pAnnot = dynamic_cast(m_pAnnot); + if ((pTextField && pTextField->IsCombFlag()) || (pAnnot && pAnnot->IsCombFlag())) { - int nMaxLen = pTextField->GetMaxLen(); + int nMaxLen = pTextField ? pTextField->GetMaxLen() : pAnnot->GetMaxLen(); if (nMaxLen > 1) { double dStep = dWidth / nMaxLen; @@ -1845,33 +1886,52 @@ namespace PdfWriter m_pStream->WriteStr("BT\012"); - m_pStream->WriteReal(dR); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(dG); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(dB); - m_pStream->WriteStr(" rg\012"); - - if (sExtGStateName) + m_dFontSize = std::min(1000.0, std::max(0.0, dFontSize)); + if (m_pField) { - m_pStream->WriteEscapeName(sExtGStateName); - m_pStream->WriteStr(" gs\012"); + m_pStream->WriteReal(dR); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(dG); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(dB); + m_pStream->WriteStr(" rg\012"); + + if (sExtGStateName) + { + m_pStream->WriteEscapeName(sExtGStateName); + m_pStream->WriteStr(" gs\012"); + } + + m_pStream->WriteEscapeName(pResources->GetFontName(pFont)); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(m_dFontSize); + m_pStream->WriteStr(" Tf\012"); + } + else + { + CWidgetAnnotation* pAnnot = (CWidgetAnnotation*)m_pAnnot; + + std::string sFontInfo = pAnnot->GetDAforAP(); + if (sFontInfo.empty()) + { + CDictObject* pOwner = pAnnot->GetObjOwnValue("DA"); + if (pOwner) + { + CStringObject* pDA = dynamic_cast(pOwner->Get("DA")); + if (pDA) + sFontInfo = std::string((const char*)pDA->GetString()); + } + } + if (!sFontInfo.empty()) + m_pStream->WriteStr(sFontInfo.c_str()); } - double _dFontSize = std::min(1000.0, std::max(0.0, dFontSize)); - - m_pStream->WriteEscapeName(pResources->GetFontName(pFont)); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(_dFontSize); - m_pStream->WriteStr(" Tf\012"); - - m_bStart = true; - m_pFont = pFont; - m_dFontSize = _dFontSize; + m_bStart = true; + m_pFont = pFont; } void CAnnotAppearanceObject::DrawTextLine(const double& dX, const double& dY, const unsigned short* pCodes, const unsigned int& unCount, CFontCidTrueType** ppFonts, const double* pShifts) { - CResourcesDict* pResources = m_pField->GetResourcesDict(); + CResourcesDict* pResources = dynamic_cast(Get("Resources")); if (!pResources) return; @@ -1994,4 +2054,18 @@ namespace PdfWriter m_pStream->WriteStr("ET\012"); m_pStream->WriteStr("Q\012EMC\012"); } + void CAnnotAppearanceObject::DrawTextComment() + { + CArrayObject* pArray = new CArrayObject(); + if (!pArray) + return; + + Add("BBox", pArray); + pArray->Add(0); + pArray->Add(0); + pArray->Add(20); + pArray->Add(20); + + m_pStream->WriteStr(""); + } } diff --git a/PdfFile/SrcWriter/Field.h b/PdfFile/SrcWriter/Field.h index a3366d672a..de1de2f5ed 100644 --- a/PdfFile/SrcWriter/Field.h +++ b/PdfFile/SrcWriter/Field.h @@ -34,7 +34,6 @@ #include "Objects.h" #include "Types.h" -#include "Annotation.h" #include "../../DesktopEditor/graphics/commands/FormField.h" namespace PdfWriter @@ -49,6 +48,60 @@ namespace PdfWriter class CImageDict; class CFontCidTrueType; class CSignatureDict; + class CAnnotation; + + enum EBorderSubtype + { + border_subtype_Solid, + border_subtype_Beveled, + border_subtype_Dashed, + border_subtype_Inset, + border_subtype_Underlined + }; + enum EAnnotType + { + AnnotUnknown = -1, + AnnotText = 0, + AnnotLink = 1, + AnnotSound = 2, + AnnotFreeText = 3, + AnnotStamp = 4, + AnnotSquare = 5, + AnnotCircle = 6, + AnnotStrikeOut = 7, + AnnotHighLight = 8, + AnnotUnderline = 9, + AnnotInk = 10, + AnnotFileAttachment = 11, + AnnotPopup = 12, + AnnotLine = 13, + AnnotSquiggly = 14, + AnnotPolygon = 15, + AnnotPolyLine = 16, + AnnotCaret = 17, + AnnotWidget = 18 + }; + enum EAnnotHighlightMode + { + AnnotNoHighlight = 0, + AnnotInvertBox, + AnnotInvertBorder, + AnnotDownAppearance, + AnnotHighlightModeEOF + }; + enum EAnnotIcon + { + AnnotIconComment = 0, + AnnotIconKey = 1, + AnnotIconNote = 2, + AnnotIconHelp = 3, + AnnotIconNewParagraph = 4, + AnnotIconParagraph = 5, + AnnotIconInsert = 6, + + AnnotIconMin = 0, + AnnotIconMax = 6 + }; class CFieldBase : public CDictObject { @@ -277,7 +330,8 @@ namespace PdfWriter class CAnnotAppearance : public CDictObject { public: - CAnnotAppearance(CXref* pXRef, CFieldBase* pField); + CAnnotAppearance(CXref* pXRef, CFieldBase* pField); + CAnnotAppearance(CXref* pXRef, CAnnotation* pAnnot); CAnnotAppearanceObject* GetNormal(); CAnnotAppearanceObject* GetRollover(); @@ -290,6 +344,7 @@ namespace PdfWriter CAnnotAppearanceObject* m_pRollover; CAnnotAppearanceObject* m_pDown; CFieldBase* m_pField; + CAnnotation* m_pAnnot; }; class CCheckBoxAnnotAppearance : public CDictObject @@ -315,7 +370,8 @@ namespace PdfWriter class CAnnotAppearanceObject : public CDictObject { public: - CAnnotAppearanceObject(CXref* pXRef, CFieldBase* pField); + CAnnotAppearanceObject(CXref* pXRef, CFieldBase* pField); + CAnnotAppearanceObject(CXref* pXRef, CAnnotation* pAnnot); void DrawSimpleText(const std::wstring& wsText, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, double dFontSize = 10.0, double dX = 0.0, double dY = 0.0, double dR = 0.0, double dG = 0.0, double dB = 0.0, const char* sExtGrStateName = NULL, double dW = 1.0, double dH = 1.0, CFontCidTrueType** ppFonts = NULL, double* pShifts = NULL); void DrawPicture(const char* sImageName = NULL, const double& dX = 0.0, const double& dY = 0.0, const double& dW = 0.0, const double& dH = 0.0, const bool& bRespectBorder = false); void StartDrawText(CFontDict* pFont, const double& dFontSize, const double& dR, const double& dG, const double& dB, const char* sExtGStateName, const double& dWidth, const double& dHeight); @@ -323,7 +379,10 @@ namespace PdfWriter void DrawTextLine(const double &dX, const double &dY, const std::wstring& wsText); void EndDrawText(); + void DrawTextComment(); + private: + void Init(CXref* pXref, CResourcesDict* pResources, TRect* pRect); CXref* m_pXref; CStream* m_pStream; @@ -333,6 +392,8 @@ namespace PdfWriter bool m_bStart; CFontDict* m_pFont; double m_dFontSize; + + CAnnotation* m_pAnnot; }; } From bcea33ed19382e061bc6d336cc676569314b53b0 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Tue, 21 Nov 2023 16:53:48 +0400 Subject: [PATCH 18/54] Implemented reference mechanism for CValue --- DesktopEditor/doctrenderer/json/json.cpp | 257 +++++++++--------- DesktopEditor/doctrenderer/json/json.h | 31 ++- DesktopEditor/doctrenderer/json/json_p.h | 28 +- .../doctrenderer/json/json_values.cpp | 17 +- DesktopEditor/doctrenderer/json/json_values.h | 5 +- .../doctrenderer/json/serialization.h | 72 +++-- DesktopEditor/doctrenderer/test/json/main.cpp | 11 +- 7 files changed, 224 insertions(+), 197 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 82e03cd9db..e70d630197 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -4,122 +4,141 @@ namespace NSJSON { - CValueContainer::CValueContainer() : m_type(vtUndefined) + CTypedValue::CTypedValue() : m_type(vtUndefined) { } - CValueContainer::CValueContainer(ValueType type, IBaseValue* pValue) : m_value(pValue), m_type(type) + CTypedValueContainer::CTypedValueContainer() : m_typedValue(new CTypedValue()), m_isReference(false) { } - CValueContainer CValueContainer::DeepCopy(const CValueContainer& other) + CTypedValueContainer::CTypedValueContainer(const CTypedValueContainer& other) : CTypedValueContainer() { - CValueContainer ret; - ValueType type = other.m_type; - ret.m_type = type; - switch (type) + *this = other; + } + + CTypedValueContainer& CTypedValueContainer::operator=(const CTypedValueContainer& other) + { + if (other.m_isReference) { - case vtPrimitive: - ret.m_value = std::make_shared(*static_cast(other.m_value.get())); - break; - case vtArray: - ret.m_value = std::make_shared(*static_cast(other.m_value.get())); - break; - case vtTypedArray: - ret.m_value = std::make_shared(*static_cast(other.m_value.get())); - break; - case vtObject: - ret.m_value = std::make_shared(*static_cast(other.m_value.get())); - break; - default: - // vtUndefined of vtNull - break; + // set pointer to the other's typed value + m_typedValue = other.m_typedValue; } - return ret; + else + { + // copy typed value without changing pointer to it + *m_typedValue = *other.m_typedValue; + } + return *this; } - CValue::CValue() : m_internal(new CValueContainer()) + CValue::CValue() : m_internal(new CTypedValueContainer()) { } + CValue::CValue(const CValue& other) : m_internal(new CTypedValueContainer(*other.m_internal)) + { + } + + CValue::~CValue() + { + delete m_internal; + } + + CValue& CValue::operator=(const CValue& other) + { + *m_internal = *other.m_internal; + return *this; + } + bool CValue::IsUndefined() const { - return m_internal->m_type == CValueContainer::vtUndefined; + return m_internal->m_typedValue->m_type == CTypedValue::vtUndefined; } bool CValue::IsNull() const { - return m_internal->m_type == CValueContainer::vtNull; + return m_internal->m_typedValue->m_type == CTypedValue::vtNull; } bool CValue::IsBool() const { - return (m_internal->m_type == CValueContainer::vtPrimitive && - static_cast(m_internal->m_value.get())->isBool()); + return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_typedValue->m_value.get())->isBool()); } bool CValue::IsInt() const { - return (m_internal->m_type == CValueContainer::vtPrimitive && - static_cast(m_internal->m_value.get())->isInt()); + return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_typedValue->m_value.get())->isInt()); } bool CValue::IsDouble() const { - return (m_internal->m_type == CValueContainer::vtPrimitive && - static_cast(m_internal->m_value.get())->isDouble()); + return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_typedValue->m_value.get())->isDouble()); } bool CValue::IsStringA() const { - return (m_internal->m_type == CValueContainer::vtPrimitive && - static_cast(m_internal->m_value.get())->isStringA()); + return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_typedValue->m_value.get())->isStringA()); } bool CValue::IsStringW() const { - return (m_internal->m_type == CValueContainer::vtPrimitive && - static_cast(m_internal->m_value.get())->isStringW()); + return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_typedValue->m_value.get())->isStringW()); } bool CValue::IsArray() const { - return m_internal->m_type == CValueContainer::vtArray; + return m_internal->m_typedValue->m_type == CTypedValue::vtArray; } bool CValue::IsTypedArray() const { - return m_internal->m_type == CValueContainer::vtTypedArray; + return m_internal->m_typedValue->m_type == CTypedValue::vtTypedArray; } bool CValue::IsObject() const { - return m_internal->m_type == CValueContainer::vtObject; + return m_internal->m_typedValue->m_type == CTypedValue::vtObject; } bool CValue::ToBool() const { - return static_cast(m_internal->m_value.get())->toBool(); + if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) + return false; + return static_cast(m_internal->m_typedValue->m_value.get())->toBool(); } int CValue::ToInt() const { - return static_cast(m_internal->m_value.get())->toInt(); + if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) + return 0; + return static_cast(m_internal->m_typedValue->m_value.get())->toInt(); } double CValue::ToDouble() const { - return static_cast(m_internal->m_value.get())->toDouble(); + if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) + return 0.0; + return static_cast(m_internal->m_typedValue->m_value.get())->toDouble(); } std::string CValue::ToStringA() const { - return static_cast(m_internal->m_value.get())->toStringA(); + if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) + return ""; + return static_cast(m_internal->m_typedValue->m_value.get())->toStringA(); } std::wstring CValue::ToStringW() const { - return static_cast(m_internal->m_value.get())->toStringW(); + if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) + return L""; + return static_cast(m_internal->m_typedValue->m_value.get())->toStringW(); } CValue::operator bool() const @@ -147,108 +166,70 @@ namespace NSJSON return ToStringW(); } - CValue::CValue(bool value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + CValue::CValue(bool value) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(value); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } - CValue::CValue(int value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + CValue::CValue(int value) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(value); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } - CValue::CValue(double value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + CValue::CValue(double value) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(value); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } - CValue::CValue(const char* value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(std::string(value)))) + CValue::CValue(const char* value) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(std::string(value)); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } - CValue::CValue(const std::string& value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + CValue::CValue(const std::string& value) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(value); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } - CValue::CValue(const wchar_t* value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(std::wstring(value)))) + CValue::CValue(const wchar_t* value) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(std::wstring(value)); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } - CValue::CValue(const std::wstring& value) : m_internal(new CValueContainer(CValueContainer::vtPrimitive, new CPrimitive(value))) + CValue::CValue(const std::wstring& value) : CValue() { - } - - // Helper function to reduce code duplication for further assignment operators - template - static inline void setPrimitive(const std::shared_ptr& value, T primitive) - { - if (value->m_type != CValueContainer::vtPrimitive) - { - value->m_type = CValueContainer::vtPrimitive; - value->m_value = std::make_shared(primitive); - } - else - { - static_cast(value->m_value.get())->set(primitive); - } - } - - CValue& CValue::operator=(bool value) - { - setPrimitive(m_internal, value); - return *this; - } - - CValue& CValue::operator=(int value) - { - setPrimitive(m_internal, value); - return *this; - } - - CValue& CValue::operator=(double value) - { - setPrimitive(m_internal, value); - return *this; - } - - CValue& CValue::operator=(const char* value) - { - setPrimitive(m_internal, value); - return *this; - } - - CValue& CValue::operator=(const std::string& value) - { - setPrimitive(m_internal, value); - return *this; - } - - CValue& CValue::operator=(const wchar_t* value) - { - setPrimitive(m_internal, value); - return *this; - } - - CValue& CValue::operator=(const std::wstring& value) - { - setPrimitive(m_internal, value); - return *this; + m_internal->m_typedValue->m_value = std::make_shared(value); + m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; } int CValue::GetCount() const { - if (m_internal->m_type != CValueContainer::vtArray) + if (m_internal->m_typedValue->m_type != CTypedValue::vtArray) return 0; - return static_cast(m_internal->m_value.get())->getCount(); + return static_cast(m_internal->m_typedValue->m_value.get())->getCount(); } const CValue CValue::Get(int index) const { - if (m_internal->m_type != CValueContainer::vtArray) + if (m_internal->m_typedValue->m_type != CTypedValue::vtArray) return CValue(); - return static_cast(m_internal->m_value.get())->get(index); + // don't set reference mode, because this is a const method + return static_cast(m_internal->m_typedValue->m_value.get())->get(index); } CValue CValue::Get(int index) { - return static_cast(*this).Get(index); + if (m_internal->m_typedValue->m_type != CTypedValue::vtArray) + return CValue(); + CValue& value = static_cast(m_internal->m_typedValue->m_value.get())->get(index); + value.m_internal->m_isReference = true; + return value; } const CValue CValue::operator[](int index) const @@ -258,25 +239,30 @@ namespace NSJSON CValue CValue::operator[](int index) { - return Get(index); + CValue ret = Get(index); + ret.m_internal->m_isReference = true; + return ret; } - CValue::CValue(std::initializer_list elements) : m_internal(new CValueContainer(CValueContainer::vtArray, new CArray(elements))) + CValue::CValue(std::initializer_list elements) : CValue() { + m_internal->m_typedValue->m_value = std::make_shared(elements); + m_internal->m_typedValue->m_type = CTypedValue::vtArray; } CValue CValue::CreateArray(int count) { CValue ret; - ret.m_internal = std::make_shared(CValueContainer::vtArray, new CArray(count)); + ret.m_internal->m_typedValue->m_value = std::make_shared(count); + ret.m_internal->m_typedValue->m_type = CTypedValue::vtArray; return ret; } const BYTE* CValue::GetData() const { - if (m_internal->m_type != CValueContainer::vtTypedArray) + if (m_internal->m_typedValue->m_type != CTypedValue::vtTypedArray) return nullptr; - return static_cast(m_internal->m_value.get())->getData(); + return static_cast(m_internal->m_typedValue->m_value.get())->getData(); } BYTE* CValue::GetData() @@ -303,19 +289,19 @@ namespace NSJSON const CValue CValue::Get(const char* name) const { - if (m_internal->m_type != CValueContainer::vtObject) + if (m_internal->m_typedValue->m_type != CTypedValue::vtObject) return CValue(); - return static_cast(m_internal->m_value.get())->get(name); + // don't set reference mode, because this is a const method + return static_cast(m_internal->m_typedValue->m_value.get())->get(name); } CValue CValue::Get(const char* name) { - return static_cast(*this).Get(name); - } - - CValue CValue::operator[](const char* name) - { - return Get(name); + if (m_internal->m_typedValue->m_type != CTypedValue::vtObject) + return CValue(); + CValue& value = static_cast(m_internal->m_typedValue->m_value.get())->get(name); + value.m_internal->m_isReference = true; + return value; } const CValue CValue::operator[](const char* name) const @@ -323,10 +309,25 @@ namespace NSJSON return Get(name); } + CValue CValue::operator[](const char* name) + { + CValue ret = Get(name); + ret.m_internal->m_isReference = true; + return ret; + } + + std::vector CValue::GetPropertyNames() const + { + if (m_internal->m_typedValue->m_type != CTypedValue::vtObject) + return {}; + return static_cast(m_internal->m_typedValue->m_value.get())->getPropertyNames(); + } + CValue CValue::CreateObject() { CValue ret; - ret.m_internal = std::make_shared(CValueContainer::vtObject, new CObject()); + ret.m_internal->m_typedValue->m_value = std::make_shared(); + ret.m_internal->m_typedValue->m_type = CTypedValue::vtObject; return ret; } @@ -338,7 +339,7 @@ namespace NSJSON CValue CValue::CreateNull() { CValue ret; - ret.m_internal->m_type = CValueContainer::vtNull; + ret.m_internal->m_typedValue->m_type = CTypedValue::vtNull; return ret; } } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index f4793fbee6..47c79b7274 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -1,9 +1,9 @@ #ifndef JSON_H_ #define JSON_H_ -#include #include -#include +#include +#include #ifdef JSBASE_NO_USE_DYNAMIC_LIBRARY #define JSON_DECL @@ -19,14 +19,18 @@ namespace NSJSON { typedef unsigned char BYTE; - - class CValueContainer; + + class CTypedValueContainer; // Main class for storing values. // This class provide interface to work with each type of values. class JSON_DECL CValue { public: CValue(); + CValue(const CValue& other); + ~CValue(); + + CValue& operator=(const CValue& other); public: // TYPE CHECKS @@ -114,15 +118,6 @@ namespace NSJSON CValue(const wchar_t* value); CValue(const std::wstring& value); - // Assigns primitive - CValue& operator=(bool value); - CValue& operator=(int value); - CValue& operator=(double value); - CValue& operator=(const char* value); - CValue& operator=(const std::string& value); - CValue& operator=(const wchar_t* value); - CValue& operator=(const std::wstring& value); - // FUNCTIONS FOR WORKING WITH ARRAYS /** * Gets lengths of the array/typed array. @@ -185,7 +180,7 @@ namespace NSJSON /** * Gets a property of this object. * @param name The name of the property. - * @returns the value of the object's property. If current value is not an object returns undefined value. + * @returns the value of the object's property. If current value is not an object, returns undefined value. */ const CValue Get(const char* name) const; CValue Get(const char* name); @@ -194,6 +189,12 @@ namespace NSJSON const CValue operator[](const char* name) const; CValue operator[](const char* name); + /** + * Retrieves all property names from current object. + * @returns a vector containing the names of the properties of this object as strings. If current value is not an object, returns an empty vector. + */ + std::vector GetPropertyNames() const; + /** * Creates and returns empty object. */ @@ -210,7 +211,7 @@ namespace NSJSON static CValue CreateNull(); private: - std::shared_ptr m_internal; + CTypedValueContainer* m_internal; }; } diff --git a/DesktopEditor/doctrenderer/json/json_p.h b/DesktopEditor/doctrenderer/json/json_p.h index 9f3be1ac0e..aaa8fc040a 100644 --- a/DesktopEditor/doctrenderer/json/json_p.h +++ b/DesktopEditor/doctrenderer/json/json_p.h @@ -6,7 +6,8 @@ namespace NSJSON { class IBaseValue; - class CValueContainer + // Wrapper around IBaseValue with specific value type + class CTypedValue { public: enum ValueType @@ -20,15 +21,32 @@ namespace NSJSON }; public: - CValueContainer(); - CValueContainer(ValueType type, IBaseValue* pValue); - - static CValueContainer DeepCopy(const CValueContainer& other); + CTypedValue(); public: std::shared_ptr m_value; ValueType m_type; }; + + // Container for CTypedValue which is also allows to treat typed value as reference + class CTypedValueContainer + { + public: + CTypedValueContainer(); + CTypedValueContainer(const CTypedValueContainer& other); + + CTypedValueContainer& operator=(const CTypedValueContainer& other); + + public: + std::shared_ptr m_typedValue; + /* We need some sort of "reference mode" for values, returned from arrays (with CValue::Get(int)) + * and from objects (with CValue::Get(const char*)), because they should not be simply the COPY of that values, but + * instead they should be some sort of REFERENCES to original values, that are stored in array or object. + * That is because we want to be able to change them. + * m_isReference is TRUE for that type of values. For all the rest it is FALSE. + */ + bool m_isReference; + }; } #endif // JSON_PRIVATE_H_ diff --git a/DesktopEditor/doctrenderer/json/json_values.cpp b/DesktopEditor/doctrenderer/json/json_values.cpp index 70414e0444..acb92da57c 100644 --- a/DesktopEditor/doctrenderer/json/json_values.cpp +++ b/DesktopEditor/doctrenderer/json/json_values.cpp @@ -216,10 +216,10 @@ namespace NSJSON int CArray::getCount() const { - return static_cast(m_values.size()); + return (int)m_values.size(); } - CValue CArray::get(int index) + CValue& CArray::get(int index) { return m_values[index]; } @@ -251,8 +251,19 @@ namespace NSJSON { } - CValue CObject::get(const std::string& name) + CValue& CObject::get(const std::string& name) { return m_values[name]; } + + std::vector CObject::getPropertyNames() + { + std::vector ret; + for (const storage_t::value_type& entry : m_values) + { + if (!entry.second.IsUndefined()) + ret.push_back(entry.first); + } + return ret; + } } diff --git a/DesktopEditor/doctrenderer/json/json_values.h b/DesktopEditor/doctrenderer/json/json_values.h index 43c5ec7618..d9d5a58ba8 100644 --- a/DesktopEditor/doctrenderer/json/json_values.h +++ b/DesktopEditor/doctrenderer/json/json_values.h @@ -87,7 +87,7 @@ namespace NSJSON public: int getCount() const; - CValue get(int index); + CValue& get(int index); private: std::vector m_values; @@ -118,7 +118,8 @@ namespace NSJSON ~CObject(); public: - CValue get(const std::string& name); + CValue& get(const std::string& name); + std::vector getPropertyNames(); private: storage_t m_values; diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index 10c4c5f721..27f0d133f3 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -9,65 +9,57 @@ namespace NSJSON { - static JSSmart toJS(const CValue& pValue) + static JSSmart toJS(const CValue& value) { - IBaseValue::ValueType type = pValue->m_type; - if (type == IBaseValue::vtUndefined) + if (value.IsUndefined()) return NSJSBase::CJSContext::createUndefined(); - if (type == IBaseValue::vtNull) + if (value.IsNull()) return NSJSBase::CJSContext::createNull(); JSSmart ret; - if (type == IBaseValue::vtObject) + if (value.IsObject()) { - const CObject* pObject = static_cast(pValue); JSSmart jsObj = NSJSBase::CJSContext::createObject(); - for (const auto& entry : pObject->m_values) + std::vector properties = value.GetPropertyNames(); + for (const std::string& name : properties) { - JSSmart jsValue = toJS(entry.second); - jsObj->set(entry.first.c_str(), jsValue); + JSSmart jsValue = toJS(value[name.c_str()]); + jsObj->set(name.c_str(), jsValue); } ret = jsObj->toValue(); } - else if (type == IBaseValue::vtArray) + else if (value.IsArray()) { - const CArray* pArray = static_cast(pValue); - JSSmart jsArr = NSJSBase::CJSContext::createArray(0); - for (const IBaseValue* pArrValue : pArray->m_values) + const int len = value.GetCount(); + JSSmart jsArr = NSJSBase::CJSContext::createArray(len); + for (int i = 0; i < len; i++) { - jsArr->add(toJS(pArrValue).GetPointer()); + jsArr->set(i, toJS(value[i]).GetPointer()); } ret = jsArr->toValue(); } - else if (type == IBaseValue::vtTypedArray) + else if (value.IsTypedArray()) { - const CTypedArray* pTypedArray = static_cast(pValue); - JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(pTypedArray->m_data, pTypedArray->m_len); + // TODO: + /* + JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(value.GetData(), value.GetCount()); ret = jsTypedArr->toValue(); + */ + ret = NSJSBase::CJSContext::createUndefined(); } else { - // primitive type - const CPrimitive* pPrimitiveValue = static_cast(pValue); - switch (type) { - case IBaseValue::vtBoolean: - ret = NSJSBase::CJSContext::createBool(pPrimitiveValue->m_bool); - break; - case IBaseValue::vtInteger: - ret = NSJSBase::CJSContext::createInt(pPrimitiveValue->m_int); - break; - case IBaseValue::vtDouble: - ret = NSJSBase::CJSContext::createDouble(pPrimitiveValue->m_double); - break; - case IBaseValue::vtStringA: - ret = NSJSBase::CJSContext::createString(pPrimitiveValue->m_string); - break; - case IBaseValue::vtStringW: - ret = NSJSBase::CJSContext::createString(pPrimitiveValue->m_wstring); - break; - default: - break; - } + // primitive types + if (value.IsBool()) + ret = NSJSBase::CJSContext::createBool((bool)value); + else if (value.IsInt()) + ret = NSJSBase::CJSContext::createInt((int)value); + else if (value.IsDouble()) + ret = NSJSBase::CJSContext::createDouble((double)value); + else if (value.IsStringA()) + ret = NSJSBase::CJSContext::createString((std::string)value); + else + ret = NSJSBase::CJSContext::createString((std::wstring)value); } return ret; @@ -75,6 +67,7 @@ namespace NSJSON static CValue fromJS(JSSmart jsValue) { + /* if (jsValue->isUndefined()) return new CPrimitive(); @@ -138,8 +131,9 @@ namespace NSJSON // TODO: how do we know whether string consist of char or wchar_t? Can we convert all strings to std::wstring? } // else ret is nullptr + */ - return ret; + return CValue(); } } diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index edda7aa998..8027f47e0a 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -1,7 +1,6 @@ //#include "gtest/gtest.h" #include "js_internal/js_base.h" -//#include "json/serialization.h" -#include "json/json.h" +#include "json/serialization.h" #include #include @@ -40,7 +39,7 @@ int main() JSSmart pContext = new CJSContext(); CJSContextScope scope(pContext); - // top object with text parameters + // top object with some text parameters CValue textPr = CValue::CreateObject(); CValue colorRGB = CValue::CreateObject(); @@ -53,6 +52,10 @@ int main() colorRGBA["alpha"] = 80; textPr["size"] = 4.2; + // CValue behaves as reference, when it was initialized with value returned from Get() (or operator[]) of objects & arrays. + CValue name = textPr["name"]; + // from now on, name - is a reference to the property "name" of textPr. Changing it will affect this object property: + name = "Foo"; textPr["color"] = colorRGBA; textPr["font"] = CValue::CreateObject(); textPr["font"]["fontName"] = L"Times New Roman"; @@ -81,7 +84,6 @@ int main() */ // convert to JS - /* JSSmart jsObj = toJS(textPr)->toObject(); JSSmart global = pContext->GetGlobal(); global->set("textPr", jsObj); @@ -90,7 +92,6 @@ int main() { std::cout << ret->toStringA() << std::endl; } - */ return 0; } From 49d3e46a0f5cebfd50286f43fa170c681326b339 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Tue, 21 Nov 2023 18:25:32 +0300 Subject: [PATCH 19/54] Create GetWidgetFonts --- PdfFile/PdfFile.cpp | 6 +++ PdfFile/PdfFile.h | 1 + PdfFile/PdfReader.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++ PdfFile/PdfReader.h | 1 + 4 files changed, 123 insertions(+) diff --git a/PdfFile/PdfFile.cpp b/PdfFile/PdfFile.cpp index 11a1570230..5d84fe953d 100644 --- a/PdfFile/PdfFile.cpp +++ b/PdfFile/PdfFile.cpp @@ -1292,6 +1292,12 @@ BYTE* CPdfFile::GetWidgets() return NULL; return m_pInternal->pReader->GetWidgets(); } +BYTE* CPdfFile::GetWidgetFonts() +{ + if (!m_pInternal->pReader) + return NULL; + return m_pInternal->pReader->GetWidgetFonts(); +} BYTE* CPdfFile::GetAnnots(int nPageIndex) { if (!m_pInternal->pReader) diff --git a/PdfFile/PdfFile.h b/PdfFile/PdfFile.h index b11e596a2c..feddd7c826 100644 --- a/PdfFile/PdfFile.h +++ b/PdfFile/PdfFile.h @@ -129,6 +129,7 @@ public: int GetRotate(int nPageIndex); int GetMaxRefID(); BYTE* GetWidgets(); + BYTE* GetWidgetFonts(); BYTE* GetAnnots (int nPageIndex = -1); BYTE* VerifySign (const std::wstring& sFile, ICertificate* pCertificate, int nWidget = -1); BYTE* GetAPWidget (int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, int nWidget = -1, const char* sView = NULL, const char* sBView = NULL); diff --git a/PdfFile/PdfReader.cpp b/PdfFile/PdfReader.cpp index a7171d0cff..6cd2f80ae9 100644 --- a/PdfFile/PdfReader.cpp +++ b/PdfFile/PdfReader.cpp @@ -883,6 +883,121 @@ BYTE* CPdfReader::GetWidgets() oRes.ClearWithoutAttack(); return bRes; } +BYTE* CPdfReader::GetWidgetFonts() +{ + if (!m_pPDFDocument || !m_pPDFDocument->getCatalog()) + return NULL; + + AcroForm* pAcroForms = m_pPDFDocument->getCatalog()->getForm(); + XRef* xref = m_pPDFDocument->getXRef(); + if (!pAcroForms || !xref) + return NULL; + + NSWasm::CData oRes; + oRes.SkipLen(); + + Object oObj1, oObj2; + + for (int i = 0, nNum = pAcroForms->getNumFields(); i < nNum; ++i) + { + AcroFormField* pField = pAcroForms->getField(i); + Object oFieldRef, oField; + if (!pField || !pField->getFieldRef(&oFieldRef)->isRef() || !oFieldRef.fetch(xref, &oField)->isDict()) + { + oField.free(); oFieldRef.free(); + continue; + } + + GfxFont* gfxFont = NULL; + GfxFontDict *gfxFontDict = NULL; + + // Шрифт и размер шрифта - из DA + Ref fontID; + double dFontSize = 0; + pField->getFont(&fontID, &dFontSize); + if (fontID.num > 0) + { + Object oObj, oField, oFont; + pField->getFieldRef(&oObj); + oObj.fetch(xref, &oField); + oObj.free(); + + bool bFindResources = false; + + if (oField.dictLookup("DR", &oObj)->isDict() && oObj.dictLookup("Font", &oFont)->isDict()) + { + for (int i = 0; i < oFont.dictGetLength(); ++i) + { + Object oFontRef; + if (oFont.dictGetValNF(i, &oFontRef)->isRef() && oFontRef.getRef() == fontID) + { + bFindResources = true; + oFontRef.free(); + break; + } + oFontRef.free(); + } + } + oFont.free(); oField.free(); + + if (!bFindResources) + { + oObj.free(); + Object* oAcroForm = pAcroForms->getAcroFormObj(); + if (oAcroForm->isDict() && oAcroForm->dictLookup("DR", &oObj)->isDict() && oObj.dictLookup("Font", &oFont)->isDict()) + { + for (int i = 0; i < oFont.dictGetLength(); ++i) + { + Object oFontRef; + if (oFont.dictGetValNF(i, &oFontRef)->isRef() && oFontRef.getRef() == fontID) + { + bFindResources = true; + oFontRef.free(); + break; + } + oFontRef.free(); + } + } + oFont.free(); + } + + if (bFindResources) + { + Object oFontRef; + if (oObj.dictLookupNF("Font", &oFontRef)->isRef()) + { + if (oFontRef.fetch(xref, &oFont)->isDict()) + { + Ref r = oFontRef.getRef(); + gfxFontDict = new GfxFontDict(xref, &r, oFont.getDict()); + gfxFont = gfxFontDict->lookupByRef(fontID); + } + oFont.free(); + } + else if (oFontRef.isDict()) + { + gfxFontDict = new GfxFontDict(xref, NULL, oFontRef.getDict()); + gfxFont = gfxFontDict->lookupByRef(fontID); + } + oFontRef.free(); + } + oObj.free(); + } + + std::wstring wsFileName, wsFontName; + if (gfxFont) + GetFont(xref, m_pFontManager, m_pFontList, gfxFont, wsFileName, wsFontName); + + std::string m_sFontName = U_TO_UTF8(wsFileName); + + RELEASEOBJECT(gfxFontDict); + } + + oRes.WriteLen(); + BYTE* bRes = oRes.GetBuffer(); + oRes.ClearWithoutAttack(); + return bRes; +} BYTE* CPdfReader::VerifySign(const std::wstring& sFile, ICertificate* pCertificate, int nWidget) { if (!m_pPDFDocument || !m_pPDFDocument->getCatalog()) diff --git a/PdfFile/PdfReader.h b/PdfFile/PdfReader.h index 9618d7eebb..76c155273b 100644 --- a/PdfFile/PdfReader.h +++ b/PdfFile/PdfReader.h @@ -73,6 +73,7 @@ public: BYTE* GetStructure(); BYTE* GetLinks(int nPageIndex); BYTE* GetWidgets(); + BYTE* GetWidgetFonts(); BYTE* GetAnnots(int nPageIndex = -1); BYTE* VerifySign(const std::wstring& sFile, ICertificate* pCertificate, int nWidget = -1); BYTE* GetAPWidget (int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, int nWidget = -1, const char* sView = NULL, const char* sBView = NULL); From 44ef271b925e38584c034ca4ba309d3555fefb52 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Wed, 22 Nov 2023 11:58:19 +0300 Subject: [PATCH 20/54] Release GetWidgetFonts --- .../graphics/pro/js/drawingfile.json | 2 + .../graphics/pro/js/wasm/src/drawingfile.cpp | 19 +++ .../graphics/pro/js/wasm/src/drawingfile.h | 6 + .../pro/js/wasm/src/drawingfile_test.cpp | 33 ++++- PdfFile/PdfReader.cpp | 113 +++++++++--------- 5 files changed, 115 insertions(+), 58 deletions(-) diff --git a/DesktopEditor/graphics/pro/js/drawingfile.json b/DesktopEditor/graphics/pro/js/drawingfile.json index b8521a7c21..b5d73d545c 100644 --- a/DesktopEditor/graphics/pro/js/drawingfile.json +++ b/DesktopEditor/graphics/pro/js/drawingfile.json @@ -31,6 +31,7 @@ "_GetLinks", "_GetStructure", "_GetInteractiveFormsInfo", + "_GetInteractiveFormsFonts", "_GetInteractiveFormsAP", "_GetButtonIcons", "_GetAnnotationsInfo", @@ -39,6 +40,7 @@ "_InitializeFontsBase64", "_InitializeFontsRanges", "_SetFontBinary", + "_GetFontBinary", "_IsFontBinaryExist", "_DestroyTextInfo", "_IsNeedCMap", diff --git a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp index 909c4b4c59..2d5c838c7f 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp +++ b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp @@ -57,6 +57,21 @@ WASM_EXPORT void SetFontBinary(char* path, BYTE* data, int size) pStorage->Add(UTF8_TO_U(sPathA), data, size, true); } } +WASM_EXPORT void GetFontBinary(char* path, BYTE*& data, int& size) +{ + NSFonts::IFontsMemoryStorage* pStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); + if (pStorage) + { + std::string sPathA(path); + NSFonts::IFontStream* pStream = pStorage->Get(UTF8_TO_U(sPathA)); + if (pStream) + { + long lLength = 0; + pStream->GetMemory(data, lLength); + size = lLength; + } + } +} WASM_EXPORT int IsFontBinaryExist(char* path) { NSFonts::IFontsMemoryStorage* pStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); @@ -156,6 +171,10 @@ WASM_EXPORT BYTE* GetInteractiveFormsInfo(CGraphicsFileDrawing* pGraphics) { return pGraphics->GetInteractiveFormsInfo(); } +WASM_EXPORT BYTE* GetInteractiveFormsFonts(CGraphicsFileDrawing* pGraphics) +{ + return pGraphics->GetWidgetFontsID(); +} WASM_EXPORT BYTE* GetInteractiveFormsAP(CGraphicsFileDrawing* pGraphics, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, int nWidget, int nView, int nButtonView) { const char* sView = NULL; diff --git a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.h b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.h index 7d2dccf469..aea2993e95 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.h +++ b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.h @@ -123,6 +123,12 @@ public: return ((CPdfFile*)pReader)->GetWidgets(); return NULL; } + BYTE* GetWidgetFontsID() + { + if (nType == 0) + return ((CPdfFile*)pReader)->GetWidgetFonts(); + return NULL; + } BYTE* GetAnnots(int nPageIndex = -1) { if (nType == 0) diff --git a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp index 20dfa05b8e..4065c3a654 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp +++ b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp @@ -651,10 +651,11 @@ void ReadAnnotAP(BYTE* pWidgetsAP, int& i) int nAPLength = READ_INT(pWidgetsAP + i); i += 4; + if (nAPLength > 0) + std::cout << "APName "; for (int j = 0; j < nAPLength; ++j) { - std::cout << std::endl; nPathLength = READ_INT(pWidgetsAP + i); i += 4; std::string sAPName = std::string((char*)(pWidgetsAP + i), nPathLength); @@ -665,7 +666,7 @@ void ReadAnnotAP(BYTE* pWidgetsAP, int& i) sAPName += nPathLength ? ("." + std::string((char*)(pWidgetsAP + i), nPathLength)) : ""; i += nPathLength; - std::cout << "APName " << sAPName << ", "; + std::cout << sAPName << ", "; unsigned long long npBgraData1 = READ_INT(pWidgetsAP + i); i += 4; unsigned long long npBgraData2 = READ_INT(pWidgetsAP + i); @@ -774,7 +775,7 @@ int main(int argc, char* argv[]) std::cout << " Page " << nTestPage << " width " << nWidth << " height " << nHeight << " dpi " << dpi << " rotate " << rotate << std::endl; nLength = READ_INT(pInfo + nPagesCount * 16 + 12); - std::cout << "json "<< std::string((char*)(pInfo + nPagesCount * 16 + 16), nLength) << std::endl;; + std::cout << "json "<< std::string((char*)(pInfo + nPagesCount * 16 + 16), nLength) << std::endl << std::endl; } } @@ -886,9 +887,33 @@ int main(int argc, char* argv[]) // INTERACTIVE FORMS if (true) { + BYTE* pFonts = GetInteractiveFormsFontsID(pGrFile); + nLength = READ_INT(pFonts); + int i = 4; + nLength -= 4; + + while (i < nLength) + { + int nFontsLength = READ_INT(pFonts + i); + i += 4; + std::cout << "Fonts"; + + for (int j = 0; j < nFontsLength; ++j) + { + int nPathLength = READ_INT(pFonts + i); + i += 4; + std::cout << " " << std::string((char*)(pFonts + i), nPathLength); + i += nPathLength; + } + std::cout << std::endl; + } + + if (pFonts) + free(pFonts); + BYTE* pWidgets = GetInteractiveFormsInfo(pGrFile); nLength = READ_INT(pWidgets); - int i = 4; + i = 4; nLength -= 4; if (i < nLength) diff --git a/PdfFile/PdfReader.cpp b/PdfFile/PdfReader.cpp index 6cd2f80ae9..80e215df0e 100644 --- a/PdfFile/PdfReader.cpp +++ b/PdfFile/PdfReader.cpp @@ -896,35 +896,51 @@ BYTE* CPdfReader::GetWidgetFonts() NSWasm::CData oRes; oRes.SkipLen(); - Object oObj1, oObj2; + int nFontsID = 0; + int nFontsPos = oRes.GetSize(); + oRes.AddInt(nFontsID); + std::vector arrFontsRef; for (int i = 0, nNum = pAcroForms->getNumFields(); i < nNum; ++i) { AcroFormField* pField = pAcroForms->getField(i); - Object oFieldRef, oField; - if (!pField || !pField->getFieldRef(&oFieldRef)->isRef() || !oFieldRef.fetch(xref, &oField)->isDict()) - { - oField.free(); oFieldRef.free(); + if (!pField) continue; - } - - GfxFont* gfxFont = NULL; - GfxFontDict *gfxFontDict = NULL; // Шрифт и размер шрифта - из DA Ref fontID; double dFontSize = 0; pField->getFont(&fontID, &dFontSize); - if (fontID.num > 0) + if (fontID.num < 0 || std::find(arrFontsRef.begin(), arrFontsRef.end(), fontID.num) != arrFontsRef.end()) + continue; + + Object oObj, oField, oFont; + pField->getFieldRef(&oObj); + oObj.fetch(xref, &oField); + oObj.free(); + + bool bFindResources = false; + if (oField.dictLookup("DR", &oObj)->isDict() && oObj.dictLookup("Font", &oFont)->isDict()) + { + for (int i = 0; i < oFont.dictGetLength(); ++i) + { + Object oFontRef; + if (oFont.dictGetValNF(i, &oFontRef)->isRef() && oFontRef.getRef() == fontID) + { + bFindResources = true; + oFontRef.free(); + break; + } + oFontRef.free(); + } + } + oFont.free(); oField.free(); + + if (!bFindResources) { - Object oObj, oField, oFont; - pField->getFieldRef(&oObj); - oObj.fetch(xref, &oField); oObj.free(); - - bool bFindResources = false; - - if (oField.dictLookup("DR", &oObj)->isDict() && oObj.dictLookup("Font", &oFont)->isDict()) + Object* oAcroForm = pAcroForms->getAcroFormObj(); + if (oAcroForm->isDict() && oAcroForm->dictLookup("DR", &oObj)->isDict() && oObj.dictLookup("Font", &oFont)->isDict()) { for (int i = 0; i < oFont.dictGetLength(); ++i) { @@ -938,61 +954,50 @@ BYTE* CPdfReader::GetWidgetFonts() oFontRef.free(); } } - oFont.free(); oField.free(); + oFont.free(); + } - if (!bFindResources) + GfxFont* gfxFont = NULL; + GfxFontDict *gfxFontDict = NULL; + if (bFindResources) + { + Object oFontRef; + if (oObj.dictLookupNF("Font", &oFontRef)->isRef()) { - oObj.free(); - Object* oAcroForm = pAcroForms->getAcroFormObj(); - if (oAcroForm->isDict() && oAcroForm->dictLookup("DR", &oObj)->isDict() && oObj.dictLookup("Font", &oFont)->isDict()) + if (oFontRef.fetch(xref, &oFont)->isDict()) { - for (int i = 0; i < oFont.dictGetLength(); ++i) - { - Object oFontRef; - if (oFont.dictGetValNF(i, &oFontRef)->isRef() && oFontRef.getRef() == fontID) - { - bFindResources = true; - oFontRef.free(); - break; - } - oFontRef.free(); - } + Ref r = oFontRef.getRef(); + gfxFontDict = new GfxFontDict(xref, &r, oFont.getDict()); + gfxFont = gfxFontDict->lookupByRef(fontID); } oFont.free(); } - - if (bFindResources) + else if (oFontRef.isDict()) { - Object oFontRef; - if (oObj.dictLookupNF("Font", &oFontRef)->isRef()) - { - if (oFontRef.fetch(xref, &oFont)->isDict()) - { - Ref r = oFontRef.getRef(); - gfxFontDict = new GfxFontDict(xref, &r, oFont.getDict()); - gfxFont = gfxFontDict->lookupByRef(fontID); - } - oFont.free(); - } - else if (oFontRef.isDict()) - { - gfxFontDict = new GfxFontDict(xref, NULL, oFontRef.getDict()); - gfxFont = gfxFontDict->lookupByRef(fontID); - } - oFontRef.free(); + gfxFontDict = new GfxFontDict(xref, NULL, oFontRef.getDict()); + gfxFont = gfxFontDict->lookupByRef(fontID); } - oObj.free(); + oFontRef.free(); } + oObj.free(); std::wstring wsFileName, wsFontName; if (gfxFont) GetFont(xref, m_pFontManager, m_pFontList, gfxFont, wsFileName, wsFontName); - std::string m_sFontName = U_TO_UTF8(wsFileName); + if (wsFileName.length() > 17 && wsFileName.substr(0, 17) == L"storage_internal_") + { + std::string sFileName = U_TO_UTF8(wsFileName); + oRes.WriteString(sFileName); + nFontsID++; + arrFontsRef.push_back(fontID.num); + } RELEASEOBJECT(gfxFontDict); } + oRes.AddInt(nFontsID, nFontsPos); + oRes.WriteLen(); BYTE* bRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); From 0c282767534e2cfe814ab5f39b2523c06b7a341e Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Wed, 22 Nov 2023 16:20:46 +0300 Subject: [PATCH 21/54] Create getInteractiveFormsFonts and getFontByID --- .../pro/js/wasm/js/drawingfile_base.js | 82 +++++++++++++++++++ .../graphics/pro/js/wasm/src/drawingfile.cpp | 26 +++++- .../pro/js/wasm/src/drawingfile_test.cpp | 28 ++++++- 3 files changed, 130 insertions(+), 6 deletions(-) diff --git a/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js b/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js index a2e4a1f95f..ecb19ecc18 100644 --- a/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js +++ b/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js @@ -845,6 +845,41 @@ Module["_free"](ext); return res; }; + CFile.prototype["getInteractiveFormsFonts"] = function() + { + let res = []; + let ext = Module["_GetInteractiveFormsFonts"](this.nativeFile); + if (ext == 0) + return res; + + let lenArray = new Int32Array(Module["HEAP8"].buffer, ext, 4); + if (lenArray == null) + { + Module["_free"](ext); + return res; + } + + let len = lenArray[0]; + len -= 4; + if (len <= 0) + { + Module["_free"](ext); + return res; + } + + let buffer = new Uint8Array(Module["HEAP8"].buffer, ext + 4, len); + let reader = new CBinaryReader(buffer, 0, len); + + while (reader.isValid()) + { + let n = reader.readInt(); + for (let i = 0; i < n; ++i) + res.push(reader.readString()); + } + + Module["_free"](ext); + return res; + }; // optional nWidget - rec["AP"]["i"] // optional sView - N/D/R // optional sButtonView - state pushbutton-annotation - Off/Yes(or rec["ExportValue"]) @@ -1322,6 +1357,53 @@ Module["_free"](str); return res; }; + CFile.prototype["getFontByID"] = function(ID) + { + if (ID === undefined) + return null; + + let idBuffer = ID.toUtf8(); + let idPointer = Module["_malloc"](idBuffer.length); + Module["HEAP8"].set(idBuffer, idPointer); + + let ext = Module["_GetFontBinary"](idPointer); + if (ext == 0) + return null; + + let lenArray = new Int32Array(Module["HEAP8"].buffer, ext, 4); + if (lenArray == null) + { + Module["_free"](ext); + return null; + } + + let len = lenArray[0]; + len -= 4; + if (len <= 0) + { + Module["_free"](ext); + return null; + } + + let buffer = new Uint8Array(Module["HEAP8"].buffer, ext + 4, len); + let reader = new CBinaryReader(buffer, 0, len); + + let res = null; + while (reader.isValid()) + { + let nFontLength = reader.readInt(); + let np1 = reader.readInt(); + let np2 = reader.readInt(); + let pFontPoint = np2 << 32 | np1; + + res = new Uint8Array(Module["HEAP8"].buffer, pFontPoint, nFontLength); + } + + Module["_free"](idPointer); + Module["_free"](ext); + + return res; + }; CFile.prototype.memory = function() { diff --git a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp index 2d5c838c7f..32788a3dbc 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp +++ b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp @@ -57,8 +57,11 @@ WASM_EXPORT void SetFontBinary(char* path, BYTE* data, int size) pStorage->Add(UTF8_TO_U(sPathA), data, size, true); } } -WASM_EXPORT void GetFontBinary(char* path, BYTE*& data, int& size) +WASM_EXPORT BYTE* GetFontBinary(char* path) { + NSWasm::CData oRes; + oRes.SkipLen(); + NSFonts::IFontsMemoryStorage* pStorage = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage(); if (pStorage) { @@ -66,11 +69,26 @@ WASM_EXPORT void GetFontBinary(char* path, BYTE*& data, int& size) NSFonts::IFontStream* pStream = pStorage->Get(UTF8_TO_U(sPathA)); if (pStream) { - long lLength = 0; - pStream->GetMemory(data, lLength); - size = lLength; + BYTE* pData = NULL; + LONG lLength = 0; + pStream->GetMemory(pData, lLength); + + if (pData) + { + oRes.AddInt(lLength); + + unsigned long long npSubMatrix = (unsigned long long)pData; + unsigned int npSubMatrix1 = npSubMatrix & 0xFFFFFFFF; + oRes.AddInt(npSubMatrix1); + oRes.AddInt(npSubMatrix >> 32); + } } } + + oRes.WriteLen(); + BYTE* bRes = oRes.GetBuffer(); + oRes.ClearWithoutAttack(); + return bRes; } WASM_EXPORT int IsFontBinaryExist(char* path) { diff --git a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp index 4065c3a654..d4f2db4a2f 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp +++ b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile_test.cpp @@ -887,7 +887,7 @@ int main(int argc, char* argv[]) // INTERACTIVE FORMS if (true) { - BYTE* pFonts = GetInteractiveFormsFontsID(pGrFile); + BYTE* pFonts = GetInteractiveFormsFonts(pGrFile); nLength = READ_INT(pFonts); int i = 4; nLength -= 4; @@ -902,8 +902,32 @@ int main(int argc, char* argv[]) { int nPathLength = READ_INT(pFonts + i); i += 4; - std::cout << " " << std::string((char*)(pFonts + i), nPathLength); + std::string sFontName = std::string((char*)(pFonts + i), nPathLength); + std::cout << " " << sFontName; i += nPathLength; + + BYTE* pFont = GetFontBinary((char*)sFontName.c_str()); + int nLength2 = READ_INT(pFont); + int i2 = 4; + nLength2 -= 4; + + while (i2 < nLength2) + { + int nFontLength = READ_INT(pFont + i2); + i2 += 4; + + unsigned long long npFont1 = READ_INT(pFont + i2); + i2 += 4; + unsigned long long npFont2 = READ_INT(pFont + i2); + i2 += 4; + + BYTE* res = (BYTE*)(npFont2 << 32 | npFont1); + + NSFile::CFileBinary oFile; + if (oFile.CreateFileW(NSFile::GetProcessDirectory() + L"/font" + std::to_wstring(j) + L".txt")) + oFile.WriteFile(res, nFontLength); + oFile.CloseFile(); + } } std::cout << std::endl; } From 7f9164ddb2afcc34b9389d4ee8ac5172bc573d4d Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Wed, 22 Nov 2023 16:32:23 +0300 Subject: [PATCH 22/54] Fix --- .../graphics/pro/js/wasm/js/drawingfile_base.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js b/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js index ecb19ecc18..11762b97f1 100644 --- a/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js +++ b/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js @@ -1359,8 +1359,9 @@ }; CFile.prototype["getFontByID"] = function(ID) { + let res = null; if (ID === undefined) - return null; + return res; let idBuffer = ID.toUtf8(); let idPointer = Module["_malloc"](idBuffer.length); @@ -1368,13 +1369,13 @@ let ext = Module["_GetFontBinary"](idPointer); if (ext == 0) - return null; + return res; let lenArray = new Int32Array(Module["HEAP8"].buffer, ext, 4); if (lenArray == null) { Module["_free"](ext); - return null; + return res; } let len = lenArray[0]; @@ -1382,13 +1383,12 @@ if (len <= 0) { Module["_free"](ext); - return null; + return res; } let buffer = new Uint8Array(Module["HEAP8"].buffer, ext + 4, len); let reader = new CBinaryReader(buffer, 0, len); - let res = null; while (reader.isValid()) { let nFontLength = reader.readInt(); From 07c9efd29f991b32ec6da4cd89450a70cb8ad596 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Wed, 22 Nov 2023 17:24:19 +0300 Subject: [PATCH 23/54] Fix changes --- .../graphics/commands/AnnotField.cpp | 9 +- PdfFile/PdfWriter.cpp | 187 +-------------- PdfFile/SrcWriter/Annotation.cpp | 212 +++++++++--------- PdfFile/SrcWriter/Annotation.h | 95 ++++++-- PdfFile/SrcWriter/Field.cpp | 184 +++++---------- PdfFile/SrcWriter/Field.h | 67 +----- 6 files changed, 245 insertions(+), 509 deletions(-) diff --git a/DesktopEditor/graphics/commands/AnnotField.cpp b/DesktopEditor/graphics/commands/AnnotField.cpp index 6035767f1f..9c3f6782e4 100644 --- a/DesktopEditor/graphics/commands/AnnotField.cpp +++ b/DesktopEditor/graphics/commands/AnnotField.cpp @@ -457,12 +457,9 @@ bool CAnnotFieldInfo::Read(NSOnlineOfficeBinToPdf::CBufferReader* pReader, IMeta { m_oBorder.nType = pReader->ReadByte(); m_oBorder.dWidth = pReader->ReadDouble(); - if (m_oBorder.nType == 2) - { - int n = pReader->ReadInt(); - for (int i = 0; i < n; ++i) - m_oBorder.arrDash.push_back(pReader->ReadDouble()); - } + int n = pReader->ReadInt(); + for (int i = 0; i < n; ++i) + m_oBorder.arrDash.push_back(pReader->ReadDouble()); } if (nFlags & (1 << 5)) m_wsLM = pReader->ReadString(); diff --git a/PdfFile/PdfWriter.cpp b/PdfFile/PdfWriter.cpp index 97aa3f940a..450118984d 100644 --- a/PdfFile/PdfWriter.cpp +++ b/PdfFile/PdfWriter.cpp @@ -2017,22 +2017,20 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF PdfWriter::CWidgetAnnotation* pWidgetAnnot = (PdfWriter::CWidgetAnnotation*)pAnnot; put_FontName(pPr->GetFontName()); - int nStyle = pPr->GetFontStyle(); - double dFontSize = pPr->GetFontSizeAP(); - put_FontStyle(nStyle); + put_FontStyle(pPr->GetFontStyle()); if (m_bNeedUpdateTextFont) UpdateFont(); + // TODO почему важно добавить CFontTrueType, а не CFontCidTrueType PdfWriter::CFontTrueType* pFontTT = NULL; if (m_pFont) pFontTT = m_pDocument->CreateTrueTypeFont(m_pFont); pWidgetAnnot->SetDocument(m_pDocument); - pWidgetAnnot->SetDA(pFontTT, pPr->GetFontSize(), dFontSize, pPr->GetTC()); + pWidgetAnnot->SetDA(pFontTT, pPr->GetFontSize(), pPr->GetFontSizeAP(), pPr->GetTC()); - BYTE nAlign = pPr->GetQ(); - pWidgetAnnot->SetQ(nAlign); + pWidgetAnnot->SetQ(pPr->GetQ()); int nWidgetFlag = pPr->GetFlag(); pWidgetAnnot->SetFlag(nWidgetFlag); @@ -2146,9 +2144,6 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF pWidgetAnnot->AddAction(pA); } - bool isBold = (nStyle & 1 ? true : false); - bool isItalic = (nStyle & 2 ? true : false); - if (oInfo.IsButtonWidget()) { CAnnotFieldInfo::CWidgetAnnotPr::CButtonWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetButtonWidgetPr(); @@ -2192,182 +2187,14 @@ HRESULT CPdfWriter::AddAnnotField(NSFonts::IApplicationFonts* pAppFonts, CAnnotF CAnnotFieldInfo::CWidgetAnnotPr::CTextWidgetPr* pPr = oInfo.GetWidgetAnnotPr()->GetTextWidgetPr(); PdfWriter::CTextWidget* pTextWidget = (PdfWriter::CTextWidget*)pAnnot; - std::wstring wsValue; if (nFlags & (1 << 9)) - { - wsValue = pPr->GetV(); - pTextWidget->SetV(wsValue); - } - unsigned int unMaxLen = 0; + pTextWidget->SetV(pPr->GetV()); if (nFlags & (1 << 10)) - { - unMaxLen = pPr->GetMaxLen(); - pTextWidget->SetMaxLen(unMaxLen); - } + pTextWidget->SetMaxLen(pPr->GetMaxLen()); if (nWidgetFlag & (1 << 25)) pTextWidget->SetRV(pPr->GetRV()); - // Коды, шрифты, количество - unsigned int unLen; - unsigned int* pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsValue, unLen); - if (!pUnicodes) - return S_FALSE; - unsigned short* pCodes = new unsigned short[unLen]; - if (!pCodes) - { - RELEASEARRAYOBJECTS(pUnicodes); - return S_FALSE; - } - PdfWriter::CFontCidTrueType** ppFonts = new PdfWriter::CFontCidTrueType*[unLen]; - if (!ppFonts) - { - RELEASEARRAYOBJECTS(pUnicodes); - RELEASEARRAYOBJECTS(pCodes); - return S_FALSE; - } - - for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) - { - unsigned int unUnicode = pUnicodes[unIndex]; - - if (!m_pFont->HaveChar(unUnicode)) - { - std::wstring wsFontFamily = pAppFonts->GetFontBySymbol(unUnicode); - PdfWriter::CFontCidTrueType* pTempFont = GetFont(wsFontFamily, isBold, isItalic); - if (pTempFont) - { - pCodes[unIndex] = pTempFont->EncodeUnicode(unUnicode); - ppFonts[unIndex] = pTempFont; - continue; - } - } - - pCodes[unIndex] = m_pFont->EncodeUnicode(unUnicode); - ppFonts[unIndex] = m_pFont; - } - - double _dY = pPage->GetHeight() - dY1; - double _dB = pPage->GetHeight() - dY2; - double dMargin = 2; // Отступ используемый в Adobe - double dBaseLine = dY2 - dY1; // TODO -BaseLineOffset - double dShiftX = dMargin; - - bool isComb = pTextWidget->IsCombFlag(); - - // TODO PlaceHolder заполнитель без значения - - if (!isComb && pTextWidget->IsMultiLine()) - { - unsigned short* pCodes2 = new unsigned short[unLen]; - unsigned int* pWidths = new unsigned int[unLen]; - - unsigned short ushSpaceCode = 0xFFFF; - unsigned short ushNewLineCode = 0xFFFE; - for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) - { - unsigned short ushCode = 0; - if (0x0020 == pUnicodes[unIndex]) - ushCode = ushSpaceCode; - else if (0x000D == pUnicodes[unIndex] || 0x000A == pUnicodes[unIndex]) - ushCode = ushNewLineCode; - - pCodes2[unIndex] = ushCode; - pWidths[unIndex] = ppFonts[unIndex]->GetWidth(pCodes[unIndex]); - } - - m_oLinesManager.Init(pCodes2, pWidths, unLen, ushSpaceCode, ushNewLineCode, pFontTT->GetLineHeight(), pFontTT->GetAscent()); - - // TODO Автоподбор размера шрифта dFontSize - if (!dFontSize) - dFontSize = m_oLinesManager.ProcessAutoFit(dX2 - dX1, (dY2 - dY1 - 3 * dMargin)); - - double dLineHeight = pFontTT->GetLineHeight() * dFontSize / 1000.0; - - m_oLinesManager.CalculateLines(dFontSize, dX2 - dX1); - - pTextWidget->StartAP(m_pFont, dFontSize, 1.0); - - unsigned int unLinesCount = m_oLinesManager.GetLinesCount(); - double dLineShiftY = dY2 - dY1 - pFontTT->GetLineHeight() * dFontSize / 1000.0 - dMargin; - for (unsigned int unIndex = 0; unIndex < unLinesCount; ++unIndex) - { - unsigned int unLineStart = m_oLinesManager.GetLineStartPos(unIndex); - double dLineShiftX = dShiftX; - double dLineWidth = m_oLinesManager.GetLineWidth(unIndex, dFontSize); - if (0 == nAlign) - dLineShiftX += (dX2 - dX1 - dLineWidth); - else if (2 == nAlign) - dLineShiftX += (dX2 - dX1 - dLineWidth) / 2; - - int nInLineCount = m_oLinesManager.GetLineEndPos(unIndex) - m_oLinesManager.GetLineStartPos(unIndex); - if (nInLineCount > 0) - pTextWidget->AddLineToAP(dLineShiftX, dLineShiftY, pCodes + unLineStart, nInLineCount, ppFonts + unLineStart, NULL); - - dLineShiftY -= dLineHeight; - } - - pTextWidget->EndAP(); - - m_oLinesManager.Clear(); - - RELEASEARRAYOBJECTS(pCodes2); - RELEASEARRAYOBJECTS(pWidths); - } - else - { - double* pShifts = NULL; - unsigned int unShiftsCount = 0; - - if (isComb) - { - // TODO для безопасности перевыставить в Ff DoNotScroll=true, DoNotSpellCheck=true, Multiline=false - - unShiftsCount = unLen; - pShifts = new double[unShiftsCount]; - if (pShifts && unShiftsCount) - { - // Сдвиг нулевой для comb форм и не забываем, что мы к ширине добавили 2 * dMargin - dShiftX = 0; - unsigned int unCellsCount = std::max(unShiftsCount, unMaxLen); - double dPrevW = 0; - double dCellW = (dX2 - dX1 + 2 * dMargin) / unCellsCount; - - if (0 == nAlign && unShiftsCount) - dPrevW = (unCellsCount - unShiftsCount) * dCellW; - - for (unsigned int unIndex = 0; unIndex < unShiftsCount; ++unIndex) - { - unsigned short ushCode = pCodes[unIndex]; - double dGlyphWidth = ppFonts[unIndex]->GetGlyphWidth(ushCode) / 1000.0 * dFontSize; - double dTempShift = (dCellW - dGlyphWidth) / 2; - pShifts[unIndex] = dPrevW + dTempShift; - dPrevW = dCellW - dTempShift; - } - } - } - else if (0 == nAlign || 2 == nAlign) - { - double dSumWidth = 0; - for (unsigned int unIndex = 0; unIndex < unLen; ++unIndex) - { - unsigned short ushCode = pCodes[unIndex]; - double dLetterWidth = ppFonts[unIndex]->GetWidth(ushCode) / 1000.0 * dFontSize; - dSumWidth += dLetterWidth; - } - - if (0 == nAlign && dX2 - dX1 - dSumWidth > 0) - dShiftX += dX2 - dX1 - dSumWidth; - else if (2 == nAlign && (dX2 - dX1 - dSumWidth) / 2 > 0) - dShiftX += (dX2 - dX1 - dSumWidth) / 2; - } - - pTextWidget->SetAP(wsValue, pCodes, unLen, m_pFont, {}, 1.0, m_oFont.GetSize(), dShiftX, dBaseLine, ppFonts, pShifts); - RELEASEARRAYOBJECTS(pShifts); - } - - RELEASEARRAYOBJECTS(pUnicodes); - RELEASEARRAYOBJECTS(pCodes); - RELEASEARRAYOBJECTS(ppFonts); + pTextWidget->CreateAP(); } else if (oInfo.IsChoiceWidget()) { diff --git a/PdfFile/SrcWriter/Annotation.cpp b/PdfFile/SrcWriter/Annotation.cpp index 93cdb5b905..b537203f3f 100644 --- a/PdfFile/SrcWriter/Annotation.cpp +++ b/PdfFile/SrcWriter/Annotation.cpp @@ -123,24 +123,6 @@ namespace PdfWriter pArray->Add(dRD3); pArray->Add(dRD4); } - std::string GetColor(const std::vector& arr, bool bCaps) - { - std::string sDA; - for (double dColoc : arr) - { - sDA.append(std::to_string(dColoc)); - sDA.append(" "); - } - if (arr.size() == 3) - sDA.append(bCaps ? "RG" : "rg"); - else if (arr.size() == 4) - sDA.append(bCaps ? "K" : "k"); - else if (arr.size() == 1) - sDA.append(bCaps ? "G" : "g"); - else - sDA.append(bCaps ? "SC" : "sc"); - return sDA; - } //---------------------------------------------------------------------------------------- // CAnnotation @@ -155,8 +137,6 @@ namespace PdfWriter // Для PDFA нужно, чтобы 0, 1, 4 биты были выключены, а второй включен Add("F", 4); - - bHaveBorder = false; } void CAnnotation::SetRect(const TRect& oRect) { @@ -199,7 +179,7 @@ namespace PdfWriter EBorderSubtype eSubtype = EBorderSubtype(nType); if (border_subtype_Dashed == eSubtype) - AddToVectorD(pBorderStyleDict, "D", arrDash); + AddToVectorD(this, "D", arrDash); switch (eSubtype) { @@ -209,9 +189,6 @@ namespace PdfWriter case border_subtype_Inset: pBorderStyleDict->Add("S", "I"); break; case border_subtype_Underlined: pBorderStyleDict->Add("S", "U"); break; } - - bHaveBorder = true; - dBorderWidth = dWidth; } void CAnnotation::SetAnnotFlag(const int& nAnnotFlag) { @@ -272,6 +249,10 @@ namespace PdfWriter CDocument* CAnnotation::GetDocument() { return m_pDocument; + } + void CAnnotation::CreateAP() + { + } //---------------------------------------------------------------------------------------- // CMarkupAnnotation @@ -328,6 +309,10 @@ namespace PdfWriter void CMarkupAnnotation::SetIRTID(CAnnotation* pAnnot) { Add("IRT", pAnnot); + } + void CMarkupAnnotation::CreateAP() + { + } //---------------------------------------------------------------------------------------- // CLinkAnnotation @@ -427,13 +412,13 @@ namespace PdfWriter Add("StateModel", new CStringObject(sValue.c_str())); } - void CTextAnnotation::SetAP() + void CTextAnnotation::CreateAP() { switch (m_nName) { case 3: { - CAnnotAppearanceObject* pAP = new CAnnotAppearanceObject(m_pXref, this); + CAnnotationAppearance* pAP = new CAnnotationAppearance(m_pXref, this); Add("AP", pAP); pAP->DrawTextComment(); @@ -794,7 +779,21 @@ namespace PdfWriter CResourcesDict* pFieldsResources = m_pDocument->GetFieldsResources(); const char* sFontName = pFieldsResources->GetFontName(pFont); - std::string sDA = GetColor(arrTC, false); + std::string sDA; + for (double dColoc : arrTC) + { + sDA.append(std::to_string(dColoc)); + sDA.append(" "); + } + if (arrTC.size() == 3) + sDA.append("rg"); + else if (arrTC.size() == 4) + sDA.append("k"); + else if (arrTC.size() == 1) + sDA.append("g"); + else + sDA.append("sc"); + if (sFontName) { sDA.append(" /"); @@ -895,13 +894,11 @@ namespace PdfWriter { CheckMK(); AddToVectorD(m_pMK, "BC", arrBC); - m_arrBC = arrBC; } void CWidgetAnnotation::SetBG(const std::vector& arrBG) { CheckMK(); AddToVectorD(m_pMK, "BG", arrBG); - m_arrBG = arrBG; } void CWidgetAnnotation::AddAction(CAction* pAction) { @@ -931,14 +928,6 @@ namespace PdfWriter m_pAA->Add(pAction->m_sType.c_str(), pAction); } - std::string CWidgetAnnotation::GetBGforAP() - { - return GetColor(m_arrBG, false); - } - std::string CWidgetAnnotation::GetBCforAP() - { - return GetColor(m_arrBC, true); - } //---------------------------------------------------------------------------------------- // CButtonWidget //---------------------------------------------------------------------------------------- @@ -1119,75 +1108,16 @@ namespace PdfWriter std::string sValue = U_TO_UTF8(wsRV); Add("RV", new CStringObject(sValue.c_str())); } - void CTextWidget::SetAP(const std::wstring& wsValue, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, const TRgb& oColor, const double& dAlpha, double dFontSize, double dX, double dY, CFontCidTrueType** ppFonts, double* pShifts) + void CTextWidget::CreateAP() { - m_pAppearance = new CAnnotAppearance(m_pXref, this); - if (!m_pAppearance) - return; - Add("AP", m_pAppearance); + CAnnotationAppearance* pAPN = new CAnnotationAppearance(m_pXref, this); - CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); - CResourcesDict* pFieldsResources = m_pDocument->GetFieldsResources(); + CDictObject* pAP = new CDictObject(); + pAP->Add("N", pAPN); - const char* sExtGrStateName = NULL; - if (fabs(dAlpha - 1.0) > 0.001) - { - CExtGrState* pExtGrState = m_pDocument->GetFillAlpha(dAlpha); - sExtGrStateName = pFieldsResources->GetExtGrStateName(pExtGrState); - } + Add("AP", pAP); - pNormal->DrawSimpleText(wsValue, pCodes, unCount, pFont, dFontSize, dX, dY, oColor.r, oColor.g, oColor.b, sExtGrStateName, fabs(m_oRect.fRight - m_oRect.fLeft), fabs(m_oRect.fBottom - m_oRect.fTop), ppFonts, pShifts); - } - void CTextWidget::StartAP(CFontDict* pFont, const double& dFontSize, const double& dAlpha) - { - m_pAppearance = new CAnnotAppearance(m_pXref, this); - if (!m_pAppearance) - return; - - Add("AP", m_pAppearance); - - CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); - CResourcesDict* pFieldsResources = m_pDocument->GetFieldsResources(); - - const char* sExtGrStateName = NULL; - if (fabs(dAlpha - 1.0) > 0.001) - { - CExtGrState* pExtGrState = m_pDocument->GetFillAlpha(dAlpha); - sExtGrStateName = pFieldsResources->GetExtGrStateName(pExtGrState); - } - - pNormal->StartDrawText(pFont, dFontSize, 0, 0, 0, sExtGrStateName, fabs(m_oRect.fRight - m_oRect.fLeft), fabs(m_oRect.fBottom - m_oRect.fTop)); - } - void CTextWidget::AddLineToAP(const double& dX, const double& dY, unsigned short* pCodes, const unsigned int& unCodesCount, CFontCidTrueType** ppFonts, const double* pShifts) - { - if (!m_pAppearance) - return; - - CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); - pNormal->DrawTextLine(dX, dY, pCodes, unCodesCount, ppFonts, pShifts); - } - void CTextWidget::EndAP() - { - if (!m_pAppearance) - return; - - CAnnotAppearanceObject* pNormal = m_pAppearance->GetNormal(); - pNormal->EndDrawText(); - } - bool CTextWidget::IsCombFlag() - { - int nFlags = ((CNumberObject*)Get("Ff"))->Get(); - return (nFlags & (1 << 24)); - } - bool CTextWidget::IsMultiLine() - { - int nFlags = ((CNumberObject*)Get("Ff"))->Get(); - return (nFlags & (1 << 12)); - } - int CTextWidget::GetMaxLen() - { - CNumberObject* oMaxLen = m_pParent ? (CNumberObject*)m_pParent->Get("MaxLen") : (CNumberObject*)Get("MaxLen"); - return oMaxLen ? oMaxLen->Get() : 0; + pAPN->DrawTextWidget(); } //---------------------------------------------------------------------------------------- // CChoiceWidget @@ -1244,21 +1174,87 @@ namespace PdfWriter CSignatureWidget::CSignatureWidget(CXref* pXref) : CWidgetAnnotation(pXref, AnnotWidget) { } - /* + //---------------------------------------------------------------------------------------- + // CAnnotationAppearance + //---------------------------------------------------------------------------------------- + CAnnotationAppearance::CAnnotationAppearance(CXref* pXref, CAnnotation* pAnnot) + { + m_pXref = pXref; + m_pStream = new CMemoryStream(); + m_pAnnot = pAnnot; + + SetStream(m_pXref, m_pStream); + + Add("Type", "XObject"); + Add("Subtype", "Form"); + + Add("Resources", pAnnot->GetDocument()->GetFieldsResources()); + } + void CAnnotationAppearance::DrawTextComment() + { + CArrayObject* pArray = new CArrayObject(); + if (!pArray) + return; + + Add("BBox", pArray); + pArray->Add(0); + pArray->Add(0); + pArray->Add(20); + pArray->Add(20); + + m_pStream->WriteStr(""); + } void CAnnotationAppearance::DrawTextWidget() { + CArrayObject* pArray = new CArrayObject(); + if (!pArray) + return; + + TRect oRect = m_pAnnot->GetRect(); + + Add("BBox", pArray); + pArray->Add(0); + pArray->Add(0); + pArray->Add(oRect.fRight - oRect.fLeft); + pArray->Add(oRect.fTop - oRect.fBottom); + CTextWidget* pAnnot = (CTextWidget*)m_pAnnot; + m_pStream->WriteStr("Tx BMC\012"); + // TODO если имеется фоновый цвет + double dBorderSize = 0; + double dBorderSize2 = 0; + // TODO если имеется граница + m_pStream->WriteStr("q\012"); + m_pStream->WriteReal(dBorderSize); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(dBorderSize); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(std::max(oRect.fRight - oRect.fLeft - dBorderSize2, 0.0)); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(std::max(oRect.fTop - oRect.fBottom - dBorderSize2, 0.0)); + m_pStream->WriteStr(" re\012W\012n\012BT\012"); + std::string sFontInfo = pAnnot->GetDAforAP(); + if (sFontInfo.empty()) + { + CDictObject* pOwner = pAnnot->GetObjOwnValue("DA"); + if (pOwner) + { + CStringObject* pDA = dynamic_cast(pOwner->Get("DA")); + if (pDA) + sFontInfo = std::string((const char*)pDA->GetString()); + } + } + if (!sFontInfo.empty()) + m_pStream->WriteStr(sFontInfo.c_str()); // TODO потребуется смещение Y-координаты в зависимости от размеров области и размеров шрифта // TODO требуется запись юникод значений, т.е необходимо писать по глифам - m_pStream->WriteStr(" 2 6.548 Td\012"); - std::string sV = pAnnot->GetV(); - m_pStream->WriteEscapeText((BYTE*)sV.c_str(), sV.length()); - m_pStream->WriteStr(" Tj\012ET\012Q\012EMC\012"); + m_pStream->WriteStr(" 2 6.548 Td ("); + m_pStream->WriteStr(pAnnot->GetV().c_str()); + m_pStream->WriteStr(") Tj ET\012Q\012EMC\012"); } - */ //---------------------------------------------------------------------------------------- // CAction //---------------------------------------------------------------------------------------- diff --git a/PdfFile/SrcWriter/Annotation.h b/PdfFile/SrcWriter/Annotation.h index 73df7c3a51..7785659654 100644 --- a/PdfFile/SrcWriter/Annotation.h +++ b/PdfFile/SrcWriter/Annotation.h @@ -36,12 +36,64 @@ #include "Types.h" #include "Pages.h" #include "Document.h" -#include "Field.h" namespace PdfWriter { class CDestination; + enum EBorderSubtype + { + border_subtype_Solid, + border_subtype_Beveled, + border_subtype_Dashed, + border_subtype_Inset, + border_subtype_Underlined + }; + enum EAnnotType + { + AnnotUnknown = -1, + AnnotText = 0, + AnnotLink = 1, + AnnotSound = 2, + AnnotFreeText = 3, + AnnotStamp = 4, + AnnotSquare = 5, + AnnotCircle = 6, + AnnotStrikeOut = 7, + AnnotHighLight = 8, + AnnotUnderline = 9, + AnnotInk = 10, + AnnotFileAttachment = 11, + AnnotPopup = 12, + AnnotLine = 13, + AnnotSquiggly = 14, + AnnotPolygon = 15, + AnnotPolyLine = 16, + AnnotCaret = 17, + AnnotWidget = 18 + }; + enum EAnnotHighlightMode + { + AnnotNoHighlight = 0, + AnnotInvertBox, + AnnotInvertBorder, + AnnotDownAppearance, + AnnotHighlightModeEOF + }; + enum EAnnotIcon + { + AnnotIconComment = 0, + AnnotIconKey = 1, + AnnotIconNote = 2, + AnnotIconHelp = 3, + AnnotIconNewParagraph = 4, + AnnotIconParagraph = 5, + AnnotIconInsert = 6, + + AnnotIconMin = 0, + AnnotIconMax = 6 + }; + class CAction : public CDictObject { public: @@ -107,9 +159,6 @@ namespace PdfWriter double m_dPageHeight = 0; CDocument* m_pDocument; - bool bHaveBorder; - double dBorderWidth; - public: EDictType GetDictType() const { @@ -134,13 +183,12 @@ namespace PdfWriter void SetNM(const std::wstring& wsNM); void SetLM(const std::wstring& wsLM); void SetC(const std::vector& arrC); - - TRect& GetRect() { return m_oRect; } + // TODO AP Необходимо генерировать внешний вид аннотации как у Widget + virtual void CreateAP(); + TRect GetRect() { return m_oRect; } void SetXref(CXref* pXref) { m_pXref = pXref; } void SetDocument(CDocument* pDocument); CDocument* GetDocument(); - bool HaveBorder() { return bHaveBorder; } - double GetBorderWidth() { return dBorderWidth; } }; class CPopupAnnotation : public CAnnotation { @@ -175,6 +223,7 @@ namespace PdfWriter void SetIRTID(CAnnotation* pAnnot); CPopupAnnotation* CreatePopup(); + virtual void CreateAP() override; }; class CLinkAnnotation : public CAnnotation { @@ -203,7 +252,7 @@ namespace PdfWriter void SetState(BYTE nState); void SetStateModel(BYTE nStateModel); - void SetAP(); + void CreateAP() override; }; class CUriLinkAnnotation : public CAnnotation { @@ -328,9 +377,6 @@ namespace PdfWriter CDictObject* m_pA; std::string m_sDAforAP; - std::vector m_arrBC; - std::vector m_arrBG; - void CheckMK(); public: @@ -353,8 +399,6 @@ namespace PdfWriter void AddAction(CAction* pAction); std::string GetDAforAP() { return m_sDAforAP; } - std::string GetBGforAP(); - std::string GetBCforAP(); }; class CButtonWidget : public CWidgetAnnotation { @@ -390,7 +434,6 @@ namespace PdfWriter private: EAnnotType m_nSubtype; std::string m_sV; - CAnnotAppearance* m_pAppearance; public: CTextWidget(CXref* pXref); @@ -403,14 +446,8 @@ namespace PdfWriter void SetV (const std::wstring& wsV); void SetRV(const std::wstring& wsRV); - void SetAP(const std::wstring& wsValue, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, const TRgb& oColor, const double& dAlpha, double dFontSize, double dX, double dY, CFontCidTrueType** ppFonts, double* pShifts); - void StartAP(CFontDict* pFont, const double& dFontSize, const double& dAlpha); - void AddLineToAP(const double& dX, const double& dY, unsigned short* pCodes, const unsigned int& unCodesCount, CFontCidTrueType** ppFonts = NULL, const double* pShifts = NULL); - void EndAP(); + void CreateAP() override; std::string GetV() { return m_sV; } - bool IsCombFlag(); - bool IsMultiLine(); - int GetMaxLen(); }; class CChoiceWidget : public CWidgetAnnotation { @@ -440,5 +477,19 @@ namespace PdfWriter return m_nSubtype; } }; + + class CAnnotationAppearance : public CDictObject + { + public: + CAnnotationAppearance(CXref* pXref, CAnnotation* pAnnot); + + void DrawTextComment(); + void DrawTextWidget(); + + private: + CXref* m_pXref; + CStream* m_pStream; + CAnnotation* m_pAnnot; + }; } #endif // _PDF_WRITER_SRC_ANNOTATION_H diff --git a/PdfFile/SrcWriter/Field.cpp b/PdfFile/SrcWriter/Field.cpp index 3664f99e9e..fc92c70f86 100644 --- a/PdfFile/SrcWriter/Field.cpp +++ b/PdfFile/SrcWriter/Field.cpp @@ -39,7 +39,6 @@ #include "Font.h" #include "Info.h" #include "EncryptDictionary.h" -#include "Annotation.h" #include #include @@ -1519,7 +1518,6 @@ namespace PdfWriter { m_pXref = pXref; m_pField = pField; - m_pAnnot = NULL; m_pNormal = new CAnnotAppearanceObject(pXref, pField); m_pRollover = NULL; @@ -1527,18 +1525,6 @@ namespace PdfWriter Add("N", m_pNormal); } - CAnnotAppearance::CAnnotAppearance(CXref* pXref, CAnnotation* pAnnot) - { - m_pXref = pXref; - m_pAnnot = pAnnot; - m_pField = NULL; - - m_pNormal = new CAnnotAppearanceObject(pXref, pAnnot); - m_pRollover = NULL; - m_pDown = NULL; - - Add("N", m_pNormal); - } CAnnotAppearanceObject* CAnnotAppearance::GetNormal() { return m_pNormal; @@ -1547,10 +1533,7 @@ namespace PdfWriter { if (!m_pRollover) { - if (m_pField) - m_pRollover = new CAnnotAppearanceObject(m_pXref, m_pField); - else if (m_pAnnot) - m_pRollover = new CAnnotAppearanceObject(m_pXref, m_pAnnot); + m_pRollover = new CAnnotAppearanceObject(m_pXref, m_pField); Add("R", m_pRollover); } @@ -1560,10 +1543,7 @@ namespace PdfWriter { if (!m_pDown) { - if (m_pField) - m_pDown = new CAnnotAppearanceObject(m_pXref, m_pField); - else if (m_pAnnot) - m_pDown = new CAnnotAppearanceObject(m_pXref, m_pAnnot); + m_pDown = new CAnnotAppearanceObject(m_pXref, m_pField); Add("D", m_pDown); } @@ -1611,10 +1591,11 @@ namespace PdfWriter //---------------------------------------------------------------------------------------- // CAnnotAppearanceObject //---------------------------------------------------------------------------------------- - void CAnnotAppearanceObject::Init(CXref* pXref, CResourcesDict* pResources, TRect* pRect) + CAnnotAppearanceObject::CAnnotAppearanceObject(CXref* pXref, CFieldBase* pField) { m_pXref = pXref; m_pStream = new CMemoryStream(); + m_pField = pField; m_pFont = NULL; m_dFontSize = 10.0; @@ -1622,7 +1603,8 @@ namespace PdfWriter Add("Type", "XObject"); Add("Subtype", "Form"); - Add("Resources", pResources); + + TRect oRect = pField->GetRect(); CArrayObject* pArray = new CArrayObject(); if (!pArray) @@ -1631,20 +1613,14 @@ namespace PdfWriter Add("BBox", pArray); pArray->Add(0); pArray->Add(0); - pArray->Add(pRect->fRight - pRect->fLeft); - pArray->Add(pRect->fBottom - pRect->fTop); - } - CAnnotAppearanceObject::CAnnotAppearanceObject(CXref* pXref, CFieldBase* pField) - { - Init(pXref, pField->GetResourcesDict(), &pField->GetRect()); - m_pField = pField; - m_pAnnot = NULL; - } - CAnnotAppearanceObject::CAnnotAppearanceObject(CXref* pXRef, CAnnotation* pAnnot) - { - Init(pXRef, pAnnot->GetDocument()->GetFieldsResources(), &pAnnot->GetRect()); - m_pAnnot = pAnnot; - m_pField = NULL; + pArray->Add(oRect.fRight - oRect.fLeft); + pArray->Add(oRect.fBottom - oRect.fTop); + + Add("Resources", pField->GetResourcesDict()); + +#ifndef FILTER_FLATE_DECODE_DISABLED + //SetFilter(STREAM_FILTER_FLATE_DECODE); +#endif } void CAnnotAppearanceObject::DrawSimpleText(const std::wstring& wsText, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, double dFontSize, double dX, double dY, double dR, double dG, double dB, const char* sExtGStateName, double dWidth, double dHeight, CFontCidTrueType** ppFonts, double* pShifts) { @@ -1770,31 +1746,23 @@ namespace PdfWriter } void CAnnotAppearanceObject::StartDrawText(CFontDict* pFont, const double& dFontSize, const double& dR, const double& dG, const double& dB, const char* sExtGStateName, const double& dWidth, const double& dHeight) { - CResourcesDict* pResources = dynamic_cast(Get("Resources")); + CResourcesDict* pResources = m_pField->GetResourcesDict(); if (!m_pStream || !pFont || !pResources) return; m_pStream->WriteEscapeName("Tx"); m_pStream->WriteStr(" BMC\012"); - if ((m_pField && m_pField->HaveShd()) || (m_pAnnot && m_pAnnot->Get("BG"))) + if (m_pField->HaveShd()) { m_pStream->WriteStr("q\012"); - if (m_pField) - { - TRgb oColor = m_pField->GetShdColor(); - m_pStream->WriteReal(oColor.r); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.g); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.b); - m_pStream->WriteStr(" rg\012"); - } - else - { - CWidgetAnnotation* pAnnot = (CWidgetAnnotation*)m_pAnnot; - m_pStream->WriteStr(pAnnot->GetBGforAP().c_str()); - } + TRgb oColor = m_pField->GetShdColor(); + m_pStream->WriteReal(oColor.r); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.g); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.b); + m_pStream->WriteStr(" rg\012"); m_pStream->WriteStr("1 0 0 1 0 0 cm\012"); m_pStream->WriteStr("0 0 "); @@ -1808,27 +1776,19 @@ namespace PdfWriter double dBorderSize = 0; double dBorderSize_2 = 0; double dBorderSize2 = 0; - if ((m_pField && m_pField->HaveBorder()) || (m_pAnnot && m_pAnnot->HaveBorder())) + if (m_pField && m_pField->HaveBorder()) { + TRgb oColor = m_pField->GetBorderColor(); m_pStream->WriteStr("q\012"); - if (m_pField) - { - TRgb oColor = m_pField->GetBorderColor(); - m_pStream->WriteReal(oColor.r); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.g); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(oColor.b); - m_pStream->WriteStr(" RG\012"); - } - else - { - CWidgetAnnotation* pAnnot = (CWidgetAnnotation*)m_pAnnot; - m_pStream->WriteStr(pAnnot->GetBCforAP().c_str()); - } + m_pStream->WriteReal(oColor.r); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.g); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(oColor.b); + m_pStream->WriteStr(" RG\012"); - dBorderSize = m_pField ? m_pField->GetBorderSize() : m_pAnnot->GetBorderWidth(); + dBorderSize = m_pField->GetBorderSize(); dBorderSize_2 = dBorderSize / 2; dBorderSize2 = dBorderSize * 2; m_pStream->WriteReal(dBorderSize); @@ -1844,10 +1804,9 @@ namespace PdfWriter m_pStream->WriteStr(" re\012S\012"); CTextField* pTextField = dynamic_cast(m_pField); - CTextWidget* pAnnot = dynamic_cast(m_pAnnot); - if ((pTextField && pTextField->IsCombFlag()) || (pAnnot && pAnnot->IsCombFlag())) + if (pTextField && pTextField->IsCombFlag()) { - int nMaxLen = pTextField ? pTextField->GetMaxLen() : pAnnot->GetMaxLen(); + int nMaxLen = pTextField->GetMaxLen(); if (nMaxLen > 1) { double dStep = dWidth / nMaxLen; @@ -1886,52 +1845,33 @@ namespace PdfWriter m_pStream->WriteStr("BT\012"); - m_dFontSize = std::min(1000.0, std::max(0.0, dFontSize)); - if (m_pField) + m_pStream->WriteReal(dR); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(dG); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(dB); + m_pStream->WriteStr(" rg\012"); + + if (sExtGStateName) { - m_pStream->WriteReal(dR); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(dG); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(dB); - m_pStream->WriteStr(" rg\012"); - - if (sExtGStateName) - { - m_pStream->WriteEscapeName(sExtGStateName); - m_pStream->WriteStr(" gs\012"); - } - - m_pStream->WriteEscapeName(pResources->GetFontName(pFont)); - m_pStream->WriteChar(' '); - m_pStream->WriteReal(m_dFontSize); - m_pStream->WriteStr(" Tf\012"); - } - else - { - CWidgetAnnotation* pAnnot = (CWidgetAnnotation*)m_pAnnot; - - std::string sFontInfo = pAnnot->GetDAforAP(); - if (sFontInfo.empty()) - { - CDictObject* pOwner = pAnnot->GetObjOwnValue("DA"); - if (pOwner) - { - CStringObject* pDA = dynamic_cast(pOwner->Get("DA")); - if (pDA) - sFontInfo = std::string((const char*)pDA->GetString()); - } - } - if (!sFontInfo.empty()) - m_pStream->WriteStr(sFontInfo.c_str()); + m_pStream->WriteEscapeName(sExtGStateName); + m_pStream->WriteStr(" gs\012"); } - m_bStart = true; - m_pFont = pFont; + double _dFontSize = std::min(1000.0, std::max(0.0, dFontSize)); + + m_pStream->WriteEscapeName(pResources->GetFontName(pFont)); + m_pStream->WriteChar(' '); + m_pStream->WriteReal(_dFontSize); + m_pStream->WriteStr(" Tf\012"); + + m_bStart = true; + m_pFont = pFont; + m_dFontSize = _dFontSize; } void CAnnotAppearanceObject::DrawTextLine(const double& dX, const double& dY, const unsigned short* pCodes, const unsigned int& unCount, CFontCidTrueType** ppFonts, const double* pShifts) { - CResourcesDict* pResources = dynamic_cast(Get("Resources")); + CResourcesDict* pResources = m_pField->GetResourcesDict(); if (!pResources) return; @@ -2054,18 +1994,4 @@ namespace PdfWriter m_pStream->WriteStr("ET\012"); m_pStream->WriteStr("Q\012EMC\012"); } - void CAnnotAppearanceObject::DrawTextComment() - { - CArrayObject* pArray = new CArrayObject(); - if (!pArray) - return; - - Add("BBox", pArray); - pArray->Add(0); - pArray->Add(0); - pArray->Add(20); - pArray->Add(20); - - m_pStream->WriteStr(""); - } } diff --git a/PdfFile/SrcWriter/Field.h b/PdfFile/SrcWriter/Field.h index de1de2f5ed..a3366d672a 100644 --- a/PdfFile/SrcWriter/Field.h +++ b/PdfFile/SrcWriter/Field.h @@ -34,6 +34,7 @@ #include "Objects.h" #include "Types.h" +#include "Annotation.h" #include "../../DesktopEditor/graphics/commands/FormField.h" namespace PdfWriter @@ -48,60 +49,6 @@ namespace PdfWriter class CImageDict; class CFontCidTrueType; class CSignatureDict; - class CAnnotation; - - enum EBorderSubtype - { - border_subtype_Solid, - border_subtype_Beveled, - border_subtype_Dashed, - border_subtype_Inset, - border_subtype_Underlined - }; - enum EAnnotType - { - AnnotUnknown = -1, - AnnotText = 0, - AnnotLink = 1, - AnnotSound = 2, - AnnotFreeText = 3, - AnnotStamp = 4, - AnnotSquare = 5, - AnnotCircle = 6, - AnnotStrikeOut = 7, - AnnotHighLight = 8, - AnnotUnderline = 9, - AnnotInk = 10, - AnnotFileAttachment = 11, - AnnotPopup = 12, - AnnotLine = 13, - AnnotSquiggly = 14, - AnnotPolygon = 15, - AnnotPolyLine = 16, - AnnotCaret = 17, - AnnotWidget = 18 - }; - enum EAnnotHighlightMode - { - AnnotNoHighlight = 0, - AnnotInvertBox, - AnnotInvertBorder, - AnnotDownAppearance, - AnnotHighlightModeEOF - }; - enum EAnnotIcon - { - AnnotIconComment = 0, - AnnotIconKey = 1, - AnnotIconNote = 2, - AnnotIconHelp = 3, - AnnotIconNewParagraph = 4, - AnnotIconParagraph = 5, - AnnotIconInsert = 6, - - AnnotIconMin = 0, - AnnotIconMax = 6 - }; class CFieldBase : public CDictObject { @@ -330,8 +277,7 @@ namespace PdfWriter class CAnnotAppearance : public CDictObject { public: - CAnnotAppearance(CXref* pXRef, CFieldBase* pField); - CAnnotAppearance(CXref* pXRef, CAnnotation* pAnnot); + CAnnotAppearance(CXref* pXRef, CFieldBase* pField); CAnnotAppearanceObject* GetNormal(); CAnnotAppearanceObject* GetRollover(); @@ -344,7 +290,6 @@ namespace PdfWriter CAnnotAppearanceObject* m_pRollover; CAnnotAppearanceObject* m_pDown; CFieldBase* m_pField; - CAnnotation* m_pAnnot; }; class CCheckBoxAnnotAppearance : public CDictObject @@ -370,8 +315,7 @@ namespace PdfWriter class CAnnotAppearanceObject : public CDictObject { public: - CAnnotAppearanceObject(CXref* pXRef, CFieldBase* pField); - CAnnotAppearanceObject(CXref* pXRef, CAnnotation* pAnnot); + CAnnotAppearanceObject(CXref* pXRef, CFieldBase* pField); void DrawSimpleText(const std::wstring& wsText, unsigned short* pCodes, unsigned int unCount, CFontDict* pFont, double dFontSize = 10.0, double dX = 0.0, double dY = 0.0, double dR = 0.0, double dG = 0.0, double dB = 0.0, const char* sExtGrStateName = NULL, double dW = 1.0, double dH = 1.0, CFontCidTrueType** ppFonts = NULL, double* pShifts = NULL); void DrawPicture(const char* sImageName = NULL, const double& dX = 0.0, const double& dY = 0.0, const double& dW = 0.0, const double& dH = 0.0, const bool& bRespectBorder = false); void StartDrawText(CFontDict* pFont, const double& dFontSize, const double& dR, const double& dG, const double& dB, const char* sExtGStateName, const double& dWidth, const double& dHeight); @@ -379,10 +323,7 @@ namespace PdfWriter void DrawTextLine(const double &dX, const double &dY, const std::wstring& wsText); void EndDrawText(); - void DrawTextComment(); - private: - void Init(CXref* pXref, CResourcesDict* pResources, TRect* pRect); CXref* m_pXref; CStream* m_pStream; @@ -392,8 +333,6 @@ namespace PdfWriter bool m_bStart; CFontDict* m_pFont; double m_dFontSize; - - CAnnotation* m_pAnnot; }; } From 3ae6927ac33c2388e60cb88620ef70747fdb923e Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 23 Nov 2023 16:25:21 +0400 Subject: [PATCH 24/54] Reworked CValue, added CValueRef --- DesktopEditor/doctrenderer/json/json.cpp | 539 ++++++++++-------- DesktopEditor/doctrenderer/json/json.h | 150 +++-- DesktopEditor/doctrenderer/json/json_p.h | 25 +- DesktopEditor/doctrenderer/test/json/main.cpp | 13 +- 4 files changed, 407 insertions(+), 320 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index e70d630197..0f38193fca 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -8,41 +8,261 @@ namespace NSJSON { } - CTypedValueContainer::CTypedValueContainer() : m_typedValue(new CTypedValue()), m_isReference(false) + CTypedValue::CTypedValue(IBaseValue* value, ValueType type) : m_value(value), m_type(type) { } - CTypedValueContainer::CTypedValueContainer(const CTypedValueContainer& other) : CTypedValueContainer() - { - *this = other; - } - - CTypedValueContainer& CTypedValueContainer::operator=(const CTypedValueContainer& other) - { - if (other.m_isReference) - { - // set pointer to the other's typed value - m_typedValue = other.m_typedValue; - } - else - { - // copy typed value without changing pointer to it - *m_typedValue = *other.m_typedValue; - } - return *this; - } - - CValue::CValue() : m_internal(new CTypedValueContainer()) + CTypedValue::~CTypedValue() { } - CValue::CValue(const CValue& other) : m_internal(new CTypedValueContainer(*other.m_internal)) + + IValue::IValue() : m_internal(new CTypedValue()) + { + } + + IValue::IValue(const std::shared_ptr& internal) : m_internal(internal) + { + } + + IValue::~IValue() + { + } + + bool IValue::IsUndefined() const + { + return m_internal->m_type == CTypedValue::vtUndefined; + } + + bool IValue::IsNull() const + { + return m_internal->m_type == CTypedValue::vtNull; + } + + bool IValue::IsBool() const + { + return (m_internal->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_value.get())->isBool()); + } + + bool IValue::IsInt() const + { + return (m_internal->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_value.get())->isInt()); + } + + bool IValue::IsDouble() const + { + return (m_internal->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_value.get())->isDouble()); + } + + bool IValue::IsStringA() const + { + return (m_internal->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_value.get())->isStringA()); + } + + bool IValue::IsStringW() const + { + return (m_internal->m_type == CTypedValue::vtPrimitive && + static_cast(m_internal->m_value.get())->isStringW()); + } + + bool IValue::IsArray() const + { + return m_internal->m_type == CTypedValue::vtArray; + } + + bool IValue::IsTypedArray() const + { + return m_internal->m_type == CTypedValue::vtTypedArray; + } + + bool IValue::IsObject() const + { + return m_internal->m_type == CTypedValue::vtObject; + } + + bool IValue::ToBool() const + { + if (m_internal->m_type != CTypedValue::vtPrimitive) + return false; + return static_cast(m_internal->m_value.get())->toBool(); + } + + int IValue::ToInt() const + { + if (m_internal->m_type != CTypedValue::vtPrimitive) + return 0; + return static_cast(m_internal->m_value.get())->toInt(); + } + + double IValue::ToDouble() const + { + if (m_internal->m_type != CTypedValue::vtPrimitive) + return 0.0; + return static_cast(m_internal->m_value.get())->toDouble(); + } + + std::string IValue::ToStringA() const + { + if (m_internal->m_type != CTypedValue::vtPrimitive) + return ""; + return static_cast(m_internal->m_value.get())->toStringA(); + } + + std::wstring IValue::ToStringW() const + { + if (m_internal->m_type != CTypedValue::vtPrimitive) + return L""; + return static_cast(m_internal->m_value.get())->toStringW(); + } + + IValue::operator bool() const + { + return ToBool(); + } + + IValue::operator int() const + { + return ToInt(); + } + + IValue::operator double() const + { + return ToDouble(); + } + + IValue::operator std::string() const + { + return ToStringA(); + } + + IValue::operator std::wstring() const + { + return ToStringW(); + } + + IValue::IValue(bool value) : m_internal(new CTypedValue(new CPrimitive(value), CTypedValue::vtPrimitive)) + { + } + + IValue::IValue(int value) : m_internal(new CTypedValue(new CPrimitive(value), CTypedValue::vtPrimitive)) + { + } + + IValue::IValue(double value) : m_internal(new CTypedValue(new CPrimitive(value), CTypedValue::vtPrimitive)) + { + } + + IValue::IValue(const char* value) : m_internal(new CTypedValue(new CPrimitive(std::string(value)), CTypedValue::vtPrimitive)) + { + } + + IValue::IValue(const std::string& value) : m_internal(new CTypedValue(new CPrimitive(value), CTypedValue::vtPrimitive)) + { + } + + IValue::IValue(const wchar_t* value) : m_internal(new CTypedValue(new CPrimitive(std::wstring(value)), CTypedValue::vtPrimitive)) + { + } + + IValue::IValue(const std::wstring& value) : m_internal(new CTypedValue(new CPrimitive(value), CTypedValue::vtPrimitive)) + { + } + + int IValue::GetCount() const + { + if (m_internal->m_type != CTypedValue::vtArray) + return 0; + return static_cast(m_internal->m_value.get())->getCount(); + } + + const CValueRef IValue::Get(int index) const + { + if (m_internal->m_type != CTypedValue::vtArray) + return CValue(); + if (index < 0 || index >= GetCount()) + return CValue(); + return static_cast(m_internal->m_value.get())->get(index); + } + + CValueRef IValue::Get(int index) + { + return static_cast(*this).Get(index); + } + + const CValueRef IValue::operator[](int index) const + { + return Get(index); + } + + CValueRef IValue::operator[](int index) + { + return Get(index); + } + + IValue::IValue(std::initializer_list elements) : m_internal(new CTypedValue(new CArray(elements), CTypedValue::vtArray)) + { + } + + const BYTE* IValue::GetData() const + { + if (m_internal->m_type != CTypedValue::vtTypedArray) + return nullptr; + return static_cast(m_internal->m_value.get())->getData(); + } + + BYTE* IValue::GetData() + { + return const_cast(static_cast(*this).GetData()); + } + + const CValueRef IValue::Get(const char* name) const + { + if (m_internal->m_type != CTypedValue::vtObject) + return CValue(); + return static_cast(m_internal->m_value.get())->get(name); + } + + CValueRef IValue::Get(const char* name) + { + return static_cast(*this).Get(name); + } + + const CValueRef IValue::operator[](const char* name) const + { + return Get(name); + } + + CValueRef IValue::operator[](const char* name) + { + return Get(name); + } + + std::vector IValue::GetPropertyNames() const + { + if (m_internal->m_type != CTypedValue::vtObject) + return {}; + return static_cast(m_internal->m_value.get())->getPropertyNames(); + } + + + CValue::CValue() : IValue() + { + } + + CValue::CValue(const CValue& other) : IValue(std::make_shared(*other.m_internal)) + { + } + + CValue::CValue(const CValueRef& ref) : IValue(std::make_shared(*ref.m_internal)) { } CValue::~CValue() { - delete m_internal; } CValue& CValue::operator=(const CValue& other) @@ -51,225 +271,52 @@ namespace NSJSON return *this; } - bool CValue::IsUndefined() const + CValue& CValue::operator=(const CValueRef& ref) { - return m_internal->m_typedValue->m_type == CTypedValue::vtUndefined; + *m_internal = *ref.m_internal; + return *this; } - bool CValue::IsNull() const + CValue::CValue(bool value) : IValue(value) { - return m_internal->m_typedValue->m_type == CTypedValue::vtNull; } - bool CValue::IsBool() const + CValue::CValue(int value) : IValue(value) { - return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && - static_cast(m_internal->m_typedValue->m_value.get())->isBool()); } - bool CValue::IsInt() const + CValue::CValue(double value) : IValue(value) { - return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && - static_cast(m_internal->m_typedValue->m_value.get())->isInt()); } - bool CValue::IsDouble() const + CValue::CValue(const char* value) : IValue(value) { - return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && - static_cast(m_internal->m_typedValue->m_value.get())->isDouble()); } - bool CValue::IsStringA() const + CValue::CValue(const std::string& value) : IValue(value) { - return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && - static_cast(m_internal->m_typedValue->m_value.get())->isStringA()); } - bool CValue::IsStringW() const + CValue::CValue(const wchar_t* value) : IValue(value) { - return (m_internal->m_typedValue->m_type == CTypedValue::vtPrimitive && - static_cast(m_internal->m_typedValue->m_value.get())->isStringW()); } - bool CValue::IsArray() const + CValue::CValue(const std::wstring& value) : IValue(value) { - return m_internal->m_typedValue->m_type == CTypedValue::vtArray; } - bool CValue::IsTypedArray() const + CValue::CValue(std::initializer_list elements) : IValue(elements) { - return m_internal->m_typedValue->m_type == CTypedValue::vtTypedArray; - } - - bool CValue::IsObject() const - { - return m_internal->m_typedValue->m_type == CTypedValue::vtObject; - } - - bool CValue::ToBool() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) - return false; - return static_cast(m_internal->m_typedValue->m_value.get())->toBool(); - } - - int CValue::ToInt() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) - return 0; - return static_cast(m_internal->m_typedValue->m_value.get())->toInt(); - } - - double CValue::ToDouble() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) - return 0.0; - return static_cast(m_internal->m_typedValue->m_value.get())->toDouble(); - } - - std::string CValue::ToStringA() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) - return ""; - return static_cast(m_internal->m_typedValue->m_value.get())->toStringA(); - } - - std::wstring CValue::ToStringW() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtPrimitive) - return L""; - return static_cast(m_internal->m_typedValue->m_value.get())->toStringW(); - } - - CValue::operator bool() const - { - return ToBool(); - } - - CValue::operator int() const - { - return ToInt(); - } - - CValue::operator double() const - { - return ToDouble(); - } - - CValue::operator std::string() const - { - return ToStringA(); - } - - CValue::operator std::wstring() const - { - return ToStringW(); - } - - CValue::CValue(bool value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(value); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - CValue::CValue(int value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(value); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - CValue::CValue(double value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(value); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - CValue::CValue(const char* value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(std::string(value)); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - CValue::CValue(const std::string& value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(value); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - CValue::CValue(const wchar_t* value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(std::wstring(value)); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - CValue::CValue(const std::wstring& value) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(value); - m_internal->m_typedValue->m_type = CTypedValue::vtPrimitive; - } - - int CValue::GetCount() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtArray) - return 0; - return static_cast(m_internal->m_typedValue->m_value.get())->getCount(); - } - - const CValue CValue::Get(int index) const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtArray) - return CValue(); - // don't set reference mode, because this is a const method - return static_cast(m_internal->m_typedValue->m_value.get())->get(index); - } - - CValue CValue::Get(int index) - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtArray) - return CValue(); - CValue& value = static_cast(m_internal->m_typedValue->m_value.get())->get(index); - value.m_internal->m_isReference = true; - return value; - } - - const CValue CValue::operator[](int index) const - { - return Get(index); - } - - CValue CValue::operator[](int index) - { - CValue ret = Get(index); - ret.m_internal->m_isReference = true; - return ret; - } - - CValue::CValue(std::initializer_list elements) : CValue() - { - m_internal->m_typedValue->m_value = std::make_shared(elements); - m_internal->m_typedValue->m_type = CTypedValue::vtArray; } CValue CValue::CreateArray(int count) { CValue ret; - ret.m_internal->m_typedValue->m_value = std::make_shared(count); - ret.m_internal->m_typedValue->m_type = CTypedValue::vtArray; + ret.m_internal->m_value = std::make_shared(count); + ret.m_internal->m_type = CTypedValue::vtArray; return ret; } - const BYTE* CValue::GetData() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtTypedArray) - return nullptr; - return static_cast(m_internal->m_typedValue->m_value.get())->getData(); - } - - BYTE* CValue::GetData() - { - return const_cast(static_cast(*this).GetData()); - } - CValue CValue::CreateTypedArray(BYTE* data, int count, bool isExternalize) { // TODO: @@ -287,47 +334,11 @@ namespace NSJSON // TODO: } - const CValue CValue::Get(const char* name) const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtObject) - return CValue(); - // don't set reference mode, because this is a const method - return static_cast(m_internal->m_typedValue->m_value.get())->get(name); - } - - CValue CValue::Get(const char* name) - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtObject) - return CValue(); - CValue& value = static_cast(m_internal->m_typedValue->m_value.get())->get(name); - value.m_internal->m_isReference = true; - return value; - } - - const CValue CValue::operator[](const char* name) const - { - return Get(name); - } - - CValue CValue::operator[](const char* name) - { - CValue ret = Get(name); - ret.m_internal->m_isReference = true; - return ret; - } - - std::vector CValue::GetPropertyNames() const - { - if (m_internal->m_typedValue->m_type != CTypedValue::vtObject) - return {}; - return static_cast(m_internal->m_typedValue->m_value.get())->getPropertyNames(); - } - CValue CValue::CreateObject() { CValue ret; - ret.m_internal->m_typedValue->m_value = std::make_shared(); - ret.m_internal->m_typedValue->m_type = CTypedValue::vtObject; + ret.m_internal->m_value = std::make_shared(); + ret.m_internal->m_type = CTypedValue::vtObject; return ret; } @@ -339,7 +350,37 @@ namespace NSJSON CValue CValue::CreateNull() { CValue ret; - ret.m_internal->m_typedValue->m_type = CTypedValue::vtNull; + ret.m_internal->m_type = CTypedValue::vtNull; return ret; } + + CValueRef::CValueRef() : IValue() + { + } + + CValueRef::CValueRef(const CValueRef& other) : IValue(other.m_internal) + { + } + + CValueRef::CValueRef(const CValue& value) : IValue(value.m_internal) + { + } + + CValueRef::~CValueRef() + { + } + + CValueRef& CValueRef::operator=(const CValueRef& other) + { + // not reassign the pointer, but copy its content! + *m_internal = *other.m_internal; + return *this; + } + + CValueRef& CValueRef::operator=(const CValue& value) + { + // not reassign the pointer, but copy its content! + *m_internal = *value.m_internal; + return *this; + } } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 47c79b7274..0535ea746d 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -2,6 +2,7 @@ #define JSON_H_ #include +#include #include #include @@ -20,17 +21,21 @@ namespace NSJSON { typedef unsigned char BYTE; - class CTypedValueContainer; - // Main class for storing values. + class CValue; + class CValueRef; + class CTypedValue; + // Main value interface. // This class provide interface to work with each type of values. - class JSON_DECL CValue + class JSON_DECL IValue { - public: - CValue(); - CValue(const CValue& other); - ~CValue(); + protected: + IValue(); + IValue(const std::shared_ptr& internal); + virtual ~IValue(); - CValue& operator=(const CValue& other); + // Disable copy for this class (implemented in heirs) + IValue(const IValue& other) = delete; + IValue& operator=(const IValue& other) = delete; public: // TYPE CHECKS @@ -109,15 +114,17 @@ namespace NSJSON operator std::string() const; operator std::wstring() const; + protected: // Creates a value from primitive types - CValue(bool value); - CValue(int value); - CValue(double value); - CValue(const char* value); - CValue(const std::string& value); - CValue(const wchar_t* value); - CValue(const std::wstring& value); + IValue(bool value); + IValue(int value); + IValue(double value); + IValue(const char* value); + IValue(const std::string& value); + IValue(const wchar_t* value); + IValue(const std::wstring& value); + public: // FUNCTIONS FOR WORKING WITH ARRAYS /** * Gets lengths of the array/typed array. @@ -130,13 +137,71 @@ namespace NSJSON * @param index The index of the array value. * @returns the value in the array. If current value is not an array, returns undefined value. */ - const CValue Get(int index) const; - CValue Get(int index); + const CValueRef Get(int index) const; + CValueRef Get(int index); // operators [] works the same way as Get(index) - const CValue operator[](int index) const; - CValue operator[](int index); + const CValueRef operator[](int index) const; + CValueRef operator[](int index); + protected: + // create array from initializer list + IValue(std::initializer_list elements); + + public: + // FUNCTIONS FOR WORKING WITH TYPED ARRAYS + /** + * Gets data of typed array. + * @return the pointer to memory, allocated for this typed array. If current value is not a typed array, returns nullptr. + */ + const BYTE* GetData() const; + BYTE* GetData(); + + // FUNCTIONS FOR WORKING WITH OBJECTS + /** + * Gets a property of this object. + * @param name The name of the property. + * @returns the value of the object's property. If current value is not an object, returns undefined value. + */ + const CValueRef Get(const char* name) const; + CValueRef Get(const char* name); + + // operators [] works the same way as Get(name) + const CValueRef operator[](const char* name) const; + CValueRef operator[](const char* name); + + /** + * Retrieves all property names from current object. + * @returns a vector containing the names of the properties of this object as strings. If current value is not an object, returns an empty vector. + */ + std::vector GetPropertyNames() const; + + protected: + std::shared_ptr m_internal; + }; + + // Main value implementation + class JSON_DECL CValue : public IValue + { + public: + CValue(); + CValue(const CValue& other); + CValue(const CValueRef& ref); + ~CValue(); + + CValue& operator=(const CValue& other); + CValue& operator=(const CValueRef& ref); + + // PRIMITIVES CONSTRUCTORS + CValue(bool value); + CValue(int value); + CValue(double value); + CValue(const char* value); + CValue(const std::string& value); + CValue(const wchar_t* value); + CValue(const std::wstring& value); + + // ARRAY CONSTRUCTORS /** * Creates an array with initializer list syntax (CValue arr = {1, 2, 3}). * @param elements The elements of an array as an std::initializer_list. @@ -148,14 +213,7 @@ namespace NSJSON */ static CValue CreateArray(int count); - // FUNCTIONS FOR WORKING WITH TYPED ARRAYS - /** - * Gets data of typed array. - * @return the pointer to memory, allocated for this typed array. If current value is not a typed array, returns nullptr. - */ - const BYTE* GetData() const; - BYTE* GetData(); - + // TYPED ARRAY /** * Creates and returns new typed array. * @param data The pointer to binary data. The pointer should be acquired with AllocTypedArray()! @@ -176,25 +234,7 @@ namespace NSJSON */ static void FreeTypedArray(BYTE* data, size_t size); - // FUNCTIONS FOR WORKING WITH OBJECTS - /** - * Gets a property of this object. - * @param name The name of the property. - * @returns the value of the object's property. If current value is not an object, returns undefined value. - */ - const CValue Get(const char* name) const; - CValue Get(const char* name); - - // operators [] works the same way as Get(name) - const CValue operator[](const char* name) const; - CValue operator[](const char* name); - - /** - * Retrieves all property names from current object. - * @returns a vector containing the names of the properties of this object as strings. If current value is not an object, returns an empty vector. - */ - std::vector GetPropertyNames() const; - + // OBJECT CONSTRUCTOR /** * Creates and returns empty object. */ @@ -210,8 +250,22 @@ namespace NSJSON */ static CValue CreateNull(); - private: - CTypedValueContainer* m_internal; + friend class CValueRef; + }; + + // Main value reference implementation + class JSON_DECL CValueRef : public IValue + { + public: + CValueRef(); + CValueRef(const CValueRef& other); + CValueRef(const CValue& value); + ~CValueRef(); + + CValueRef& operator=(const CValueRef& other); + CValueRef& operator=(const CValue& value); + + friend class CValue; }; } diff --git a/DesktopEditor/doctrenderer/json/json_p.h b/DesktopEditor/doctrenderer/json/json_p.h index aaa8fc040a..0198a402d0 100644 --- a/DesktopEditor/doctrenderer/json/json_p.h +++ b/DesktopEditor/doctrenderer/json/json_p.h @@ -22,31 +22,16 @@ namespace NSJSON public: CTypedValue(); + CTypedValue(IBaseValue* value, ValueType type); + ~CTypedValue(); + // default copy behaviour + CTypedValue(const CTypedValue& other) = default; + CTypedValue& operator=(const CTypedValue& other) = default; public: std::shared_ptr m_value; ValueType m_type; }; - - // Container for CTypedValue which is also allows to treat typed value as reference - class CTypedValueContainer - { - public: - CTypedValueContainer(); - CTypedValueContainer(const CTypedValueContainer& other); - - CTypedValueContainer& operator=(const CTypedValueContainer& other); - - public: - std::shared_ptr m_typedValue; - /* We need some sort of "reference mode" for values, returned from arrays (with CValue::Get(int)) - * and from objects (with CValue::Get(const char*)), because they should not be simply the COPY of that values, but - * instead they should be some sort of REFERENCES to original values, that are stored in array or object. - * That is because we want to be able to change them. - * m_isReference is TRUE for that type of values. For all the rest it is FALSE. - */ - bool m_isReference; - }; } #endif // JSON_PRIVATE_H_ diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 8027f47e0a..0073b53a9a 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -51,11 +51,18 @@ int main() colorRGBA["rgb"] = colorRGB; colorRGBA["alpha"] = 80; - textPr["size"] = 4.2; - // CValue behaves as reference, when it was initialized with value returned from Get() (or operator[]) of objects & arrays. - CValue name = textPr["name"]; + // CValueRef behaves as reference + CValueRef name = textPr["name"]; // from now on, name - is a reference to the property "name" of textPr. Changing it will affect this object property: name = "Foo"; + // Also you can chain references + CValueRef name3 = name; + name3 = "FooBar"; // this change applies to textPr["name"] + // The same but with CValue wouldnt' work: + CValue name2 = textPr["name"]; + name2 = "Bar"; // this change doesn't affect the property "name" of textPr + + textPr["size"] = 4.2; textPr["color"] = colorRGBA; textPr["font"] = CValue::CreateObject(); textPr["font"]["fontName"] = L"Times New Roman"; From fe6590366df9eba3e530a15f2fd098ee50acbfaf Mon Sep 17 00:00:00 2001 From: Kirill Polyakov Date: Thu, 23 Nov 2023 16:32:27 +0300 Subject: [PATCH 25/54] Added implementation of graphic layers --- DesktopEditor/graphics/Graphics.cpp | 114 +++++++++++++++++++- DesktopEditor/graphics/Graphics.h | 13 +++ DesktopEditor/graphics/GraphicsLayer.cpp | 50 +++++++++ DesktopEditor/graphics/GraphicsLayer.h | 80 ++++++++++++++ DesktopEditor/graphics/GraphicsRenderer.cpp | 15 +++ DesktopEditor/graphics/GraphicsRenderer.h | 3 + DesktopEditor/graphics/IRenderer.h | 2 + DesktopEditor/graphics/pro/Graphics.h | 3 + DesktopEditor/graphics/pro/graphics.pro | 7 ++ 9 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 DesktopEditor/graphics/GraphicsLayer.cpp create mode 100644 DesktopEditor/graphics/GraphicsLayer.h diff --git a/DesktopEditor/graphics/Graphics.cpp b/DesktopEditor/graphics/Graphics.cpp index 769310a6d6..48c685f300 100644 --- a/DesktopEditor/graphics/Graphics.cpp +++ b/DesktopEditor/graphics/Graphics.cpp @@ -105,7 +105,9 @@ namespace Aggplus #endif m_dDpiTile = -1; - + + m_pAlphaMask = NULL; + m_nTextRenderMode = FT_RENDER_MODE_NORMAL; m_nBlendMode = agg::comp_op_src_over; @@ -146,7 +148,9 @@ namespace Aggplus #endif m_dDpiTile = -1; - + + m_pAlphaMask = NULL; + m_nTextRenderMode = FT_RENDER_MODE_NORMAL; m_nBlendMode = agg::comp_op_src_over; @@ -161,6 +165,12 @@ namespace Aggplus #endif RELEASEINTERFACE(m_pAlphaMask); + + while (!m_arLayers.empty()) + { + RELEASEINTERFACE(m_arLayers.top()); + m_arLayers.pop(); + } } INT CGraphics::IsDib() @@ -1242,6 +1252,106 @@ namespace Aggplus m_pAlphaMask->m_internal->StartApplying(); return Ok; } + + Status CGraphics::AddLayer(CGraphicsLayer *pGraphicsLayer) + { + if (NULL == pGraphicsLayer || pGraphicsLayer->Empty()) + return InvalidParameter; + + m_arLayers.push(pGraphicsLayer); + pGraphicsLayer->AddRef(); + + int nStride = m_frame_buffer.ren_buf().stride(); + const unsigned int unWidth = m_frame_buffer.ren_buf().width(); + const unsigned int unHeight = m_frame_buffer.ren_buf().height(); + + m_frame_buffer.create(unWidth, unHeight, false, nStride, pGraphicsLayer->GetBuffer()); + + return Ok; + } + + Status CGraphics::CreateLayer() + { + int nStride = m_frame_buffer.ren_buf().stride(); + const unsigned int unWidth = m_frame_buffer.ren_buf().width(); + const unsigned int unHeight = m_frame_buffer.ren_buf().height(); + + BYTE *pBuffer = new BYTE[unWidth * unHeight * m_frame_buffer.pix_size]; + + for (unsigned long unIndex = 0; unIndex < unWidth * unHeight * m_frame_buffer.pix_size; unIndex += 4) + ((BYTE*)pBuffer)[unIndex + pixfmt_type::order_type::A] = 0x00; + + m_frame_buffer.create(unWidth, unHeight, false, nStride, pBuffer); + + m_arLayers.push(new CGraphicsLayer(pBuffer, false)); + return Ok; + } + + Status CGraphics::BlendLayer() + { + if (m_arLayers.empty()) + return WrongState; + + CGraphicsLayer *pCurrentGraphicsLayer = m_arLayers.top(); + m_arLayers.pop(); + + BYTE* pBuffer = NULL; + + if (!m_arLayers.empty()) + pBuffer = m_arLayers.top()->GetBuffer(); + else + pBuffer = m_pPixels; + + if (NULL == pBuffer) + { + RELEASEINTERFACE(pCurrentGraphicsLayer); + return WrongState; + } + + agg::rendering_buffer *pRenBuffer = &GetRenderingBuffer(); + + pRenBuffer->attach(pBuffer, m_frame_buffer.ren_buf().width(), m_frame_buffer.ren_buf().height(), pRenBuffer->stride()); + + pCurrentGraphicsLayer->BlendTo(m_frame_buffer.pixfmt()); + + RELEASEINTERFACE(pCurrentGraphicsLayer); + return Ok; + } + + Status CGraphics::RemoveLayer() + { + if (m_arLayers.empty()) + return WrongState; + + CGraphicsLayer *pCurrentGraphicsLayer = m_arLayers.top(); + m_arLayers.pop(); + + RELEASEINTERFACE(pCurrentGraphicsLayer); + return Ok; + } + + Status CGraphics::SetLayerSettings(const TGraphicsLayerSettings &oSettings) + { + if (m_arLayers.empty()) + return WrongState; + + m_arLayers.top()->SetSettings(oSettings); + + return Ok; + } + + Status CGraphics::SetLayerOpacity(double dOpacity) + { + if (dOpacity < 0. || dOpacity > 1.) + return InvalidParameter; + + if (m_arLayers.empty()) + return WrongState; + + m_arLayers.top()->SetOpacity(dOpacity); + + return Ok; + } void CGraphics::CalculateFullTransform() { diff --git a/DesktopEditor/graphics/Graphics.h b/DesktopEditor/graphics/Graphics.h index 8895dbfa2a..87f0969477 100644 --- a/DesktopEditor/graphics/Graphics.h +++ b/DesktopEditor/graphics/Graphics.h @@ -64,6 +64,7 @@ #include "Color.h" #include "Matrix.h" +#include "GraphicsLayer.h" #include "GraphicsPath.h" #include "AlphaMask.h" #include "Clip.h" @@ -71,6 +72,7 @@ #include "Image.h" #include "../fontengine/FontManager.h" +#include #include #if defined(_WIN32) || defined (_WIN64) @@ -281,6 +283,8 @@ protected: CAlphaMask* m_pAlphaMask; + std::stack m_arLayers; + agg::svg::frame_buffer_rgba m_frame_buffer; agg::svg::rasterizer m_rasterizer; @@ -402,6 +406,15 @@ public: Status ResetAlphaMask(); Status StartApplyingAlphaMask(); + //Работа со слоями + Status AddLayer(CGraphicsLayer* pGraphicsLayer); + Status CreateLayer(); + Status BlendLayer(); + Status RemoveLayer(); + + Status SetLayerSettings(const TGraphicsLayerSettings& oSettings); + Status SetLayerOpacity(double dOpacity); + void CalculateFullTransform(); bool IsClip(); diff --git a/DesktopEditor/graphics/GraphicsLayer.cpp b/DesktopEditor/graphics/GraphicsLayer.cpp new file mode 100644 index 0000000000..5c223f41e4 --- /dev/null +++ b/DesktopEditor/graphics/GraphicsLayer.cpp @@ -0,0 +1,50 @@ +#include "GraphicsLayer.h" + +namespace Aggplus +{ + CGraphicsLayer::CGraphicsLayer(BYTE *pBuffer, bool bExternalBuffer) + : m_pBuffer(pBuffer), m_bExternalBuffer(NULL != pBuffer && bExternalBuffer) + { + SetDefaultSettings(); + } + + CGraphicsLayer::~CGraphicsLayer() + { + if (!m_bExternalBuffer) + RELEASEARRAYOBJECTS(m_pBuffer); + } + + bool CGraphicsLayer::Empty() const + { + return NULL == m_pBuffer; + } + + BYTE *CGraphicsLayer::GetBuffer() + { + return m_pBuffer; + } + + void CGraphicsLayer::SetDefaultSettings() + { + m_oSettings.m_dOpacity = 1.; + } + + void CGraphicsLayer::SetSettings(const TGraphicsLayerSettings &oSettings) + { + m_oSettings = oSettings; + } + + const TGraphicsLayerSettings &CGraphicsLayer::GetSettings() const + { + return m_oSettings; + } + + void CGraphicsLayer::SetOpacity(double dOpacity) + { + if (dOpacity > 1. || dOpacity < 0.) + m_oSettings.m_dOpacity = 1.; + else + m_oSettings.m_dOpacity = dOpacity; + } +} + diff --git a/DesktopEditor/graphics/GraphicsLayer.h b/DesktopEditor/graphics/GraphicsLayer.h new file mode 100644 index 0000000000..c6dd6cad45 --- /dev/null +++ b/DesktopEditor/graphics/GraphicsLayer.h @@ -0,0 +1,80 @@ +#ifndef CGRAPHICSLAYER_H +#define CGRAPHICSLAYER_H + +#include "Defines.h" +#include "./config.h" +#include "../common/IGrObject.h" + +namespace Aggplus +{ + struct TGraphicsLayerSettings + { + double m_dOpacity; + }; + + class GRAPHICS_DECL CGraphicsLayer : public IGrObject + { + public: + CGraphicsLayer(BYTE* pBuffer, bool bExternalBuffer = true); + ~CGraphicsLayer(); + + bool Empty() const; + BYTE* GetBuffer(); + + void SetDefaultSettings(); + + void SetSettings(const TGraphicsLayerSettings& oSettings); + const TGraphicsLayerSettings& GetSettings() const; + + void SetOpacity(double dOpacity); + + template + void BlendTo(SrcPixelFormatRenderer& oSrc) + { + if (NULL == m_pBuffer) + return; + + typedef typename SrcPixelFormatRenderer::order_type order_type; + typedef typename SrcPixelFormatRenderer::value_type value_type; + + int nStep = 4; + BYTE* pSrcBuffer = m_pBuffer; + value_type* pDstBuffer = NULL; + BYTE uchAlpha; + + for (unsigned int unY = 0; unY < oSrc.height(); ++unY) + { + pDstBuffer = oSrc.row_ptr(unY); + for (unsigned int unX = 0; unX < oSrc.width(); ++unX) + { + uchAlpha = (pSrcBuffer[order_type::A] * ((value_type)(m_oSettings.m_dOpacity * 255.)) + 1) >> 8; + if(uchAlpha) + { + if(uchAlpha == SrcPixelFormatRenderer::base_mask) + { + pDstBuffer[order_type::R] = pSrcBuffer[order_type::R]; + pDstBuffer[order_type::G] = pSrcBuffer[order_type::G]; + pDstBuffer[order_type::B] = pSrcBuffer[order_type::B]; + pDstBuffer[order_type::A] = SrcPixelFormatRenderer::base_mask; + } + else + { + SrcPixelFormatRenderer::blender_type::blend_pix(pDstBuffer, pSrcBuffer[order_type::R], pSrcBuffer[order_type::G], pSrcBuffer[order_type::B], uchAlpha); + } + } + + pSrcBuffer += nStep; + pDstBuffer += nStep; + } + } + } + private: + BYTE* m_pBuffer; + bool m_bExternalBuffer; + + TGraphicsLayerSettings m_oSettings; + }; + +} + +#endif // CGRAPHICSLAYER_H diff --git a/DesktopEditor/graphics/GraphicsRenderer.cpp b/DesktopEditor/graphics/GraphicsRenderer.cpp index 7304897791..7402a1ecf5 100644 --- a/DesktopEditor/graphics/GraphicsRenderer.cpp +++ b/DesktopEditor/graphics/GraphicsRenderer.cpp @@ -799,6 +799,11 @@ HRESULT CGraphicsRenderer::BeginCommand(const DWORD& lType) m_pRenderer->CreateAlphaMask(); break; } + case c_nLayerType: + { + m_pRenderer->CreateLayer(); + break; + } default: break; }; @@ -838,6 +843,11 @@ HRESULT CGraphicsRenderer::EndCommand(const DWORD& lType) m_pRenderer->ResetAlphaMask(); break; } + case c_nLayerType: + { + m_pRenderer->BlendLayer(); + break; + } default: break; }; @@ -1406,6 +1416,11 @@ void CGraphicsRenderer::SetAlphaMask(Aggplus::CAlphaMask* pAlphaMask) m_pRenderer->SetAlphaMask(pAlphaMask); } +void CGraphicsRenderer::SetLayerOpacity(double dOpacity) +{ + m_pRenderer->SetLayerOpacity(dOpacity); +} + void CGraphicsRenderer::put_GlobalAlphaEnabled(const bool& bEnabled, const double& dVal) { m_bGlobalAlphaEnabled = bEnabled; diff --git a/DesktopEditor/graphics/GraphicsRenderer.h b/DesktopEditor/graphics/GraphicsRenderer.h index e0d67d8628..ef2f314208 100644 --- a/DesktopEditor/graphics/GraphicsRenderer.h +++ b/DesktopEditor/graphics/GraphicsRenderer.h @@ -351,6 +351,9 @@ public: // alpha mask methods void SetAlphaMask(Aggplus::CAlphaMask* pAlphaMask); + + // layer methods + void SetLayerOpacity(double dOpacity); // smart methods void drawHorLine(BYTE align, double y, double x, double r, double penW) diff --git a/DesktopEditor/graphics/IRenderer.h b/DesktopEditor/graphics/IRenderer.h index 849f6e6d56..0fd87bbd3a 100644 --- a/DesktopEditor/graphics/IRenderer.h +++ b/DesktopEditor/graphics/IRenderer.h @@ -67,6 +67,8 @@ const long c_nTableCell = 0x2000; const long c_nMaskType = 0x3000; const long c_nResetMaskType = 0x4000; +const long c_nLayerType = 0x5000; + const long c_nPDFTilingFill = 0x2001; const long c_nPDFTilingFillIteration = 0x2002; diff --git a/DesktopEditor/graphics/pro/Graphics.h b/DesktopEditor/graphics/pro/Graphics.h index 508b1dca98..e98d28a9ab 100644 --- a/DesktopEditor/graphics/pro/Graphics.h +++ b/DesktopEditor/graphics/pro/Graphics.h @@ -121,6 +121,9 @@ namespace NSGraphics //alpha mask methods virtual void SetAlphaMask(Aggplus::CAlphaMask* pAlphaMask) = 0; + //layer methods + virtual void SetLayerOpacity(double dOpacity) = 0; + // smart methods virtual void drawHorLine(BYTE align, double y, double x, double r, double penW) = 0; virtual void drawHorLine2(BYTE align, double y, double x, double r, double penW) = 0; diff --git a/DesktopEditor/graphics/pro/graphics.pro b/DesktopEditor/graphics/pro/graphics.pro index ce20b972e5..04483815a7 100644 --- a/DesktopEditor/graphics/pro/graphics.pro +++ b/DesktopEditor/graphics/pro/graphics.pro @@ -63,6 +63,13 @@ SOURCES += \ ./../AlphaMask_private.cpp \ ./../AlphaMask.cpp +# grapgics layer +HEADERS += \ + ./../GraphicsLayer.h + +SOURCES += \ + ./../GraphicsLayer.cpp + SOURCES += \ $$GRAPHICS_AGG_PATH/src/agg_arc.cpp \ $$GRAPHICS_AGG_PATH/src/agg_bezier_arc.cpp \ From 254e5168af37f98cb3827ff17328bd5541897e95 Mon Sep 17 00:00:00 2001 From: Kirill Polyakov Date: Thu, 23 Nov 2023 16:32:46 +0300 Subject: [PATCH 26/54] Added a test example of using graphics layers --- .../tests/graphicsLayers/graphicsLayers.pro | 26 +++++ .../graphics/tests/graphicsLayers/main.cpp | 106 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 DesktopEditor/graphics/tests/graphicsLayers/graphicsLayers.pro create mode 100644 DesktopEditor/graphics/tests/graphicsLayers/main.cpp diff --git a/DesktopEditor/graphics/tests/graphicsLayers/graphicsLayers.pro b/DesktopEditor/graphics/tests/graphicsLayers/graphicsLayers.pro new file mode 100644 index 0000000000..2787314412 --- /dev/null +++ b/DesktopEditor/graphics/tests/graphicsLayers/graphicsLayers.pro @@ -0,0 +1,26 @@ +#CONFIG += c++11 cmdline + +#SOURCES += \ +QT -= core + +QT -= gui + +TARGET = test +CONFIG += console +TEMPLATE = app + +CORE_ROOT_DIR = $$PWD/../../../.. +PWD_ROOT_DIR = $$PWD +include($$CORE_ROOT_DIR/Common/base.pri) +include($$CORE_ROOT_DIR/Common/3dParty/icu/icu.pri) + +ADD_DEPENDENCY(kernel, graphics, UnicodeConverter) + +GRAPHICS_AGG_PATH = $$PWD/../../../agg-2.4 + +INCLUDEPATH += \ + $$GRAPHICS_AGG_PATH/include + +SOURCES += main.cpp + +DESTDIR = $$PWD_ROOT_DIR/build/$$CORE_BUILDS_PLATFORM_PREFIX/$$CORE_BUILDS_CONFIGURATION_PREFIX diff --git a/DesktopEditor/graphics/tests/graphicsLayers/main.cpp b/DesktopEditor/graphics/tests/graphicsLayers/main.cpp new file mode 100644 index 0000000000..a49e0f1473 --- /dev/null +++ b/DesktopEditor/graphics/tests/graphicsLayers/main.cpp @@ -0,0 +1,106 @@ +#include "../../pro/Graphics.h" +#include "../../../raster/BgraFrame.h" +#include "../../../common/Directory.h" + +#define RGB_TO_INT(r, g, b) ((unsigned int)( ( (unsigned char)(r) )| ( ( (unsigned char)(g) ) << 8 ) | ( ( (unsigned char)(b) ) << 16 ) | ( (unsigned char)(0) << 24 ) ) ) + +int main(int argc, char *argv[]) +{ + NSGraphics::IGraphicsRenderer* pRasterRenderer = NSGraphics::Create(); + + const unsigned int unWidth = 1000; + const unsigned int unHeight = 1000; + + // Создание основной картинки + BYTE* pData = new BYTE[4 * unWidth * unHeight]; + + for (unsigned long unIndex = 0; unIndex < unWidth * unHeight; ++unIndex) + ((unsigned int*)pData)[unIndex] = 0xffffff; + + CBgraFrame oFrame; + oFrame.put_Data(pData); + oFrame.put_Width(unWidth); + oFrame.put_Height(unHeight); + oFrame.put_Stride(4 * unWidth); + + pRasterRenderer->CreateFromBgraFrame(&oFrame); + pRasterRenderer->SetSwapRGB(false); + + double dW_MM = unWidth; + double dH_MM = unHeight; + + pRasterRenderer->put_Width(dW_MM); + pRasterRenderer->put_Height(dH_MM); + + pRasterRenderer->BeginCommand(c_nPathType); + pRasterRenderer->PathCommandStart(); + + // Отрисовываем основной слой + pRasterRenderer->PathCommandRect(50, 200, 300, 300); + + pRasterRenderer->put_BrushAlpha1(255); + pRasterRenderer->put_BrushColor1(RGB_TO_INT(255, 0, 0)); // красный + + pRasterRenderer->put_PenAlpha(255); + pRasterRenderer->put_PenColor(RGB_TO_INT(255, 0, 255)); + pRasterRenderer->put_PenSize(40); + + pRasterRenderer->DrawPath(c_nWindingFillMode | c_nStroke); + + pRasterRenderer->PathCommandEnd(); + pRasterRenderer->EndCommand(c_nPathType); + + // Отрисовываем второй слой + pRasterRenderer->BeginCommand(c_nPathType); + pRasterRenderer->PathCommandStart(); + + pRasterRenderer->BeginCommand(c_nLayerType); + pRasterRenderer->PathCommandRect(300, 300, 300, 300); + + pRasterRenderer->put_BrushAlpha1(255); + pRasterRenderer->put_BrushColor1(RGB_TO_INT(0, 255, 0)); // зеленый + + pRasterRenderer->put_PenAlpha(150); + pRasterRenderer->put_PenColor(RGB_TO_INT(0, 0, 255)); + pRasterRenderer->put_PenSize(40); + + pRasterRenderer->SetLayerOpacity(0.5); + + pRasterRenderer->DrawPath(c_nWindingFillMode | c_nStroke); + + pRasterRenderer->PathCommandEnd(); + pRasterRenderer->EndCommand(c_nPathType); + + //Отрисовываем третий слой + pRasterRenderer->BeginCommand(c_nPathType); + pRasterRenderer->PathCommandStart(); + + pRasterRenderer->BeginCommand(c_nLayerType); + pRasterRenderer->PathCommandRect(500, 400, 300, 300); + + pRasterRenderer->put_BrushAlpha1(150); + pRasterRenderer->put_BrushColor1(RGB_TO_INT(0, 0, 255)); // синий + + pRasterRenderer->put_PenAlpha(255); + pRasterRenderer->put_PenColor(RGB_TO_INT(255, 0, 0)); + pRasterRenderer->put_PenSize(40); + + pRasterRenderer->SetLayerOpacity(1); + + pRasterRenderer->DrawPath(c_nWindingFillMode | c_nStroke); + + pRasterRenderer->PathCommandEnd(); + pRasterRenderer->EndCommand(c_nPathType); + + // блитируем трутий слой на второй + pRasterRenderer->EndCommand(c_nLayerType); + + // блитируем второй слой на основной + pRasterRenderer->EndCommand(c_nLayerType); + + oFrame.SaveFile(L"testGraphicsLayers.png", 4); + + RELEASEINTERFACE(pRasterRenderer); + + return 0; +} From b0dfb4c731a9b942787d1f03d17c1cdb078624a5 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 23 Nov 2023 19:13:03 +0400 Subject: [PATCH 27/54] Added allocator and deallocator for typed arrays --- DesktopEditor/doctrenderer/json/json.cpp | 21 ++++++++++++------- .../doctrenderer/json/json_values.cpp | 7 +++++-- DesktopEditor/doctrenderer/json/json_values.h | 3 ++- .../doctrenderer/json/serialization.h | 8 ++----- DesktopEditor/doctrenderer/test/json/main.cpp | 7 +++---- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 0f38193fca..32d5c07071 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -2,6 +2,9 @@ #include "json_p.h" #include "json_values.h" +// for working with typed arrays: Alloc() and Free() +#include "js_base.h" + namespace NSJSON { CTypedValue::CTypedValue() : m_type(vtUndefined) @@ -174,9 +177,12 @@ namespace NSJSON int IValue::GetCount() const { - if (m_internal->m_type != CTypedValue::vtArray) + if (m_internal->m_type == CTypedValue::vtArray) + return static_cast(m_internal->m_value.get())->getCount(); + else if (m_internal->m_type == CTypedValue::vtTypedArray) + return static_cast(m_internal->m_value.get())->getCount(); + else return 0; - return static_cast(m_internal->m_value.get())->getCount(); } const CValueRef IValue::Get(int index) const @@ -319,19 +325,20 @@ namespace NSJSON CValue CValue::CreateTypedArray(BYTE* data, int count, bool isExternalize) { - // TODO: - return CValue(); + CValue ret; + ret.m_internal->m_value = std::make_shared(data, count, isExternalize); + ret.m_internal->m_type = CTypedValue::vtTypedArray; + return ret; } BYTE* CValue::AllocTypedArray(size_t size) { - // TODO: - return nullptr; + return NSJSBase::NSAllocator::Alloc(size); } void CValue::FreeTypedArray(BYTE* data, size_t size) { - // TODO: + NSJSBase::NSAllocator::Free(data, size); } CValue CValue::CreateObject() diff --git a/DesktopEditor/doctrenderer/json/json_values.cpp b/DesktopEditor/doctrenderer/json/json_values.cpp index acb92da57c..eaab4b5963 100644 --- a/DesktopEditor/doctrenderer/json/json_values.cpp +++ b/DesktopEditor/doctrenderer/json/json_values.cpp @@ -224,13 +224,16 @@ namespace NSJSON return m_values[index]; } - CTypedArray::CTypedArray(BYTE* data, int len) : m_data(data), m_len(len) + CTypedArray::CTypedArray(BYTE* data, int len, bool isExternalize) : m_data(data), m_len(len), m_isExternalize(isExternalize) { } CTypedArray::~CTypedArray() { - // TODO: + if (!m_isExternalize) + { + CValue::FreeTypedArray(m_data, m_len); + } } BYTE* CTypedArray::getData() diff --git a/DesktopEditor/doctrenderer/json/json_values.h b/DesktopEditor/doctrenderer/json/json_values.h index d9d5a58ba8..d7d378d875 100644 --- a/DesktopEditor/doctrenderer/json/json_values.h +++ b/DesktopEditor/doctrenderer/json/json_values.h @@ -96,7 +96,7 @@ namespace NSJSON class CTypedArray : public IBaseValue { public: - CTypedArray(BYTE* data = nullptr, int len = 0); + CTypedArray(BYTE* data, int len, bool isExternalize = true); ~CTypedArray(); public: @@ -106,6 +106,7 @@ namespace NSJSON private: BYTE* m_data; int m_len; + bool m_isExternalize; }; class CObject : public IBaseValue diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index 27f0d133f3..c17722d080 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -2,7 +2,7 @@ #define SERIALIZATION_H_ #include "json.h" -#include "json_values.h" +//#include "json_values.h" #include "../js_internal/js_base.h" #include @@ -40,12 +40,8 @@ namespace NSJSON } else if (value.IsTypedArray()) { - // TODO: - /* - JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(value.GetData(), value.GetCount()); + JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(const_cast(value.GetData()), value.GetCount()); ret = jsTypedArr->toValue(); - */ - ret = NSJSBase::CJSContext::createUndefined(); } else { diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 0073b53a9a..30124e2d8d 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -80,15 +80,14 @@ int main() numbers[3] = innerArray; textPr["numbers"] = numbers; // create typed array - /* - BYTE* pData = new BYTE[4]; + BYTE* pData = CValue::AllocTypedArray(4); pData[0] = 11; pData[1] = 23; pData[2] = 58; pData[3] = 13; // add typed array - ... - */ + CValue typedArr = CValue::CreateTypedArray(pData, 4, false); + textPr["typedArr"] = typedArr; // convert to JS JSSmart jsObj = toJS(textPr)->toObject(); From fdaf8e6c6b046e22adbc8b52842a96480ba747f3 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 24 Nov 2023 16:23:16 +0400 Subject: [PATCH 28/54] Fixed fromJS() --- .../doctrenderer/json/serialization.h | 58 ++++++++----------- DesktopEditor/doctrenderer/test/json/main.cpp | 10 ++++ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index c17722d080..78f84367c0 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -63,73 +63,65 @@ namespace NSJSON static CValue fromJS(JSSmart jsValue) { - /* if (jsValue->isUndefined()) - return new CPrimitive(); - + return CValue::CreateUndefined(); if (jsValue->isNull()) - { - CPrimitive* pValue = new CPrimitive; - pValue->setNull(); - return pValue; - } + return CValue::CreateNull(); - IBaseValue* ret = nullptr; - if (jsValue->isObject()) - { - JSSmart jsObj = jsValue->toObject(); - CObject* pObject = new CObject; - // TODO: add CJSObject::getPropertyNames() - ret = pObject; - } - else if (jsValue->isArray()) + CValue ret; + + if (jsValue->isArray()) { JSSmart jsArr = jsValue->toArray(); const int len = jsArr->getCount(); - CArray* pArray = new CArray(); + ret = CValue::CreateArray(len); for (int i = 0; i < len; i++) { JSSmart jsElement = jsArr->get(i); - pArray->add(fromJS(jsElement)); + ret[i] = fromJS(jsElement); } - ret = pArray; } else if (jsValue->isTypedArray()) { JSSmart jsTypedArr = jsValue->toTypedArray(); const int len = jsTypedArr->getCount(); BYTE* data = jsTypedArr->getData().Data; - ret = new CTypedArray(data, len); + ret = CValue::CreateTypedArray(data, len); + } + else if (jsValue->isObject()) + { + JSSmart jsObj = jsValue->toObject(); + std::vector properties = jsObj->getPropertyNames(); + ret = CValue::CreateObject(); + for (const std::string& name : properties) + { + JSSmart jsPropertyValue = jsObj->get(name.c_str()); + ret[name.c_str()] = fromJS(jsPropertyValue); + } } // primitives else if (jsValue->isBool()) { - ret = new CPrimitive(jsValue->toBool()); + ret = CValue(jsValue->toBool()); } else if (jsValue->isNumber()) { - // TODO: this check seems redundant. Similiar to string (look further). // check if number is an integer or double double number = jsValue->toDouble(); double integral; // integral part double fractional = std::modf(number, &integral); // fractional part if (fractional == 0.0 && integral >= INT_MIN && integral <= INT_MAX) - { - ret = new CPrimitive(static_cast(integral)); - } + ret = (int)integral; else - { - ret = new CPrimitive(number); - } + ret = number; } else if (jsValue->isString()) { - // TODO: how do we know whether string consist of char or wchar_t? Can we convert all strings to std::wstring? + // convert all strings to std::wstring, cause in JS all strings are encoded in UTF-16 + ret = jsValue->toStringW(); } - // else ret is nullptr - */ - return CValue(); + return ret; } } diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 30124e2d8d..f4adb40fec 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -99,5 +99,15 @@ int main() std::cout << ret->toStringA() << std::endl; } + // Test fromJS() on the same object: + CValue textPr2 = fromJS(jsObj->toValue()); + JSSmart jsObj2 = toJS(textPr2)->toObject(); + global->set("textPr2", jsObj2); + ret = pContext->runScript("(function () { return JSON.stringify(textPr2, null, 4); })();"); + if (ret.IsInit()) + { + std::cout << ret->toStringA() << std::endl; + } + return 0; } From a096559e29c4c261f96c417446a51072c8b5c336 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 24 Nov 2023 17:07:09 +0400 Subject: [PATCH 29/54] Changed the order of comparison in toJS() --- .../doctrenderer/json/serialization.h | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index 78f84367c0..cbac145489 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -2,7 +2,6 @@ #define SERIALIZATION_H_ #include "json.h" -//#include "json_values.h" #include "../js_internal/js_base.h" #include @@ -17,18 +16,7 @@ namespace NSJSON return NSJSBase::CJSContext::createNull(); JSSmart ret; - if (value.IsObject()) - { - JSSmart jsObj = NSJSBase::CJSContext::createObject(); - std::vector properties = value.GetPropertyNames(); - for (const std::string& name : properties) - { - JSSmart jsValue = toJS(value[name.c_str()]); - jsObj->set(name.c_str(), jsValue); - } - ret = jsObj->toValue(); - } - else if (value.IsArray()) + if (value.IsArray()) { const int len = value.GetCount(); JSSmart jsArr = NSJSBase::CJSContext::createArray(len); @@ -43,6 +31,17 @@ namespace NSJSON JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(const_cast(value.GetData()), value.GetCount()); ret = jsTypedArr->toValue(); } + else if (value.IsObject()) + { + JSSmart jsObj = NSJSBase::CJSContext::createObject(); + std::vector properties = value.GetPropertyNames(); + for (const std::string& name : properties) + { + JSSmart jsValue = toJS(value[name.c_str()]); + jsObj->set(name.c_str(), jsValue); + } + ret = jsObj->toValue(); + } else { // primitive types From 14962ccaefe3b47d86e97160f26898db7f1748ff Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 27 Nov 2023 17:44:16 +0400 Subject: [PATCH 30/54] set()-s and add() now take JSSmart --- .../doctrenderer/js_internal/js_base.cpp | 7 +------ .../doctrenderer/js_internal/js_base.h | 10 ++++------ .../doctrenderer/js_internal/v8/v8_base.h | 17 ++++++----------- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/js_base.cpp b/DesktopEditor/doctrenderer/js_internal/js_base.cpp index 4f275ae2d2..7df327b703 100644 --- a/DesktopEditor/doctrenderer/js_internal/js_base.cpp +++ b/DesktopEditor/doctrenderer/js_internal/js_base.cpp @@ -65,14 +65,9 @@ namespace NSJSBase { { } - void CJSObject::set(const char* name, JSSmart value) - { - this->set(name, value.GetPointer()); - } void CJSObject::set(const char* name, JSSmart obj) { - JSSmart value = obj->toValue(); - this->set(name, value.GetPointer()); + this->set(name, obj->toValue()); } CJSArray::CJSArray() diff --git a/DesktopEditor/doctrenderer/js_internal/js_base.h b/DesktopEditor/doctrenderer/js_internal/js_base.h index ba61ce1a6b..e7d9184e85 100644 --- a/DesktopEditor/doctrenderer/js_internal/js_base.h +++ b/DesktopEditor/doctrenderer/js_internal/js_base.h @@ -221,11 +221,10 @@ namespace NSJSBase * @param name The name of a property. * @param value The value of a property. */ - virtual void set(const char* name, CJSValue* value) = 0; + virtual void set(const char* name, JSSmart value) = 0; virtual void set(const char* name, const int& value) = 0; virtual void set(const char* name, const double& value) = 0; - // Common funcs - void set(const char* name, JSSmart value); + // Common function void set(const char* name, JSSmart value); /** @@ -273,8 +272,7 @@ namespace NSJSBase * @param index The index of the array value. * @param value The array value to be set. */ - virtual void set(const int& index, CJSValue* value) = 0; - virtual void set(const int& index, const bool& value) = 0; + virtual void set(const int& index, JSSmart value) = 0; virtual void set(const int& index, const int& value) = 0; virtual void set(const int& index, const double& value) = 0; @@ -282,7 +280,7 @@ namespace NSJSBase * Add the specified value to the array. * @param value The value to be added. */ - virtual void add(CJSValue* value) = 0; + virtual void add(JSSmart value) = 0; /** * Add null to the array. */ diff --git a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h index 8e0456e36e..01c6d1bc37 100644 --- a/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h +++ b/DesktopEditor/doctrenderer/js_internal/v8/v8_base.h @@ -425,9 +425,9 @@ namespace NSJSBase return _value; } - virtual void set(const char* name, CJSValue* value_param) + virtual void set(const char* name, JSSmart value_param) { - CJSValueV8* _value = static_cast(value_param); + CJSValueV8* _value = static_cast(value_param.GetPointer()); v8::Local _name = CreateV8String(CV8Worker::GetCurrent(), name); value->Set(V8ContextFirstArg _name, _value->value); } @@ -552,23 +552,18 @@ namespace NSJSBase return _value; } - virtual void set(const int& index, CJSValue* value_param) + virtual void set(const int& index, JSSmart value_param) { - CJSValueV8* _value = static_cast(value_param); + CJSValueV8* _value = static_cast(value_param.GetPointer()); value->Set(V8ContextFirstArg index, _value->value); } - virtual void add(CJSValue* value_param) + virtual void add(JSSmart value_param) { - CJSValueV8* _value = static_cast(value_param); + CJSValueV8* _value = static_cast(value_param.GetPointer()); value->Set(V8ContextFirstArg getCount(), _value->value); } - virtual void set(const int& index, const bool& _value) - { - value->Set(V8ContextFirstArg index, v8::Boolean::New(CV8Worker::GetCurrent(), _value)); - } - virtual void set(const int& index, const int& _value) { value->Set(V8ContextFirstArg index, v8::Integer::New(CV8Worker::GetCurrent(), _value)); From f6e126026a709227e6200d612b2d90305bbcd07e Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 27 Nov 2023 17:55:57 +0400 Subject: [PATCH 31/54] Changed set()-s and add() for JSC --- .../doctrenderer/js_internal/jsc/jsc_base.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h index 547dcb0f3b..8fb6246d1b 100644 --- a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h +++ b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h @@ -117,9 +117,9 @@ namespace NSJSBase return _value; } - virtual void set(const char* name, CJSValue* value_param) + virtual void set(const char* name, JSSmart value_param) { - CJSValueJSC* _value = static_cast(value_param); + CJSValueJSC* _value = static_cast(value_param.GetPointer()); [value setValue:_value->value forProperty:[[NSString alloc] initWithUTF8String:name]]; } @@ -219,22 +219,17 @@ namespace NSJSBase return _value; } - virtual void set(const int& index, CJSValue* value_param) + virtual void set(const int& index, JSSmart value_param) { - CJSValueJSC* _value = static_cast(value_param); + CJSValueJSC* _value = static_cast(value_param.GetPointer()); [value setValue:_value->value atIndex:index]; } - virtual void add(CJSValue* value_param) + virtual void add(JSSmart value_param) { set(getCount(), value_param); } - virtual void set(const int& index, const bool& _value) - { - [value setValue:[JSValue valueWithBool:_value inContext : getContext()] atIndex:index]; - } - virtual void set(const int& index, const int& _value) { [value setValue:[JSValue valueWithInt32:_value inContext : getContext()] atIndex:index]; From 2d9206b79b973899032d1798b29bf62f67632aaa Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 27 Nov 2023 18:05:53 +0400 Subject: [PATCH 32/54] Changed some places where set() were used --- DesktopEditor/doctrenderer/docbuilder_p.cpp | 8 ++++---- DesktopEditor/doctrenderer/json/serialization.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DesktopEditor/doctrenderer/docbuilder_p.cpp b/DesktopEditor/doctrenderer/docbuilder_p.cpp index 038da31197..6abc4f0684 100644 --- a/DesktopEditor/doctrenderer/docbuilder_p.cpp +++ b/DesktopEditor/doctrenderer/docbuilder_p.cpp @@ -492,12 +492,12 @@ namespace NSDoctRenderer if (oParent->isArray()) { JSSmart oParentArray = oParent->toArray(); - oParentArray->set(m_internal->m_parent->m_parent_index, m_internal->m_value.GetPointer()); + oParentArray->set(m_internal->m_parent->m_parent_index, m_internal->m_value); } else if (oParent->isObject() && !m_internal->m_parent->m_parent_prop_name.empty()) { JSSmart oParentObject = oParent->toObject(); - oParentObject->set(m_internal->m_parent->m_parent_prop_name.c_str(), m_internal->m_value.GetPointer()); + oParentObject->set(m_internal->m_parent->m_parent_prop_name.c_str(), m_internal->m_value); } } @@ -729,7 +729,7 @@ namespace NSDoctRenderer std::string sPropA = U_TO_UTF8(sProp); value.m_internal->CheckNative(); - m_internal->m_value->toObject()->set(sPropA.c_str(), value.m_internal->m_value.GetPointer()); + m_internal->m_value->toObject()->set(sPropA.c_str(), value.m_internal->m_value); } void CDocBuilderValue::SetProperty(const wchar_t* name, CDocBuilderValue value) { @@ -742,7 +742,7 @@ namespace NSDoctRenderer JSSmart array = m_internal->m_value->toArray(); value.m_internal->CheckNative(); - array->set(index, value.m_internal->m_value.GetPointer()); + array->set(index, value.m_internal->m_value); } // primitives diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index cbac145489..450e2241f9 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -22,7 +22,7 @@ namespace NSJSON JSSmart jsArr = NSJSBase::CJSContext::createArray(len); for (int i = 0; i < len; i++) { - jsArr->set(i, toJS(value[i]).GetPointer()); + jsArr->set(i, toJS(value[i])); } ret = jsArr->toValue(); } From 1eeaea8c34d5205feece505c83c96960c4d4f598 Mon Sep 17 00:00:00 2001 From: Kirill Polyakov Date: Mon, 27 Nov 2023 17:21:14 +0300 Subject: [PATCH 33/54] Refactoring --- DesktopEditor/graphics/GraphicsRenderer.cpp | 4 ++-- DesktopEditor/graphics/GraphicsRenderer.h | 4 ++-- DesktopEditor/graphics/IRenderer.h | 3 +++ DesktopEditor/graphics/pro/Graphics.h | 3 --- DesktopEditor/graphics/tests/graphicsLayers/main.cpp | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/DesktopEditor/graphics/GraphicsRenderer.cpp b/DesktopEditor/graphics/GraphicsRenderer.cpp index 7402a1ecf5..ca30c7c629 100644 --- a/DesktopEditor/graphics/GraphicsRenderer.cpp +++ b/DesktopEditor/graphics/GraphicsRenderer.cpp @@ -1416,9 +1416,9 @@ void CGraphicsRenderer::SetAlphaMask(Aggplus::CAlphaMask* pAlphaMask) m_pRenderer->SetAlphaMask(pAlphaMask); } -void CGraphicsRenderer::SetLayerOpacity(double dOpacity) +HRESULT CGraphicsRenderer::put_LayerOpacity(double dValue) { - m_pRenderer->SetLayerOpacity(dOpacity); + return m_pRenderer->SetLayerOpacity(dValue); } void CGraphicsRenderer::put_GlobalAlphaEnabled(const bool& bEnabled, const double& dVal) diff --git a/DesktopEditor/graphics/GraphicsRenderer.h b/DesktopEditor/graphics/GraphicsRenderer.h index ef2f314208..eba5cc8647 100644 --- a/DesktopEditor/graphics/GraphicsRenderer.h +++ b/DesktopEditor/graphics/GraphicsRenderer.h @@ -351,9 +351,9 @@ public: // alpha mask methods void SetAlphaMask(Aggplus::CAlphaMask* pAlphaMask); - + // layer methods - void SetLayerOpacity(double dOpacity); + HRESULT put_LayerOpacity(double dValue); // smart methods void drawHorLine(BYTE align, double y, double x, double r, double penW) diff --git a/DesktopEditor/graphics/IRenderer.h b/DesktopEditor/graphics/IRenderer.h index 0fd87bbd3a..feb28daab3 100644 --- a/DesktopEditor/graphics/IRenderer.h +++ b/DesktopEditor/graphics/IRenderer.h @@ -357,6 +357,9 @@ public: virtual HRESULT IsSupportAdvancedCommand(const IAdvancedCommand::AdvancedCommandType& type) { return S_FALSE; } virtual HRESULT AdvancedCommand(IAdvancedCommand* command) { return S_FALSE; } + + // graphics layer settings + virtual HRESULT put_LayerOpacity(double dValue) { return S_FALSE; } }; #define PROPERTY_RENDERER(NameBase, Name, Type) \ diff --git a/DesktopEditor/graphics/pro/Graphics.h b/DesktopEditor/graphics/pro/Graphics.h index e98d28a9ab..508b1dca98 100644 --- a/DesktopEditor/graphics/pro/Graphics.h +++ b/DesktopEditor/graphics/pro/Graphics.h @@ -121,9 +121,6 @@ namespace NSGraphics //alpha mask methods virtual void SetAlphaMask(Aggplus::CAlphaMask* pAlphaMask) = 0; - //layer methods - virtual void SetLayerOpacity(double dOpacity) = 0; - // smart methods virtual void drawHorLine(BYTE align, double y, double x, double r, double penW) = 0; virtual void drawHorLine2(BYTE align, double y, double x, double r, double penW) = 0; diff --git a/DesktopEditor/graphics/tests/graphicsLayers/main.cpp b/DesktopEditor/graphics/tests/graphicsLayers/main.cpp index a49e0f1473..9be43dc456 100644 --- a/DesktopEditor/graphics/tests/graphicsLayers/main.cpp +++ b/DesktopEditor/graphics/tests/graphicsLayers/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) pRasterRenderer->PathCommandStart(); // Отрисовываем основной слой - pRasterRenderer->PathCommandRect(50, 200, 300, 300); + pRasterRenderer->PathCommandRect(50, 200, 600, 300); pRasterRenderer->put_BrushAlpha1(255); pRasterRenderer->put_BrushColor1(RGB_TO_INT(255, 0, 0)); // красный @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) pRasterRenderer->put_PenColor(RGB_TO_INT(0, 0, 255)); pRasterRenderer->put_PenSize(40); - pRasterRenderer->SetLayerOpacity(0.5); + pRasterRenderer->put_LayerOpacity(0.5); pRasterRenderer->DrawPath(c_nWindingFillMode | c_nStroke); @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) pRasterRenderer->put_PenColor(RGB_TO_INT(255, 0, 0)); pRasterRenderer->put_PenSize(40); - pRasterRenderer->SetLayerOpacity(1); + pRasterRenderer->put_LayerOpacity(1); pRasterRenderer->DrawPath(c_nWindingFillMode | c_nStroke); From bb3de819cdaabb8e5837cdcc1b780d6700533a56 Mon Sep 17 00:00:00 2001 From: Kirill Polyakov Date: Mon, 27 Nov 2023 17:22:07 +0300 Subject: [PATCH 34/54] Added the use of multi-layer rendering in Svg reader --- .../Metafile/svg/SvgObjects/CObjectBase.cpp | 35 +++++++++++++------ .../Metafile/svg/SvgObjects/CObjectBase.h | 4 ++- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp index 50f33ab399..2cf135dcbf 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp @@ -68,7 +68,7 @@ namespace SVG SetData(NSCSS::NS_STATIC_FUNCTIONS::GetRules(wsStyles), ushLevel, bHardMode); } - + void CObject::SetTransform(const std::map &mAttributes, unsigned short ushLevel, bool bHardMode) { if (mAttributes.end() != mAttributes.find(L"transform")) @@ -112,6 +112,12 @@ namespace SVG m_oTransformtaion.m_bDraw = true; } + void CObject::SetOpacity(const std::map &mAttributes, unsigned short ushLevel, bool bHardMode) + { + if (mAttributes.end() != mAttributes.find(L"opacity")) + m_oTransformtaion.m_oOpacity.SetValue(mAttributes.at(L"opacity"), ushLevel, bHardMode); + } + bool CObject::ApplyTransform(IRenderer *pRenderer, const NSCSS::NSProperties::CTransform *pTransform, Aggplus::CMatrix& oOldMatrix) const { if (NULL == pRenderer || NULL == pTransform) @@ -147,7 +153,7 @@ namespace SVG pRenderer->BeginCommand(c_nResetClipType); pRenderer->EndCommand(c_nResetClipType); - + return ApplyDef(pRenderer, pFile, pClip->m_oHref.ToWString(), oBounds); } @@ -205,9 +211,10 @@ namespace SVG void CRenderedObject::SetData(const std::map &mAttributes, unsigned short ushLevel, bool bHardMode) { SetTransform(mAttributes, ushLevel, bHardMode); - SetDisplay(mAttributes, ushLevel, bHardMode); - SetClip(mAttributes, ushLevel, bHardMode); - SetMask(mAttributes, ushLevel, bHardMode); + SetDisplay (mAttributes, ushLevel, bHardMode); + SetOpacity (mAttributes, ushLevel, bHardMode); + SetClip (mAttributes, ushLevel, bHardMode); + SetMask (mAttributes, ushLevel, bHardMode); } std::vector CRenderedObject::GetFullPath() const @@ -229,7 +236,8 @@ namespace SVG m_oStyles.m_oStroke.m_oLineCap = Aggplus::LineJoinMiter; m_oStyles.m_oStroke.m_oMiterlimit = 4.; - + + m_oTransformtaion.m_oOpacity = 1.; m_oTransformtaion.m_bDraw = true; } @@ -267,14 +275,11 @@ namespace SVG if (mAttributes.end() != mAttributes.find(L"fill-opacity")) m_oStyles.m_oFill.SetOpacity(mAttributes.at(L"fill-opacity"), ushLevel, bHardMode); - - if (mAttributes.end() != mAttributes.find(L"opacity")) - m_oStyles.m_oFill.SetOpacity(mAttributes.at(L"opacity"), ushLevel, bHardMode); } bool CRenderedObject::StartPath(IRenderer *pRenderer, const CSvgFile *pFile, Aggplus::CMatrix &oOldTransform, CommandeMode oMode) const { - if (NULL == pRenderer || !m_oTransformtaion.m_bDraw) + if (NULL == pRenderer || !m_oTransformtaion.m_bDraw || Equals(0., m_oTransformtaion.m_oOpacity.ToDouble())) return false; ApplyTransform(pRenderer, &m_oTransformtaion.m_oTransform, oOldTransform); @@ -283,6 +288,11 @@ namespace SVG if (CommandeModeClip == oMode) pRenderer->BeginCommand(c_nClipType); + else if (1. != m_oTransformtaion.m_oOpacity.ToDouble()) + { + pRenderer->BeginCommand(c_nLayerType); + pRenderer->put_LayerOpacity(m_oTransformtaion.m_oOpacity.ToDouble()); + } pRenderer->BeginCommand(c_nPathType); pRenderer->PathCommandStart(); @@ -300,7 +310,7 @@ namespace SVG pRenderer->SetTransform(oOldTransform.sx(), oOldTransform.shy(), oOldTransform.shx(), oOldTransform.sy(), oOldTransform.tx(), oOldTransform.ty()); return; } - + int nPathType = 0; if (NULL == pOtherStyles) @@ -327,6 +337,9 @@ namespace SVG pRenderer->BeginCommand(c_nResetMaskType); pRenderer->EndCommand(c_nResetMaskType); } + + if (1. != m_oTransformtaion.m_oOpacity.ToDouble()) + pRenderer->EndCommand(c_nLayerType); pRenderer->SetTransform(oOldTransform.sx(), oOldTransform.shy(), oOldTransform.shx(), oOldTransform.sy(), oOldTransform.tx(), oOldTransform.ty()); } diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h index 41a4ceca0e..70593e6938 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h @@ -24,6 +24,7 @@ namespace SVG SvgTransform m_oTransform; TClip m_oClip; SvgColor m_oMask; + SvgDigit m_oOpacity; bool m_bDraw; }; @@ -49,7 +50,8 @@ namespace SVG void SetTransform(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); void SetClip(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); void SetMask(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); - void SetDisplay(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); + void SetDisplay(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); + void SetOpacity(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); std::wstring GetId() const; virtual std::vector GetFullPath() const; From 3e5eb3d2510f4615824b6f8f38b304bc0c623227 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Mon, 27 Nov 2023 21:29:56 +0400 Subject: [PATCH 35/54] Added tests to basic CValue functionality --- DesktopEditor/doctrenderer/json/json.cpp | 6 + .../doctrenderer/json/json_values.cpp | 2 +- DesktopEditor/doctrenderer/test/json/main.cpp | 467 +++++++++++++++++- DesktopEditor/doctrenderer/test/json/test.pro | 10 +- 4 files changed, 475 insertions(+), 10 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index 32d5c07071..f2ded6054e 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -318,6 +318,9 @@ namespace NSJSON CValue CValue::CreateArray(int count) { CValue ret; + if (count < 0) + return ret; + ret.m_internal->m_value = std::make_shared(count); ret.m_internal->m_type = CTypedValue::vtArray; return ret; @@ -326,6 +329,9 @@ namespace NSJSON CValue CValue::CreateTypedArray(BYTE* data, int count, bool isExternalize) { CValue ret; + if (count <= 0) + return ret; + ret.m_internal->m_value = std::make_shared(data, count, isExternalize); ret.m_internal->m_type = CTypedValue::vtTypedArray; return ret; diff --git a/DesktopEditor/doctrenderer/json/json_values.cpp b/DesktopEditor/doctrenderer/json/json_values.cpp index eaab4b5963..d37ea38804 100644 --- a/DesktopEditor/doctrenderer/json/json_values.cpp +++ b/DesktopEditor/doctrenderer/json/json_values.cpp @@ -125,7 +125,7 @@ namespace NSJSON if (m_type == ptDouble) return m_double; if (m_type == ptInteger) - return (double)m_double; + return (double)m_int; #ifdef JSON_DEBUG throw std::bad_cast(); #endif diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index f4adb40fec..c0df5bbc45 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -1,14 +1,17 @@ -//#include "gtest/gtest.h" -#include "js_internal/js_base.h" #include "json/serialization.h" +#ifdef JSON_GOOGLE_TEST +#include "gtest/gtest.h" +#include +#else #include -#include +#endif using namespace NSJSBase; using namespace NSJSON; -/* +#ifdef JSON_GOOGLE_TEST + class CJSONTest : public testing::Test { public: @@ -24,16 +27,462 @@ public: m_pContext->Exit(); } + bool compare(const CValue& value, JSSmart jsValue, bool makeExpects = true) + { + if (value.IsUndefined()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isUndefined()); + return jsValue->isUndefined(); + } + if (value.IsNull()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isNull()); + return jsValue->isNull(); + } + + if (value.IsArray()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isArray()); + if (!jsValue->isArray()) + return false; + + JSSmart jsArr = jsValue->toArray(); + const int len = value.GetCount(); + + if (makeExpects) + EXPECT_EQ(len, jsArr->getCount()); + if (len != jsArr->getCount()) + return false; + + for (int i = 0; i < len; i++) + { + if (!compare(value[i], jsArr->get(i), makeExpects)) + { + if (makeExpects) + ADD_FAILURE() << "Array values at index [" << i << "] are different!"; + return false; + } + } + } + else if (value.IsTypedArray()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isTypedArray()); + if (!jsValue->isTypedArray()) + return false; + + JSSmart jsTypedArr = jsValue->toTypedArray(); + + if (makeExpects) + EXPECT_EQ(value.GetCount(), jsTypedArr->getCount()); + if (value.GetCount() != jsTypedArr->getCount()) + return false; + + // compare pointers, not values + if (makeExpects) + EXPECT_EQ(value.GetData(), jsTypedArr->getData().Data); + if (value.GetData() != jsTypedArr->getData().Data) + return false; + } + else if (value.IsObject()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isObject()); + if (!jsValue->isObject()) + return false; + + JSSmart jsObj = jsValue->toObject(); + std::vector properties = value.GetPropertyNames(); + std::vector jsProperties = jsObj->getPropertyNames(); + + const int len = properties.size(); + if (makeExpects) + EXPECT_EQ(len, jsProperties.size()); + if (len != jsProperties.size()) + return false; + + // sort both vectors since the order of properties may vary in them + std::sort(properties.begin(), properties.end()); + std::sort(jsProperties.begin(), jsProperties.end()); + + for (int i = 0; i < len; i++) + { + if (makeExpects) + EXPECT_EQ(properties[i], jsProperties[i]); + if (properties[i] != jsProperties[i]) + return false; + + const char* sProperty = properties[i].c_str(); + if (!compare(value[sProperty], jsObj->get(sProperty), makeExpects)) + { + if (makeExpects) + ADD_FAILURE() << "Object property values for property \"" << sProperty << "\" are different!"; + return false; + } + } + } + else + { + // primitive types + if (value.IsBool()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isBool()); + if (!jsValue->isBool()) + return false; + + bool val = (bool)value; + bool jsVal = jsValue->toBool(); + if (makeExpects) + EXPECT_EQ(val, jsVal); + if (val != jsVal) + return false; + } + else if (value.IsInt()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isNumber()); + if (!jsValue->isNumber()) + return false; + + int val = (int)value; + int jsVal = jsValue->toInt32(); + if (makeExpects) + EXPECT_EQ(val, jsVal); + if (val != jsVal) + return false; + } + else if (value.IsDouble()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isNumber()); + if (!jsValue->isNumber()) + return false; + + double val = (double)value; + double jsVal = jsValue->toDouble(); + // strict check without tolerance + if (makeExpects) + EXPECT_EQ(val, jsVal); + if (val != jsVal) + return false; + } + else if (value.IsStringA()) + { + if (makeExpects) + EXPECT_TRUE(jsValue->isString()); + if (!jsValue->isString()) + return false; + + std::string val = value.ToStringA(); + std::string jsVal = jsValue->toStringA(); + if (makeExpects) + EXPECT_EQ(val, jsVal); + if (val != jsVal) + return false; + } + else + { + if (makeExpects) + EXPECT_TRUE(jsValue->isString()); + if (!jsValue->isString()) + return false; + + std::wstring val = value.ToStringW(); + std::wstring jsVal = jsValue->toStringW(); + if (makeExpects) + EXPECT_EQ(val, jsVal); + if (val != jsVal) + return false; + } + } + + return true; + } + + JSSmart getObject(const std::string& objLiteral) + { + JSSmart jsObj = m_pContext->runScript("(() => { return " + objLiteral + ";})();")->toObject(); + return jsObj; + } + public: JSSmart m_pContext; }; -TEST_F(..., ...) +TEST_F(CJSONTest, undefined_from_default_constructor) { - ... + CValue val; + JSSmart jsVal = CJSContext::createUndefined(); + EXPECT_TRUE(compare(val, jsVal)); + val = 0; + EXPECT_FALSE(compare(val, jsVal, false)); } -*/ +TEST_F(CJSONTest, undefined_from_static_method) +{ + CValue val = CValue::CreateUndefined(); + JSSmart jsVal = CJSContext::createUndefined(); + EXPECT_TRUE(compare(val, jsVal)); + val = 5; + EXPECT_FALSE(compare(val, jsVal, false)); +} + +TEST_F(CJSONTest, null_) +{ + CValue val = CValue::CreateNull(); + JSSmart jsVal = CJSContext::createNull(); + EXPECT_TRUE(compare(val, jsVal)); + val = CValue(); + EXPECT_FALSE(compare(val, jsVal, false)); +} + +TEST_F(CJSONTest, bool_) +{ + CValue val = true; + JSSmart jsVal = CJSContext::createBool(true); + EXPECT_TRUE(compare(val, jsVal)); + val = false; + EXPECT_FALSE(compare(val, jsVal, false)); +} + +TEST_F(CJSONTest, int_) +{ + CValue val = 42; + EXPECT_FALSE(val.IsDouble()); + JSSmart jsVal = CJSContext::createInt(42); + EXPECT_TRUE(compare(val, jsVal)); + val = 100; + EXPECT_FALSE(compare(val, jsVal, false)); + val = 3; + jsVal = CJSContext::createDouble(3.0); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, double_) +{ + CValue val = 3.141592; + EXPECT_FALSE(val.IsInt()); + JSSmart jsVal = CJSContext::createDouble(3.141592); + EXPECT_TRUE(compare(val, jsVal)); + val = 2.81828; + jsVal = CJSContext::createDouble(3.0); + EXPECT_FALSE(compare(val, jsVal, false)); + val = 3.0; + jsVal = CJSContext::createInt(3); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, string_char_constructor) +{ + CValue val = "test"; + JSSmart jsVal = CJSContext::createString("test"); + EXPECT_TRUE(compare(val, jsVal)); + jsVal = CJSContext::createString(L"test"); + EXPECT_TRUE(compare(val, jsVal)); + val = ""; + EXPECT_FALSE(compare(val, jsVal, false)); +} + +TEST_F(CJSONTest, string_string_constructor) +{ + CValue val = std::string("test"); + JSSmart jsVal = CJSContext::createString("test"); + EXPECT_TRUE(compare(val, jsVal)); + jsVal = CJSContext::createString(L"test"); + EXPECT_TRUE(compare(val, jsVal)); + val = ""; + EXPECT_FALSE(compare(val, jsVal, false)); +} + +TEST_F(CJSONTest, wstring_wchar_constructor) +{ + CValue val = L"тест"; + JSSmart jsVal = CJSContext::createString(L"тест"); + EXPECT_TRUE(compare(val, jsVal)); + val = "test"; + EXPECT_FALSE(compare(val, jsVal, false)); + jsVal = CJSContext::createString(L"test"); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, wstring_wstring_constructor) +{ + CValue val = std::wstring(L"тест"); + JSSmart jsVal = CJSContext::createString(L"тест"); + EXPECT_TRUE(compare(val, jsVal)); + val = "test"; + EXPECT_FALSE(compare(val, jsVal, false)); + jsVal = CJSContext::createString(L"test"); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, array_from_static_method) +{ + CValue arr = CValue::CreateArray(4); + arr[0] = CValue::CreateNull(); + arr[1] = 42; + arr[2] = CValue::CreateArray(2); + arr[2][0] = true; + arr[2][1] = 2.5; + EXPECT_TRUE(arr[3].IsUndefined()); + EXPECT_TRUE(arr[100].IsUndefined()); + EXPECT_TRUE(arr[-1].IsUndefined()); + arr[5] = 1; + JSSmart jsArr = CJSContext::createArray(4); + jsArr->set(0, CJSContext::createNull()); + jsArr->set(1, CJSContext::createInt(42)); + jsArr->set(2, CJSContext::createArray(2)); + jsArr->get(2)->toArray()->set(0, CJSContext::createBool(true)); + jsArr->get(2)->toArray()->set(1, CJSContext::createDouble(2.5)); + EXPECT_TRUE(compare(arr, jsArr->toValue())); + arr[1] = 41; + EXPECT_FALSE(compare(arr, jsArr->toValue(), false)); +} + +TEST_F(CJSONTest, array_from_initializer_list) +{ + CValue arr = {CValue::CreateNull(), 42, {true, 2.5}, CValue::CreateUndefined()}; + EXPECT_TRUE(arr[3].IsUndefined()); + EXPECT_TRUE(arr[100].IsUndefined()); + EXPECT_TRUE(arr[-1].IsUndefined()); + arr[5] = 1; + JSSmart jsArr = CJSContext::createArray(4); + jsArr->set(0, CJSContext::createNull()); + jsArr->set(1, CJSContext::createInt(42)); + jsArr->set(2, CJSContext::createArray(2)); + jsArr->get(2)->toArray()->set(0, CJSContext::createBool(true)); + jsArr->get(2)->toArray()->set(1, CJSContext::createDouble(2.5)); + EXPECT_TRUE(compare(arr, jsArr->toValue())); + arr[1] = 41; + EXPECT_FALSE(compare(arr, jsArr->toValue(), false)); +} + +TEST_F(CJSONTest, array_empty) +{ + CValue arr = CValue::CreateArray(0); + EXPECT_TRUE(arr.IsArray()); + EXPECT_EQ(arr.GetCount(), 0); + EXPECT_TRUE(arr[0].IsUndefined()); +} + +TEST_F(CJSONTest, array_negative_size) +{ + CValue arr = CValue::CreateArray(-1); + EXPECT_TRUE(arr.IsUndefined()); + EXPECT_TRUE(arr[100].IsUndefined()); +} + +TEST_F(CJSONTest, typed_array_externalize) +{ + BYTE* data = CValue::AllocTypedArray(10); + CValue typedArr = CValue::CreateTypedArray(data, 10); + JSSmart jsTypedArr = CJSContext::createUint8Array(data, 10); + EXPECT_TRUE(compare(typedArr, jsTypedArr->toValue())); + typedArr = CValue::CreateTypedArray(data, 11); + EXPECT_FALSE(compare(typedArr, jsTypedArr->toValue(), false)); + BYTE* data2 = CValue::AllocTypedArray(10); + typedArr = CValue::CreateTypedArray(data2, 10); + EXPECT_FALSE(compare(typedArr, jsTypedArr->toValue(), false)); + + CValue::FreeTypedArray(data, 10); + CValue::FreeTypedArray(data2, 10); +} + +TEST_F(CJSONTest, typed_array_not_externalize) +{ + BYTE* data = CValue::AllocTypedArray(10); + CValue typedArr = CValue::CreateTypedArray(data, 10, false); + JSSmart jsTypedArr = CJSContext::createUint8Array(data, 10); + EXPECT_TRUE(compare(typedArr, jsTypedArr->toValue())); +} + +TEST_F(CJSONTest, typed_array_empty) +{ + BYTE* data = CValue::AllocTypedArray(0); + CValue typedArr = CValue::CreateTypedArray(data, 0, false); + EXPECT_TRUE(typedArr.IsUndefined()); +} + +TEST_F(CJSONTest, typed_array_negative_size) +{ + BYTE* data = CValue::AllocTypedArray(10); + CValue typedArr = CValue::CreateTypedArray(nullptr, -10); + EXPECT_TRUE(typedArr.IsUndefined()); + CValue::FreeTypedArray(data, 10); +} + +TEST_F(CJSONTest, object) +{ + CValue obj = CValue::CreateObject(); + JSSmart jsObj = CJSContext::createObject(); + EXPECT_TRUE(compare(obj, jsObj->toValue())); + obj["name"] = "Foo"; + jsObj->set("name", CJSContext::createString("Foo")); + EXPECT_TRUE(compare(obj, jsObj->toValue())); + obj["name"] = "Bar"; + EXPECT_FALSE(compare(obj, jsObj->toValue(), false)); + obj["number"] = 42; + jsObj->set("name", CJSContext::createString("Bar")); + jsObj->set("number", CJSContext::createInt(42)); + EXPECT_TRUE(compare(obj, jsObj->toValue())); + obj["extra"] = CValue::CreateUndefined(); + EXPECT_TRUE(compare(obj, jsObj->toValue())); + obj["extra"] = CValue::CreateNull(); + EXPECT_FALSE(compare(obj, jsObj->toValue(), false)); +} + +TEST_F(CJSONTest, references) +{ + CValue val = 42; + CValueRef ref = val; + EXPECT_EQ((int)val, 42); + EXPECT_EQ((int)ref, 42); + ref = 10; + EXPECT_EQ((int)val, 10); + EXPECT_EQ((int)ref, 10); + CValueRef ref2 = ref; + val = "foo"; + EXPECT_EQ((std::string)ref, "foo"); + EXPECT_EQ((std::string)ref2, "foo"); + val = {1, 2, 3}; + EXPECT_EQ((int)ref[1], 2); + CValueRef ref3 = val[2]; + ref3 = ref2[0]; + EXPECT_EQ((int)val[2], 1); +} + +TEST_F(CJSONTest, constants) +{ + const CValue val = 42; + // you can't change constant value explicitly, but you can do it using references: + CValueRef ref = val; + ref = 10; + EXPECT_EQ((int)val, 10); + EXPECT_EQ((int)ref, 10); + // const references saves its const properties + const CValueRef ref2 = ref; + EXPECT_EQ((int)ref2, 10); +} + +TEST_F(CJSONTest, wrong_usage) +{ + CValue val = 42; + EXPECT_TRUE(val["name"].IsUndefined()); + EXPECT_TRUE(val[0].IsUndefined()); + EXPECT_TRUE(val.GetPropertyNames().empty()); + EXPECT_EQ(val.GetCount(), 0); + EXPECT_EQ(val.GetData(), nullptr); + EXPECT_EQ(val.ToStringA(), ""); + EXPECT_EQ(val.ToStringW(), L""); + EXPECT_EQ(val.ToBool(), false); + EXPECT_DOUBLE_EQ(val.ToDouble(), 42.0); +} + +#else int main() { JSSmart pContext = new CJSContext(); @@ -99,8 +548,9 @@ int main() std::cout << ret->toStringA() << std::endl; } - // Test fromJS() on the same object: + // convert fromJS() the same object: CValue textPr2 = fromJS(jsObj->toValue()); + // and then back toJS() to see if result is the same JSSmart jsObj2 = toJS(textPr2)->toObject(); global->set("textPr2", jsObj2); ret = pContext->runScript("(function () { return JSON.stringify(textPr2, null, 4); })();"); @@ -111,3 +561,4 @@ int main() return 0; } +#endif // JSON_GOOGLE_TEST diff --git a/DesktopEditor/doctrenderer/test/json/test.pro b/DesktopEditor/doctrenderer/test/json/test.pro index 2669f84897..e6323902bf 100644 --- a/DesktopEditor/doctrenderer/test/json/test.pro +++ b/DesktopEditor/doctrenderer/test/json/test.pro @@ -14,7 +14,15 @@ CORE_3DPARTY_DIR = $$CORE_ROOT_DIR/Common/3dParty PWD_ROOT_DIR = $$PWD include($$CORE_ROOT_DIR/Common/base.pri) -#include($$CORE_3DPARTY_DIR/googletest/googletest.pri) + +# Comment to inspect simple usage example +# Uncomment to run google tests +CONFIG += json_google_test + +json_google_test { + include($$CORE_3DPARTY_DIR/googletest/googletest.pri) + DEFINES += JSON_GOOGLE_TEST +} DESTDIR = $$PWD/build From d75c7c93f04aff1201936eb7b0bc84fbd37e0034 Mon Sep 17 00:00:00 2001 From: Kirill Polyakov Date: Tue, 28 Nov 2023 13:47:02 +0300 Subject: [PATCH 36/54] Optimization --- DesktopEditor/graphics/Graphics.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DesktopEditor/graphics/Graphics.cpp b/DesktopEditor/graphics/Graphics.cpp index 48c685f300..8a83395f5b 100644 --- a/DesktopEditor/graphics/Graphics.cpp +++ b/DesktopEditor/graphics/Graphics.cpp @@ -1278,8 +1278,7 @@ namespace Aggplus BYTE *pBuffer = new BYTE[unWidth * unHeight * m_frame_buffer.pix_size]; - for (unsigned long unIndex = 0; unIndex < unWidth * unHeight * m_frame_buffer.pix_size; unIndex += 4) - ((BYTE*)pBuffer)[unIndex + pixfmt_type::order_type::A] = 0x00; + memset(pBuffer, 0x00, unWidth * unHeight * m_frame_buffer.pix_size); m_frame_buffer.create(unWidth, unHeight, false, nStride, pBuffer); From 2895e27c324dbfb1682e6b1f1bd5c0b4a3a0be22 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Tue, 28 Nov 2023 15:19:51 +0400 Subject: [PATCH 37/54] Made code coverage 100% for CValue & CValueRef --- DesktopEditor/doctrenderer/json/json.cpp | 29 ++++++- DesktopEditor/doctrenderer/json/json.h | 4 +- .../doctrenderer/json/json_values.cpp | 81 +------------------ DesktopEditor/doctrenderer/json/json_values.h | 20 +---- DesktopEditor/doctrenderer/test/json/main.cpp | 76 ++++++++++++++++- 5 files changed, 109 insertions(+), 101 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/json.cpp b/DesktopEditor/doctrenderer/json/json.cpp index f2ded6054e..96cc8bef95 100644 --- a/DesktopEditor/doctrenderer/json/json.cpp +++ b/DesktopEditor/doctrenderer/json/json.cpp @@ -90,35 +90,60 @@ namespace NSJSON bool IValue::ToBool() const { if (m_internal->m_type != CTypedValue::vtPrimitive) + { +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif return false; + } return static_cast(m_internal->m_value.get())->toBool(); } int IValue::ToInt() const { if (m_internal->m_type != CTypedValue::vtPrimitive) + { +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif return 0; + } return static_cast(m_internal->m_value.get())->toInt(); } double IValue::ToDouble() const { if (m_internal->m_type != CTypedValue::vtPrimitive) + { +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif return 0.0; + } return static_cast(m_internal->m_value.get())->toDouble(); } std::string IValue::ToStringA() const { if (m_internal->m_type != CTypedValue::vtPrimitive) + { +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif return ""; + } return static_cast(m_internal->m_value.get())->toStringA(); } std::wstring IValue::ToStringW() const { if (m_internal->m_type != CTypedValue::vtPrimitive) + { +#ifdef JSON_DEBUG + throw std::bad_cast(); +#endif return L""; + } return static_cast(m_internal->m_value.get())->toStringW(); } @@ -367,10 +392,6 @@ namespace NSJSON return ret; } - CValueRef::CValueRef() : IValue() - { - } - CValueRef::CValueRef(const CValueRef& other) : IValue(other.m_internal) { } diff --git a/DesktopEditor/doctrenderer/json/json.h b/DesktopEditor/doctrenderer/json/json.h index 0535ea746d..fef572ead7 100644 --- a/DesktopEditor/doctrenderer/json/json.h +++ b/DesktopEditor/doctrenderer/json/json.h @@ -17,6 +17,9 @@ #endif #endif +// uncomment to enable exceptions throwing +//#define JSON_DEBUG + namespace NSJSON { typedef unsigned char BYTE; @@ -257,7 +260,6 @@ namespace NSJSON class JSON_DECL CValueRef : public IValue { public: - CValueRef(); CValueRef(const CValueRef& other); CValueRef(const CValue& value); ~CValueRef(); diff --git a/DesktopEditor/doctrenderer/json/json_values.cpp b/DesktopEditor/doctrenderer/json/json_values.cpp index d37ea38804..8b15705622 100644 --- a/DesktopEditor/doctrenderer/json/json_values.cpp +++ b/DesktopEditor/doctrenderer/json/json_values.cpp @@ -10,10 +10,6 @@ namespace NSJSON { } - CPrimitive::CPrimitive() - { - } - CPrimitive::CPrimitive(bool value) : m_type(ptBoolean) { m_bool = value; @@ -39,36 +35,17 @@ namespace NSJSON new (&m_wstring) std::wstring(wstr); } - CPrimitive::CPrimitive(const CPrimitive& other) - { - this->set(other); - } - CPrimitive::~CPrimitive() { - clear(); - } - - void CPrimitive::set(const CPrimitive& other) - { - clear(); - m_type = other.m_type; switch (m_type) { - case ptBoolean: - m_bool = other.m_bool; - break; - case ptInteger: - m_int = other.m_int; - break; - case ptDouble: - m_double = other.m_double; - break; case ptStringA: - new (&m_string) std::string(other.m_string); + m_string.~basic_string(); break; case ptStringW: - new (&m_wstring) std::wstring(other.m_wstring); + m_wstring.~basic_string(); + break; + default: break; } } @@ -152,56 +129,6 @@ namespace NSJSON return L""; } - void CPrimitive::set(bool value) - { - clear(); - m_type = ptBoolean; - m_bool = value; - } - - void CPrimitive::set(int value) - { - clear(); - m_type = ptInteger; - m_int = value; - } - - void CPrimitive::set(double value) - { - clear(); - m_type = ptDouble; - m_double = value; - } - - void CPrimitive::set(const std::string& str) - { - clear(); - m_type = ptStringA; - new (&m_string) std::string(str); - } - - void CPrimitive::set(const std::wstring& wstr) - { - clear(); - m_type = ptStringW; - new (&m_wstring) std::wstring(wstr); - } - - void CPrimitive::clear() - { - switch (m_type) - { - case ptStringA: - m_string.~basic_string(); - break; - case ptStringW: - m_wstring.~basic_string(); - break; - default: - break; - } - } - CArray::CArray(int count) : m_values(count) { } diff --git a/DesktopEditor/doctrenderer/json/json_values.h b/DesktopEditor/doctrenderer/json/json_values.h index d7d378d875..e3c01ecaf4 100644 --- a/DesktopEditor/doctrenderer/json/json_values.h +++ b/DesktopEditor/doctrenderer/json/json_values.h @@ -7,9 +7,6 @@ #include "json.h" -// uncomment to see debug output and exceptions -//#define JSON_DEBUG - namespace NSJSON { class IBaseValue @@ -32,8 +29,6 @@ namespace NSJSON }; public: - CPrimitive(); - CPrimitive(const CPrimitive& other); CPrimitive(bool value); CPrimitive(int value); CPrimitive(double value); @@ -41,6 +36,10 @@ namespace NSJSON CPrimitive(const std::wstring& wstr); ~CPrimitive(); + // disable copy + CPrimitive(const CPrimitive& other) = delete; + CPrimitive& operator=(const CPrimitive& other) = delete; + // type check bool isBool() const; bool isInt() const; @@ -55,17 +54,6 @@ namespace NSJSON std::string toStringA() const; std::wstring toStringW() const; - // setters - void set(const CPrimitive& other); - void set(bool value); - void set(int value); - void set(double value); - void set(const std::string& str); - void set(const std::wstring& wstr); - - private: - void clear(); - private: union { diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index c0df5bbc45..e742157c78 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -187,7 +187,10 @@ public: else { if (makeExpects) + { + EXPECT_TRUE(value.IsStringW()); EXPECT_TRUE(jsValue->isString()); + } if (!jsValue->isString()) return false; @@ -444,12 +447,27 @@ TEST_F(CJSONTest, references) ref = 10; EXPECT_EQ((int)val, 10); EXPECT_EQ((int)ref, 10); + // CValue from CValueRef + CValue val2 = ref; + val2 = 12; + EXPECT_EQ((int)val2, 12); + EXPECT_EQ((int)ref, 10); + EXPECT_EQ((int)val, 10); + // chaining CValueRef-s CValueRef ref2 = ref; val = "foo"; EXPECT_EQ((std::string)ref, "foo"); EXPECT_EQ((std::string)ref2, "foo"); val = {1, 2, 3}; EXPECT_EQ((int)ref[1], 2); + // CValue assignment to CValueRef + val2 = ref2; + EXPECT_EQ((int)val2[0], 1); + val2 = true; + EXPECT_EQ((bool)val2, true); + EXPECT_TRUE(ref.IsArray()); + EXPECT_TRUE(ref2.IsArray()); + // CValueRef from operator[] CValueRef ref3 = val[2]; ref3 = ref2[0]; EXPECT_EQ((int)val[2], 1); @@ -465,6 +483,8 @@ TEST_F(CJSONTest, constants) EXPECT_EQ((int)ref, 10); // const references saves its const properties const CValueRef ref2 = ref; + // you can't do that: + // ref2 = 100; EXPECT_EQ((int)ref2, 10); } @@ -476,10 +496,60 @@ TEST_F(CJSONTest, wrong_usage) EXPECT_TRUE(val.GetPropertyNames().empty()); EXPECT_EQ(val.GetCount(), 0); EXPECT_EQ(val.GetData(), nullptr); - EXPECT_EQ(val.ToStringA(), ""); - EXPECT_EQ(val.ToStringW(), L""); - EXPECT_EQ(val.ToBool(), false); EXPECT_DOUBLE_EQ(val.ToDouble(), 42.0); +#ifdef JSON_DEBUG + EXPECT_THROW((bool)val, std::bad_cast); + EXPECT_THROW((std::string)val, std::bad_cast); + EXPECT_THROW((std::wstring)val, std::bad_cast); +#else + EXPECT_EQ((bool)val, false); + EXPECT_EQ((std::string)val, ""); + EXPECT_EQ((std::wstring)val, L""); +#endif + + val = 3.1415926535; + EXPECT_EQ((int)val, 3); + + val = "test"; +#ifdef JSON_DEBUG + EXPECT_THROW((bool)val, std::bad_cast); + EXPECT_THROW((int)val, std::bad_cast); + EXPECT_THROW((double)val, std::bad_cast); + EXPECT_THROW((std::wstring)val, std::bad_cast); +#else + EXPECT_EQ((bool)val, false); + EXPECT_EQ((int)val, 0); + EXPECT_EQ((double)val, 0.0); + EXPECT_EQ((std::wstring)val, L""); +#endif + + val = L"тест"; +#ifdef JSON_DEBUG + EXPECT_THROW((bool)val, std::bad_cast); + EXPECT_THROW((int)val, std::bad_cast); + EXPECT_THROW((double)val, std::bad_cast); + EXPECT_THROW((std::string)val, std::bad_cast); +#else + EXPECT_EQ((bool)val, false); + EXPECT_EQ((int)val, 0); + EXPECT_EQ((double)val, 0.0); + EXPECT_EQ((std::string)val, ""); +#endif + + val = CValue::CreateObject(); +#ifdef JSON_DEBUG + EXPECT_THROW((bool)val, std::bad_cast); + EXPECT_THROW((int)val, std::bad_cast); + EXPECT_THROW((double)val, std::bad_cast); + EXPECT_THROW((std::string)val, std::bad_cast); + EXPECT_THROW((std::wstring)val, std::bad_cast); +#else + EXPECT_EQ((bool)val, false); + EXPECT_EQ((int)val, 0); + EXPECT_EQ((double)val, 0.0); + EXPECT_EQ((std::string)val, ""); + EXPECT_EQ((std::wstring)val, L""); +#endif } #else From 97c314e3797523000bd038eb025c8f8d768f6e44 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Wed, 29 Nov 2023 14:22:51 +0400 Subject: [PATCH 38/54] All tests were added. Small serialization rework. - Code coverage: 100% - Restructured serialization code to handle primitives first --- .../doctrenderer/json/serialization.h | 100 ++++--- DesktopEditor/doctrenderer/test/json/main.cpp | 270 +++++++++++++++++- 2 files changed, 323 insertions(+), 47 deletions(-) diff --git a/DesktopEditor/doctrenderer/json/serialization.h b/DesktopEditor/doctrenderer/json/serialization.h index 450e2241f9..844d625633 100644 --- a/DesktopEditor/doctrenderer/json/serialization.h +++ b/DesktopEditor/doctrenderer/json/serialization.h @@ -16,7 +16,29 @@ namespace NSJSON return NSJSBase::CJSContext::createNull(); JSSmart ret; - if (value.IsArray()) + // handle primitive types first, as they are most commonly used + if (value.IsBool()) + { + ret = NSJSBase::CJSContext::createBool((bool)value); + } + else if (value.IsInt()) + { + ret = NSJSBase::CJSContext::createInt((int)value); + } + else if (value.IsDouble()) + { + ret = NSJSBase::CJSContext::createDouble((double)value); + } + else if (value.IsStringA()) + { + ret = NSJSBase::CJSContext::createString((std::string)value); + } + else if (value.IsStringW()) + { + ret = NSJSBase::CJSContext::createString((std::wstring)value); + } + // arrays + else if (value.IsArray()) { const int len = value.GetCount(); JSSmart jsArr = NSJSBase::CJSContext::createArray(len); @@ -26,12 +48,14 @@ namespace NSJSON } ret = jsArr->toValue(); } + // typed arrays else if (value.IsTypedArray()) { JSSmart jsTypedArr = NSJSBase::CJSContext::createUint8Array(const_cast(value.GetData()), value.GetCount()); ret = jsTypedArr->toValue(); } - else if (value.IsObject()) + // objects (there is no need for IsObject()) + else { JSSmart jsObj = NSJSBase::CJSContext::createObject(); std::vector properties = value.GetPropertyNames(); @@ -42,20 +66,6 @@ namespace NSJSON } ret = jsObj->toValue(); } - else - { - // primitive types - if (value.IsBool()) - ret = NSJSBase::CJSContext::createBool((bool)value); - else if (value.IsInt()) - ret = NSJSBase::CJSContext::createInt((int)value); - else if (value.IsDouble()) - ret = NSJSBase::CJSContext::createDouble((double)value); - else if (value.IsStringA()) - ret = NSJSBase::CJSContext::createString((std::string)value); - else - ret = NSJSBase::CJSContext::createString((std::wstring)value); - } return ret; } @@ -68,8 +78,38 @@ namespace NSJSON return CValue::CreateNull(); CValue ret; - - if (jsValue->isArray()) + // handle primitive types first, as they are most commonly used + if (jsValue->isBool()) + { + ret = CValue(jsValue->toBool()); + } + else if (jsValue->isNumber()) + { + double number = jsValue->toDouble(); + if (std::isfinite(number)) + { + // check if number is an integer or double + double integral; // integral part + double fractional = std::modf(number, &integral); // fractional part + // TODO: this may not work for non-32 bit integers + if (fractional == 0.0 && integral >= INT_MIN && integral <= INT_MAX) + ret = (int)integral; + else + ret = number; + } + else + { + // handle NaN, inf, -inf + ret = number; + } + } + else if (jsValue->isString()) + { + // convert all strings to std::wstring, because in JS all strings are encoded in UTF-16 + ret = jsValue->toStringW(); + } + // arrays + else if (jsValue->isArray()) { JSSmart jsArr = jsValue->toArray(); const int len = jsArr->getCount(); @@ -80,6 +120,7 @@ namespace NSJSON ret[i] = fromJS(jsElement); } } + // typed arrays else if (jsValue->isTypedArray()) { JSSmart jsTypedArr = jsValue->toTypedArray(); @@ -87,6 +128,7 @@ namespace NSJSON BYTE* data = jsTypedArr->getData().Data; ret = CValue::CreateTypedArray(data, len); } + // objects else if (jsValue->isObject()) { JSSmart jsObj = jsValue->toObject(); @@ -98,27 +140,7 @@ namespace NSJSON ret[name.c_str()] = fromJS(jsPropertyValue); } } - // primitives - else if (jsValue->isBool()) - { - ret = CValue(jsValue->toBool()); - } - else if (jsValue->isNumber()) - { - // check if number is an integer or double - double number = jsValue->toDouble(); - double integral; // integral part - double fractional = std::modf(number, &integral); // fractional part - if (fractional == 0.0 && integral >= INT_MIN && integral <= INT_MAX) - ret = (int)integral; - else - ret = number; - } - else if (jsValue->isString()) - { - // convert all strings to std::wstring, cause in JS all strings are encoded in UTF-16 - ret = jsValue->toStringW(); - } + // else the type is not supported and will be converted as undefined value return ret; } diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index e742157c78..9d82952cab 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -164,11 +164,21 @@ public: double val = (double)value; double jsVal = jsValue->toDouble(); - // strict check without tolerance - if (makeExpects) - EXPECT_EQ(val, jsVal); - if (val != jsVal) - return false; + if (!std::isnan(val)) + { + // strict check without tolerance + if (makeExpects) + EXPECT_EQ(val, jsVal); + if (val != jsVal) + return false; + } + else + { + if (makeExpects) + EXPECT_TRUE(std::isnan(jsVal)); + if (!std::isnan(jsVal)) + return false; + } } else if (value.IsStringA()) { @@ -216,6 +226,8 @@ public: JSSmart m_pContext; }; +// --------- CValue basic functinality tests ---------- + TEST_F(CJSONTest, undefined_from_default_constructor) { CValue val; @@ -418,6 +430,17 @@ TEST_F(CJSONTest, typed_array_negative_size) CValue::FreeTypedArray(data, 10); } +TEST_F(CJSONTest, typed_array_copy) +{ + BYTE* data = CValue::AllocTypedArray(10); + CValue typedArr = CValue::CreateTypedArray(data, 10, false); + { + CValue typedArr2 = typedArr; + typedArr2.GetData()[4] = 0x42; + } + EXPECT_EQ(typedArr.GetData()[4], 0x42); +} + TEST_F(CJSONTest, object) { CValue obj = CValue::CreateObject(); @@ -476,15 +499,15 @@ TEST_F(CJSONTest, references) TEST_F(CJSONTest, constants) { const CValue val = 42; - // you can't change constant value explicitly, but you can do it using references: + // NOTE: you can't change constant value explicitly, but you can do it using references: CValueRef ref = val; ref = 10; EXPECT_EQ((int)val, 10); EXPECT_EQ((int)ref, 10); - // const references saves its const properties + // NOTE: const references saves its const properties const CValueRef ref2 = ref; // you can't do that: - // ref2 = 100; +// ref2 = 100; EXPECT_EQ((int)ref2, 10); } @@ -552,6 +575,237 @@ TEST_F(CJSONTest, wrong_usage) #endif } +// ----------- toJS() tests ----------- + +TEST_F(CJSONTest, toJS_undefined) +{ + CValue val; + JSSmart jsVal = toJS(val); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, toJS_null) +{ + CValue val = CValue::CreateNull(); + JSSmart jsVal = toJS(val); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, toJS_typed_arrays) +{ + BYTE* data = CValue::AllocTypedArray(4); + data[0] = 0x1A; + data[1] = 0x54; + data[2] = 0xFE; + data[3] = 0xFF; + CValue typedArr = CValue::CreateTypedArray(data, 4, false); + JSSmart jsTypedArr = toJS(typedArr); + // NOTE: BE CAREFUL WHEN CALLLING toJS() MULTIPLE TIMES WITH THE SAME TYPED ARRAY! + // second typed array will NOT be initialized properly, since there is another `CJSTypedArray` containing this memory! +// JSSmart jsTypedArr2 = toJS(typedArr); + EXPECT_TRUE(compare(typedArr, jsTypedArr)); +} + +TEST_F(CJSONTest, toJS_arrays) +{ + BYTE* data = CValue::AllocTypedArray(4); + data[0] = 0x1A; + data[1] = 0x54; + data[2] = 0xFE; + data[3] = 0xFF; + CValue typedArr = CValue::CreateTypedArray(data, 4, false); + + // can't add typed array to this inner array (see test above), only to external array + CValue arrInner = {true, 42, L"тест функции toJS()", 2.71828, CValue(), "abc de f", L"test"}; + CValue arr = {0, arrInner, arrInner, CValue::CreateNull(), arrInner, CValue::CreateArray(4), typedArr}; + + JSSmart jsArr = toJS(arr); + EXPECT_TRUE(compare(arr, jsArr)); +} + +TEST_F(CJSONTest, toJS_arrays_circular) +{ + // NOTE: BE CAREFULL WHEN CREATING CIRCULAR REFERENCE DEPENDENCY IN YOUR ARRAY OR OBJECT! + CValue arr = CValue::CreateArray(2); + CValueRef ref = arr; + arr[0] = 3; + arr[1] = ref; + // or simply: +// arr[1] = arr; + + EXPECT_EQ((int)arr[0], 3); + EXPECT_EQ((int)arr[1][0], 3); + EXPECT_EQ((int)arr[1][1][1][1][1][1][1][1][1][1][0], 3); + EXPECT_TRUE(arr[1][1][1][1].IsArray()); + // here you will get stack overflow, because each inner array reference will be transformed to a new copy of `CJSArray` +// JSSmart jsArr = toJS(arr); + + // keep only 2 inner recursions + CValue arrRec = arr[1][1]; + arrRec[1] = 42; + EXPECT_TRUE(arr[1].IsInt()); + + JSSmart jsArr = toJS(arr); + EXPECT_TRUE(compare(arr, jsArr)); +} + +TEST_F(CJSONTest, toJS_objects) +{ + CValue obj = CValue::CreateObject(); + obj["name"] = L"Foo"; + obj["parameters"] = CValue::CreateObject(); + CValueRef parameters = obj["parameters"]; + parameters["size"] = 42; + parameters["arr"] = {CValue::CreateNull(), CValue::CreateArray(0), {42, L"тест функции toJS()", 2.71828}, CValue::CreateObject(), CValue(), "abc de f", L"test"}; + parameters["0"] = 0; + + BYTE* data = CValue::AllocTypedArray(4); + data[0] = 0x1A; + data[1] = 0x54; + data[2] = 0xFE; + data[3] = 0xFF; + CValue typedArr = CValue::CreateTypedArray(data, 4, false); + obj["typed"] = typedArr; + // NOTE: you can create property even without a name (like in JS) + obj[""] = "Bar"; + + JSSmart jsObj = toJS(obj); + EXPECT_TRUE(compare(obj, jsObj)); +} + +// ----------- fromJS() tests ----------- + +TEST_F(CJSONTest, fromJS_undefined) +{ + JSSmart jsVal = CJSContext::createUndefined(); + CValue val = fromJS(jsVal); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, fromJS_null) +{ + JSSmart jsVal = CJSContext::createNull(); + CValue val = fromJS(jsVal); + EXPECT_TRUE(compare(val, jsVal)); +} + +TEST_F(CJSONTest, fromJS_and_toJS_edge_numbers) +{ + JSSmart jsVal = CJSContext::createArray(16); + jsVal->set(0, INT_MIN); + jsVal->set(1, INT_MAX); + jsVal->set(2, 0); + jsVal->set(3, 42); + jsVal->set(4, 0.0); + jsVal->set(5, 3.1415926535); + jsVal->set(6, 42.0); + jsVal->set(7, (double)INT_MIN); + jsVal->set(8, (double)INT_MAX); + jsVal->set(9, std::pow(2.0, 31) - 1); + jsVal->set(10, std::pow(2.0, 31)); + jsVal->set(11, -std::pow(2.0, 31)); + jsVal->set(12, -std::pow(2.0, 31) - 1); + jsVal->set(13, INFINITY); + jsVal->set(14, NAN); + jsVal->set(15, -INFINITY); + + CValue val = fromJS(jsVal->toValue()); + EXPECT_TRUE(compare(val, jsVal->toValue())); + EXPECT_TRUE(val[0].IsInt()); // INT_MIN + EXPECT_TRUE(val[1].IsInt()); // INT_MAX + EXPECT_TRUE(val[2].IsInt()); // 0 + EXPECT_TRUE(val[3].IsInt()); // 42 + EXPECT_TRUE(val[4].IsInt()); // 0.0 + EXPECT_TRUE(val[5].IsDouble()); // 3.1415926535 + EXPECT_TRUE(val[6].IsInt()); // 42.0 + EXPECT_TRUE(val[7].IsInt()); // (double)INT_MIN + EXPECT_TRUE(val[8].IsInt()); // (double)INT_MAX + EXPECT_TRUE(val[9].IsInt()); // 2^31 - 1 == INT_MAX + EXPECT_TRUE(val[10].IsDouble()); // 2^31 + EXPECT_TRUE(val[11].IsInt()); // -2^31 == INT_MIN + EXPECT_TRUE(val[12].IsDouble()); // -2^31 - 1 + EXPECT_TRUE(val[13].IsDouble()); // inf + EXPECT_TRUE(val[14].IsDouble()); // NaN + EXPECT_TRUE(val[15].IsDouble()); // -inf + + JSSmart jsVal2 = toJS(val); + EXPECT_TRUE(compare(val, jsVal2)); +} + +TEST_F(CJSONTest, fromJS_typed_arrays) +{ + BYTE* data = NSAllocator::Alloc(4); + data[0] = 0x1A; + data[1] = 0x54; + data[2] = 0xFE; + data[3] = 0xFF; + JSSmart jsTypedArr = CJSContext::createUint8Array(data, 4, false); + CValue typedArr = fromJS(jsTypedArr); + EXPECT_TRUE(compare(typedArr, jsTypedArr)); +} + +TEST_F(CJSONTest, fromJS_arrays) +{ + BYTE* data = NSAllocator::Alloc(4); + data[0] = 0x1A; + data[1] = 0x54; + data[2] = 0xFE; + data[3] = 0xFF; + JSSmart jsTypedArr = CJSContext::createUint8Array(data, 4, false); + JSSmart jsArrInner = CJSContext::createArray(0); + jsArrInner->add_bool(true); + jsArrInner->add_int(42); + jsArrInner->add_string(L"тест функции fromJS()"); + jsArrInner->add_double(2.71828); + jsArrInner->add_undefined(); + jsArrInner->add_stringa("abc de f"); + jsArrInner->add_string(L"test"); + JSSmart jsArr = CJSContext::createArray(0); + jsArr->add_int(0); + jsArr->add(jsArrInner->toValue()); + jsArr->add(jsArrInner->toValue()); + jsArr->add_null(); + jsArr->add(jsArrInner->toValue()); + jsArr->add(CJSContext::createArray(4)); + jsArr->add(jsTypedArr); + + CValue arr = fromJS(jsArr->toValue()); + EXPECT_TRUE(compare(arr, jsArr->toValue())); +} + +TEST_F(CJSONTest, fromJS_objects) +{ + JSSmart jsObj = CJSContext::createObject(); + jsObj->set("name", CJSContext::createString(L"Foo")); + + JSSmart jsParam = CJSContext::createObject(); + jsParam->set("size", 42); + jsParam->set("arr", CJSContext::createArray(0)); + + JSSmart jsArr = jsParam->get("arr")->toArray(); + jsArr->add_null(); + jsArr->add(CJSContext::createArray(0)); + jsArr->add(CJSContext::createArray(3)); + jsArr->get(2)->toArray()->set(0, 42); + jsArr->get(2)->toArray()->set(1, CJSContext::createString(L"тест функции fromJS()")); + jsArr->get(2)->toArray()->set(2, 2.71828); + jsArr->add(CJSContext::createObject()); + jsArr->add_undefined(); + jsArr->add_stringa("abc de f"); + jsArr->add_bool(true); + jsParam->set("0", 0); + + BYTE* data = NSAllocator::Alloc(4); + data[0] = 0x1A; + data[1] = 0x54; + data[2] = 0xFE; + data[3] = 0xFF; + JSSmart jsTypedArr = CJSContext::createUint8Array(data, 4, false); + + CValue obj = fromJS(jsObj->toValue()); + EXPECT_TRUE(compare(obj, jsObj->toValue())); +} + #else int main() { From 8ad3170a26be0f4527b1ec00adacb4379b0b616a Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Wed, 29 Nov 2023 20:12:49 +0400 Subject: [PATCH 39/54] JSC: fixed createString() functions --- DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm index 504aec74bf..a4b629b06a 100644 --- a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm +++ b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm @@ -293,7 +293,7 @@ namespace NSJSBase CJSValue* CJSContext::createString(const char* value, const int& len) { CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [NSString stringWithUtf8Buffer:value length:(size_t)((len == -1) ? strlen(value) : len)]; + _value->value = [JSValue valueWithObject:[NSString stringWithUtf8Buffer:value length:(size_t)((len == -1) ? strlen(value) : len)] inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; return _value; } @@ -306,14 +306,14 @@ namespace NSJSBase CJSValue* CJSContext::createString(const std::string& value) { CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [NSString stringWithAString:value]; + _value->value = [JSValue valueWithObject:[NSString stringWithAString:value] inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; return _value; } CJSValue* CJSContext::createString(const std::wstring& value) { CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [NSString stringWithWString:value]; + _value->value = [JSValue valueWithObject:[NSString stringWithWString:value] inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; return _value; } From 610b0b08313b8bb9b03c01d7d546acfce3ba17ca Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Wed, 29 Nov 2023 20:13:07 +0400 Subject: [PATCH 40/54] JSC: fixed json tests --- DesktopEditor/doctrenderer/test/json/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 9d82952cab..9b67013081 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -353,6 +353,7 @@ TEST_F(CJSONTest, array_from_static_method) jsArr->set(2, CJSContext::createArray(2)); jsArr->get(2)->toArray()->set(0, CJSContext::createBool(true)); jsArr->get(2)->toArray()->set(1, CJSContext::createDouble(2.5)); + jsArr->set(3, CJSContext::createUndefined()); EXPECT_TRUE(compare(arr, jsArr->toValue())); arr[1] = 41; EXPECT_FALSE(compare(arr, jsArr->toValue(), false)); @@ -371,6 +372,7 @@ TEST_F(CJSONTest, array_from_initializer_list) jsArr->set(2, CJSContext::createArray(2)); jsArr->get(2)->toArray()->set(0, CJSContext::createBool(true)); jsArr->get(2)->toArray()->set(1, CJSContext::createDouble(2.5)); + jsArr->set(3, CJSContext::createUndefined()); EXPECT_TRUE(compare(arr, jsArr->toValue())); arr[1] = 41; EXPECT_FALSE(compare(arr, jsArr->toValue(), false)); From 0258c0340064a690d8ddb40000f0cbd787d2fd75 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Thu, 30 Nov 2023 09:46:52 +0300 Subject: [PATCH 41/54] Fix build --- DesktopEditor/graphics/commands/AnnotField.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/DesktopEditor/graphics/commands/AnnotField.cpp b/DesktopEditor/graphics/commands/AnnotField.cpp index 9c3f6782e4..6035767f1f 100644 --- a/DesktopEditor/graphics/commands/AnnotField.cpp +++ b/DesktopEditor/graphics/commands/AnnotField.cpp @@ -457,9 +457,12 @@ bool CAnnotFieldInfo::Read(NSOnlineOfficeBinToPdf::CBufferReader* pReader, IMeta { m_oBorder.nType = pReader->ReadByte(); m_oBorder.dWidth = pReader->ReadDouble(); - int n = pReader->ReadInt(); - for (int i = 0; i < n; ++i) - m_oBorder.arrDash.push_back(pReader->ReadDouble()); + if (m_oBorder.nType == 2) + { + int n = pReader->ReadInt(); + for (int i = 0; i < n; ++i) + m_oBorder.arrDash.push_back(pReader->ReadDouble()); + } } if (nFlags & (1 << 5)) m_wsLM = pReader->ReadString(); From 61d75ed09231b29cb626642019795ecdf890a28b Mon Sep 17 00:00:00 2001 From: "Elena.Subbotina" Date: Thu, 30 Nov 2023 10:38:21 +0300 Subject: [PATCH 42/54] revert test --- .../test/ExampleFiles/xlsb2xlsx/simple1.xlsb | Bin 6973 -> 0 bytes .../test/ExampleFiles/xlsb2xlsx/simple1.xlsx | Bin 7310 -> 0 bytes .../test/ExampleFiles/xlsb2xlsx/simple2.xlsb | Bin 14044 -> 0 bytes .../test/ExampleFiles/xlsb2xlsx/simple2.xlsx | Bin 18500 -> 0 bytes X2tConverter/test/qmake/common.cpp | 175 ------------- X2tConverter/test/qmake/common.h | 42 --- X2tConverter/test/qmake/main.cpp | 173 +++++++++++- X2tConverter/test/qmake/test.pro | 10 +- X2tConverter/test/xlsb2xlsx/conversion.cpp | 246 ------------------ 9 files changed, 169 insertions(+), 477 deletions(-) delete mode 100644 X2tConverter/test/ExampleFiles/xlsb2xlsx/simple1.xlsb delete mode 100644 X2tConverter/test/ExampleFiles/xlsb2xlsx/simple1.xlsx delete mode 100644 X2tConverter/test/ExampleFiles/xlsb2xlsx/simple2.xlsb delete mode 100644 X2tConverter/test/ExampleFiles/xlsb2xlsx/simple2.xlsx delete mode 100644 X2tConverter/test/qmake/common.cpp delete mode 100644 X2tConverter/test/qmake/common.h delete mode 100644 X2tConverter/test/xlsb2xlsx/conversion.cpp diff --git a/X2tConverter/test/ExampleFiles/xlsb2xlsx/simple1.xlsb b/X2tConverter/test/ExampleFiles/xlsb2xlsx/simple1.xlsb deleted file mode 100644 index c71a49e25f38717f7bf71cf02a1e2946ccfcfd05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6973 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 diff --git a/X2tConverter/test/ExampleFiles/xlsb2xlsx/simple1.xlsx b/X2tConverter/test/ExampleFiles/xlsb2xlsx/simple1.xlsx deleted file mode 100644 index 6f10ff38a5c0f1f5178ac2415bc6c29d267998b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7310 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 diff --git a/X2tConverter/test/ExampleFiles/xlsb2xlsx/simple2.xlsb b/X2tConverter/test/ExampleFiles/xlsb2xlsx/simple2.xlsb deleted file mode 100644 index b6e5e04031d0669c92005dfc13117e648a3853c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14044 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 YMM|20Kr3W3zneYB-!0;`0w4_ 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 APXGV_ diff --git a/X2tConverter/test/qmake/common.cpp b/X2tConverter/test/qmake/common.cpp deleted file mode 100644 index cd7b3bba23..0000000000 --- a/X2tConverter/test/qmake/common.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * (c) Copyright Ascensio System SIA 2010-2023 - * - * 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-6 Ernesta Birznieka-Upish - * 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 "common.h" - -#include "../../../DesktopEditor/common/Directory.h" -#include "../../../DesktopEditor/common/Path.h" -#include "../../../OfficeUtils/src/OfficeUtils.h" -#include "../../../DesktopEditor/fontengine/ApplicationFontsWorker.h" -#include "../../../Common/OfficeFileFormatChecker.h" -#include "../../../DesktopEditor/common/StringBuilder.h" -#include "../../src/dylib/x2t.h" -#include "tchar.h" -#include -#include -#include -#include - - -std::wstring GetWorkDir() -{ - std::wstring curDir = NSFile::GetProcessDirectory(); - return NSDirectory::CreateDirectoryWithUniqueName(curDir); -} - -void RemoveWorkDir(const std::wstring &dir) -{ - NSDirectory::DeleteDirectory(dir); -} - -int ConvertFile(const std::wstring &fileName) -{ - x2tchar* args[2]; - args[0] = NULL; - args[1] = (x2tchar*)fileName.c_str(); - - int nResultCode = X2T_Convert(2, args); - return nResultCode; -} - -void PrepareFiles(const std::wstring &fileName, const std::wstring &exampleFileName, const std::wstring &tempDirName) -{ - std::wstring sTempUnpackedXLSB = tempDirName + FILE_SEPARATOR_STR + _T("result_unpacked"); - NSDirectory::CreateDirectory(sTempUnpackedXLSB); - COfficeUtils oCOfficeUtils(NULL); - _UINT32 nRes = oCOfficeUtils.ExtractToDirectory(fileName, sTempUnpackedXLSB, NULL, 0); - - std::wstring sTempUnpackedXLSX = tempDirName + FILE_SEPARATOR_STR + _T("example_unpacked"); - NSDirectory::CreateDirectory(sTempUnpackedXLSX); - nRes = oCOfficeUtils.ExtractToDirectory(exampleFileName, sTempUnpackedXLSX, NULL, 0); -} - -void CheckFonts(const std::wstring& fontsDir, bool isUseSystem, const std::vector& addtitionalFontsDirs) -{ - CApplicationFontsWorker fonts_worker; - - fonts_worker.m_sDirectory = fontsDir; - if (!NSDirectory::Exists(fonts_worker.m_sDirectory)) - NSDirectory::CreateDirectory(fonts_worker.m_sDirectory); - - fonts_worker.m_bIsUseSystemFonts = isUseSystem; - - for (const auto& additional : addtitionalFontsDirs) - { - std::wstring sFolder = additional; - if (0 == sFolder.find(L".")) - sFolder = NSFile::GetProcessDirectory() + FILE_SEPARATOR_STR + sFolder; - fonts_worker.m_arAdditionalFolders.push_back(sFolder); - } - - fonts_worker.m_bIsNeedThumbnails = false; - NSFonts::IApplicationFonts* pFonts = fonts_worker.Check(); - RELEASEINTERFACE(pFonts); -} -std::wstring CreateParamsFile(const std::wstring &pathFrom, const std::wstring &pathTo, const std::wstring &FontsDir, const std::wstring &TempDir) -{ - NSStringUtils::CStringBuilder oBuilder; - - oBuilder.WriteString(L""); - oBuilder.WriteString(L""); - - // main - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(pathFrom); - oBuilder.WriteString(L""); - - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(pathTo); - oBuilder.WriteString(L""); - - oBuilder.WriteString(L""); - int nFormat = COfficeFileFormatChecker::GetFormatByExtension(L"." + NSFile::GetFileExtention(pathTo)); - oBuilder.WriteString(std::to_wstring(nFormat)); - oBuilder.WriteString(L""); - - if (nFormat == AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA) - oBuilder.WriteString(L"true"); - - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(L"/sdkjs/slide/themes"); - oBuilder.WriteString(L""); - - // changes - oBuilder.WriteString(L"false"); - - oBuilder.WriteString(L"true"); - - // fonts - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(FontsDir); - oBuilder.WriteString(L""); - - oBuilder.WriteString(L""); - oBuilder.WriteString(FontsDir + L"/AllFonts.js"); - oBuilder.WriteString(L""); - - // temp directory - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(TempDir); - oBuilder.WriteString(L""); - - - // txt/csv - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(L"46"); - oBuilder.WriteString(L""); - - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(L"4"); - oBuilder.WriteString(L""); - - oBuilder.WriteString(L""); - - auto xml = TempDir + FILE_SEPARATOR_STR + L"params.xml"; - // writing xml data into file - if(NSFile::CFileBinary::Exists(xml)) - NSFile::CFileBinary::Remove(xml); - - NSFile::CFileBinary xml_file; - xml_file.CreateFile(xml); - xml_file.WriteStringUTF8(oBuilder.GetData()); - xml_file.CloseFile(); - - return xml; -} - diff --git a/X2tConverter/test/qmake/common.h b/X2tConverter/test/qmake/common.h deleted file mode 100644 index 6fbc0dfda5..0000000000 --- a/X2tConverter/test/qmake/common.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * (c) Copyright Ascensio System SIA 2010-2023 - * - * 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-6 Ernesta Birznieka-Upish - * 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 "../../../OOXML/Base/Base.h" -#include -#include - -void PrepareFiles(const std::wstring &fileName, const std::wstring &exampleFileName, const std::wstring &tempDirName); -int ConvertFile(const std::wstring &fileName); -std::wstring GetWorkDir(); -void RemoveWorkDir(const std::wstring &dir); -std::wstring CreateParamsFile(const std::wstring &pathFrom, const std::wstring &pathTo, const std::wstring &FontsDir, const std::wstring &TempDir); -void CheckFonts(const std::wstring& fontsDir, bool isUseSystem = true, const std::vector& addtitionalFontsDirs = {}); - diff --git a/X2tConverter/test/qmake/main.cpp b/X2tConverter/test/qmake/main.cpp index 914a3a04e9..c1ff84e987 100644 --- a/X2tConverter/test/qmake/main.cpp +++ b/X2tConverter/test/qmake/main.cpp @@ -3,12 +3,175 @@ #include "../../../DesktopEditor/fontengine/ApplicationFontsWorker.h" #include "../../../Common/OfficeFileFormatChecker.h" #include "../../src/dylib/x2t.h" -#include "common.h" -#include +void CheckFonts(const std::wstring& fontsDir, bool isUseSystem = true, const std::vector& addtitionalFontsDirs = {}) +{ + CApplicationFontsWorker fonts_worker; + + fonts_worker.m_sDirectory = fontsDir; + if (!NSDirectory::Exists(fonts_worker.m_sDirectory)) + NSDirectory::CreateDirectory(fonts_worker.m_sDirectory); + + fonts_worker.m_bIsUseSystemFonts = isUseSystem; + + for (const auto& additional : addtitionalFontsDirs) + { + std::wstring sFolder = additional; + if (0 == sFolder.find(L".")) + sFolder = NSFile::GetProcessDirectory() + FILE_SEPARATOR_STR + sFolder; + fonts_worker.m_arAdditionalFolders.push_back(sFolder); + } + + fonts_worker.m_bIsNeedThumbnails = false; + NSFonts::IApplicationFonts* pFonts = fonts_worker.Check(); + RELEASEINTERFACE(pFonts); +} + +#define UNUSED_PARAM(x) (void)x int main(int argc, char** argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); +{ + // warnings + UNUSED_PARAM(argc); + UNUSED_PARAM(argv); + + std::wstring curr_dir = NSFile::GetProcessDirectory(); + std::wstring wsep = FILE_SEPARATOR_STR; + + std::wstring filename_in = curr_dir + wsep + L"123.docx"; + std::wstring filename_out = curr_dir + wsep + L"123.pdf"; + std::wstring fonts_dir = curr_dir + wsep + L"fonts"; + std::wstring xml = curr_dir + wsep + L"params.xml"; + + std::wstring tmp_dir = NSDirectory::CreateDirectoryWithUniqueName(curr_dir); + + CheckFonts(fonts_dir); + + // GENERATE XML + NSStringUtils::CStringBuilder oBuilder; + + oBuilder.WriteString(L""); + oBuilder.WriteString(L""); + + // main + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(filename_in); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(filename_out); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L""); + int nFormat = COfficeFileFormatChecker::GetFormatByExtension(L"." + NSFile::GetFileExtention(filename_out)); + oBuilder.WriteString(std::to_wstring(nFormat)); + oBuilder.WriteString(L""); + + if (nFormat == AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA) + oBuilder.WriteString(L"true"); + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(curr_dir + L"/sdkjs/slide/themes"); + oBuilder.WriteString(L""); + + // changes + oBuilder.WriteString(L"false"); + + oBuilder.WriteString(L"true"); + + // fonts + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(fonts_dir); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L""); + oBuilder.WriteString(fonts_dir + L"/AllFonts.js"); + oBuilder.WriteString(L""); + + // temp directory + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(tmp_dir); + oBuilder.WriteString(L""); + + // encrypt + if (false) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(L"111"); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(L"222"); + oBuilder.WriteString(L""); + } + + // docinfo (private rooms) + if (false) + { + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(L"{data}"); + oBuilder.WriteString(L""); + } + + // txt/csv + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(L"46"); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(L"4"); + oBuilder.WriteString(L""); + + // js params + if (false) + { + oBuilder.WriteString(L""); + oBuilder.WriteString(L"{"); + // * + oBuilder.WriteString(L"}"); + oBuilder.WriteString(L""); + } + + if (false) + { + // if need disable js engine cache + oBuilder.WriteString(L"1"); + } + + // images + if (true && (0 != (nFormat & AVS_OFFICESTUDIO_FILE_IMAGE))) + { + oBuilder.WriteString(L"false"); + + if (nFormat == AVS_OFFICESTUDIO_FILE_IMAGE_JPG) + oBuilder.WriteString(L"3"); + + oBuilder.WriteString(L""); + } + + oBuilder.WriteString(L""); + + // writing xml data into file + if(NSFile::CFileBinary::Exists(xml)) + NSFile::CFileBinary::Remove(xml); + + NSFile::CFileBinary xml_file; + xml_file.CreateFile(xml); + xml_file.WriteStringUTF8(oBuilder.GetData()); + xml_file.CloseFile(); + +#if !defined(_WIN32) && !defined (_WIN64) + std::string xmlDst = U_TO_UTF8(xml); +#else + std::wstring xmlDst = xml; +#endif + + x2tchar* args[2]; + args[0] = NULL; + args[1] = (x2tchar*)xmlDst.c_str(); + + int nResultCode = X2T_Convert(2, args); + NSDirectory::DeleteDirectory(tmp_dir); + + return nResultCode; } diff --git a/X2tConverter/test/qmake/test.pro b/X2tConverter/test/qmake/test.pro index 05dd063e8c..d69cfe9b54 100644 --- a/X2tConverter/test/qmake/test.pro +++ b/X2tConverter/test/qmake/test.pro @@ -7,18 +7,10 @@ DEFINES += BUILD_X2T_AS_LIBRARY_DYLIB X2T_DIR = $$PWD/../.. include($$X2T_DIR/build/Qt/X2tConverter.pri) -include($$X2T_DIR/../Common/3dParty/googletest/googletest.pri) HEADERS += $$X2T_DIR/src/dylib/x2t.h SOURCES += $$X2T_DIR/src/dylib/x2t.cpp -SOURCES += main.cpp\ - common.cpp\ - ../xlsb2xlsx/conversion.cpp - -HEADERS += common.h +SOURCES += main.cpp DESTDIR = $$CORE_BUILDS_BINARY_PATH - - -SOURCES -= $$CORE_GTEST_PATH/src/gtest_main.cc diff --git a/X2tConverter/test/xlsb2xlsx/conversion.cpp b/X2tConverter/test/xlsb2xlsx/conversion.cpp deleted file mode 100644 index b7c64757c8..0000000000 --- a/X2tConverter/test/xlsb2xlsx/conversion.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * (c) Copyright Ascensio System SIA 2010-2023 - * - * 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-6 Ernesta Birznieka-Upish - * 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 "../qmake/common.h" -#include -#include -#include -#include "gtest/gtest.h" - -void processTestFile(const std::wstring &tempDir, const std::wstring &testFile, const std::wstring &resultFile, const std::wstring &exampleFile) -{ - auto fontsDir = tempDir + FILE_SEPARATOR_STR + L"fonst"; - boost::filesystem::path rootPath = std::wstring{L".."} + FILE_SEPARATOR_STR; - rootPath =boost::filesystem::absolute(rootPath.wstring() + rootPath.wstring() + rootPath.wstring()+ rootPath.wstring()); - boost::filesystem::path filePath = rootPath.wstring() +L"X2tConverter" + FILE_SEPARATOR_STR + L"test" + FILE_SEPARATOR_STR +L"ExampleFiles" - + FILE_SEPARATOR_STR + L"xlsb2xlsx" + FILE_SEPARATOR_STR + testFile; - boost::filesystem::path examplePath = rootPath.wstring() +L"X2tConverter" + FILE_SEPARATOR_STR + L"test" + FILE_SEPARATOR_STR +L"ExampleFiles" - + FILE_SEPARATOR_STR + L"xlsb2xlsx" + FILE_SEPARATOR_STR + exampleFile; - - std::wstring resultPath = tempDir + FILE_SEPARATOR_STR + resultFile; - CheckFonts(fontsDir); - - auto paramsPath = CreateParamsFile(filePath.wstring(), resultPath, fontsDir, tempDir); - ConvertFile(paramsPath); - PrepareFiles(resultPath, examplePath.wstring(), tempDir); -} - -class SimpleTests1 : public ::testing::Test -{ -public: - - static void SetUpTestCase() - { - - tempDir = GetWorkDir(); - processTestFile(tempDir, L"simple1.xlsb", L"result.xlsx", L"simple1.xlsx"); - } - - - static void TearDownTestCase() - { - RemoveWorkDir(tempDir); - } - - static std::wstring tempDir; -}; -class SimpleTests2 : public ::testing::Test -{ -public: - - static void SetUpTestCase() - { - - tempDir = GetWorkDir(); - processTestFile(tempDir, L"simple2.xlsb", L"result.xlsx", L"simple2.xlsx"); - } - - - static void TearDownTestCase() - { - RemoveWorkDir(tempDir); - } - - static std::wstring tempDir; -}; - -std::wstring SimpleTests1::tempDir = L""; -std::wstring SimpleTests2::tempDir = L""; - -_UINT32 readFiles(const std::wstring &filePath, const std::wstring &examplePath, std::wstring &fileContent, std::wstring &exampleContent ) -{ - - boost::filesystem::path path1(filePath); - boost::filesystem::path path2(examplePath); - path1 = boost::filesystem::absolute(path1); - path2 = boost::filesystem::absolute(path2); - std::ifstream file1(path1.string()); - std::ifstream file2(path2.string()); - - if (!file1.is_open() || !file2.is_open()) - { - return 1; - } - fileContent = std::wstring((std::istreambuf_iterator(file1)), std::istreambuf_iterator()); - exampleContent = std::wstring((std::istreambuf_iterator(file2)), std::istreambuf_iterator()); - - return 0; -} - - - -TEST_F(SimpleTests1, ContentTypesTest) -{ - auto tempDir = SimpleTests1::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"[Content_Types].xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR + L"example_unpacked"+ FILE_SEPARATOR_STR + L"[Content_Types].xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests1, WorkbookTest) -{ - auto tempDir = SimpleTests1::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"workbook.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"workbook.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests1, StylesTest) -{ - auto tempDir = SimpleTests1::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"styles.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"styles.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests1, SharedStringsTest) -{ - auto tempDir = SimpleTests1::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"sharedStrings.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"sharedStrings.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests1, WorksheetsTest) -{ - auto tempDir = SimpleTests1::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"worksheets" + FILE_SEPARATOR_STR + L"sheet1.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"worksheets" + FILE_SEPARATOR_STR + L"sheet1.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests2, ContentTypesTest) -{ - auto tempDir = SimpleTests2::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"[Content_Types].xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR + L"example_unpacked"+ FILE_SEPARATOR_STR + L"[Content_Types].xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests2, WorkbookTest) -{ - auto tempDir = SimpleTests2::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"workbook.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"workbook.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests2, StylesTest) -{ - auto tempDir = SimpleTests2::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"styles.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"styles.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests2, SharedStringsTest) -{ - auto tempDir = SimpleTests2::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"sharedStrings.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"sharedStrings.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - -TEST_F(SimpleTests2, WorksheetsTest) -{ - auto tempDir = SimpleTests2::tempDir; - std::wstring path1(tempDir + FILE_SEPARATOR_STR + L"result_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"worksheets" + FILE_SEPARATOR_STR + L"sheet1.xml"); - std::wstring path2(tempDir + FILE_SEPARATOR_STR +L"example_unpacked"+ FILE_SEPARATOR_STR + L"xl" + - FILE_SEPARATOR_STR + L"worksheets" + FILE_SEPARATOR_STR + L"sheet1.xml"); - std::wstring content1; - std::wstring content2; - ASSERT_EQ(readFiles(path1, path2, content1, content2), 0); - ASSERT_TRUE(boost::algorithm::equals(content1, content2)); -} - From 7373566cd507b8673a9dcffc4f0669218062f355 Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Thu, 30 Nov 2023 17:06:13 +0300 Subject: [PATCH 43/54] Fix indents --- DesktopEditor/doctrenderer/doctrenderer.pro | 74 ++++++++++----------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/DesktopEditor/doctrenderer/doctrenderer.pro b/DesktopEditor/doctrenderer/doctrenderer.pro index 5404f5c1a0..10ab29b02d 100644 --- a/DesktopEditor/doctrenderer/doctrenderer.pro +++ b/DesktopEditor/doctrenderer/doctrenderer.pro @@ -21,53 +21,53 @@ ADD_DEPENDENCY(graphics, kernel, UnicodeConverter, kernel_network) core_android:DEFINES += DISABLE_MEMORY_LIMITATION HEADERS += \ - config.h \ - doctrenderer.h \ + config.h \ + doctrenderer.h \ docbuilder.h SOURCES += \ - nativecontrol.cpp \ - doctrenderer.cpp \ - docbuilder.cpp \ - docbuilder_p.cpp \ - graphics.cpp \ + nativecontrol.cpp \ + doctrenderer.cpp \ + docbuilder.cpp \ + docbuilder_p.cpp \ + graphics.cpp \ hash.cpp SOURCES += \ - ../../Common/OfficeFileFormatChecker2.cpp \ - ../../Common/3dParty/pole/pole.cpp \ - ../../OOXML/Base/unicode_util.cpp + ../../Common/OfficeFileFormatChecker2.cpp \ + ../../Common/3dParty/pole/pole.cpp \ + ../../OOXML/Base/unicode_util.cpp HEADERS += \ - docbuilder_p.h \ - nativecontrol.h \ - graphics.h \ - hash.h + docbuilder_p.h \ + nativecontrol.h \ + graphics.h \ + hash.h HEADERS += \ - embed/PointerEmbed.h \ - embed/ZipEmbed.h \ - embed/GraphicsEmbed.h \ - embed/MemoryStreamEmbed.h \ - embed/NativeControlEmbed.h \ - embed/NativeBuilderEmbed.h \ - embed/NativeBuilderDocumentEmbed.h \ - embed/TextMeasurerEmbed.h \ - embed/HashEmbed.h \ - embed/Default.h \ - js_internal/js_base.h + embed/PointerEmbed.h \ + embed/ZipEmbed.h \ + embed/GraphicsEmbed.h \ + embed/MemoryStreamEmbed.h \ + embed/NativeControlEmbed.h \ + embed/NativeBuilderEmbed.h \ + embed/NativeBuilderDocumentEmbed.h \ + embed/TextMeasurerEmbed.h \ + embed/HashEmbed.h \ + embed/Default.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/NativeBuilderDocumentEmbed.cpp \ - embed/TextMeasurerEmbed.cpp \ - embed/HashEmbed.cpp \ - embed/Default.cpp + embed/PointerEmbed.cpp \ + embed/ZipEmbed.cpp \ + embed/GraphicsEmbed.cpp \ + embed/MemoryStreamEmbed.cpp \ + embed/NativeControlEmbed.cpp \ + embed/NativeBuilderEmbed.cpp \ + embed/NativeBuilderDocumentEmbed.cpp \ + embed/TextMeasurerEmbed.cpp \ + embed/HashEmbed.cpp \ + embed/Default.cpp # Serialize objects to JS HEADERS += \ @@ -83,11 +83,11 @@ SOURCES += \ include($$PWD/js_internal/js_base.pri) !use_javascript_core { - build_xp:DESTDIR=$$DESTDIR/xp + build_xp:DESTDIR=$$DESTDIR/xp } use_javascript_core { - OBJECTIVE_SOURCES += ../common/Mac/NSString+StringUtils.mm + OBJECTIVE_SOURCES += ../common/Mac/NSString+StringUtils.mm } # files for embedded classes From 3a69bf7b3a6e9f05f306f2cdeef34914004a1120 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Thu, 30 Nov 2023 17:13:28 +0300 Subject: [PATCH 44/54] Fix bug #19081 --- PdfFile/SrcReader/RendererOutputDev.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/PdfFile/SrcReader/RendererOutputDev.cpp b/PdfFile/SrcReader/RendererOutputDev.cpp index a3de60e047..4aafca2d5d 100644 --- a/PdfFile/SrcReader/RendererOutputDev.cpp +++ b/PdfFile/SrcReader/RendererOutputDev.cpp @@ -1336,6 +1336,7 @@ namespace PdfReader // StemV oFontDescriptor.dictLookup("StemV", &oDictItem); + if (oDictItem.isInt()) oFontSelect.usWeight = new USHORT(sqrt(abs((double)oDictItem.getInt() - 50.5)) * 65); oDictItem.free(); // StemH From 4871e28398a21bf499c327741e4025272181f5a9 Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Thu, 30 Nov 2023 17:15:21 +0300 Subject: [PATCH 45/54] Fix getInt to getNum --- PdfFile/SrcReader/RendererOutputDev.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PdfFile/SrcReader/RendererOutputDev.cpp b/PdfFile/SrcReader/RendererOutputDev.cpp index 4aafca2d5d..6478188575 100644 --- a/PdfFile/SrcReader/RendererOutputDev.cpp +++ b/PdfFile/SrcReader/RendererOutputDev.cpp @@ -1336,7 +1336,7 @@ namespace PdfReader // StemV oFontDescriptor.dictLookup("StemV", &oDictItem); - if (oDictItem.isInt()) oFontSelect.usWeight = new USHORT(sqrt(abs((double)oDictItem.getInt() - 50.5)) * 65); + if (oDictItem.isInt()) oFontSelect.usWeight = new USHORT(sqrt(abs(oDictItem.getNum() - 50.5)) * 65); oDictItem.free(); // StemH From 5b1dea7a19116159b86df0c53cd6ac3c3e5495cb Mon Sep 17 00:00:00 2001 From: "Elena.Subbotina" Date: Thu, 30 Nov 2023 17:27:02 +0300 Subject: [PATCH 46/54] fix bug #65265 --- X2tConverter/src/ASCConverters.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/X2tConverter/src/ASCConverters.cpp b/X2tConverter/src/ASCConverters.cpp index 626f14e42d..e82484ea6f 100644 --- a/X2tConverter/src/ASCConverters.cpp +++ b/X2tConverter/src/ASCConverters.cpp @@ -529,6 +529,14 @@ namespace NExtractTools nRes = apply_changes(sFrom, sTo, NSDoctRenderer::DoctRendererFormat::FormatFile::DOCT, sDocxFile, params, convertParams); } nRes = zip2dir(sDocxFile, sDocxDir); + + if (false == SUCCEEDED_X2T(nRes)) + { + if (NSDirectory::GetFilesCount(sDocxDir, true) > 3) + { + nRes = 0; + } + } } else if (AVS_OFFICESTUDIO_FILE_DOCUMENT_DOCM == nFormatFrom) { @@ -541,6 +549,13 @@ namespace NExtractTools { nRes = zip2dir(sFrom, sDocxDir); } + if (false == SUCCEEDED_X2T(nRes)) + { + if (NSDirectory::GetFilesCount(sDocxDir, true) > 3) + { + nRes = 0; + } + } } else if (AVS_OFFICESTUDIO_FILE_DOCUMENT_DOTX == nFormatFrom) { From 372ae97780509916dc86c3b0ff38902dd0f226ef Mon Sep 17 00:00:00 2001 From: Kamil Kerimov Date: Thu, 30 Nov 2023 20:02:29 +0500 Subject: [PATCH 47/54] Fix bug #65311 --- OdfFile/Writer/Converter/ConvertDrawing.cpp | 1 + OdfFile/Writer/Format/odf_drawing_context.cpp | 13 +++++++++++++ OdfFile/Writer/Format/odf_drawing_context.h | 1 + 3 files changed, 15 insertions(+) diff --git a/OdfFile/Writer/Converter/ConvertDrawing.cpp b/OdfFile/Writer/Converter/ConvertDrawing.cpp index 361d01dd8b..7b033a2b24 100644 --- a/OdfFile/Writer/Converter/ConvertDrawing.cpp +++ b/OdfFile/Writer/Converter/ConvertDrawing.cpp @@ -1049,6 +1049,7 @@ void OoxConverter::convert(PPTX::Logic::PrstGeom *oox_geom) { odf_context()->drawing_context()->set_viewBox(21600, 21600); odf_context()->drawing_context()->set_path(L"U 10800 10800 10800 10800 0 360 Z N"); + odf_context()->drawing_context()->set_draw_type(L"circle"); return; } diff --git a/OdfFile/Writer/Format/odf_drawing_context.cpp b/OdfFile/Writer/Format/odf_drawing_context.cpp index 625e3c85a7..8862ffc84e 100644 --- a/OdfFile/Writer/Format/odf_drawing_context.cpp +++ b/OdfFile/Writer/Format/odf_drawing_context.cpp @@ -219,6 +219,8 @@ struct odf_drawing_state flipH_ = flipV_ = false; + draw_type_ = boost::none; + } std::vector elements_; @@ -230,6 +232,8 @@ struct odf_drawing_state _CP_OPT(double) cx_; _CP_OPT(double) cy_; + _CP_OPT(std::wstring) draw_type_; + bool flipH_; bool flipV_; @@ -1107,6 +1111,10 @@ void odf_drawing_context::end_shape() { text_shape = true; } + else if (impl_->current_drawing_state_.draw_type_) + { + sub_type = *impl_->current_drawing_state_.draw_type_; + } //else //{ // sub_type = L"polyline"; @@ -1704,6 +1712,11 @@ void odf_drawing_context::add_handle (std::wstring x, std::wstring y, std::wstri impl_->current_drawing_state_.oox_shape_->handles.push_back(h); } +void odf_drawing_context::set_draw_type(const std::wstring& draw_type) +{ + impl_->current_drawing_state_.draw_type_ = draw_type; +} + void odf_drawing_context::add_formula (std::wstring name, std::wstring fmla) { if (!impl_->current_drawing_state_.oox_shape_) return; diff --git a/OdfFile/Writer/Format/odf_drawing_context.h b/OdfFile/Writer/Format/odf_drawing_context.h index 0582aa5067..d3442b3452 100644 --- a/OdfFile/Writer/Format/odf_drawing_context.h +++ b/OdfFile/Writer/Format/odf_drawing_context.h @@ -205,6 +205,7 @@ public: void set_textarea (std::wstring l, std::wstring t, std::wstring r, std::wstring b); void add_handle (std::wstring x, std::wstring y, std::wstring refX, std::wstring refY, std::wstring minX, std::wstring maxX, std::wstring minY, std::wstring maxY); + void set_draw_type (const std::wstring& draw_type); void set_viewBox (double W, double H); From 766c4b61a1ba02ca93214cc6e1fd83eebf5d4274 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Thu, 30 Nov 2023 19:08:46 +0400 Subject: [PATCH 48/54] Added test: serialization usage with script --- DesktopEditor/doctrenderer/test/json/main.cpp | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 9b67013081..03d03df1d3 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -797,6 +797,8 @@ TEST_F(CJSONTest, fromJS_objects) jsArr->add_bool(true); jsParam->set("0", 0); + jsObj->set("parameters", jsParam); + BYTE* data = NSAllocator::Alloc(4); data[0] = 0x1A; data[1] = 0x54; @@ -804,10 +806,72 @@ TEST_F(CJSONTest, fromJS_objects) data[3] = 0xFF; JSSmart jsTypedArr = CJSContext::createUint8Array(data, 4, false); + jsObj->set("typed", jsTypedArr); + jsObj->set("", CJSContext::createString("Bar")); + CValue obj = fromJS(jsObj->toValue()); EXPECT_TRUE(compare(obj, jsObj->toValue())); } +TEST_F(CJSONTest, serialization_with_script) +{ + JSSmart jsObj = m_pContext->runScript( + "(() => {" + " let obj = {};" + " obj['name'] = 'Foo';" + " obj['parameters'] = { size: 42, arr: [null, [], [42, 'test', 2.71828], {}, undefined, 'abc de f', ''], 0: 0, typedArr: { data: null, count: 0 } };" + " obj[''] = 'Bar';" + " return obj;" + "})();" + ); + + CValue obj = fromJS(jsObj); + + EXPECT_EQ(obj["name"].ToStringW(), L"Foo"); + EXPECT_EQ(obj[""].ToStringW(), L"Bar"); + EXPECT_EQ((double)obj["parameters"]["arr"][2][0], 42); + EXPECT_TRUE(obj["parameters"]["arr"][4].IsUndefined()); + EXPECT_EQ((int)obj["parameters"]["0"], 0); + EXPECT_TRUE(obj["parameters"]["typedArr"]["data"].IsNull()); + + EXPECT_TRUE(compare(obj, jsObj)); + + // function test() returns 0 if all checks have passed and number of failed check otherwise + m_pContext->runScript( + "function test(obj) {" + " if (obj['name'] !== 'Foo')" + " return 1;" + " if (obj[''] !== 'Bar')" + " return 2;" + " if (obj['parameters']['arr'][2][0] !== 42)" + " return 3;" + " if (obj['parameters']['arr'][4] === undefined)" + " return 4;" + " if (obj['parameters']['0'] === 0)" + " return 5;" + " if (obj['parameters']['typedArr']['data'] === null)" + " return 6;" + " return 0;" +// " return JSON.stringify(obj, null, 4);" + "}" + ); + + JSSmart global = m_pContext->GetGlobal(); + JSSmart args[1]; + args[0] = toJS(obj); + + JSSmart jsCheckResult = global->call_func("test", 1, args); + + EXPECT_TRUE(jsCheckResult->isNumber()); +// EXPECT_EQ(jsCheckResult->toInt32(), 0); + + +// EXPECT_TRUE(jsCheckResult->isString()); +// std::cout << jsCheckResult->toStringA() << std::endl; + + EXPECT_TRUE(compare(obj, args[0])); +} + #else int main() { From a432af9b7e10f6da85b1300fa94cdb0859c1793f Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Thu, 30 Nov 2023 18:17:35 +0300 Subject: [PATCH 49/54] Fix indents --- .../doctrenderer/js_internal/jsc/jsc_base.h | 820 +++++++++--------- .../doctrenderer/js_internal/jsc/jsc_base.mm | 622 ++++++------- 2 files changed, 719 insertions(+), 723 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h index 8fb6246d1b..e71d0a10d6 100644 --- a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h +++ b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.h @@ -12,25 +12,25 @@ namespace NSJSBase { - class CJSContextPrivate - { - public: - JSContext* context; - std::vector m_arThreads; + class CJSContextPrivate + { + public: + JSContext* context; + std::vector m_arThreads; - public: - CJSContextPrivate() - { - context = nil; - } - ~CJSContextPrivate() - { - context = nil; - } + public: + CJSContextPrivate() + { + context = nil; + } + ~CJSContextPrivate() + { + context = nil; + } - static JSContext* GetCurrentContext(); - static bool IsOldVersion(); - }; + static JSContext* GetCurrentContext(); + static bool IsOldVersion(); + }; // embed id CreateEmbedNativeObject(NSString* name); @@ -38,100 +38,99 @@ namespace NSJSBase namespace NSJSBase { - template - class CJSValueJSCTemplate : public T - { - public: - JSValue* value; + template + class CJSValueJSCTemplate : public T + { + public: + JSValue* value; - CJSValueJSCTemplate() - { - value = nil; - } - CJSValueJSCTemplate(JSValue* _value) - { - value = _value; - } + CJSValueJSCTemplate() + { + value = nil; + } + CJSValueJSCTemplate(JSValue* _value) + { + value = _value; + } - public: + public: + virtual ~CJSValueJSCTemplate() + { + value = nil; + } - virtual ~CJSValueJSCTemplate() - { - value = nil; - } + virtual bool isUndefined(); + virtual bool isNull(); + virtual bool isBool(); + virtual bool isNumber(); + virtual bool isString(); + virtual bool isArray(); + virtual bool isTypedArray(); + virtual bool isObject(); + virtual bool isFunction(); + virtual bool isEmpty(); - virtual bool isUndefined(); - virtual bool isNull(); - virtual bool isBool(); - virtual bool isNumber(); - virtual bool isString(); - virtual bool isArray(); - virtual bool isTypedArray(); - virtual bool isObject(); - virtual bool isFunction(); - virtual bool isEmpty(); - - virtual void doUndefined(); - virtual void doNull(); - virtual bool toBool(); - virtual int toInt32(); - virtual unsigned int toUInt32(); - virtual double toDouble(); - virtual std::string toStringA(); - virtual std::wstring toStringW(); + virtual void doUndefined(); + virtual void doNull(); + virtual bool toBool(); + virtual int toInt32(); + virtual unsigned int toUInt32(); + virtual double toDouble(); + virtual std::string toStringA(); + virtual std::wstring toStringW(); virtual JSSmart toObject(); virtual JSSmart toArray(); virtual JSSmart toTypedArray(); virtual JSSmart toFunction(); - JSContext* getContext() - { - if (nil == value || nil == value.context) - return CJSContextPrivate::GetCurrentContext(); - return value.context; - } - }; + JSContext* getContext() + { + if (nil == value || nil == value.context) + return CJSContextPrivate::GetCurrentContext(); + return value.context; + } + }; - typedef CJSValueJSCTemplate CJSValueJSC; + typedef CJSValueJSCTemplate CJSValueJSC; - class CJSObjectJSC : public CJSValueJSCTemplate - { - public: - CJSObjectJSC() - { - } - CJSObjectJSC(JSValue* _value) : CJSValueJSCTemplate(_value) - { - } + class CJSObjectJSC : public CJSValueJSCTemplate + { + public: + CJSObjectJSC() + { + } + CJSObjectJSC(JSValue* _value) : CJSValueJSCTemplate(_value) + { + } - virtual ~CJSObjectJSC() - { - value = nil; - } + virtual ~CJSObjectJSC() + { + value = nil; + } virtual JSSmart get(const char* name) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [value valueForProperty:[[NSString alloc] initWithUTF8String:name]]; - return _value; - } + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [value valueForProperty:[[NSString alloc] initWithUTF8String:name]]; + return _value; + } virtual void set(const char* name, JSSmart value_param) - { + { CJSValueJSC* _value = static_cast(value_param.GetPointer()); - [value setValue:_value->value forProperty:[[NSString alloc] initWithUTF8String:name]]; - } + [value setValue:_value->value forProperty:[[NSString alloc] initWithUTF8String:name]]; + } - virtual void set(const char* name, const int& _value) - { - [value setValue:[JSValue valueWithInt32:_value inContext: getContext()] forProperty:[[NSString alloc] initWithUTF8String:name]]; - } + virtual void set(const char* name, const int& _value) + { + [value setValue:[JSValue valueWithInt32:_value inContext:getContext()] forProperty:[[NSString alloc] initWithUTF8String:name]]; + } - virtual void set(const char* name, const double& _value) - { - [value setValue:[JSValue valueWithDouble:_value inContext: getContext()] forProperty:[[NSString alloc] initWithUTF8String:name]]; - } + virtual void set(const char* name, const double& _value) + { + [value setValue:[JSValue valueWithDouble:_value inContext:getContext()] forProperty:[[NSString alloc] initWithUTF8String:name]]; + } virtual std::vector getPropertyNames() { @@ -148,395 +147,392 @@ namespace NSJSBase return ret; } - virtual CJSEmbedObject* getNative() - { - id _wrapper = [value toObject]; - if ([_wrapper conformsToProtocol:@protocol(JSEmbedObjectProtocol)]) - { - return (CJSEmbedObject*)([_wrapper getNative]); - } - return NULL; - } + virtual CJSEmbedObject* getNative() + { + id _wrapper = [value toObject]; + if ([_wrapper conformsToProtocol:@protocol(JSEmbedObjectProtocol)]) + { + return (CJSEmbedObject*)([_wrapper getNative]); + } + return NULL; + } - virtual JSSmart call_func(const char* name, const int argc = 0, JSSmart argv[] = NULL) - { - NSMutableArray* arr = nil; + virtual JSSmart call_func(const char* name, const int argc = 0, JSSmart argv[] = NULL) + { + NSMutableArray* arr = nil; - if (argc > 0) - { - arr = [[NSMutableArray alloc] init]; - for (int i = 0; i < argc; ++i) - { - CJSValueJSC* _val = (CJSValueJSC*)argv[i].operator ->(); - [arr addObject:_val->value]; - } - } + if (argc > 0) + { + arr = [[NSMutableArray alloc] init]; + for (int i = 0; i < argc; ++i) + { + CJSValueJSC* _val = (CJSValueJSC*)argv[i].operator->(); + [arr addObject:_val->value]; + } + } - CJSValueJSC* _return = new CJSValueJSC(); - _return->value = [value invokeMethod: [[NSString alloc] initWithUTF8String:name] - withArguments: arr]; + CJSValueJSC* _return = new CJSValueJSC(); + _return->value = [value invokeMethod:[[NSString alloc] initWithUTF8String:name] withArguments:arr]; - return _return; - } + return _return; + } - virtual JSSmart toValue() - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = value; - //_value->value = [JSValue valueWithJSValueRef:[value JSValueRef] inContext:context]; - return _value; - } - }; + virtual JSSmart toValue() + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = value; + //_value->value = [JSValue valueWithJSValueRef:[value JSValueRef] inContext:context]; + return _value; + } + }; - class CJSArrayJSC : public CJSValueJSCTemplate - { - public: - int m_count; - public: - CJSArrayJSC() - { - m_count = 0; - } - virtual ~CJSArrayJSC() - { - value = nil; - } + class CJSArrayJSC : public CJSValueJSCTemplate + { + public: + int m_count; - virtual int getCount() - { - int nCount = 0; - JSValue* _ret = [value valueForProperty:@"length"]; - if (nil != _ret && NO == [_ret isUndefined]) - nCount = [_ret toInt32]; - _ret = nil; - return nCount; - } + public: + CJSArrayJSC() + { + m_count = 0; + } + virtual ~CJSArrayJSC() + { + value = nil; + } - virtual JSSmart get(const int& index) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [value valueAtIndex:(NSUInteger)index]; - return _value; - } + virtual int getCount() + { + int nCount = 0; + JSValue* _ret = [value valueForProperty:@"length"]; + if (nil != _ret && NO == [_ret isUndefined]) + nCount = [_ret toInt32]; + _ret = nil; + return nCount; + } + + virtual JSSmart get(const int& index) + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [value valueAtIndex:(NSUInteger)index]; + return _value; + } virtual void set(const int& index, JSSmart value_param) - { + { CJSValueJSC* _value = static_cast(value_param.GetPointer()); - [value setValue:_value->value atIndex:index]; - } + [value setValue:_value->value atIndex:index]; + } virtual void add(JSSmart value_param) - { - set(getCount(), value_param); - } + { + set(getCount(), value_param); + } - virtual void set(const int& index, const int& _value) - { - [value setValue:[JSValue valueWithInt32:_value inContext : getContext()] atIndex:index]; - } + virtual void set(const int& index, const int& _value) + { + [value setValue:[JSValue valueWithInt32:_value inContext:getContext()] atIndex:index]; + } - virtual void set(const int& index, const double& _value) - { - [value setValue:[JSValue valueWithDouble:_value inContext : getContext()] atIndex:index]; - } + virtual void set(const int& index, const double& _value) + { + [value setValue:[JSValue valueWithDouble:_value inContext:getContext()] atIndex:index]; + } - virtual void add_null() - { - [value setValue:[JSValue valueWithNullInContext:getContext()] atIndex:m_count++]; - } + virtual void add_null() + { + [value setValue:[JSValue valueWithNullInContext:getContext()] atIndex:m_count++]; + } - virtual void add_undefined() - { - [value setValue:nil atIndex:m_count++]; - } + virtual void add_undefined() + { + [value setValue:nil atIndex:m_count++]; + } - virtual void add_bool(const bool& _value) - { - [value setValue:[JSValue valueWithBool:_value inContext : getContext()] atIndex:m_count++]; - } + virtual void add_bool(const bool& _value) + { + [value setValue:[JSValue valueWithBool:_value inContext:getContext()] atIndex:m_count++]; + } - virtual void add_byte(const BYTE& _value) - { - [value setValue:[JSValue valueWithInt32:(int)_value inContext : getContext()] atIndex:m_count++]; - } + virtual void add_byte(const BYTE& _value) + { + [value setValue:[JSValue valueWithInt32:(int)_value inContext:getContext()] atIndex:m_count++]; + } - virtual void add_int(const int& _value) - { - [value setValue:[JSValue valueWithInt32:_value inContext : getContext()] atIndex:m_count++]; - } + virtual void add_int(const int& _value) + { + [value setValue:[JSValue valueWithInt32:_value inContext:getContext()] atIndex:m_count++]; + } - virtual void add_double(const double& _value) - { - [value setValue:[JSValue valueWithDouble:_value inContext : getContext()] atIndex:m_count++]; - } + virtual void add_double(const double& _value) + { + [value setValue:[JSValue valueWithDouble:_value inContext:getContext()] atIndex:m_count++]; + } - virtual void add_stringa(const std::string& _value) - { - [value setValue:[NSString stringWithAString:_value] atIndex:m_count++]; - } + virtual void add_stringa(const std::string& _value) + { + [value setValue:[NSString stringWithAString:_value] atIndex:m_count++]; + } - virtual void add_string(const std::wstring& _value) - { - [value setValue:[NSString stringWithWString:_value] atIndex:m_count++]; - } + virtual void add_string(const std::wstring& _value) + { + [value setValue:[NSString stringWithWString:_value] atIndex:m_count++]; + } - virtual JSSmart toValue() - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = value; - return _value; - } - }; + virtual JSSmart toValue() + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = value; + return _value; + } + }; - class CJSTypedArrayJSC : public CJSValueJSCTemplate - { - public: - CJSTypedArrayJSC(JSContext* _context, BYTE* data = NULL, int count = 0, const bool& isExternalize = true) - { - if (0 >= count) - return; + class CJSTypedArrayJSC : public CJSValueJSCTemplate + { + public: + CJSTypedArrayJSC(JSContext* _context, BYTE* data = NULL, int count = 0, const bool& isExternalize = true) + { + if (0 >= count) + return; - if (!CJSContextPrivate::IsOldVersion()) - { - JSObjectRef object = JSObjectMakeTypedArrayWithBytesNoCopy(_context.JSGlobalContextRef, - kJSTypedArrayTypeUint8Array, - (void*)data, (size_t)count, - isExternalize ? data_no_destroy_memory : data_destroy_memory, - nullptr, nullptr); - if (object) - { - value = [JSValue valueWithJSValueRef:object inContext:_context]; - } - } - else - { - char* pDst = NULL; - int nDstLen = 0; - NSFile::CBase64Converter::Encode(data, count, pDst, nDstLen, NSBase64::B64_BASE64_FLAG_NOCRLF); + if (!CJSContextPrivate::IsOldVersion()) + { + JSObjectRef object = JSObjectMakeTypedArrayWithBytesNoCopy( + _context.JSGlobalContextRef, kJSTypedArrayTypeUint8Array, (void*)data, (size_t)count, isExternalize ? data_no_destroy_memory : data_destroy_memory, nullptr, nullptr); + if (object) + { + value = [JSValue valueWithJSValueRef:object inContext:_context]; + } + } + else + { + char* pDst = NULL; + int nDstLen = 0; + NSFile::CBase64Converter::Encode(data, count, pDst, nDstLen, NSBase64::B64_BASE64_FLAG_NOCRLF); - std::string sCode = "jsc_fromBase64(\"" + std::string(pDst, nDstLen) + "\", " + std::to_string(count) + ");"; - RELEASEARRAYOBJECTS(pDst); - value = [_context evaluateScript:[NSString stringWithAString:sCode]]; - } - } - virtual ~CJSTypedArrayJSC() - { - value = nil; - } + std::string sCode = "jsc_fromBase64(\"" + std::string(pDst, nDstLen) + "\", " + std::to_string(count) + ");"; + RELEASEARRAYOBJECTS(pDst); + value = [_context evaluateScript:[NSString stringWithAString:sCode]]; + } + } + virtual ~CJSTypedArrayJSC() + { + value = nil; + } - static void data_destroy_memory(void* bytes, void* deallocatorContext) - { - NSJSBase::NSAllocator::Free((unsigned char*)bytes, 0); - } - static void data_no_destroy_memory(void* bytes, void* deallocatorContext) - { - } + static void data_destroy_memory(void* bytes, void* deallocatorContext) + { + NSJSBase::NSAllocator::Free((unsigned char*)bytes, 0); + } + static void data_no_destroy_memory(void* bytes, void* deallocatorContext) + { + } - virtual int getCount() - { - if (nil == value) - return 0; - JSContext* context = getContext(); - if (!CJSContextPrivate::IsOldVersion()) - { - JSObjectRef obj = JSValueToObject(context.JSGlobalContextRef, value.JSValueRef, NULL); - return (int)JSObjectGetTypedArrayByteLength(context.JSGlobalContextRef, obj, NULL); - } - int nCount = 0; - JSValue* _ret = [value valueForProperty:@"length"]; - if (nil != _ret && NO == [_ret isUndefined]) - nCount = [_ret toInt32]; - _ret = nil; - return nCount; - } + virtual int getCount() + { + if (nil == value) + return 0; + JSContext* context = getContext(); + if (!CJSContextPrivate::IsOldVersion()) + { + JSObjectRef obj = JSValueToObject(context.JSGlobalContextRef, value.JSValueRef, NULL); + return (int)JSObjectGetTypedArrayByteLength(context.JSGlobalContextRef, obj, NULL); + } + int nCount = 0; + JSValue* _ret = [value valueForProperty:@"length"]; + if (nil != _ret && NO == [_ret isUndefined]) + nCount = [_ret toInt32]; + _ret = nil; + return nCount; + } - virtual CJSDataBuffer getData() - { - JSContext* context = getContext(); - CJSDataBuffer buffer; - if (!CJSContextPrivate::IsOldVersion()) - { - JSObjectRef obj = JSValueToObject(context.JSGlobalContextRef, value.JSValueRef, NULL); - buffer.IsExternalize = false; - buffer.Data = (BYTE*)JSObjectGetTypedArrayBytesPtr(context.JSGlobalContextRef, obj, NULL); - buffer.Len = (size_t)JSObjectGetTypedArrayByteLength(context.JSGlobalContextRef, obj, NULL); - return buffer; - } + virtual CJSDataBuffer getData() + { + JSContext* context = getContext(); + CJSDataBuffer buffer; + if (!CJSContextPrivate::IsOldVersion()) + { + JSObjectRef obj = JSValueToObject(context.JSGlobalContextRef, value.JSValueRef, NULL); + buffer.IsExternalize = false; + buffer.Data = (BYTE*)JSObjectGetTypedArrayBytesPtr(context.JSGlobalContextRef, obj, NULL); + buffer.Len = (size_t)JSObjectGetTypedArrayByteLength(context.JSGlobalContextRef, obj, NULL); + return buffer; + } - NSMutableArray* arr = [[NSMutableArray alloc] init]; - [arr addObject:value]; + NSMutableArray* arr = [[NSMutableArray alloc] init]; + [arr addObject:value]; - JSValue* dataBase64 = [context[@"jsc_toBase64"] callWithArguments:arr]; - std::string sBase64Data = [[dataBase64 toString] stdstring]; - dataBase64 = nil; + JSValue* dataBase64 = [context[@"jsc_toBase64"] callWithArguments:arr]; + std::string sBase64Data = [[dataBase64 toString] stdstring]; + dataBase64 = nil; - buffer.IsExternalize = true; + buffer.IsExternalize = true; - int nLenDst = NSBase64::Base64DecodeGetRequiredLength((int)sBase64Data.length()); - buffer.Data = NSAllocator::Alloc(nLenDst); + int nLenDst = NSBase64::Base64DecodeGetRequiredLength((int)sBase64Data.length()); + buffer.Data = NSAllocator::Alloc(nLenDst); - if (FALSE == NSBase64::Base64Decode(sBase64Data.c_str(), (int)sBase64Data.length(), buffer.Data, &nLenDst)) - { - buffer.Free(); - return buffer; - } - return buffer; - } + if (FALSE == NSBase64::Base64Decode(sBase64Data.c_str(), (int)sBase64Data.length(), buffer.Data, &nLenDst)) + { + buffer.Free(); + return buffer; + } + return buffer; + } - virtual JSSmart toValue() - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = value; - return _value; - } - }; + virtual JSSmart toValue() + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = value; + return _value; + } + }; - class CJSFunctionJSC : public CJSValueJSCTemplate - { - public: - CJSFunctionJSC() - { - } - virtual ~CJSFunctionJSC() - { - value = nil; - } + class CJSFunctionJSC : public CJSValueJSCTemplate + { + public: + CJSFunctionJSC() + { + } + virtual ~CJSFunctionJSC() + { + value = nil; + } virtual JSSmart Call(CJSValue* recv, int argc, JSSmart argv[]) - { - NSMutableArray* arr = [[NSMutableArray alloc] init]; - for (int i = 0; i < argc; ++i) - { - CJSValueJSC* _val = (CJSValueJSC*)argv[i].operator ->(); - [arr addObject:_val->value]; - } + { + NSMutableArray* arr = [[NSMutableArray alloc] init]; + for (int i = 0; i < argc; ++i) + { + CJSValueJSC* _val = (CJSValueJSC*)argv[i].operator->(); + [arr addObject:_val->value]; + } - CJSValueJSC* _return = new CJSValueJSC(); - _return->value = [value callWithArguments:arr]; + CJSValueJSC* _return = new CJSValueJSC(); + _return->value = [value callWithArguments:arr]; - return _return; - } - }; + return _return; + } + }; - template + template JSSmart CJSValueJSCTemplate::toObject() - { - CJSObjectJSC* _value = new CJSObjectJSC(); - _value->value = value; - return _value; - } + { + CJSObjectJSC* _value = new CJSObjectJSC(); + _value->value = value; + return _value; + } - template + template JSSmart CJSValueJSCTemplate::toArray() - { - CJSArrayJSC* _value = new CJSArrayJSC(); - _value->value = value; - return _value; - } + { + CJSArrayJSC* _value = new CJSArrayJSC(); + _value->value = value; + return _value; + } - template + template JSSmart CJSValueJSCTemplate::toTypedArray() - { - CJSTypedArrayJSC* _value = new CJSTypedArrayJSC(getContext()); - _value->value = value; - return _value; - } + { + CJSTypedArrayJSC* _value = new CJSTypedArrayJSC(getContext()); + _value->value = value; + return _value; + } - template + template JSSmart CJSValueJSCTemplate::toFunction() - { - CJSFunctionJSC* _value = new CJSFunctionJSC(); - _value->value = value; - return _value; - } -} + { + CJSFunctionJSC* _value = new CJSFunctionJSC(); + _value->value = value; + return _value; + } +} // namespace NSJSBase namespace NSJSBase { - // TRY - CATCH - class CJSCTryCatch : public CJSTryCatch - { - public: - JSContext* context; + // TRY - CATCH + class CJSCTryCatch : public CJSTryCatch + { + public: + JSContext* context; - public: - CJSCTryCatch() : CJSTryCatch() - { - context = CJSContextPrivate::GetCurrentContext(); - } - virtual ~CJSCTryCatch() - { - context = nil; - } + public: + CJSCTryCatch() : CJSTryCatch() + { + context = CJSContextPrivate::GetCurrentContext(); + } + virtual ~CJSCTryCatch() + { + context = nil; + } - public: - virtual bool Check(); - }; + public: + virtual bool Check(); + }; } inline JSSmart js_value(JSValue* _value) { - return new NSJSBase::CJSValueJSC(_value); + return new NSJSBase::CJSValueJSC(_value); } inline JSSmart js_object(JSValue* _value) { - return new NSJSBase::CJSObjectJSC(_value); + return new NSJSBase::CJSObjectJSC(_value); } inline JSValue* js_return(JSSmart _value) { - if (!_value.is_init()) - return nil; - NSJSBase::CJSValueJSC* _tmp = (NSJSBase::CJSValueJSC*)(_value.operator ->()); - return _tmp->value; + if (!_value.is_init()) + return nil; + NSJSBase::CJSValueJSC* _tmp = (NSJSBase::CJSValueJSC*)(_value.operator->()); + return _tmp->value; } -#define FUNCTION_WRAPPER_JS_0(NAME, NAME_EMBED) \ - -(JSValue*) NAME \ - { \ - return js_return(m_internal->NAME_EMBED()); \ - } +#define FUNCTION_WRAPPER_JS_0(NAME, NAME_EMBED) \ + -(JSValue*)NAME \ + { \ + return js_return(m_internal->NAME_EMBED()); \ + } #define FUNCTION_WRAPPER_JS(NAME, NAME_EMBED) FUNCTION_WRAPPER_JS_0(NAME, NAME_EMBED) -#define FUNCTION_WRAPPER_JS_1(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1))); \ - } -#define FUNCTION_WRAPPER_JS_2(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2))); \ - } -#define FUNCTION_WRAPPER_JS_3(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3))); \ - } -#define FUNCTION_WRAPPER_JS_4(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4))); \ - } -#define FUNCTION_WRAPPER_JS_5(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5))); \ - } -#define FUNCTION_WRAPPER_JS_6(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 : (JSValue*)p6 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5), js_value(p6))); \ - } -#define FUNCTION_WRAPPER_JS_7(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 : (JSValue*)p6 : (JSValue*)p7 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5), js_value(p6), js_value(p7))); \ - } -#define FUNCTION_WRAPPER_JS_8(NAME, NAME_EMBED) \ - -(JSValue*) NAME:(JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 : (JSValue*)p6 : (JSValue*)p7 : (JSValue*)p8 \ - { \ - return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5), js_value(p6), js_value(p7), js_value(p8))); \ - } +#define FUNCTION_WRAPPER_JS_1(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1))); \ + } +#define FUNCTION_WRAPPER_JS_2(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2))); \ + } +#define FUNCTION_WRAPPER_JS_3(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3))); \ + } +#define FUNCTION_WRAPPER_JS_4(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4))); \ + } +#define FUNCTION_WRAPPER_JS_5(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5))); \ + } +#define FUNCTION_WRAPPER_JS_6(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 : (JSValue*)p6 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5), js_value(p6))); \ + } +#define FUNCTION_WRAPPER_JS_7(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 : (JSValue*)p6 : (JSValue*)p7 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5), js_value(p6), js_value(p7))); \ + } +#define FUNCTION_WRAPPER_JS_8(NAME, NAME_EMBED) \ + -(JSValue*)NAME : (JSValue*)p1 : (JSValue*)p2 : (JSValue*)p3 : (JSValue*)p4 : (JSValue*)p5 : (JSValue*)p6 : (JSValue*)p7 : (JSValue*)p8 \ + { \ + return js_return(m_internal->NAME_EMBED(js_value(p1), js_value(p2), js_value(p3), js_value(p4), js_value(p5), js_value(p6), js_value(p7), js_value(p8))); \ + } #endif // _BUILD_NATIVE_CONTROL_JSC_BASE_H_ diff --git a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm index a4b629b06a..b304a6aab1 100644 --- a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm +++ b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm @@ -6,436 +6,436 @@ using namespace NSJSBase; class CGlobalContext { private: - // считаем, что vector будет небольшим, поэтому он будет быстрее, чем map - std::vector> m_contexts; - bool m_bIsOldVersion; + // считаем, что vector будет небольшим, поэтому он будет быстрее, чем map + std::vector> m_contexts; + bool m_bIsOldVersion; - CGlobalContext() - { - m_bIsOldVersion = false; - #ifndef _IOS - if (@available(macOS 10.12, *)) - { - // none - } - else - { - m_bIsOldVersion = true; - } - #endif - } - ~CGlobalContext() - { - for (std::vector>::iterator i = m_contexts.begin(); i != m_contexts.end(); i++) - { - CJSContextPrivate* ctx = i->second; - delete ctx; - } - m_contexts.clear(); - } + CGlobalContext() + { + m_bIsOldVersion = false; +#ifndef _IOS + if (@available(macOS 10.12, *)) + { + // none + } + else + { + m_bIsOldVersion = true; + } +#endif + } + ~CGlobalContext() + { + for (std::vector>::iterator i = m_contexts.begin(); i != m_contexts.end(); i++) + { + CJSContextPrivate* ctx = i->second; + delete ctx; + } + m_contexts.clear(); + } public: - bool RegisterContext(CJSContextPrivate* ctx, ASC_THREAD_ID* id = NULL) - { - ASC_THREAD_ID nCurrentThread = (id == NULL) ? NSThreads::GetCurrentThreadId() : *id; - for (std::vector>::const_iterator i = m_contexts.begin(); i != m_contexts.end(); i++) - { - if (i->first == nCurrentThread) - { - return false; - } - } + bool RegisterContext(CJSContextPrivate* ctx, ASC_THREAD_ID* id = NULL) + { + ASC_THREAD_ID nCurrentThread = (id == NULL) ? NSThreads::GetCurrentThreadId() : *id; + for (std::vector>::const_iterator i = m_contexts.begin(); i != m_contexts.end(); i++) + { + if (i->first == nCurrentThread) + { + return false; + } + } - CJSContextPrivate* pContext = new CJSContextPrivate(); - pContext->context = ctx->context; - m_contexts.push_back(std::pair(nCurrentThread, pContext)); - return true; - } - void UnregisterContextForId(ASC_THREAD_ID nCurrentThread) - { - for (std::vector>::iterator i = m_contexts.begin(); i != m_contexts.end(); i++) - { - if (i->first == nCurrentThread) - { - CJSContextPrivate* ctx = i->second; - delete ctx; + CJSContextPrivate* pContext = new CJSContextPrivate(); + pContext->context = ctx->context; + m_contexts.push_back(std::pair(nCurrentThread, pContext)); + return true; + } + void UnregisterContextForId(ASC_THREAD_ID nCurrentThread) + { + for (std::vector>::iterator i = m_contexts.begin(); i != m_contexts.end(); i++) + { + if (i->first == nCurrentThread) + { + CJSContextPrivate* ctx = i->second; + delete ctx; - m_contexts.erase(i); - return; - } - } - } - void UnregisterContext() - { - UnregisterContextForId(NSThreads::GetCurrentThreadId()); - } + m_contexts.erase(i); + return; + } + } + } + void UnregisterContext() + { + UnregisterContextForId(NSThreads::GetCurrentThreadId()); + } - bool IsOldVersion() - { - return m_bIsOldVersion; - } + bool IsOldVersion() + { + return m_bIsOldVersion; + } - JSContext* GetCurrent() - { - ASC_THREAD_ID nCurrentThread = NSThreads::GetCurrentThreadId(); - for (std::vector>::const_iterator i = m_contexts.begin(); i != m_contexts.end(); i++) - { - if (i->first == nCurrentThread) - { - return i->second->context; - } - } - return [JSContext currentContext]; - } + JSContext* GetCurrent() + { + ASC_THREAD_ID nCurrentThread = NSThreads::GetCurrentThreadId(); + for (std::vector>::const_iterator i = m_contexts.begin(); i != m_contexts.end(); i++) + { + if (i->first == nCurrentThread) + { + return i->second->context; + } + } + return [JSContext currentContext]; + } - static CGlobalContext& GetInstance() - { - static CGlobalContext instance; - return instance; - } + static CGlobalContext& GetInstance() + { + static CGlobalContext instance; + return instance; + } }; JSContext* CJSContextPrivate::GetCurrentContext() { - return CGlobalContext::GetInstance().GetCurrent(); + return CGlobalContext::GetInstance().GetCurrent(); } bool CJSContextPrivate::IsOldVersion() { - return CGlobalContext::GetInstance().IsOldVersion(); + return CGlobalContext::GetInstance().IsOldVersion(); } -template +template bool CJSValueJSCTemplate::isUndefined() { - return (value == nil) ? true : ([value isUndefined] == YES); + return (value == nil) ? true : ([value isUndefined] == YES); } -template +template bool CJSValueJSCTemplate::isNull() { - return (value == nil) ? false : ([value isNull] == YES); + return (value == nil) ? false : ([value isNull] == YES); } -template +template bool CJSValueJSCTemplate::isBool() { - return (value == nil) ? false : ([value isBoolean] == YES); + return (value == nil) ? false : ([value isBoolean] == YES); } -template +template bool CJSValueJSCTemplate::isNumber() { - return (value == nil) ? false : ([value isNumber] == YES); + return (value == nil) ? false : ([value isNumber] == YES); } -template +template bool CJSValueJSCTemplate::isString() { - return (value == nil) ? false : ([value isString] == YES); + return (value == nil) ? false : ([value isString] == YES); } -template +template bool CJSValueJSCTemplate::isArray() { - return (value == nil) ? false : JSValueIsArray(getContext().JSGlobalContextRef, value.JSValueRef); + return (value == nil) ? false : JSValueIsArray(getContext().JSGlobalContextRef, value.JSValueRef); } -template +template bool CJSValueJSCTemplate::isTypedArray() { - return (value == nil) ? false : (kJSTypedArrayTypeNone != JSValueGetTypedArrayType(getContext().JSGlobalContextRef, value.JSValueRef, NULL)); + return (value == nil) ? false : (kJSTypedArrayTypeNone != JSValueGetTypedArrayType(getContext().JSGlobalContextRef, value.JSValueRef, NULL)); } -template +template bool CJSValueJSCTemplate::isObject() { - return (value == nil) ? false : ([value isObject] == YES); + return (value == nil) ? false : ([value isObject] == YES); } -template +template bool CJSValueJSCTemplate::isFunction() { - return isObject(); + return isObject(); } -template +template bool CJSValueJSCTemplate::isEmpty() { - return (value == nil) ? true : false; + return (value == nil) ? true : false; } -template +template void CJSValueJSCTemplate::doUndefined() { - value = [JSValue valueWithUndefinedInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + value = [JSValue valueWithUndefinedInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; } -template +template void CJSValueJSCTemplate::doNull() { - value = [JSValue valueWithNullInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + value = [JSValue valueWithNullInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; } -template +template bool CJSValueJSCTemplate::toBool() { - return ([value toBool] == YES) ? true : false; + return ([value toBool] == YES) ? true : false; } -template +template int CJSValueJSCTemplate::toInt32() { - return [value toInt32]; + return [value toInt32]; } -template +template unsigned int CJSValueJSCTemplate::toUInt32() { - return [value toUInt32]; + return [value toUInt32]; } -template +template double CJSValueJSCTemplate::toDouble() { - return [value toDouble]; + return [value toDouble]; } -template +template std::string CJSValueJSCTemplate::toStringA() { - return [[value toString] stdstring]; + return [[value toString] stdstring]; } -template +template std::wstring CJSValueJSCTemplate::toStringW() { - return [[value toString] stdwstring]; + return [[value toString] stdwstring]; } namespace NSJSBase { - CJSContext::CJSContext(const bool& bIsInitialize) - { - m_internal = new CJSContextPrivate(); - if (bIsInitialize) - Initialize(); - } - CJSContext::~CJSContext() - { - m_internal->context = nil; - RELEASEOBJECT(m_internal); - } + CJSContext::CJSContext(const bool& bIsInitialize) + { + m_internal = new CJSContextPrivate(); + if (bIsInitialize) + Initialize(); + } + CJSContext::~CJSContext() + { + m_internal->context = nil; + RELEASEOBJECT(m_internal); + } JSSmart CJSContext::GetExceptions() - { - return new CJSCTryCatch(); - } + { + return new CJSCTryCatch(); + } - void CJSContext::Initialize() - { - m_internal->context = [[JSContext alloc] init]; + void CJSContext::Initialize() + { + m_internal->context = [[JSContext alloc] init]; - ASC_THREAD_ID nThreadId = NSThreads::GetCurrentThreadId(); - MoveToThread(&nThreadId); - if (CGlobalContext::GetInstance().IsOldVersion()) - { - [m_internal->context evaluateScript:@"function jsc_toBase64(r){for(var o=[\"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\",\"P\",\"Q\",\"R\",\"S\",\"T\",\"U\",\"V\",\"W\",\"X\",\"Y\",\"Z\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\",\"j\",\"k\",\"l\",\"m\",\"n\",\"o\",\"p\",\"q\",\"r\",\"s\",\"t\",\"u\",\"v\",\"w\",\"x\",\"y\",\"z\",\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"+\",\"/\"],a=r.length,f=4*(a/3>>0),n=f/76>>0,t=19,v=0,e=[],i=\"\",s=0;s<=n;s++){s==n&&(t=f%76/4>>0);for(var u=0;u>>26&255],c<<=6,c&=4294967295}e.push(i)}}if(n=a%3!=0?a%3+1:0){for(c=0,h=0;h<3;h++)h>>26&255],c<<=6}t=0!=n?4-n:0;for(u=0;u>>3,c=0;c>>16,s<<=8}return t}\n"]; - } + ASC_THREAD_ID nThreadId = NSThreads::GetCurrentThreadId(); + MoveToThread(&nThreadId); + if (CGlobalContext::GetInstance().IsOldVersion()) + { + [m_internal->context evaluateScript:@"function jsc_toBase64(r){for(var o=[\"A\",\"B\",\"C\",\"D\",\"E\",\"F\",\"G\",\"H\",\"I\",\"J\",\"K\",\"L\",\"M\",\"N\",\"O\",\"P\",\"Q\",\"R\",\"S\",\"T\",\"U\",\"V\",\"W\",\"X\",\"Y\",\"Z\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\",\"g\",\"h\",\"i\",\"j\",\"k\",\"l\",\"m\",\"n\",\"o\",\"p\",\"q\",\"r\",\"s\",\"t\",\"u\",\"v\",\"w\",\"x\",\"y\",\"z\",\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"+\",\"/\"],a=r.length,f=4*(a/3>>0),n=f/76>>0,t=19,v=0,e=[],i=\"\",s=0;s<=n;s++){s==n&&(t=f%76/4>>0);for(var u=0;u>>26&255],c<<=6,c&=4294967295}e.push(i)}}if(n=a%3!=0?a%3+1:0){for(c=0,h=0;h<3;h++)h>>26&255],c<<=6}t=0!=n?4-n:0;for(u=0;u>>3,c=0;c>>16,s<<=8}return t}\n"]; + } // insert CreateEmbedObject() function to global object of this context m_internal->context[@"CreateEmbedObject"] = ^(NSString* name) { return CreateEmbedNativeObject(name); }; - JSValue* global_js = [m_internal->context globalObject]; - [global_js setValue:global_js forProperty:[[NSString alloc] initWithUTF8String:"window"]]; - } - void CJSContext::Dispose() - { - for (std::vector::const_iterator i = m_internal->m_arThreads.begin(); i != m_internal->m_arThreads.end(); i++) - { - CGlobalContext::GetInstance().UnregisterContextForId(*i); - } - m_internal->context = nil; - } + JSValue* global_js = [m_internal->context globalObject]; + [global_js setValue:global_js forProperty:[[NSString alloc] initWithUTF8String:"window"]]; + } + void CJSContext::Dispose() + { + for (std::vector::const_iterator i = m_internal->m_arThreads.begin(); i != m_internal->m_arThreads.end(); i++) + { + CGlobalContext::GetInstance().UnregisterContextForId(*i); + } + m_internal->context = nil; + } JSSmart CJSContext::GetGlobal() - { - CJSObjectJSC* ret = new CJSObjectJSC(); - ret->value = [m_internal->context globalObject]; - return ret; - } + { + CJSObjectJSC* ret = new CJSObjectJSC(); + ret->value = [m_internal->context globalObject]; + return ret; + } - CJSValue* CJSContext::createUndefined() - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->doUndefined(); - return _value; - } + CJSValue* CJSContext::createUndefined() + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->doUndefined(); + return _value; + } - CJSValue* CJSContext::createNull() - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->doNull(); - return _value; - } + CJSValue* CJSContext::createNull() + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->doNull(); + return _value; + } - CJSValue* CJSContext::createBool(const bool& value) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [JSValue valueWithBool:(value ? YES : NO) inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + CJSValue* CJSContext::createBool(const bool& value) + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [JSValue valueWithBool:(value ? YES : NO) inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + return _value; + } - CJSValue* CJSContext::createInt(const int& value) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [JSValue valueWithInt32:((int32_t) value) inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + CJSValue* CJSContext::createInt(const int& value) + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [JSValue valueWithInt32:((int32_t)value) inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + return _value; + } - CJSValue* CJSContext::createUInt(const unsigned int& value) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [JSValue valueWithUInt32:((uint32_t) value) inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + CJSValue* CJSContext::createUInt(const unsigned int& value) + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [JSValue valueWithUInt32:((uint32_t)value) inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + return _value; + } - CJSValue* CJSContext::createDouble(const double& value) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [JSValue valueWithDouble:value inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + CJSValue* CJSContext::createDouble(const double& value) + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [JSValue valueWithDouble:value inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + return _value; + } - CJSValue* CJSContext::createString(const char* value, const int& len) - { - CJSValueJSC* _value = new CJSValueJSC(); + CJSValue* CJSContext::createString(const char* value, const int& len) + { + CJSValueJSC* _value = new CJSValueJSC(); _value->value = [JSValue valueWithObject:[NSString stringWithUtf8Buffer:value length:(size_t)((len == -1) ? strlen(value) : len)] inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + return _value; + } - CJSValue* CJSContext::createString(const wchar_t* value, const int& length) - { - std::string sUtf8 = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(value, (length != -1) ? (LONG)length : (LONG)wcslen(value)); - return createString((const char*)sUtf8.c_str(), (int)sUtf8.length()); - } + CJSValue* CJSContext::createString(const wchar_t* value, const int& length) + { + std::string sUtf8 = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(value, (length != -1) ? (LONG)length : (LONG)wcslen(value)); + return createString((const char*)sUtf8.c_str(), (int)sUtf8.length()); + } - CJSValue* CJSContext::createString(const std::string& value) - { - CJSValueJSC* _value = new CJSValueJSC(); + CJSValue* CJSContext::createString(const std::string& value) + { + CJSValueJSC* _value = new CJSValueJSC(); _value->value = [JSValue valueWithObject:[NSString stringWithAString:value] inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + return _value; + } - CJSValue* CJSContext::createString(const std::wstring& value) - { - CJSValueJSC* _value = new CJSValueJSC(); + CJSValue* CJSContext::createString(const std::wstring& value) + { + CJSValueJSC* _value = new CJSValueJSC(); _value->value = [JSValue valueWithObject:[NSString stringWithWString:value] inContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + return _value; + } - CJSObject* CJSContext::createObject() - { - CJSObjectJSC* _value = new CJSObjectJSC(); - _value->value = [JSValue valueWithNewObjectInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + CJSObject* CJSContext::createObject() + { + CJSObjectJSC* _value = new CJSObjectJSC(); + _value->value = [JSValue valueWithNewObjectInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + return _value; + } - CJSArray* CJSContext::createArray(const int& count) - { - CJSArrayJSC* _value = new CJSArrayJSC(); - _value->value = [JSValue valueWithNewArrayInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; - return _value; - } + CJSArray* CJSContext::createArray(const int& count) + { + CJSArrayJSC* _value = new CJSArrayJSC(); + _value->value = [JSValue valueWithNewArrayInContext:NSJSBase::CJSContextPrivate::GetCurrentContext()]; + return _value; + } - CJSTypedArray* CJSContext::createUint8Array(BYTE* data, int count, const bool& isExternalize) - { - JSContext* _current = NSJSBase::CJSContextPrivate::GetCurrentContext(); - CJSTypedArrayJSC* _value = new CJSTypedArrayJSC(_current, data, count, isExternalize); - return _value; - } + CJSTypedArray* CJSContext::createUint8Array(BYTE* data, int count, const bool& isExternalize) + { + JSContext* _current = NSJSBase::CJSContextPrivate::GetCurrentContext(); + CJSTypedArrayJSC* _value = new CJSTypedArrayJSC(_current, data, count, isExternalize); + return _value; + } - JSSmart CJSContext::runScript(const std::string& script, JSSmart exception, const std::wstring& scriptPath) - { - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [m_internal->context evaluateScript:[NSString stringWithAString:script]]; - return _value; - } + JSSmart CJSContext::runScript(const std::string& script, JSSmart exception, const std::wstring& scriptPath) + { + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [m_internal->context evaluateScript:[NSString stringWithAString:script]]; + return _value; + } - unsigned char* NSAllocator::Alloc(const size_t& size) - { - return (unsigned char*)malloc(size); - } - void NSAllocator::Free(unsigned char* data, const size_t& size) - { - free(data); - } + unsigned char* NSAllocator::Alloc(const size_t& size) + { + return (unsigned char*)malloc(size); + } + void NSAllocator::Free(unsigned char* data, const size_t& size) + { + free(data); + } - JSSmart CJSContext::GetCurrent() - { - CJSContext* ret = new CJSContext(); - ret->m_internal->context = NSJSBase::CJSContextPrivate::GetCurrentContext(); - return ret; - } + JSSmart CJSContext::GetCurrent() + { + CJSContext* ret = new CJSContext(); + ret->m_internal->context = NSJSBase::CJSContextPrivate::GetCurrentContext(); + return ret; + } - void CJSContext::ExternalInitialize(const std::wstring& sDirectory) - { - } - void CJSContext::ExternalDispose() - { - } - bool CJSContext::IsSupportNativeTypedArrays() - { - return (CJSContextPrivate::IsOldVersion() == false) ? true : false; - } + void CJSContext::ExternalInitialize(const std::wstring& sDirectory) + { + } + void CJSContext::ExternalDispose() + { + } + bool CJSContext::IsSupportNativeTypedArrays() + { + return (CJSContextPrivate::IsOldVersion() == false) ? true : false; + } - JSSmart CJSContext::JSON_Parse(const char *sTmp) - { - if (!sTmp) - return CJSContext::createUndefined(); + JSSmart CJSContext::JSON_Parse(const char* sTmp) + { + if (!sTmp) + return CJSContext::createUndefined(); - NSString* sValue = [[NSString alloc] initWithUTF8String:sTmp]; - JSStringRef sValueRef = JSStringCreateWithCFString((__bridge CFStringRef)sValue); - JSValueRef oValueJSRef = JSValueMakeFromJSONString(m_internal->context.JSGlobalContextRef, sValueRef); + NSString* sValue = [[NSString alloc] initWithUTF8String:sTmp]; + JSStringRef sValueRef = JSStringCreateWithCFString((__bridge CFStringRef)sValue); + JSValueRef oValueJSRef = JSValueMakeFromJSONString(m_internal->context.JSGlobalContextRef, sValueRef); - CJSValueJSC* _value = new CJSValueJSC(); - _value->value = [JSValue valueWithJSValueRef:oValueJSRef inContext: m_internal->context]; - return _value; - } + CJSValueJSC* _value = new CJSValueJSC(); + _value->value = [JSValue valueWithJSValueRef:oValueJSRef inContext:m_internal->context]; + return _value; + } - void CJSContext::MoveToThread(ASC_THREAD_ID* id) - { - if (CGlobalContext::GetInstance().RegisterContext(m_internal, id)) - { - m_internal->m_arThreads.push_back((NULL == id) ? NSThreads::GetCurrentThreadId() : *id); - } - } + void CJSContext::MoveToThread(ASC_THREAD_ID* id) + { + if (CGlobalContext::GetInstance().RegisterContext(m_internal, id)) + { + m_internal->m_arThreads.push_back((NULL == id) ? NSThreads::GetCurrentThreadId() : *id); + } + } - void CJSContext::Enter() - { - } + void CJSContext::Enter() + { + } - void CJSContext::Exit() - { - } + void CJSContext::Exit() + { + } - class CJSLocalScopePrivate - { - public: - CJSLocalScopePrivate() - { - } - ~CJSLocalScopePrivate() - { - } - }; - CJSLocalScope::CJSLocalScope() : m_internal(nullptr) - { - } + class CJSLocalScopePrivate + { + public: + CJSLocalScopePrivate() + { + } + ~CJSLocalScopePrivate() + { + } + }; + CJSLocalScope::CJSLocalScope() : m_internal(nullptr) + { + } - CJSLocalScope::~CJSLocalScope() - { - } + CJSLocalScope::~CJSLocalScope() + { + } } namespace NSJSBase { - bool CJSCTryCatch::Check() - { - JSValue* exc = [context exception]; - if (exc == nil || [exc isNull] || [exc isUndefined]) - return false; + bool CJSCTryCatch::Check() + { + JSValue* exc = [context exception]; + if (exc == nil || [exc isNull] || [exc isUndefined]) + return false; - NSString* pExсeption = [exc toString]; - std::cerr << [pExсeption stdstring] << std::endl; - NSLog(@"%@", pExсeption); + NSString* pExсeption = [exc toString]; + std::cerr << [pExсeption stdstring] << std::endl; + NSLog(@"%@", pExсeption); - exc = nil; - return true; - } + exc = nil; + return true; + } } // embed From 2c3ebd218e8c799fbc62d3e5dffa833268b3b999 Mon Sep 17 00:00:00 2001 From: "Elena.Subbotina" Date: Fri, 1 Dec 2023 16:13:34 +0300 Subject: [PATCH 50/54] fix bug #65309 --- .../PptFile/Reader/PPTDocumentInfoOneUser.cpp | 52 +- .../PptFile/Reader/PPTDocumentInfoOneUser.h | 4 + OdfFile/DataTypes/presentationclass.cpp | 5 +- .../Converter/pptx_conversion_context.cpp | 1200 ++++++++-------- OdfFile/Reader/Converter/pptx_drawing.cpp | 18 +- .../Reader/Converter/pptx_slide_context.cpp | 6 +- .../Reader/Converter/pptx_text_context.cpp | 2 +- OdfFile/Reader/Format/draw_frame_pptx.cpp | 2 +- OdfFile/Reader/Format/draw_page.cpp | 21 +- OdfFile/Reader/Format/odfcontext.cpp | 1233 ++++++++--------- OdfFile/Reader/Format/odfcontext.h | 17 +- OdfFile/Reader/Format/style_presentation.cpp | 88 +- OdfFile/Reader/Format/style_presentation.h | 1 + OdfFile/Writer/Converter/ConvertDrawing.cpp | 6 + OdfFile/Writer/Converter/PptxConverter.cpp | 39 +- OdfFile/Writer/Converter/PptxConverter.h | 11 +- OdfFile/Writer/Format/draw_frame.h | 2 +- OdfFile/Writer/Format/draw_shapes.h | 5 - OdfFile/Writer/Format/odf_drawing_context.cpp | 38 +- OdfFile/Writer/Format/odf_drawing_context.h | 3 + OdfFile/Writer/Format/odp_slide_context.cpp | 2 +- OdfFile/Writer/Format/style_presentation.cpp | 2 +- OdfFile/Writer/Format/style_presentation.h | 10 +- 23 files changed, 1435 insertions(+), 1332 deletions(-) diff --git a/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp b/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp index 7b2465c9c8..e8b589aeef 100644 --- a/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp +++ b/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp @@ -546,7 +546,10 @@ void CPPTUserInfo::FromDocument() if (0 != oArrayHeadersFootersInfo.size()) { - for (int i = 0; i < 3; i++) m_PlaceholdersReplaceString[i] = oArrayHeadersFootersInfo[0]->m_HeadersFootersString[i]; + for (int i = 0; i < 3; i++) + { + m_PlaceholdersReplaceString[i] = oArrayHeadersFootersInfo[0]->m_HeadersFootersString[i]; + } if (oArrayHeadersFootersInfo[0]->m_oHeadersFootersAtom) { @@ -574,6 +577,18 @@ void CPPTUserInfo::FromDocument() m_bRtl = (oArrayDoc[0]->m_bRightToLeft != 0); m_bShowComments = (oArrayDoc[0]->m_bShowComments != 0); + for (size_t i = 0; i < m_arrSlidesOrder.size(); i++) + { + std::map<_UINT32, CRecordSlide*>::iterator pPair = m_mapSlides.find(m_arrSlidesOrder[i]); + + if (pPair == m_mapSlides.end()) + continue; + + LoadSlideFromPrevUsers(pPair->first); + + TestSlide(pPair->first); + } + LoadMasters(); double DurationSlide = PPT_DEFAULT_SLIDE_DURATION; @@ -804,8 +819,33 @@ void CPPTUserInfo::LoadNotes(_UINT32 dwNoteID, CSlide* pNotes) } } } +void CPPTUserInfo::TestSlide(_UINT32 dwSlideID) +{ + std::map<_UINT32, CRecordSlide*>::iterator pPairSlide = m_mapSlides.find(dwSlideID); + if (pPairSlide == m_mapSlides.end()) return; + CRecordSlide* pRecordSlide = pPairSlide->second; + if (NULL == pRecordSlide) return; + + std::vector oArraySlideAtoms; + pRecordSlide->GetRecordsByType(&oArraySlideAtoms, false, true); + if (0 == oArraySlideAtoms.size()) + { + // ошибка!!! + return; + } + std::map<_UINT32, LONG>::iterator pFind = m_mapRealUsedMaster.find(oArraySlideAtoms[0]->m_nMasterIDRef); + + if (pFind == m_mapRealUsedMaster.end()) + { + m_mapRealUsedMaster.insert(std::make_pair(oArraySlideAtoms[0]->m_nMasterIDRef, 1)); + } + else + { + pFind->second++; + } +} void CPPTUserInfo::LoadSlide(_UINT32 dwSlideID, CSlide* pSlide) { std::map<_UINT32, CRecordSlide*>::iterator pPairSlide = m_mapSlides.find(dwSlideID); @@ -1673,9 +1713,10 @@ void CPPTUserInfo::LoadMainMaster(_UINT32 dwMasterID, bool alwaysLoad) void CPPTUserInfo::LoadMasters() { - for (size_t i = 0; i < m_arrMastersOrder.size(); i++) + //for (size_t i = 0; i < m_arrMastersOrder.size(); i++) + for (auto master : m_mapRealUsedMaster) { - std::map<_UINT32, CRecordSlide*>::iterator pPair = m_mapMasters.find(m_arrMastersOrder[i]); + std::map<_UINT32, CRecordSlide*>::iterator pPair = m_mapMasters.find(master.first/*m_arrMastersOrder[i]*/); if (pPair == m_mapMasters.end())continue; LoadMainMaster(pPair->first, false); @@ -1683,9 +1724,10 @@ void CPPTUserInfo::LoadMasters() if (m_mapMasterToTheme.empty()) { - for (size_t i = 0; i < m_arrMastersOrder.size(); i++) + // for (size_t i = 0; i < m_arrMastersOrder.size(); i++) + for (auto master : m_mapRealUsedMaster) { - std::map<_UINT32, CRecordSlide*>::iterator pPair = m_mapMasters.find(m_arrMastersOrder[i]); + std::map<_UINT32, CRecordSlide*>::iterator pPair = m_mapMasters.find(master.first/*m_arrMastersOrder[i]*/); if (pPair == m_mapMasters.end())continue; LoadMainMaster(pPair->first, true); diff --git a/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.h b/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.h index d4928ae63d..18221edeef 100644 --- a/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.h +++ b/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.h @@ -76,6 +76,8 @@ public: // перевод id мастера в индекс темы/шаблона std::map<_UINT32, LONG> m_mapMasterToTheme; + std::map<_UINT32, LONG> m_mapRealUsedMaster; + // original id -> natural id std::map<_UINT32, _UINT32> m_mapMasterOriginalIds; @@ -140,6 +142,8 @@ public: void LoadSlide(_UINT32 dwSlideID, CSlide* pSlide); void LoadNotes(_UINT32 dwNotesID, CSlide* pSlide); + void TestSlide(_UINT32 dwSlideID); + void LoadMasters(); void LoadNoMainMaster (_UINT32 dwMasterID); diff --git a/OdfFile/DataTypes/presentationclass.cpp b/OdfFile/DataTypes/presentationclass.cpp index b1054b8daf..6b2e55635e 100644 --- a/OdfFile/DataTypes/presentationclass.cpp +++ b/OdfFile/DataTypes/presentationclass.cpp @@ -95,8 +95,8 @@ std::wstring presentation_class::get_type_ms() case title: res = L"title"; break; - // case subtitle: - //res = L"subTitle"; + case subtitle: + res = L"body"; break; case graphic: res = L"body"; @@ -125,7 +125,6 @@ std::wstring presentation_class::get_type_ms() case page_number: res = L"sldNum"; break; - case subtitle: case notes: case handout: case outline: diff --git a/OdfFile/Reader/Converter/pptx_conversion_context.cpp b/OdfFile/Reader/Converter/pptx_conversion_context.cpp index 0b28fb6b7e..cd06a9bd62 100644 --- a/OdfFile/Reader/Converter/pptx_conversion_context.cpp +++ b/OdfFile/Reader/Converter/pptx_conversion_context.cpp @@ -45,47 +45,46 @@ #include "pptx_default_serializes.h" -namespace cpdoccore { +namespace cpdoccore { -namespace odf_reader -{ - class odf_document; -} + namespace odf_reader + { + class odf_document; + } -namespace oox { - -namespace package -{ - class pptx_document; -} + namespace oox { -pptx_conversion_context::pptx_conversion_context( odf_reader::odf_document * odfDocument) - :output_document_ (NULL) - ,odf_document_ (odfDocument) - ,pptx_text_context_ (odf_document_->odf_context(), *this) - ,pptx_table_context_ (*this) - ,pptx_comments_context_ (comments_context_handle_) - ,pptx_slide_context_ (*this/*, pptx_text_context_*/) - ,math_context_ (odf_document_->odf_context().fontContainer(), true) - ,last_idx_placeHolder (1) - ,last_uniq_big_id (1) -{ -} + namespace package + { + class pptx_document; + } -pptx_conversion_context::~pptx_conversion_context() -{ -} + pptx_conversion_context::pptx_conversion_context(odf_reader::odf_document* odfDocument) + :output_document_(NULL) + , odf_document_(odfDocument) + , pptx_text_context_(odf_document_->odf_context(), *this) + , pptx_table_context_(*this) + , pptx_comments_context_(comments_context_handle_) + , pptx_slide_context_(*this/*, pptx_text_context_*/) + , math_context_(odf_document_->odf_context().fontContainer(), true) + , last_idx_placeHolder(1) + , last_uniq_big_id(1) + { + } -void pptx_conversion_context::set_output_document(package::pptx_document * document) -{ - output_document_ = document; -} + pptx_conversion_context::~pptx_conversion_context() + { + } -void pptx_conversion_context::set_font_directory(std::wstring pathFonts) -{ - pptx_slide_context_.get_mediaitems()->set_font_directory(pathFonts); -} + void pptx_conversion_context::set_output_document(package::pptx_document* document) + { + output_document_ = document; + } + void pptx_conversion_context::set_font_directory(std::wstring pathFonts) + { + pptx_slide_context_.get_mediaitems()->set_font_directory(pathFonts); + } void pptx_conversion_context::add_page_name(const std::wstring& page_name) { page_names_.push_back(page_name); @@ -96,629 +95,632 @@ const std::vector& pptx_conversion_context::get_page_names() const return page_names_; } -void pptx_conversion_context::process_layouts() -{ - odf_reader::presentation_layouts_instance & layouts = root()->odf_context().styleContainer().presentation_layouts(); - - get_text_context().set_process_layouts(true); - - //актуальные - for (size_t layout_index =0; layout_index < layouts.content.size(); layout_index++) - { - start_layout(layout_index); - - odf_reader::style_presentation_page_layout * layout = - root()->odf_context().pageLayoutContainer().presentation_page_layout_by_name(layouts.content[layout_index].layout_name); - - if (layout) + void pptx_conversion_context::process_layouts() { - layout->pptx_convert(*this); - } - //нужно вытащить footers - odf_reader::style_master_page * master = - root()->odf_context().pageLayoutContainer().master_page_by_name(layouts.content[layout_index].master_name); + odf_reader::presentation_layouts_instance& layouts = root()->odf_context().styleContainer().presentation_layouts(); - if (master) - { - for (size_t i = 0; i < master->content_.size(); i++) + get_text_context().set_process_layouts(true); + + //актуальные + for (size_t layout_index = 0; layout_index < layouts.content.size(); layout_index++) { - odf_reader::draw_frame* frame = dynamic_cast(master->content_[i].get()); - if (frame) + start_layout(layout_index); + + odf_reader::style_presentation_page_layout* layout = + root()->odf_context().pageLayoutContainer().presentation_page_layout_by_name(layouts.content[layout_index].layout_name); + + if (layout) { - odf_types::common_presentation_attlist &common_presentation_attlist_= frame->common_draw_attlists_.shape_with_text_and_styles_.common_presentation_attlist_; - - if (common_presentation_attlist_.presentation_class_) + layout->pptx_convert(*this); + } + //нужно вытащить footers + odf_reader::style_master_page* master = + root()->odf_context().pageLayoutContainer().master_page_by_name(layouts.content[layout_index].master_name); + + if (master) + { + for (size_t i = 0; i < master->content_.size(); i++) { - odf_types::presentation_class::type type = common_presentation_attlist_.presentation_class_->get_type(); - - if (type == odf_types::presentation_class::footer || - type == odf_types::presentation_class::date_time || - type == odf_types::presentation_class::header || - type == odf_types::presentation_class::page_number) + odf_reader::draw_frame* frame = dynamic_cast(master->content_[i].get()); + if (frame) { - if (frame->idx_in_owner < 0) - frame->idx_in_owner = last_idx_placeHolder++; + odf_types::common_presentation_attlist& common_presentation_attlist_ = frame->common_draw_attlists_.shape_with_text_and_styles_.common_presentation_attlist_; - frame->pptx_convert_placeHolder(*this); + if (common_presentation_attlist_.presentation_class_) + { + odf_types::presentation_class::type type = common_presentation_attlist_.presentation_class_->get_type(); + + if (type == odf_types::presentation_class::footer || + type == odf_types::presentation_class::date_time || + type == odf_types::presentation_class::header || + type == odf_types::presentation_class::page_number) + { + if (frame->idx_in_owner < 0) + frame->idx_in_owner = last_idx_placeHolder++; + + frame->pptx_convert_placeHolder(*this); + } + } } } } + end_layout(); } + get_text_context().set_process_layouts(false); } - end_layout(); - } - get_text_context().set_process_layouts(false); -} -void pptx_conversion_context::process_master_pages() -{ - odf_reader::presentation_masters_instance & masters = root()->odf_context().styleContainer().presentation_masters(); - - process_masters_ = true; - get_text_context().set_process_layouts(true); - - //берем только актуальные - odf_reader::office_element_ptr master_notes_; - - for (size_t master_index = 0; master_index < masters.content.size(); master_index++) - { - start_master(master_index); - - odf_reader::style_master_page * master = - root()->odf_context().pageLayoutContainer().master_page_by_name(masters.content[master_index].master_name); - - if (master) + void pptx_conversion_context::process_master_pages() { - master->pptx_convert(*this); - - if (!master_notes_ && master->presentation_notes_) - master_notes_ = master->presentation_notes_; - } + odf_reader::presentation_masters_instance& masters = root()->odf_context().styleContainer().presentation_masters(); - - end_master(); - } + process_masters_ = true; + get_text_context().set_process_layouts(true); - if (master_notes_) - { - start_master_notes(); - master_notes_->pptx_convert(*this); - end_master_notes(); - } - process_masters_ = false; - get_text_context().set_process_layouts(false); + //берем только актуальные + odf_reader::office_element_ptr master_notes_; -} - -void pptx_conversion_context::process_styles() -{ - -} -void pptx_conversion_context::process_theme(std::wstring name) -{ - int current = themes_.size() + 1; - - if (name.empty()) - { - name = L"User Theme: " + std::to_wstring(current); - } - start_theme(name); - // - pptx_serialize_clrScheme (current_theme().clrSchemeData()); - pptx_serialize_fmtScheme (current_theme().fmtSchemeData()); - pptx_serialize_fontScheme (current_theme().fontSchemeData()); - // - end_theme(); - -} -void pptx_conversion_context::start_document() -{ - odf_reader::odf_read_context & odfContext = root()->odf_context(); - std::vector instances; - - instances.push_back(odfContext.styleContainer().style_default_by_type(odf_types::style_family::Presentation)); - instances.push_back(odfContext.styleContainer().style_by_name(L"Default", odf_types::style_family::Presentation, false)); - - odf_reader::text_format_properties_ptr textFormatProperties = calc_text_properties_content(instances); - odf_reader::paragraph_format_properties parFormatProperties = calc_paragraph_properties_content(instances); - - process_masters_ = false; -} - -void pptx_conversion_context::end_document() -{ - for (size_t i = 0; i < slideMasters_.size(); i++) - { - pptx_xml_slideMaster_ptr& slideM = slideMasters_[i]; - - package::slide_content_ptr content = package::slide_content::create(); - - slideM->write_to(content->content()); - content->add_rels(slideM->Rels());//media & links rels - - output_document_->get_ppt_files().add_slideMaster(content);//slideMaster.xml - - CP_XML_WRITER(presentation_.slideMastersData())//presentation.xml - { - CP_XML_NODE(L"p:sldMasterId") - { - CP_XML_ATTR(L"id", 0x80000000 + last_uniq_big_id++); - CP_XML_ATTR(L"r:id", slideM->rId()); - } - } - } - if (!slideMasters_.empty()) - presentation_.slidesProperties() << slideMasters_[0]->Sizes().str(); - -//////////////////////////////////////////////////////////////////////////////////////////////////// - for (size_t i = 0; i < slides_.size(); i++) - { - pptx_xml_slide_ptr& slide = slides_[i]; - - package::slide_content_ptr content = package::slide_content::create(); - - slide->write_to(content->content()); - content->add_rels(slide->Rels());//media & links rels - - output_document_->get_ppt_files().add_slide(content);//slide.xml - - CP_XML_WRITER(presentation_.slidesData())//presentation.xml - { - CP_XML_NODE(L"p:sldId") - { - CP_XML_ATTR(L"id", 0x100 + i); - CP_XML_ATTR(L"r:id", slide->rId()); - } - } - } -//---------------------------------------------------------------------------------- - for (size_t i = 0; i < slideLayouts_.size(); i++) - { - pptx_xml_slideLayout_ptr& slideL = slideLayouts_[i]; - - package::slide_content_ptr content = package::slide_content::create(); - - slideL->write_to(content->content()); - content->add_rels(slideL->Rels());//media & links rels - - output_document_->get_ppt_files().add_slideLayout(content);//slideMaster.xml - } -//---------------------------------------------------------------------------------- - for (size_t i = 0; i < notes_.size(); i++) - { - pptx_xml_slideNotes_ptr& slideN = notes_[i]; - - package::slide_content_ptr content = package::slide_content::create(); - - slideN->write_to(content->content()); - content->add_rels(slideN->Rels());//media & links rels - - output_document_->get_ppt_files().add_notes(content); - } - if (slideNotesMaster_) - { - package::slide_content_ptr content = package::slide_content::create(); - - slideNotesMaster_->write_to(content->content()); - content->add_rels(slideNotesMaster_->Rels());//media & links rels - - output_document_->get_ppt_files().add_notesMaster(content); - - CP_XML_WRITER(presentation_.slideNotesMastersData())//presentation.xml - { - CP_XML_NODE(L"p:notesMasterId") + for (size_t master_index = 0; master_index < masters.content.size(); master_index++) { - CP_XML_ATTR(L"r:id", slideNotesMaster_->rId()); + start_master(master_index); + + odf_reader::style_master_page* master = + root()->odf_context().pageLayoutContainer().master_page_by_name(masters.content[master_index].master_name); + + if (master) + { + master->pptx_convert(*this); + + if (!master_notes_ && master->presentation_notes_) + master_notes_ = master->presentation_notes_; + } + + + end_master(); + } + + if (master_notes_) + { + start_master_notes(); + master_notes_->pptx_convert(*this); + end_master_notes(); + } + process_masters_ = false; + get_text_context().set_process_layouts(false); + + } + + void pptx_conversion_context::process_styles() + { + + } + void pptx_conversion_context::process_theme(std::wstring name) + { + int current = themes_.size() + 1; + + if (name.empty()) + { + name = L"User Theme: " + std::to_wstring(current); + } + start_theme(name); + // + pptx_serialize_clrScheme(current_theme().clrSchemeData()); + pptx_serialize_fmtScheme(current_theme().fmtSchemeData()); + pptx_serialize_fontScheme(current_theme().fontSchemeData()); + // + end_theme(); + + } + void pptx_conversion_context::start_document() + { + odf_reader::odf_read_context& odfContext = root()->odf_context(); + std::vector instances; + + instances.push_back(odfContext.styleContainer().style_default_by_type(odf_types::style_family::Presentation)); + instances.push_back(odfContext.styleContainer().style_by_name(L"Default", odf_types::style_family::Presentation, false)); + + odf_reader::text_format_properties_ptr textFormatProperties = calc_text_properties_content(instances); + odf_reader::paragraph_format_properties parFormatProperties = calc_paragraph_properties_content(instances); + + process_masters_ = false; + } + + void pptx_conversion_context::end_document() + { + for (size_t i = 0; i < slideMasters_.size(); i++) + { + pptx_xml_slideMaster_ptr& slideM = slideMasters_[i]; + + package::slide_content_ptr content = package::slide_content::create(); + + slideM->write_to(content->content()); + content->add_rels(slideM->Rels());//media & links rels + + output_document_->get_ppt_files().add_slideMaster(content);//slideMaster.xml + + CP_XML_WRITER(presentation_.slideMastersData())//presentation.xml + { + CP_XML_NODE(L"p:sldMasterId") + { + CP_XML_ATTR(L"id", 0x80000000 + last_uniq_big_id++); + CP_XML_ATTR(L"r:id", slideM->rId()); + } + } + } + if (!slideMasters_.empty()) + presentation_.slidesProperties() << slideMasters_[0]->Sizes().str(); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + for (size_t i = 0; i < slides_.size(); i++) + { + pptx_xml_slide_ptr& slide = slides_[i]; + + package::slide_content_ptr content = package::slide_content::create(); + + slide->write_to(content->content()); + content->add_rels(slide->Rels());//media & links rels + + output_document_->get_ppt_files().add_slide(content);//slide.xml + + CP_XML_WRITER(presentation_.slidesData())//presentation.xml + { + CP_XML_NODE(L"p:sldId") + { + CP_XML_ATTR(L"id", 0x100 + i); + CP_XML_ATTR(L"r:id", slide->rId()); + } + } + } + //---------------------------------------------------------------------------------- + for (size_t i = 0; i < slideLayouts_.size(); i++) + { + pptx_xml_slideLayout_ptr& slideL = slideLayouts_[i]; + + package::slide_content_ptr content = package::slide_content::create(); + + slideL->write_to(content->content()); + content->add_rels(slideL->Rels());//media & links rels + + output_document_->get_ppt_files().add_slideLayout(content);//slideMaster.xml + } + //---------------------------------------------------------------------------------- + for (size_t i = 0; i < notes_.size(); i++) + { + pptx_xml_slideNotes_ptr& slideN = notes_[i]; + + package::slide_content_ptr content = package::slide_content::create(); + + slideN->write_to(content->content()); + content->add_rels(slideN->Rels());//media & links rels + + output_document_->get_ppt_files().add_notes(content); + } + if (slideNotesMaster_) + { + package::slide_content_ptr content = package::slide_content::create(); + + slideNotesMaster_->write_to(content->content()); + content->add_rels(slideNotesMaster_->Rels());//media & links rels + + output_document_->get_ppt_files().add_notesMaster(content); + + CP_XML_WRITER(presentation_.slideNotesMastersData())//presentation.xml + { + CP_XML_NODE(L"p:notesMasterId") + { + CP_XML_ATTR(L"r:id", slideNotesMaster_->rId()); + } + } + } + //else + pptx_serialize_size(current_presentation().slidesNotesProperties(), 6858000, 9144000, L"p:notesSz"); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + + for (size_t i = 0; i < charts_.size(); i++) + { + package::chart_content_ptr content = package::chart_content::create(); + + charts_[i]->serialize(content->content()); + charts_[i]->dump_rels(content->get_rel_file()->get_rels()); + + output_document_->get_ppt_files().add_charts(content); + + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (size_t i = 0; i < themes_.size(); i++) + { + output_document_->get_ppt_files().add_theme(themes_[i]); + + } + package::ppt_comments_files_ptr comments = package::ppt_comments_files::create(comments_context_handle_.content()); + + output_document_->get_ppt_files().set_presentation(presentation_); + output_document_->get_ppt_files().set_comments(comments); + output_document_->get_ppt_files().set_authors_comments(authors_comments_); + output_document_->get_ppt_files().set_media(get_mediaitems()); + + output_document_->get_content_types_file().set_media(get_mediaitems()); + } + + void pptx_conversion_context::start_body() + { + + } + + void pptx_conversion_context::end_body() + { + } + pptx_xml_slideNotesMaster& pptx_conversion_context::current_notesMaster() + { + if (slideNotesMaster_) + { + return *slideNotesMaster_; + } + else + { + throw std::runtime_error("internal error"); } } - } - //else - pptx_serialize_size(current_presentation().slidesNotesProperties(), 6858000, 9144000, L"p:notesSz"); + pptx_xml_slideNotes& pptx_conversion_context::current_notes() + { + if (!notes_.empty()) + { + return *notes_.back().get(); + } + else + { + throw std::runtime_error("internal error"); + } + } + pptx_xml_slide& pptx_conversion_context::current_slide() + { + if (!slides_.empty()) + { + return *slides_.back().get(); + } + else + { + throw std::runtime_error("internal error"); + } + } + pptx_xml_slideLayout& pptx_conversion_context::current_layout() + { + if (!slideLayouts_.empty()) + { + return *slideLayouts_.back().get(); + } + else + { + throw std::runtime_error("internal error"); + } + } + pptx_xml_theme& pptx_conversion_context::current_theme() + { + if (!themes_.empty()) + { + return *themes_.back().get(); + } + else + { + throw std::runtime_error("internal error"); + } + } + pptx_xml_presentation& pptx_conversion_context::current_presentation() + { + return presentation_; + } -//////////////////////////////////////////////////////////////////////////////////////////////////////////// + oox_chart_context& pptx_conversion_context::current_chart() + { + if (!charts_.empty()) + { + return *charts_.back().get(); + } + else + { + throw std::runtime_error("internal error"); + } + } + pptx_xml_slideMaster& pptx_conversion_context::current_master() + { + if (!slideMasters_.empty()) + { + return *slideMasters_.back().get(); + } + else + { + throw std::runtime_error("internal error"); + } + } + void pptx_conversion_context::create_new_slide(std::wstring const& name) + { + pptx_xml_slide_ptr s = pptx_xml_slide::create(name, slides_.size() + 1); + slides_.push_back(s); + } + void pptx_conversion_context::create_new_slideNotes() + { + pptx_xml_slideNotes_ptr s = pptx_xml_slideNotes::create(notes_.size() + 1); + notes_.push_back(s); + } + void pptx_conversion_context::create_new_slideNotesMaster() + { + slideNotesMaster_ = pptx_xml_slideNotesMaster::create(); + } + void pptx_conversion_context::create_new_slideLayout(int id) + { + pptx_xml_slideLayout_ptr s = pptx_xml_slideLayout::create(id); + slideLayouts_.push_back(s); + } + void pptx_conversion_context::create_new_slideMaster(int id) + { + pptx_xml_slideMaster_ptr s = pptx_xml_slideMaster::create(id); + slideMasters_.push_back(s); + } + bool pptx_conversion_context::start_page(const std::wstring& pageName, const std::wstring& pageStyleName, + const std::wstring& pageLayoutName, + const std::wstring& pageMasterName) + { + create_new_slide(pageName); + get_slide_context().start_slide();//pageName, pageStyleName); - for (size_t i = 0; i < charts_.size(); i++) - { - package::chart_content_ptr content = package::chart_content::create(); + current_master_page_name_ = pageMasterName; + current_layout_page_name_ = pageLayoutName; - charts_[i]->serialize(content->content()); - charts_[i]->dump_rels(content->get_rel_file()->get_rels()); + //const std::wstring masterPageNameLayout = root()->odf_context().pageLayoutContainer().page_layout_name_by_style(current_master_page_name_); - output_document_->get_ppt_files().add_charts(content); - - } -//////////////////////////////////////////////////////////////////////////////////////////////////////////// - for (size_t i=0; i < themes_.size(); i++) - { - output_document_->get_ppt_files().add_theme(themes_[i]); - - } - package::ppt_comments_files_ptr comments = package::ppt_comments_files::create(comments_context_handle_.content()); - - output_document_->get_ppt_files().set_presentation (presentation_); - output_document_->get_ppt_files().set_comments (comments); - output_document_->get_ppt_files().set_authors_comments (authors_comments_); - output_document_->get_ppt_files().set_media (get_mediaitems()); + std::pair layout_id = + root()->odf_context().styleContainer().presentation_layouts().add_or_find(pageLayoutName, pageMasterName); - output_document_->get_content_types_file().set_media(get_mediaitems()); -} + current_slide().Rels().add(relationship(layout_id.second, L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout", + std::wstring(L"../slideLayouts/slideLayout") + std::to_wstring(layout_id.first) + L".xml")); -void pptx_conversion_context::start_body() -{} + return true; + } -void pptx_conversion_context::end_body() -{} -pptx_xml_slideNotesMaster & pptx_conversion_context::current_notesMaster() -{ - if (slideNotesMaster_) - { - return *slideNotesMaster_; - } - else - { - throw std::runtime_error("internal error"); - } -} -pptx_xml_slideNotes & pptx_conversion_context::current_notes() -{ - if (!notes_.empty()) - { - return *notes_.back().get(); - } - else - { - throw std::runtime_error("internal error"); - } -} -pptx_xml_slide & pptx_conversion_context::current_slide() -{ - if (!slides_.empty()) - { - return *slides_.back().get(); - } - else - { - throw std::runtime_error("internal error"); - } -} -pptx_xml_slideLayout & pptx_conversion_context::current_layout() -{ - if (!slideLayouts_.empty()) - { - return *slideLayouts_.back().get(); - } - else - { - throw std::runtime_error("internal error"); - } -} -pptx_xml_theme & pptx_conversion_context::current_theme() -{ - if (!themes_.empty()) - { - return *themes_.back().get(); - } - else - { - throw std::runtime_error("internal error"); - } -} -pptx_xml_presentation & pptx_conversion_context::current_presentation() -{ - return presentation_; -} + bool pptx_conversion_context::start_layout(int layout_index) + { + if (layout_index >= 0) + { + odf_reader::presentation_layouts_instance& layouts = root()->odf_context().styleContainer().presentation_layouts(); -oox_chart_context & pptx_conversion_context::current_chart() -{ - if (!charts_.empty()) - { - return *charts_.back().get(); - } - else - { - throw std::runtime_error("internal error"); - } -} -pptx_xml_slideMaster & pptx_conversion_context::current_master() -{ - if (!slideMasters_.empty()) - { - return *slideMasters_.back().get(); - } - else - { - throw std::runtime_error("internal error"); - } -} -void pptx_conversion_context::create_new_slide(std::wstring const & name) -{ - pptx_xml_slide_ptr s = pptx_xml_slide::create(name,slides_.size() + 1); - slides_.push_back(s); -} -void pptx_conversion_context::create_new_slideNotes() -{ - pptx_xml_slideNotes_ptr s = pptx_xml_slideNotes::create( notes_.size() + 1); - notes_.push_back(s); -} -void pptx_conversion_context::create_new_slideNotesMaster() -{ - slideNotesMaster_ = pptx_xml_slideNotesMaster::create(); -} -void pptx_conversion_context::create_new_slideLayout(int id) -{ - pptx_xml_slideLayout_ptr s = pptx_xml_slideLayout::create(id); - slideLayouts_.push_back(s); -} -void pptx_conversion_context::create_new_slideMaster(int id) -{ - pptx_xml_slideMaster_ptr s = pptx_xml_slideMaster::create(id); - slideMasters_.push_back(s); -} -bool pptx_conversion_context::start_page(const std::wstring & pageName, const std::wstring & pageStyleName, - const std::wstring & pageLayoutName, - const std::wstring & pageMasterName) -{ - create_new_slide(pageName); - get_slide_context().start_slide();//pageName, pageStyleName); + create_new_slideLayout(layouts.content[layout_index].Id); - current_master_page_name_ = pageMasterName; - current_layout_page_name_ = pageLayoutName; - - //const std::wstring masterPageNameLayout = root()->odf_context().pageLayoutContainer().page_layout_name_by_style(current_master_page_name_); + get_slide_context().start_slide();//layouts.content[layout_index].layout_name, L"");//????? - std::pair layout_id = - root()->odf_context().styleContainer().presentation_layouts().add_or_find(pageLayoutName,pageMasterName); + current_master_page_name_ = layouts.content[layout_index].master_name; + current_layout_page_name_ = L""; - current_slide().Rels().add(relationship(layout_id.second, L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout", - std::wstring(L"../slideLayouts/slideLayout") + std::to_wstring(layout_id.first) + L".xml")); + std::pair master_id = //std::pair(1, L"smId1"); + root()->odf_context().styleContainer().presentation_masters().add_or_find(layouts.content[layout_index].master_name); - return true; -} + root()->odf_context().styleContainer().presentation_masters().add_layout_to(layouts.content[layout_index].master_name, layouts.content[layout_index]); -bool pptx_conversion_context::start_layout(int layout_index) -{ - if (layout_index >=0) - { - odf_reader::presentation_layouts_instance & layouts = root()->odf_context().styleContainer().presentation_layouts(); + current_layout().Rels().add(relationship(L"smId1"/*master_id.second*/, L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster", + std::wstring(L"../slideMasters/slideMaster") + std::to_wstring(master_id.first) + L".xml")); - create_new_slideLayout(layouts.content[layout_index].Id); - - get_slide_context().start_slide();//layouts.content[layout_index].layout_name, L"");//????? + // + } + else//общий шаблон (насильно пропишем к темам несоответствующие шалоны) + { + } - current_master_page_name_ = layouts.content[layout_index].master_name; - current_layout_page_name_ = L""; - - std::pair master_id = //std::pair(1,L"smId1"); - root()->odf_context().styleContainer().presentation_masters().add_or_find(layouts.content[layout_index].master_name); + //layout type - root()->odf_context().styleContainer().presentation_masters().add_layout_to(layouts.content[layout_index].master_name,layouts.content[layout_index]); + // + //1375 + //1376 + //1377 + //1378 + //1379 + //1380 + //1381 + //1382 + //1383 + //1384 + //1385 + //1386 + //1387 + //1388 + //1389 + //1390 + //1391 + //1392 + //1393 + //1394 + //1395 + //1396 + //1397 + //1398 + //1399 + //1400 + //1401 + //1402 + //1403 + //1404 + //1405 ---------------------------------- !!!!!!!!!!!!! + //1406 + //1407 + //1408 + //1409 - current_layout().Rels().add(relationship(L"smId1"/*master_id.second*/, L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster", - std::wstring(L"../slideMasters/slideMaster") + std::to_wstring(master_id.first) + L".xml")); + return true; + } + bool pptx_conversion_context::start_master(int master_index) + { + odf_reader::presentation_masters_instance& masters = root()->odf_context().styleContainer().presentation_masters(); - // - } - else//общий шаблон (насильно пропишем к темам несоответствующие шалоны) - { - } + create_new_slideMaster(masters.content[master_index].Id); -//layout type + get_slide_context().start_slide(); -// -//1375 -//1376 -//1377 -//1378 -//1379 -//1380 -//1381 -//1382 -//1383 -//1384 -//1385 -//1386 -//1387 -//1388 -//1389 -//1390 -//1391 -//1392 -//1393 -//1394 -//1395 -//1396 -//1397 -//1398 -//1399 -//1400 -//1401 -//1402 -//1403 -//1404 -//1405 ---------------------------------- !!!!!!!!!!!!! -//1406 -//1407 -//1408 -//1409 - - return true; -} -bool pptx_conversion_context::start_master(int master_index) -{ - odf_reader::presentation_masters_instance & masters = root()->odf_context().styleContainer().presentation_masters(); + current_master_page_name_ = L""; + current_layout_page_name_ = L""; - create_new_slideMaster(masters.content[master_index].Id); - - get_slide_context().start_slide(); + process_theme(masters.content[master_index].master_name);//add default theme - одинаковые но под разными именами + current_master().add_theme(current_theme().id(), L"tId1"); - current_master_page_name_ = L""; - current_layout_page_name_ = L""; - - process_theme(masters.content[master_index].master_name);//add default theme - одинаковые но под разными именами - current_master().add_theme(current_theme().id(), L"tId1"); + for (size_t i = 0; i < masters.content[master_index].layouts.size(); i++) + { + current_master().add_layout(masters.content[master_index].layouts[i].Id, masters.content[master_index].layouts[i].rId, 0x80000000 + last_uniq_big_id++); + } - for (size_t i = 0; i < masters.content[master_index].layouts.size(); i++) - { - current_master().add_layout(masters.content[master_index].layouts[i].Id, masters.content[master_index].layouts[i].rId, 0x80000000 + last_uniq_big_id++); - } + //---------------------------------------------------------------------------------- + //размеры страниц в презентации + const std::wstring pageProperties = root()->odf_context().pageLayoutContainer().page_layout_name_by_style(masters.content[master_index].master_name); -//---------------------------------------------------------------------------------- -//размеры страниц в презентации - const std::wstring pageProperties = root()->odf_context().pageLayoutContainer().page_layout_name_by_style(masters.content[master_index].master_name); + odf_reader::page_layout_instance* pages_layouts = root()->odf_context().pageLayoutContainer().page_layout_by_name(pageProperties); - odf_reader::page_layout_instance *pages_layouts = root()->odf_context().pageLayoutContainer().page_layout_by_name(pageProperties); - - if (pages_layouts) - pages_layouts->pptx_serialize(current_master().Sizes(), *this); + if (pages_layouts) + pages_layouts->pptx_serialize(current_master().Sizes(), *this); - return true; -} -void pptx_conversion_context::end_page() -{ - if (!get_comments_context().empty()) - { - std::wstringstream strm; - get_comments_context().serialize(strm); - - const std::pair commentsName = - comments_context_handle_.add_comments_xml(strm.str(), get_comments_context().get_comments() ); + return true; + } + void pptx_conversion_context::end_page() + { + if (!get_comments_context().empty()) + { + std::wstringstream strm; + get_comments_context().serialize(strm); - get_slide_context().add_rels(false, commentsName.second, L"../comments/" + commentsName.first, typeComment); - } + const std::pair commentsName = + comments_context_handle_.add_comments_xml(strm.str(), get_comments_context().get_comments()); - get_slide_context().serialize_background(current_slide().Background()); - get_slide_context().serialize_objects (current_slide().Data()); - get_slide_context().serialize_animations(current_slide().Timing()); + get_slide_context().add_rels(false, commentsName.second, L"../comments/" + commentsName.first, typeComment); + } - { - // NOTE: При использовании operator<< потока буст пушит туда лишний пробел перед значением. - // С этим пробелом наш редактор onlyoffice на распознает значение. - // Example: - // ppt_y - // ppt_y - // TODO: Figure out how to push value without redundant space character - current_slide().remove_timing_redundant_space(); - } - - get_slide_context().dump_rels(current_slide().Rels());//hyperlinks, mediaitems, ... + get_slide_context().serialize_background(current_slide().Background()); + get_slide_context().serialize_objects(current_slide().Data()); + get_slide_context().serialize_animations(current_slide().Timing()); - get_slide_context().end_slide(); -} -bool pptx_conversion_context::start_page_notes() -{ - create_new_slideNotes( ); + { + // NOTE: При использовании operator<< потока буст пушит туда лишний пробел перед значением. + // С этим пробелом наш редактор onlyoffice на распознает значение. + // Example: + // ppt_y + // ppt_y + // TODO: Figure out how to push value without redundant space character + current_slide().remove_timing_redundant_space(); + } - current_slide().Rels().add(relationship(notes_.back()->rId(), L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide", - L"../notesSlides/notesSlide" + std::to_wstring(notes_.size()) + L".xml")); + get_slide_context().dump_rels(current_slide().Rels());//hyperlinks, mediaitems, ... - get_slide_context().start_slide(); - - current_notes().Rels().add(relationship(L"nId1", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide", - L"../slides/slide" + std::to_wstring(slides_.size()) + L".xml")); - - return true; -} + get_slide_context().end_slide(); + } + bool pptx_conversion_context::start_page_notes() + { + create_new_slideNotes(); -void pptx_conversion_context::end_page_notes() -{ - get_slide_context().serialize_background(current_notes().Background()); - get_slide_context().serialize_objects(current_notes().Data()); + current_slide().Rels().add(relationship(notes_.back()->rId(), L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide", + L"../notesSlides/notesSlide" + std::to_wstring(notes_.size()) + L".xml")); - get_slide_context().dump_rels(current_notes().Rels());//hyperlinks, mediaitems, ... + get_slide_context().start_slide(); - get_slide_context().end_slide(); -} -bool pptx_conversion_context::start_master_notes() -{ - create_new_slideNotesMaster( ); - - get_slide_context().start_slide(); + current_notes().Rels().add(relationship(L"nId1", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide", + L"../slides/slide" + std::to_wstring(slides_.size()) + L".xml")); - process_theme(L"");//add default theme - одинаковые но под разными именами - current_notesMaster().add_theme(current_theme().id(), L"tId1"); + return true; + } - get_slide_context().start_slide(); - return true; -} + void pptx_conversion_context::end_page_notes() + { + get_slide_context().serialize_background(current_notes().Background()); + get_slide_context().serialize_objects(current_notes().Data()); -void pptx_conversion_context::end_master_notes() -{ - get_slide_context().serialize_background(current_notesMaster().Background()); - get_slide_context().serialize_objects(current_notesMaster().Data()); + get_slide_context().dump_rels(current_notes().Rels());//hyperlinks, mediaitems, ... - get_slide_context().dump_rels(current_notesMaster().Rels());//hyperlinks, mediaitems, ... + get_slide_context().end_slide(); + } + bool pptx_conversion_context::start_master_notes() + { + create_new_slideNotesMaster(); - get_slide_context().end_slide(); - - for (size_t i = 0; i < notes_.size(); i++) - { - notes_[i]->Rels().add(relationship(L"nmId1", - L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster", - L"../notesMasters/notesMaster1.xml")); + get_slide_context().start_slide(); + + process_theme(L"");//add default theme - одинаковые но под разными именами + current_notesMaster().add_theme(current_theme().id(), L"tId1"); + + get_slide_context().start_slide(); + return true; + } + + void pptx_conversion_context::end_master_notes() + { + get_slide_context().serialize_background(current_notesMaster().Background()); + get_slide_context().serialize_objects(current_notesMaster().Data()); + + get_slide_context().dump_rels(current_notesMaster().Rels());//hyperlinks, mediaitems, ... + + get_slide_context().end_slide(); + + for (size_t i = 0; i < notes_.size(); i++) + { + notes_[i]->Rels().add(relationship(L"nmId1", + L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster", + L"../notesMasters/notesMaster1.xml")); + } + } + void pptx_conversion_context::end_layout() + { + get_slide_context().serialize_objects(current_layout().Data()); + + get_slide_context().dump_rels(current_layout().Rels());//hyperlinks, mediaitems, ... + + get_slide_context().end_slide(); + } + + std::pair pptx_conversion_context::add_author_comments(std::wstring author) + { + if (!authors_comments_) + { + authors_comments_ = pptx_xml_authors_comments::create(); + if (!authors_comments_)return std::pair(-1, -1); + } + + return authors_comments_->add_or_find(author); + } + + void pptx_conversion_context::end_master() + { + get_slide_context().serialize_background(current_master().Background(), true); + get_slide_context().serialize_objects(current_master().Data()); + get_slide_context().serialize_HeaderFooter(current_master().DataExtra()); + + get_slide_context().dump_rels(current_master().Rels());//hyperlinks, mediaitems, ... + + get_slide_context().end_slide(); + } + void pptx_conversion_context::start_theme(std::wstring& name) + { + themes_.push_back(pptx_xml_theme::create(name, themes_.size() + 1)); + } + void pptx_conversion_context::end_theme() + { + } + void pptx_conversion_context::start_office_presentation() + { + } + + void pptx_conversion_context::end_office_presentation() + { + } + void pptx_conversion_context::start_chart(std::wstring name) + { + charts_.push_back(oox_chart_context_ptr(new oox_chart_context(get_mediaitems(), name))); + //добавляем новую форму для диаграммы + //в ней будет информационная часть - и она пишется каждый раз в свою xml (их - по числу диаграмм) + //этот контекст нужно передавать в файл + + } + void pptx_conversion_context::end_chart() + { + //current_chart().set_drawing_link(current_sheet().get_drawing_link()); + //излишняя инфа + } + void pptx_conversion_context::add_jsaProject(const std::string& content) + { + if (content.empty()) return; + + output_document_->get_ppt_files().add_jsaProject(content); + output_document_->get_content_types_file().add_or_find_default(L"bin"); + } } } -void pptx_conversion_context::end_layout() -{ - get_slide_context().serialize_objects(current_layout().Data()); - - get_slide_context().dump_rels(current_layout().Rels());//hyperlinks, mediaitems, ... - - get_slide_context().end_slide(); -} - -std::pair pptx_conversion_context::add_author_comments(std::wstring author) -{ - if (!authors_comments_) - { - authors_comments_ = pptx_xml_authors_comments::create(); - if (!authors_comments_)return std::pair(-1,-1); - } - - return authors_comments_->add_or_find(author); -} - -void pptx_conversion_context::end_master() -{ - get_slide_context().serialize_background (current_master().Background(),true); - get_slide_context().serialize_objects (current_master().Data()); - get_slide_context().serialize_HeaderFooter (current_master().DataExtra()); - - get_slide_context().dump_rels(current_master().Rels());//hyperlinks, mediaitems, ... - - get_slide_context().end_slide(); -} -void pptx_conversion_context::start_theme(std::wstring & name) -{ - themes_.push_back(pptx_xml_theme::create(name,themes_.size()+1)); -} -void pptx_conversion_context::end_theme() -{ -} -void pptx_conversion_context::start_office_presentation() -{ -} - -void pptx_conversion_context::end_office_presentation() -{ -} -void pptx_conversion_context::start_chart(std::wstring name) -{ - charts_.push_back(oox_chart_context_ptr(new oox_chart_context(get_mediaitems(), name))); - //добавляем новую форму для диаграммы - //в ней будет информационная часть - и она пишется каждый раз в свою xml (их - по числу диаграмм) - //этот контекст нужно передавать в файл - -} -void pptx_conversion_context::end_chart() -{ - //current_chart().set_drawing_link(current_sheet().get_drawing_link()); - //излишняя инфа -} -void pptx_conversion_context::add_jsaProject(const std::string &content) -{ - if (content.empty()) return; - - output_document_->get_ppt_files().add_jsaProject(content); - output_document_->get_content_types_file().add_or_find_default(L"bin"); -} -} -} diff --git a/OdfFile/Reader/Converter/pptx_drawing.cpp b/OdfFile/Reader/Converter/pptx_drawing.cpp index 04b5833624..757b27653d 100644 --- a/OdfFile/Reader/Converter/pptx_drawing.cpp +++ b/OdfFile/Reader/Converter/pptx_drawing.cpp @@ -227,7 +227,7 @@ void pptx_serialize_shape(std::wostream & strm, _pptx_drawing & val) { CP_XML_NODE(L"p:ph") { - CP_XML_ATTR(L"type",val.place_holder_type_); + CP_XML_ATTR(L"type", val.place_holder_type_); if (val.place_holder_idx_ > 0) CP_XML_ATTR(L"idx", val.place_holder_idx_); if (val.place_holder_type_ == L"dt") { CP_XML_ATTR(L"sz", L"half"); } @@ -242,19 +242,19 @@ void pptx_serialize_shape(std::wostream & strm, _pptx_drawing & val) _CP_OPT(bool) bNoRect; odf_reader::GetProperty(val.additional,L"no_rect",bNoRect); + if (val.cx != 0 || val.cy != 0) //layout + { + val.serialize_xfrm(CP_XML_STREAM(), L"a", true); + } if (!bNoRect) - { - if (val.cx != 0 || val.cy != 0) //layout - { - val.serialize_xfrm(CP_XML_STREAM(), L"a", true); - } + { val.serialize_shape(CP_XML_STREAM()); oox_serialize_ln(CP_XML_STREAM(), val.additional); oox_serialize_effects(CP_XML_STREAM(), val.additional); } } - pptx_serialize_text(CP_XML_STREAM(), val); + pptx_serialize_text(CP_XML_STREAM(), val); } } // CP_XML_WRITER } @@ -295,7 +295,7 @@ void pptx_serialize_connector(std::wostream & strm, _pptx_drawing & val) } CP_XML_NODE(L"p:nvPr") { - if (val.place_holder_type_.length()>0) + if (false == val.place_holder_type_.empty()) { CP_XML_NODE(L"p:ph") { @@ -326,7 +326,7 @@ void pptx_serialize_connector(std::wostream & strm, _pptx_drawing & val) oox_serialize_effects(CP_XML_STREAM(), val.additional); } } - pptx_serialize_text(CP_XML_STREAM(), val); + pptx_serialize_text(CP_XML_STREAM(), val); } } // CP_XML_WRITER } diff --git a/OdfFile/Reader/Converter/pptx_slide_context.cpp b/OdfFile/Reader/Converter/pptx_slide_context.cpp index a909e2a884..3b69adf2fb 100644 --- a/OdfFile/Reader/Converter/pptx_slide_context.cpp +++ b/OdfFile/Reader/Converter/pptx_slide_context.cpp @@ -322,11 +322,11 @@ void pptx_slide_context::set_placeHolder_type(std::wstring typeHolder) if (typeHolder == L"dt") impl_->date_time = true; if (typeHolder == L"sldNum")impl_->slideNum = true; - impl_->object_description_.additional_.push_back(odf_reader::_property(L"PlaceHolderType",typeHolder)); + impl_->object_description_.additional_.push_back(odf_reader::_property(L"PlaceHolderType", typeHolder)); } void pptx_slide_context::set_placeHolder_idx(int idx) { - impl_->object_description_.additional_.push_back(odf_reader::_property(L"PlaceHolderIdx",idx)); + impl_->object_description_.additional_.push_back(odf_reader::_property(L"PlaceHolderIdx", idx)); } void pptx_slide_context::set_rect(double width_pt, double height_pt, double x_pt, double y_pt) @@ -1012,7 +1012,7 @@ void pptx_slide_context::serialize_objects(std::wostream & strm) } } } - //process_drawings(); + process_drawings(); impl_->get_drawings()->serialize(strm); } diff --git a/OdfFile/Reader/Converter/pptx_text_context.cpp b/OdfFile/Reader/Converter/pptx_text_context.cpp index c09736a311..0bfc224aea 100644 --- a/OdfFile/Reader/Converter/pptx_text_context.cpp +++ b/OdfFile/Reader/Converter/pptx_text_context.cpp @@ -452,7 +452,7 @@ std::wstring pptx_text_context::Impl::dump_paragraph(/*bool last*/) std::wstring str_run = run_.str(); - if (str_run.length() > 0 || paragraph_style_name_.length() > 0) + if (false == str_run.empty() || false == paragraph_style_name_.empty() || (false == base_style_name_.empty() && process_layouts_)) { CP_XML_WRITER(paragraph_) { diff --git a/OdfFile/Reader/Format/draw_frame_pptx.cpp b/OdfFile/Reader/Format/draw_frame_pptx.cpp index bb1e0488ee..55df515d82 100644 --- a/OdfFile/Reader/Format/draw_frame_pptx.cpp +++ b/OdfFile/Reader/Format/draw_frame_pptx.cpp @@ -77,7 +77,7 @@ void draw_g::pptx_convert(oox::pptx_conversion_context & Context) } void draw_frame::pptx_convert_placeHolder(oox::pptx_conversion_context & Context) { - Context.get_slide_context().set_property(_property(L"no_rect",true)); + Context.get_slide_context().set_property(_property(L"no_rect", true)); pptx_convert(Context); } void draw_frame::pptx_convert(oox::pptx_conversion_context & Context) diff --git a/OdfFile/Reader/Format/draw_page.cpp b/OdfFile/Reader/Format/draw_page.cpp index 7b5869fe29..4e40193f40 100644 --- a/OdfFile/Reader/Format/draw_page.cpp +++ b/OdfFile/Reader/Format/draw_page.cpp @@ -88,9 +88,9 @@ void draw_page::pptx_convert_placeHolder(oox::pptx_conversion_context & Context, office_element_ptr elm = Context.root()->odf_context().drawStyles().find_by_style_name(styleName); //todooo если это элемент datatime -нужно вытащить формат поля - if (!elm)return; + if (!elm) return; - int index=-1; + int index = -1; const std::wstring masterName = attlist_.master_page_name_.get_value_or(L""); style_master_page * master = Context.root()->odf_context().pageLayoutContainer().master_page_by_name(masterName); @@ -98,7 +98,6 @@ void draw_page::pptx_convert_placeHolder(oox::pptx_conversion_context & Context, if (master) index = master->find_placeHolderIndex(PresentationClass, Context.last_idx_placeHolder); - Context.get_slide_context().start_shape(1); Context.get_slide_context().set_placeHolder_type(presentation_class(PresentationClass).get_type_ms()); Context.get_slide_context().set_placeHolder_idx(index); @@ -114,11 +113,11 @@ void draw_page::pptx_convert_placeHolder(oox::pptx_conversion_context & Context, std::wstring text_content_ = Context.get_text_context().end_object(); - if (text_content_.length()>0) + if (false == text_content_.empty()) { - Context.get_slide_context().set_property(_property(L"text-content",text_content_)); + Context.get_slide_context().set_property(_property(L"text-content", text_content_)); } - Context.get_slide_context().set_property(_property(L"no_rect",true)); + Context.get_slide_context().set_property(_property(L"no_rect", true)); Context.get_slide_context().end_shape(); } @@ -132,11 +131,11 @@ void draw_page::pptx_convert(oox::pptx_conversion_context & Context) _CP_LOG << L"[info][pptx] process page(slide) \"" << pageName /*L"" */<< L"\"" << std::endl; - Context.start_page(pageName, pageStyleName, layoutName,masterName); + Context.start_page(pageName, pageStyleName, layoutName, masterName); if (attlist_.draw_style_name_) { - style_instance * style_inst = Context.root()->odf_context().styleContainer().style_by_name(pageStyleName,style_family::DrawingPage,false); + style_instance * style_inst = Context.root()->odf_context().styleContainer().style_by_name(pageStyleName,style_family::DrawingPage, false); if ((style_inst) && (style_inst->content())) { @@ -307,11 +306,11 @@ void presentation_notes::pptx_convert_placeHolder(oox::pptx_conversion_context & std::wstring text_content_ = Context.get_text_context().end_object(); - if (text_content_.length()>0) + if (false == text_content_.empty()) { - Context.get_slide_context().set_property(_property(L"text-content",text_content_)); + Context.get_slide_context().set_property(_property(L"text-content", text_content_)); } - Context.get_slide_context().set_property(_property(L"no_rect",true)); + Context.get_slide_context().set_property(_property(L"no_rect", true)); Context.get_slide_context().end_shape(); } diff --git a/OdfFile/Reader/Format/odfcontext.cpp b/OdfFile/Reader/Format/odfcontext.cpp index 45cfde2b04..15c23001cc 100644 --- a/OdfFile/Reader/Format/odfcontext.cpp +++ b/OdfFile/Reader/Format/odfcontext.cpp @@ -32,14 +32,14 @@ #include "odfcontext.h" -namespace cpdoccore { +namespace cpdoccore { using namespace odf_types; - - std::string DecodeBase64(const std::wstring & value1) + + std::string DecodeBase64(const std::wstring& value1) { int nLength = 0; - unsigned char *pData = NULL; + unsigned char* pData = NULL; std::string result; std::string value(value1.begin(), value1.end()); @@ -48,641 +48,624 @@ namespace cpdoccore { if (pData) { result = std::string((char*)pData, nLength); - delete []pData; pData = NULL; + delete[]pData; pData = NULL; } return result; } -namespace odf_reader { + namespace odf_reader { -style_instance::style_instance( - styles_container *Container, - const std::wstring &Name, - const std::wstring &DisplayName, - style_family::type Type, - style_content *Content, - bool IsAutomatic, - bool IsDefault, - const std::wstring & ParentStyleName, - const std::wstring & NextStyleName, - const std::wstring & DataStyleName, - const std::wstring & PercentageDataStyleName, - const std::wstring & StyleClass, - _CP_OPT(std::wstring) ListStyleName, - _CP_OPT(int) ListLevel, - _CP_OPT(int) OutlineLevel - ) : - container_ (Container), - name_ (Name), - display_name_ (DisplayName), - style_type_ (Type), - content_ (Content), - is_automatic_ (IsAutomatic), - is_default_ (IsDefault), - next_name_ (NextStyleName), - style_class_ (StyleClass), - next_ (Container->style_by_name(NextStyleName, style_type_, false)), - data_style_name_(DataStyleName), - percentage_data_style_name_(PercentageDataStyleName), - list_style_name_(ListStyleName), - list_level_ (ListLevel), - outline_level_ (OutlineLevel) -{ - parent_name_ = ParentStyleName; - if (parent_name_ == L"Textformatvorlage")//http://ask.libreoffice.org/en/question/35136/textformatvorlage-style/ - { - parent_name_ = L"Standard"; - } - parent_ = Container->style_by_name(parent_name_, style_type_, false); -} - -style_instance * styles_container::hyperlink_style() -{ - if (hyperlink_style_pos_ > 0 && hyperlink_style_pos_ < (int)instances_.size()) - return instances_[hyperlink_style_pos_].get(); - else - return NULL; -} - -void styles_container::add_style( const std::wstring & Name, - const std::wstring & DisplayName, - style_content * Content, - bool IsAutomatic, - bool IsDefault, - const std::wstring & ParentStyleName_, - const std::wstring & NextStyleName, - const std::wstring & DataStyleName, - const std::wstring & PercentageDataStyleName, - const std::wstring & StyleClass, - _CP_OPT(std::wstring) ListStyleName, - _CP_OPT(int) ListLevel, - _CP_OPT(int) OutlineLevel) -{ - std::wstring ParentStyleName = ParentStyleName_; - - style_family::type Type = Content ? Content->style_family_.get_type() : style_family::None; - - if (Name == ParentStyleName) - { - ParentStyleName = L"";//иначе в коде возможно зацикливание. - } - style_instance_ptr newStyle = style_instance_ptr( new style_instance(this, Name, DisplayName, Type, Content, IsAutomatic, IsDefault, - ParentStyleName, NextStyleName, DataStyleName, PercentageDataStyleName, StyleClass, ListStyleName, ListLevel, OutlineLevel)); - - instances_.push_back(newStyle); - int pos = static_cast(instances_.size() - 1); - - if (!Name.empty()) - { - std::wstring n = Name + L":" + boost::lexical_cast( style_family(Type) ); - map_[n] = pos; - - // TODO: как правильно?? - std::wstring lName = XmlUtils::GetLower(Name); - //if ( boost::algorithm::contains(lName, L"internet_20_link") ) - if (lName == L"internet_20_link")///??????????????? - hyperlink_style_pos_ = pos; - } - - if (!DisplayName.empty()) - { - std::wstring n = DisplayName + L":" + boost::lexical_cast( style_family(Type) ); - map2_[n] = pos; - } - - if (IsDefault) - default_map_[Type] = pos; - -} - -const std::wstring & style_instance::name() const -{ - return name_; -} -const std::wstring & style_instance::display_name() const -{ - return display_name_; -} -style_family::type style_instance::type() const -{ - return style_type_; -} - -style_content * style_instance::content() const -{ - return content_; -} - -style_instance * style_instance::parent() const -{ - if (parent_) - return parent_; - else if (container_) - parent_ = container_->style_by_name(parent_name_, type(), false); - - return parent_; -} - -const std::wstring & style_instance::parent_name() const -{ - return parent_name_; -} - -style_instance * style_instance::next() const -{ - if (next_) - return next_; - else if (container_ && next_name_.empty() == false) - next_ = container_->style_by_name(next_name_, type(), false); - - return next_; -} - -const std::wstring & style_instance::next_name() const -{ - return next_name_; -} - -bool style_instance::is_automatic() const -{ - return is_automatic_; -} - -bool style_instance::is_default() const -{ - return is_default_; -} -const std::wstring & style_instance::percentage_data_style_name() const -{ - return percentage_data_style_name_; -} -const std::wstring & style_instance::data_style_name() const -{ - return data_style_name_; -} -_CP_OPT(std::wstring) style_instance::list_style_name() const -{ - return list_style_name_; -} -const std::wstring & style_instance::style_class() const -{ - return style_class_; -} -_CP_OPT(int) style_instance::list_level() const -{ - return list_level_; -} -_CP_OPT(int) style_instance::outline_level() const -{ - return outline_level_; -} - -style_instance * styles_container::style_by_name(const std::wstring & Name, style_family::type Type, bool object_in_styles) const -{ - std::wstring n = L""; - if (object_in_styles) n = L"common:"; - n = n + Name + L":" + boost::lexical_cast( style_family(Type) ); - - map_wstring_int_t::const_iterator res = map_.find(n); - - if (res != map_.end()) - { - int index = res->second; - return instances_[index].get(); - } - else if (object_in_styles) - { - //try automatic - n = Name + L":" + boost::lexical_cast( style_family(Type) ); - - map_wstring_int_t::const_iterator res = map_.find(n); - - if (res != map_.end()) + style_instance::style_instance( + styles_container* Container, + const std::wstring& Name, + const std::wstring& DisplayName, + style_family::type Type, + style_content* Content, + bool IsAutomatic, + bool IsDefault, + const std::wstring& ParentStyleName, + const std::wstring& NextStyleName, + const std::wstring& DataStyleName, + const std::wstring& PercentageDataStyleName, + const std::wstring& StyleClass, + _CP_OPT(std::wstring) ListStyleName, + _CP_OPT(int) ListLevel, + _CP_OPT(int) OutlineLevel + ) : + container_(Container), + name_(Name), + display_name_(DisplayName), + style_type_(Type), + content_(Content), + is_automatic_(IsAutomatic), + is_default_(IsDefault), + next_name_(NextStyleName), + style_class_(StyleClass), + next_(Container->style_by_name(NextStyleName, style_type_, false)), + data_style_name_(DataStyleName), + percentage_data_style_name_(PercentageDataStyleName), + list_style_name_(ListStyleName), + list_level_(ListLevel), + outline_level_(OutlineLevel) { - int index = res->second; - return instances_[index].get(); + parent_name_ = ParentStyleName; + if (parent_name_ == L"Textformatvorlage")//http://ask.libreoffice.org/en/question/35136/textformatvorlage-style/ + { + parent_name_ = L"Standard"; + } + parent_ = Container->style_by_name(parent_name_, style_type_, false); } - } - return NULL; -} -style_instance * styles_container::style_by_display_name(const std::wstring & Name, style_family::type Type, bool object_in_styles) const -{ - std::wstring n = L""; - if (object_in_styles) n = L"common:"; - n = n + Name + L":" + boost::lexical_cast( style_family(Type) ); - - map_wstring_int_t::const_iterator res = map2_.find(n); - - if (res != map2_.end()) - { - int index = res->second; - return instances_[index].get(); - } - else - return NULL; -} -void styles_container::add_master_page_name(const std::wstring & StyleName, const std::wstring & MasterPageName) -{ - master_page_name_[StyleName] = MasterPageName; -} -std::pair presentation_layouts_instance::add_or_find(const std::wstring & layout_name,const std::wstring & master_name) -{ - bool find = false; - size_t index =0; - - for (index = 0; index < content.size(); index++) - { - if (content[index].layout_name == layout_name && content[index].master_name == master_name) + style_instance* styles_container::hyperlink_style() { - find = true; - break; + if (hyperlink_style_pos_ > 0 && hyperlink_style_pos_ < (int)instances_.size()) + return instances_[hyperlink_style_pos_].get(); + else + return NULL; } - } - if (!find) - { - presentation_layouts_instance::_layout item; - item.layout_name = layout_name; - item.master_name = master_name; - item.Id = content.size() +1; - item.rId = std::wstring(L"lrId") + std::to_wstring(item.Id); - - content.push_back(item); - index = content.size()-1; - } - return std::pair(content[index].Id,content[index].rId); -} - -std::pair presentation_masters_instance::add_or_find(const std::wstring & master_name) -{ - bool find = false; - size_t index =0; - for (index = 0; index < content.size(); index++) - { - if (content[index].master_name == master_name) + void styles_container::add_style(const std::wstring& Name, + const std::wstring& DisplayName, + style_content* Content, + bool IsAutomatic, + bool IsDefault, + const std::wstring& ParentStyleName_, + const std::wstring& NextStyleName, + const std::wstring& DataStyleName, + const std::wstring& PercentageDataStyleName, + const std::wstring& StyleClass, + _CP_OPT(std::wstring) ListStyleName, + _CP_OPT(int) ListLevel, + _CP_OPT(int) OutlineLevel) { - find = true; - break; + std::wstring ParentStyleName = ParentStyleName_; + + style_family::type Type = Content ? Content->style_family_.get_type() : style_family::None; + + if (Name == ParentStyleName) + { + ParentStyleName = L"";//иначе в коде возможно зацикливание. + } + style_instance_ptr newStyle = style_instance_ptr(new style_instance(this, Name, DisplayName, Type, Content, IsAutomatic, IsDefault, + ParentStyleName, NextStyleName, DataStyleName, PercentageDataStyleName, StyleClass, ListStyleName, ListLevel, OutlineLevel)); + + instances_.push_back(newStyle); + int pos = static_cast(instances_.size() - 1); + + if (!Name.empty()) + { + std::wstring n = Name + L":" + boost::lexical_cast(style_family(Type)); + map_[n] = pos; + + // TODO: как правильно?? + std::wstring lName = XmlUtils::GetLower(Name); + //if ( boost::algorithm::contains(lName, L"internet_20_link") ) + if (lName == L"internet_20_link")///??????????????? + hyperlink_style_pos_ = pos; + } + + if (!DisplayName.empty()) + { + std::wstring n = DisplayName + L":" + boost::lexical_cast(style_family(Type)); + map2_[n] = pos; + } + + if (IsDefault) + default_map_[Type] = pos; + } - } - if (!find) - { - presentation_masters_instance::_master item; - item.master_name = master_name; - item.Id = content.size() +1; - item.rId = std::wstring(L"smId") + std::to_wstring(item.Id); - - content.push_back(item); - index = content.size()-1; - } - return std::pair(content[index].Id,content[index].rId); -} - -void presentation_masters_instance::add_layout_to(const std::wstring & master_name, presentation_layouts_instance::_layout & layout) -{ - bool find = false; - size_t index = 0; - for (index = 0; index < content.size(); index++) - { - if (content[index].master_name == master_name) + const std::wstring& style_instance::name() const { - find = true; - break; + return name_; } - } - if (find) - { - content[index].layouts.push_back(layout); + const std::wstring& style_instance::display_name() const + { + return display_name_; + } + style_family::type style_instance::type() const + { + return style_type_; + } + + style_content* style_instance::content() const + { + return content_; + } + + style_instance* style_instance::parent() const + { + if (parent_) + return parent_; + else if (container_) + parent_ = container_->style_by_name(parent_name_, type(), false); + + return parent_; + } + + const std::wstring& style_instance::parent_name() const + { + return parent_name_; + } + + style_instance* style_instance::next() const + { + if (next_) + return next_; + else if (container_ && next_name_.empty() == false) + next_ = container_->style_by_name(next_name_, type(), false); + + return next_; + } + + const std::wstring& style_instance::next_name() const + { + return next_name_; + } + + bool style_instance::is_automatic() const + { + return is_automatic_; + } + + bool style_instance::is_default() const + { + return is_default_; + } + const std::wstring& style_instance::percentage_data_style_name() const + { + return percentage_data_style_name_; + } + const std::wstring& style_instance::data_style_name() const + { + return data_style_name_; + } + _CP_OPT(std::wstring) style_instance::list_style_name() const + { + return list_style_name_; + } + const std::wstring& style_instance::style_class() const + { + return style_class_; + } + _CP_OPT(int) style_instance::list_level() const + { + return list_level_; + } + _CP_OPT(int) style_instance::outline_level() const + { + return outline_level_; + } + + style_instance* styles_container::style_by_name(const std::wstring& Name, style_family::type Type, bool object_in_styles) const + { + std::wstring n = L""; + if (object_in_styles) n = L"common:"; + n = n + Name + L":" + boost::lexical_cast(style_family(Type)); + + map_wstring_int_t::const_iterator res = map_.find(n); + + if (res != map_.end()) + { + int index = res->second; + return instances_[index].get(); + } + else if (object_in_styles) + { + //try automatic + n = Name + L":" + boost::lexical_cast(style_family(Type)); + + map_wstring_int_t::const_iterator res = map_.find(n); + + if (res != map_.end()) + { + int index = res->second; + return instances_[index].get(); + } + } + return NULL; + } + style_instance* styles_container::style_by_display_name(const std::wstring& Name, style_family::type Type, bool object_in_styles) const + { + std::wstring n = L""; + if (object_in_styles) n = L"common:"; + n = n + Name + L":" + boost::lexical_cast(style_family(Type)); + + map_wstring_int_t::const_iterator res = map2_.find(n); + + if (res != map2_.end()) + { + int index = res->second; + return instances_[index].get(); + } + else + return NULL; + } + void styles_container::add_master_page_name(const std::wstring& StyleName, const std::wstring& MasterPageName) + { + master_page_name_[StyleName] = MasterPageName; + } + + std::pair presentation_layouts_instance::add_or_find(const std::wstring& layout_name, const std::wstring& master_name) + { + std::map::iterator pFind = mapUsed.find(master_name + layout_name); + + if (pFind == mapUsed.end()) + { + presentation_layouts_instance::_layout item; + item.layout_name = layout_name; + item.master_name = master_name; + item.Id = content.size() + 1; + item.rId = std::wstring(L"lrId") + std::to_wstring(item.Id); + + content.push_back(item); + + mapUsed.insert(std::make_pair(master_name + layout_name, content.size() - 1)); + return std::pair(item.Id, item.rId); + } + else + { + return std::pair(content[pFind->second].Id, content[pFind->second].rId); + } + } + + std::pair presentation_masters_instance::add_or_find(const std::wstring& master_name) + { + std::map::iterator pFind = mapUsed.find(master_name); + + if (pFind == mapUsed.end()) + { + presentation_masters_instance::_master item; + item.master_name = master_name; + item.Id = content.size() + 1; + item.rId = std::wstring(L"smId") + std::to_wstring(item.Id); + + content.push_back(item); + + mapUsed.insert(std::make_pair(master_name, content.size() - 1)); + return std::pair(item.Id, item.rId); + } + else + { + return std::pair(content[pFind->second].Id, content[pFind->second].rId); + } + } + + void presentation_masters_instance::add_layout_to(const std::wstring& master_name, presentation_layouts_instance::_layout& layout) + { + std::map::iterator pFind = mapUsed.find(master_name); + + if (pFind != mapUsed.end()) + { + content[pFind->second].layouts.push_back(layout); + + } + } + + const _CP_OPT(std::wstring) styles_container::master_page_name_by_name(const std::wstring& StyleName) const + { + _CP_OPT(std::wstring) master_page; + + map_wstring_wstring::const_iterator res = master_page_name_.find(StyleName); + if (res != master_page_name_.end()) + master_page = res->second; + return master_page; + } + + style_instance* styles_container::style_default_by_type(style_family::type Type) const + { + map_style_family_int::const_iterator res = default_map_.find(Type); + if (res != default_map_.end()) + return instances_[res->second].get(); + else + return NULL; + } + + page_layout_instance::page_layout_instance(const style_page_layout* StylePageLayout) : style_page_layout_(StylePageLayout) + { + } + + const std::wstring& page_layout_instance::name() const + { + return style_page_layout_->style_name_; + } + + style_page_layout_properties* page_layout_instance::properties() const + { + return dynamic_cast(style_page_layout_->style_page_layout_properties_.get()); + } + + void page_layout_instance::xlsx_serialize(std::wostream& strm, oox::xlsx_conversion_context& Context) + { + const style_header_style* headerStyle = dynamic_cast(style_page_layout_->style_header_style_.get()); + const style_footer_style* footerStyle = dynamic_cast(style_page_layout_->style_footer_style_.get()); + + style_header_footer_properties* headerProp = headerStyle ? dynamic_cast(headerStyle->style_header_footer_properties_.get()) : NULL; + style_header_footer_properties* footerProp = footerStyle ? dynamic_cast(footerStyle->style_header_footer_properties_.get()) : NULL; + + if (headerProp) + { + const style_header_footer_properties_attlist& attr = headerProp->style_header_footer_properties_attlist_; + _CP_OPT(double) header; + + if (attr.fo_min_height_) header = attr.fo_min_height_->get_value_unit(length::pt); + else if (attr.svg_height_) header = attr.svg_height_->get_value_unit(length::pt); + + Context.get_table_context().set_header_page(header); + } + + if (footerProp) + { + const style_header_footer_properties_attlist& attr = footerProp->style_header_footer_properties_attlist_; + _CP_OPT(double) footer; + + if (attr.fo_min_height_) footer = attr.fo_min_height_->get_value_unit(length::pt); + else if (attr.svg_height_) footer = attr.svg_height_->get_value_unit(length::pt); + + Context.get_table_context().set_footer_page(footer); + } + + style_page_layout_properties* props = properties(); + if (props) + props->xlsx_serialize(strm, Context); + } + + void page_layout_instance::docx_serialize(std::wostream& strm, oox::docx_conversion_context& Context) + { + const style_header_style* headerStyle = dynamic_cast(style_page_layout_->style_header_style_.get()); + const style_footer_style* footerStyle = dynamic_cast(style_page_layout_->style_footer_style_.get()); + + style_header_footer_properties* headerProp = headerStyle ? dynamic_cast(headerStyle->style_header_footer_properties_.get()) : NULL; + style_header_footer_properties* footerProp = footerStyle ? dynamic_cast(footerStyle->style_header_footer_properties_.get()) : NULL; + + Context.get_header_footer_context().reset(); + + if (headerProp) + { + const style_header_footer_properties_attlist& attr = headerProp->style_header_footer_properties_attlist_; + _CP_OPT(length) top = attr.fo_min_height_ ? attr.fo_min_height_ : attr.svg_height_; + Context.get_header_footer_context().set_header(top); + } + + if (footerProp) + { + const style_header_footer_properties_attlist& attr = footerProp->style_header_footer_properties_attlist_; + _CP_OPT(length) bottom = attr.fo_min_height_ ? attr.fo_min_height_ : attr.svg_height_; + Context.get_header_footer_context().set_footer(bottom); + } + + if (style_page_layout_->style_page_usage_.get_type() == page_usage::Mirrored) + { + Context.set_settings_property(odf_reader::_property(L"mirrorMargins", true)); + } + + style_page_layout_properties* props = properties(); + if (props) + props->docx_serialize(strm, Context); + } + void page_layout_instance::pptx_serialize(std::wostream& strm, oox::pptx_conversion_context& Context) + { + style_page_layout_properties* props = properties(); + if (props) + props->pptx_serialize(strm, Context); + } + + void page_layout_container::add_page_layout(const style_page_layout* StylePageLayout) + { + page_layout_instance_ptr instance = page_layout_instance_ptr(new page_layout_instance(StylePageLayout)); + instances_.push_back(instance); + const int pos = static_cast(instances_.size() - 1); + + page_layout_names_[instance->name()] = pos; + + } + + void page_layout_container::add_master_page(const std::wstring& StyleName, const std::wstring& PageLayoutName, style_master_page* MasterPage) + { + master_page_names_array_.push_back(StyleName); + master_page_names_[StyleName] = PageLayoutName; + + master_pages_.push_back(MasterPage); + const int pos = static_cast(master_pages_.size() - 1); + master_page_names_2_[StyleName] = pos; + } + + void page_layout_container::add_presentation_page_layout(const std::wstring& StyleName, style_presentation_page_layout* StylePageLayout) + { + presentation_page_layouts_.push_back(StylePageLayout); + + const int pos = static_cast(presentation_page_layouts_.size() - 1); + presentation_page_layout_names_[StyleName] = pos; + } + + + const std::wstring page_layout_container::page_layout_name_by_style(const std::wstring& StyleName) const + { + if (master_page_names_.count(StyleName) > 0) + return master_page_names_.at(StyleName); + return L""; + } + + const page_layout_instance* page_layout_container::page_layout_by_style(const std::wstring& StyleName) const + { + if (master_page_names_.count(StyleName) > 0) + if (page_layout_names_.count(master_page_names_.at(StyleName))) + return instances_[page_layout_names_.at(master_page_names_.at(StyleName))].get(); + return NULL; + } + + page_layout_instance* page_layout_container::page_layout_by_name(const std::wstring& Name) const + { + if (page_layout_names_.count(Name)) + return instances_[page_layout_names_.at(Name)].get(); + return NULL; + } + + const page_layout_instance* page_layout_container::page_layout_first() const + { + if (master_page_names_array_.empty()) + return NULL; + + return page_layout_by_style(master_page_names_array_[0]); + } + bool page_layout_container::compare_page_properties(const std::wstring& master1, const std::wstring& master2) + { + const page_layout_instance* page_layout1 = page_layout_by_style(master1); + const page_layout_instance* page_layout2 = page_layout_by_style(master2); + + if (!page_layout1 || !page_layout2) return true; + if (!page_layout1->style_page_layout_ || !page_layout1->style_page_layout_) return true; + + style_page_layout_properties* props1 = dynamic_cast(page_layout1->style_page_layout_->style_page_layout_properties_.get()); + style_page_layout_properties* props2 = dynamic_cast(page_layout2->style_page_layout_->style_page_layout_properties_.get()); + + if (!props1 || !props2) return true; + + if (props1 == props2) return true; + + return props1->attlist_.compare(props2->attlist_); + } + + style_presentation_page_layout* page_layout_container::presentation_page_layout_by_name(const std::wstring& Name) + { + style_presentation_page_layout* res = NULL; + + if (presentation_page_layout_names_.count(Name)) + { + int ind = presentation_page_layout_names_.at(Name); + res = presentation_page_layouts_[ind]; + } + + return res; + } + style_master_page* page_layout_container::master_page_by_name(const std::wstring& Name) + { + style_master_page* res = NULL; + + if (master_page_names_2_.count(Name)) + res = master_pages_[master_page_names_2_.at(Name)]; + + return res; + } + + font_instance::font_instance(const std::wstring& StyleName, + const std::wstring& Name, + const std::wstring& Charset, + const std::wstring& Family, + const std::wstring& Pitch, + const std::wstring& AltName) : style_name_(StyleName), name_(Name), charset_(Charset), family_(Family), pitch_(Pitch), alt_name_(AltName) + {} + + const std::wstring& font_instance::style_name() const + { + return style_name_; + } + + const std::wstring& font_instance::name() const + { + return name_; + } + + const std::wstring& font_instance::charset() const + { + return charset_; + } + + const std::wstring& font_instance::family() const + { + return family_; + } + + const std::wstring& font_instance::pitch() const + { + return pitch_; + } + + const std::wstring& font_instance::alt_name() const + { + return alt_name_; + } + + font_instance* fonts_container::font_by_style_name(const std::wstring& StyleName) + { + if (font_style_names_.count(StyleName) > 0) + return instances_[font_style_names_.at(StyleName)].get(); + return NULL; + } + + font_instance* fonts_container::font_by_name(const std::wstring& Name) + { + if (font_names_.count(Name) > 0) + return instances_[font_names_.at(Name)].get(); + return NULL; + } + + void fonts_container::add_font(font_instance_ptr FontInstance) + { + instances_.push_back(FontInstance); + if (FontInstance) + { + font_style_names_[FontInstance->style_name()] = static_cast(instances_.size() - 1); + font_names_[FontInstance->name()] = static_cast(instances_.size() - 1); + } + } + + void list_style_container::add_list_style(text_list_style* textListStyle) + { + if (!textListStyle) return; + + instances_.push_back(list_style_instance_ptr(new list_style_instance(textListStyle))); + list_style_names_[textListStyle->attr_.style_name_] = static_cast(instances_.size() - 1); + } + + void list_style_container::add_list_style(text_list_style* textListStyle, const std::wstring& NewName) + { + if (!textListStyle) return; + + instances_.push_back(list_style_instance_ptr(new list_style_instance(textListStyle, NewName))); + list_style_names_[NewName] = static_cast(instances_.size() - 1); + } + void list_style_container::add_outline_style(text_outline_style* textOutlineStyle) + { + if (!textOutlineStyle) return; + + outline_ = textOutlineStyle; + outline_id_ = instances_.size(); + } + text_list_style* list_style_container::list_style_by_name(const std::wstring& Name) + { + if (list_style_names_.count(Name) > 0) + return instances_[list_style_names_.at(Name)]->get_text_list_style(); + return NULL; + } + + text_outline_style* list_style_container::outline_style() + { + return outline_; + } + int list_style_container::id_outline() + { + return outline_id_ + 1; + } + + int list_style_container::id_by_name(const std::wstring& Name) + { + if (list_style_names_.count(Name) > 0) + return list_style_names_.at(Name) + 1; + else + return 0; + } + const text_notes_configuration* notes_configuration::getConfiguration(odf_types::noteclass::type noteType) const + { + if (type_to_name_.count(noteType)) + return type_to_name_.at(noteType); + else + return NULL; + } + + void notes_configuration::add(odf_types::noteclass::type noteType, const text_notes_configuration* conf) + { + type_to_name_[noteType] = conf; + } + } } - -const _CP_OPT(std::wstring) styles_container::master_page_name_by_name(const std::wstring & StyleName) const -{ - _CP_OPT(std::wstring) master_page; - - map_wstring_wstring::const_iterator res = master_page_name_.find(StyleName); - if (res != master_page_name_.end()) - master_page = res->second; - return master_page; -} - -style_instance * styles_container::style_default_by_type(style_family::type Type) const -{ - map_style_family_int::const_iterator res = default_map_.find(Type); - if (res != default_map_.end()) - return instances_[res->second].get(); - else - return NULL; -} - -page_layout_instance::page_layout_instance(const style_page_layout * StylePageLayout) : style_page_layout_(StylePageLayout) -{ -} - -const std::wstring & page_layout_instance::name() const -{ - return style_page_layout_->style_name_; -} - -style_page_layout_properties * page_layout_instance::properties() const -{ - return dynamic_cast(style_page_layout_->style_page_layout_properties_.get()); -} - -void page_layout_instance::xlsx_serialize(std::wostream & strm, oox::xlsx_conversion_context & Context) -{ - const style_header_style * headerStyle = dynamic_cast(style_page_layout_->style_header_style_.get()); - const style_footer_style * footerStyle = dynamic_cast(style_page_layout_->style_footer_style_.get()); - - style_header_footer_properties * headerProp = headerStyle ? dynamic_cast(headerStyle->style_header_footer_properties_.get()) : NULL; - style_header_footer_properties * footerProp = footerStyle ? dynamic_cast(footerStyle->style_header_footer_properties_.get()) : NULL; - - if (headerProp) - { - const style_header_footer_properties_attlist & attr = headerProp->style_header_footer_properties_attlist_; - _CP_OPT(double) header; - - if (attr.fo_min_height_) header = attr.fo_min_height_->get_value_unit(length::pt); - else if (attr.svg_height_) header = attr.svg_height_->get_value_unit(length::pt); - - Context.get_table_context().set_header_page(header); - } - - if (footerProp) - { - const style_header_footer_properties_attlist & attr = footerProp->style_header_footer_properties_attlist_; - _CP_OPT(double) footer; - - if (attr.fo_min_height_) footer = attr.fo_min_height_->get_value_unit(length::pt); - else if (attr.svg_height_) footer = attr.svg_height_->get_value_unit(length::pt); - - Context.get_table_context().set_footer_page(footer); - } - - style_page_layout_properties * props = properties(); - if (props) - props->xlsx_serialize(strm, Context); -} - -void page_layout_instance::docx_serialize(std::wostream & strm, oox::docx_conversion_context & Context) -{ - const style_header_style * headerStyle = dynamic_cast(style_page_layout_->style_header_style_.get()); - const style_footer_style * footerStyle = dynamic_cast(style_page_layout_->style_footer_style_.get()); - - style_header_footer_properties * headerProp = headerStyle ? dynamic_cast(headerStyle->style_header_footer_properties_.get()) : NULL; - style_header_footer_properties * footerProp = footerStyle ? dynamic_cast(footerStyle->style_header_footer_properties_.get()) : NULL; - - Context.get_header_footer_context().reset(); - - if (headerProp) - { - const style_header_footer_properties_attlist & attr = headerProp->style_header_footer_properties_attlist_; - _CP_OPT(length) top = attr.fo_min_height_ ? attr.fo_min_height_ : attr.svg_height_; - Context.get_header_footer_context().set_header(top); - } - - if (footerProp) - { - const style_header_footer_properties_attlist & attr = footerProp->style_header_footer_properties_attlist_; - _CP_OPT(length) bottom = attr.fo_min_height_ ? attr.fo_min_height_ : attr.svg_height_; - Context.get_header_footer_context().set_footer(bottom); - } - - if ( style_page_layout_->style_page_usage_.get_type() == page_usage::Mirrored ) - { - Context.set_settings_property(odf_reader::_property(L"mirrorMargins",true)); - } - - style_page_layout_properties * props = properties(); - if (props) - props->docx_serialize(strm, Context); -} -void page_layout_instance::pptx_serialize(std::wostream & strm, oox::pptx_conversion_context & Context) -{ - style_page_layout_properties * props = properties(); - if (props) - props->pptx_serialize(strm, Context); -} - -void page_layout_container::add_page_layout(const style_page_layout * StylePageLayout) -{ - page_layout_instance_ptr instance = page_layout_instance_ptr( new page_layout_instance(StylePageLayout) ); - instances_.push_back(instance); - const int pos = static_cast(instances_.size() - 1); - - page_layout_names_[ instance->name() ] = pos; - -} - -void page_layout_container::add_master_page(const std::wstring & StyleName, const std::wstring & PageLayoutName, style_master_page* MasterPage) -{ - master_page_names_array_.push_back(StyleName); - master_page_names_[StyleName] = PageLayoutName; - - master_pages_.push_back(MasterPage); - const int pos = static_cast(master_pages_.size() - 1); - master_page_names_2_[StyleName] = pos; -} - -void page_layout_container::add_presentation_page_layout(const std::wstring & StyleName, style_presentation_page_layout* StylePageLayout) -{ - presentation_page_layouts_.push_back(StylePageLayout); - - const int pos = static_cast(presentation_page_layouts_.size() - 1); - presentation_page_layout_names_[ StyleName ] = pos; - -} - - -const std::wstring page_layout_container::page_layout_name_by_style(const std::wstring & StyleName) const -{ - if (master_page_names_.count(StyleName) > 0) - return master_page_names_.at(StyleName); - return L""; -} - -const page_layout_instance * page_layout_container::page_layout_by_style(const std::wstring & StyleName) const -{ - if (master_page_names_.count(StyleName) > 0) - if (page_layout_names_.count(master_page_names_.at(StyleName)) ) - return instances_[ page_layout_names_.at( master_page_names_.at(StyleName) ) ].get(); - return NULL; -} - -page_layout_instance * page_layout_container::page_layout_by_name(const std::wstring & Name) const -{ - if (page_layout_names_.count(Name)) - return instances_[ page_layout_names_.at( Name ) ].get(); - return NULL; -} - -const page_layout_instance * page_layout_container::page_layout_first() const -{ - if (master_page_names_array_.empty()) - return NULL; - - return page_layout_by_style(master_page_names_array_[0]); -} -bool page_layout_container::compare_page_properties(const std::wstring & master1, const std::wstring & master2) -{ - const page_layout_instance *page_layout1 = page_layout_by_style(master1); - const page_layout_instance *page_layout2 = page_layout_by_style(master2); - - if (!page_layout1 || !page_layout2) return true; - if (!page_layout1->style_page_layout_ || !page_layout1->style_page_layout_) return true; - - style_page_layout_properties *props1 = dynamic_cast(page_layout1->style_page_layout_->style_page_layout_properties_.get()); - style_page_layout_properties *props2 = dynamic_cast(page_layout2->style_page_layout_->style_page_layout_properties_.get()); - - if (!props1 || !props2) return true; - - if (props1 == props2) return true; - - return props1->attlist_.compare(props2->attlist_); -} - -style_presentation_page_layout * page_layout_container::presentation_page_layout_by_name(const std::wstring & Name) -{ - style_presentation_page_layout * res = NULL; - - if (presentation_page_layout_names_.count(Name)) - { - int ind = presentation_page_layout_names_.at( Name ) ; - res = presentation_page_layouts_[ind]; - } - - return res; -} -style_master_page * page_layout_container::master_page_by_name(const std::wstring & Name) -{ - style_master_page * res = NULL; - - if (master_page_names_2_.count(Name)) - res = master_pages_[ master_page_names_2_.at( Name ) ]; - - return res; -} - -font_instance::font_instance( const std::wstring & StyleName, - const std::wstring & Name, - const std::wstring & Charset, - const std::wstring & Family, - const std::wstring & Pitch, - const std::wstring & AltName) : style_name_(StyleName), name_(Name), charset_(Charset), family_(Family), pitch_(Pitch), alt_name_(AltName) -{} - -const std::wstring & font_instance::style_name() const -{ - return style_name_; -} - -const std::wstring & font_instance::name() const -{ - return name_; -} - -const std::wstring & font_instance::charset() const -{ - return charset_; -} - -const std::wstring & font_instance::family() const -{ - return family_; -} - -const std::wstring & font_instance::pitch() const -{ - return pitch_; -} - -const std::wstring & font_instance::alt_name() const -{ - return alt_name_; -} - -font_instance * fonts_container::font_by_style_name(const std::wstring & StyleName) -{ - if (font_style_names_.count(StyleName) > 0) - return instances_[font_style_names_.at(StyleName)].get(); - return NULL; -} - -font_instance * fonts_container::font_by_name(const std::wstring & Name) -{ - if (font_names_.count(Name) > 0) - return instances_[font_names_.at(Name)].get(); - return NULL; -} - -void fonts_container::add_font( font_instance_ptr FontInstance ) -{ - instances_.push_back(FontInstance); - if (FontInstance) - { - font_style_names_[FontInstance->style_name()] = static_cast(instances_.size() - 1); - font_names_[FontInstance->name()] = static_cast(instances_.size() - 1); - } -} - -void list_style_container::add_list_style(text_list_style * textListStyle) -{ - if (!textListStyle) return; - - instances_.push_back( list_style_instance_ptr(new list_style_instance(textListStyle)) ); - list_style_names_[ textListStyle->attr_.style_name_ ] = static_cast(instances_.size() - 1); -} - -void list_style_container::add_list_style(text_list_style * textListStyle, const std::wstring & NewName) -{ - if (!textListStyle) return; - - instances_.push_back( list_style_instance_ptr(new list_style_instance(textListStyle, NewName)) ); - list_style_names_[NewName] = static_cast(instances_.size() - 1); -} -void list_style_container::add_outline_style(text_outline_style *textOutlineStyle) -{ - if (!textOutlineStyle) return; - - outline_ = textOutlineStyle; - outline_id_ = instances_.size(); -} -text_list_style * list_style_container::list_style_by_name(const std::wstring & Name) -{ - if (list_style_names_.count(Name) > 0) - return instances_[list_style_names_.at(Name)]->get_text_list_style(); - return NULL; -} - -text_outline_style * list_style_container::outline_style() -{ - return outline_; -} -int list_style_container::id_outline() -{ - return outline_id_ + 1; -} - -int list_style_container::id_by_name(const std::wstring & Name) -{ - if (list_style_names_.count(Name) > 0) - return list_style_names_.at(Name) + 1; - else - return 0; -} -const text_notes_configuration * notes_configuration::getConfiguration(odf_types::noteclass::type noteType) const -{ - if (type_to_name_.count(noteType)) - return type_to_name_.at(noteType); - else - return NULL; -} - -void notes_configuration::add(odf_types::noteclass::type noteType, const text_notes_configuration * conf) -{ - type_to_name_[noteType] = conf; -} - -} -} diff --git a/OdfFile/Reader/Format/odfcontext.h b/OdfFile/Reader/Format/odfcontext.h index 82e6a55c65..751cdba747 100644 --- a/OdfFile/Reader/Format/odfcontext.h +++ b/OdfFile/Reader/Format/odfcontext.h @@ -131,6 +131,8 @@ public: }; std::vector<_layout> content; + std::map mapUsed; + std::pair add_or_find(const std::wstring & layout_name,const std::wstring & master_name); }; class presentation_masters_instance @@ -145,6 +147,7 @@ public: std::vector layouts; }; std::vector<_master> content; + std::map mapUsed; void add_layout_to(const std::wstring & master_name,presentation_layouts_instance::_layout & layout); @@ -238,9 +241,9 @@ class page_layout_container public: typedef std::vector instances_array; - void add_page_layout(const style_page_layout * StylePageLayout); - void add_master_page(const std::wstring & StyleName, const std::wstring & PageLayoutName,style_master_page* MasterPage); - void add_presentation_page_layout(const std::wstring & StyleName, style_presentation_page_layout* StylePageLayout); + void add_page_layout(const style_page_layout *stylePageLayout); + void add_master_page(const std::wstring & StyleName, const std::wstring & PageLayoutName, style_master_page* MasterPage); + void add_presentation_page_layout(const std::wstring & styleName, style_presentation_page_layout *stylePageLayout); const std::wstring page_layout_name_by_style(const std::wstring & StyleName) const; @@ -265,13 +268,13 @@ private: instances_array instances_; std::vector master_pages_; - boost::unordered_map page_layout_names_; + std::map page_layout_names_; std::vector master_page_names_array_; - boost::unordered_map master_page_names_; + std::map master_page_names_; - boost::unordered_map master_page_names_2_; + std::map master_page_names_2_; - boost::unordered_map presentation_page_layout_names_; + std::map presentation_page_layout_names_; odf_reader::text_linenumbering_configuration *linenumberingcConfiguration = NULL; }; diff --git a/OdfFile/Reader/Format/style_presentation.cpp b/OdfFile/Reader/Format/style_presentation.cpp index af38c24d12..805c6f1453 100644 --- a/OdfFile/Reader/Format/style_presentation.cpp +++ b/OdfFile/Reader/Format/style_presentation.cpp @@ -31,58 +31,74 @@ */ #include "style_presentation.h" +#include "odfcontext.h" +#include "odf_document.h" #include #include -namespace cpdoccore { +#include "calcs_styles.h" + +namespace cpdoccore { using namespace odf_types; -namespace odf_reader { + namespace odf_reader { -const wchar_t * presentation_placeholder::ns = L"presentation"; -const wchar_t * presentation_placeholder::name = L"placeholder"; + const wchar_t* presentation_placeholder::ns = L"presentation"; + const wchar_t* presentation_placeholder::name = L"placeholder"; -void presentation_placeholder::add_attributes( const xml::attributes_wc_ptr & Attributes ) -{ - CP_APPLY_ATTR(L"presentation:object", presentation_object_); - - CP_APPLY_ATTR(L"svg:height", svg_height_); - CP_APPLY_ATTR(L"svg:width", svg_width_); - CP_APPLY_ATTR(L"svg:x", svg_x_); - CP_APPLY_ATTR(L"svg:y", svg_y_); + void presentation_placeholder::add_attributes(const xml::attributes_wc_ptr& Attributes) + { + CP_APPLY_ATTR(L"presentation:object", presentation_object_); -} + CP_APPLY_ATTR(L"svg:height", svg_height_); + CP_APPLY_ATTR(L"svg:width", svg_width_); + CP_APPLY_ATTR(L"svg:x", svg_x_); + CP_APPLY_ATTR(L"svg:y", svg_y_); -void presentation_placeholder::add_child_element( xml::sax * Reader, const std::wstring & Ns, const std::wstring & Name) -{ - CP_NOT_APPLICABLE_ELM(); -} + CP_APPLY_ATTR(L"draw:text-style-name", text_style_name_); + } -void presentation_placeholder::pptx_convert(oox::pptx_conversion_context & Context) -{ - double cx = svg_width_.get_value_or(length(0)).get_value_unit(length::pt); - double cy = svg_height_.get_value_or(length(0)).get_value_unit(length::pt); + void presentation_placeholder::add_child_element(xml::sax* Reader, const std::wstring& Ns, const std::wstring& Name) + { + CP_NOT_APPLICABLE_ELM(); + } - //пока не понятно что значит отрицательная ширина ... - cx = fabs(cx); - cy = fabs(cy); - - double x = svg_x_.get_value_or(length(0)).get_value_unit(length::pt); - double y = svg_y_.get_value_or(length(0)).get_value_unit(length::pt); + void presentation_placeholder::pptx_convert(oox::pptx_conversion_context& Context) + { + double cx = svg_width_.get_value_or(length(0)).get_value_unit(length::pt); + double cy = svg_height_.get_value_or(length(0)).get_value_unit(length::pt); - Context.get_slide_context().start_shape(2);//rect - Context.get_slide_context().set_name(L"place_holder"); + //пока не понятно что значит отрицательная ширина ... + cx = fabs(cx); + cy = fabs(cy); - Context.get_slide_context().set_rect(cx,cy,x,y); - if (presentation_object_) - { - Context.get_slide_context().set_placeHolder_type(presentation_object_->get_type_ms()); - } + double x = svg_x_.get_value_or(length(0)).get_value_unit(length::pt); + double y = svg_y_.get_value_or(length(0)).get_value_unit(length::pt); - Context.get_slide_context().end_shape(); -} + Context.get_slide_context().start_shape(2);//rect + Context.get_slide_context().set_name(L"place_holder"); + + if (text_style_name_ && !text_style_name_->empty()) + { + Context.get_text_context().start_base_style(*text_style_name_, odf_types::style_family::Paragraph); + } + Context.get_slide_context().set_rect(cx, cy, x, y); + if (presentation_object_) + { + Context.get_slide_context().set_placeHolder_type(presentation_object_->get_type_ms()); + Context.get_slide_context().set_property(_property(L"no_rect", true)); + } + std::wstring text_content_ = Context.get_text_context().end_object(); + + if (!text_content_.empty()) + { + Context.get_slide_context().set_property(_property(L"text-content", text_content_)); + } + Context.get_text_context().end_base_style(); + Context.get_slide_context().end_shape(); + } //------------------------------------------------------------------------------------------------- const wchar_t * presentation_sound::ns = L"presentation"; const wchar_t * presentation_sound::name = L"sound"; diff --git a/OdfFile/Reader/Format/style_presentation.h b/OdfFile/Reader/Format/style_presentation.h index 302ce4271a..c603cbde6f 100644 --- a/OdfFile/Reader/Format/style_presentation.h +++ b/OdfFile/Reader/Format/style_presentation.h @@ -68,6 +68,7 @@ public: _CP_OPT(odf_types::presentation_class) presentation_object_; + _CP_OPT(std::wstring) text_style_name_; }; CP_REGISTER_OFFICE_ELEMENT2(presentation_placeholder); diff --git a/OdfFile/Writer/Converter/ConvertDrawing.cpp b/OdfFile/Writer/Converter/ConvertDrawing.cpp index 361d01dd8b..c382290986 100644 --- a/OdfFile/Writer/Converter/ConvertDrawing.cpp +++ b/OdfFile/Writer/Converter/ConvertDrawing.cpp @@ -2103,6 +2103,12 @@ void OoxConverter::convert(PPTX::Logic::Paragraph *oox_paragraph, PPTX::Logic::T if (odf_context()->drawing_context()->is_wordart()) odf_context()->drawing_context()->set_paragraph_properties(paragraph_properties); + + if (styled && odf_context()->drawing_context()->is_placeholder()) + { + odf_writer::odf_style_state_ptr state = odf_context()->text_context()->get_styles_context()->last_state(odf_types::style_family::Paragraph); + odf_context()->drawing_context()->set_placeholder_style(state->get_name()); + } } std::vector::iterator runIt = std::find_if_not(oox_paragraph->RunElems.begin(), oox_paragraph->RunElems.end(), diff --git a/OdfFile/Writer/Converter/PptxConverter.cpp b/OdfFile/Writer/Converter/PptxConverter.cpp index 41a1fdaedc..f600b8b7b3 100644 --- a/OdfFile/Writer/Converter/PptxConverter.cpp +++ b/OdfFile/Writer/Converter/PptxConverter.cpp @@ -216,6 +216,7 @@ bool PptxConverter::convertDocument() //convert_meta(app_ptr.GetPointer(), core_ptr.GetPointer()); -> привести к OOX::... + convert_masters_and_layouts(); convert_slides(); //удалим уже ненужный документ pptx @@ -1211,7 +1212,6 @@ std::wstring PptxConverter::convert_animation_scale_values(int x, int y) return ss.str(); } - std::wstring PptxConverter::get_page_name(PPTX::Logic::CSld* oox_slide, _typePages type) { if (!oox_slide) @@ -1251,6 +1251,38 @@ void PptxConverter::fill_in_deferred_hyperlinks() } } + +void PptxConverter::convert_masters_and_layouts() +{ + for (size_t iMaster = 0; iMaster < presentation->sldMasterIdLst.size(); ++iMaster) + { + smart_ptr slideMaster = ((*presentation)[presentation->sldMasterIdLst[iMaster].rid.get()]).smart_dynamic_cast(); + + if (slideMaster.IsInit() == false) + continue; + + for (size_t iLayout = 0; iLayout < slideMaster->sldLayoutIdLst.size(); ++iLayout) + { + std::wstring rId = slideMaster->sldLayoutIdLst[iLayout].rid.get(); + smart_ptr slideLayout = ((*slideMaster)[rId]).smart_dynamic_cast(); + + if (false == slideLayout.IsInit()) continue; + + std::map::iterator pFind = m_mapLayouts.find(slideLayout->m_sOutputFilename); + if (pFind == m_mapLayouts.end()) + { + odp_context->start_layout_slide(); + convert_layout(&slideLayout->cSld); + odp_context->end_layout_slide(); + + std::wstring layout_style_name = odp_context->page_layout_context()->get_local_styles_context()->last_state(odf_types::style_family::PresentationPageLayout)->get_name(); + + m_mapLayouts.insert(std::make_pair(slideLayout->m_sOutputFilename, layout_style_name)); + } + } + } +} + void PptxConverter::convert_slides() { for (size_t i = 0; i < presentation->sldIdLst.size(); ++i) @@ -1339,7 +1371,7 @@ void PptxConverter::convert_slides() } pFind = m_mapLayouts.find(slide->Layout->m_sOutputFilename); if (pFind == m_mapLayouts.end()) - { + {//сюда уже не попадет - выше odp_context->start_layout_slide(); convert_layout(&slide->Layout->cSld); odp_context->end_layout_slide(); @@ -2666,7 +2698,7 @@ void PptxConverter::convert_layout(PPTX::Logic::CSld *oox_slide) odf_writer::office_element_ptr elm; create_element(L"presentation", L"placeholder", elm, odp_context); - odf_context()->drawing_context()->start_drawing(); + odf_context()->drawing_context()->start_drawing(); odf_context()->drawing_context()->start_element(elm); odf_context()->drawing_context()->set_placeholder_type(type); @@ -2675,6 +2707,7 @@ void PptxConverter::convert_layout(PPTX::Logic::CSld *oox_slide) odf_context()->drawing_context()->set_placeholder_id(*pShape->nvSpPr.nvPr.ph->idx); OoxConverter::convert(pShape->spPr.xfrm.GetPointer()); + OoxConverter::convert(pShape->txBody.GetPointer()); odf_context()->drawing_context()->end_element(); odf_context()->drawing_context()->end_drawing(); diff --git a/OdfFile/Writer/Converter/PptxConverter.h b/OdfFile/Writer/Converter/PptxConverter.h index adac57d9a0..0a2ee9c93a 100644 --- a/OdfFile/Writer/Converter/PptxConverter.h +++ b/OdfFile/Writer/Converter/PptxConverter.h @@ -228,11 +228,12 @@ private: std::wstring interactive_animation_element_id; - void convert_slides (); - void convert_styles (); - void convert_settings (); - void convert_layouts (); - void convert_common (); + void convert_slides (); + void convert_styles (); + void convert_settings (); + void convert_layouts (); + void convert_common (); + void convert_masters_and_layouts(); std::wstring convert_animation_formula(std::wstring formula); std::wstring convert_animation_scale_values(int x, int y); diff --git a/OdfFile/Writer/Format/draw_frame.h b/OdfFile/Writer/Format/draw_frame.h index 7d1df17a11..b80e7ff524 100644 --- a/OdfFile/Writer/Format/draw_frame.h +++ b/OdfFile/Writer/Format/draw_frame.h @@ -155,7 +155,7 @@ public: virtual void serialize(std::wostream & _Wostream); - odf_types::union_common_draw_attlists common_draw_attlists_; + odf_types::union_common_draw_attlists common_draw_attlists_; _CP_OPT(std::wstring) xml_id_; office_element_ptr_array content_; diff --git a/OdfFile/Writer/Format/draw_shapes.h b/OdfFile/Writer/Format/draw_shapes.h index e1e0199d35..4e0bc5bc36 100644 --- a/OdfFile/Writer/Format/draw_shapes.h +++ b/OdfFile/Writer/Format/draw_shapes.h @@ -47,19 +47,14 @@ public: static const ElementType type = typeDrawShape; - virtual void serialize(std::wostream & _Wostream); virtual void serialize_attlist(CP_ATTR_NODE); odf_types::common_xlink_attlist common_xlink_attlist_; _CP_OPT(std::wstring) draw_id_;//используется для анимашек - - - int sub_type_; - }; //---------------------------------------------------------------------------------------------- class draw_rect_attlist diff --git a/OdfFile/Writer/Format/odf_drawing_context.cpp b/OdfFile/Writer/Format/odf_drawing_context.cpp index 625e3c85a7..1853335edd 100644 --- a/OdfFile/Writer/Format/odf_drawing_context.cpp +++ b/OdfFile/Writer/Format/odf_drawing_context.cpp @@ -199,8 +199,8 @@ struct odf_drawing_state hidden_ = false; z_order_ = -1; - presentation_class_ = boost::none; - presentation_placeholder_ = boost::none; + presentation_class_ = boost::none; + presentation_placeholder_id_ = boost::none; rotateAngle_ = boost::none; text_rotateAngle_ = boost::none; @@ -244,7 +244,7 @@ struct odf_drawing_state _CP_OPT(int) text_rotateAngle_; _CP_OPT(presentation_class) presentation_class_; - _CP_OPT(std::wstring) presentation_placeholder_; + _CP_OPT(std::wstring) presentation_placeholder_id_; std::wstring program_; std::wstring replacement_; @@ -417,7 +417,7 @@ void odf_drawing_context::start_group() if (false == impl_->current_level_.empty()) impl_->current_level_.back().elm->add_child_element(group_elm); - if (group == NULL)return; + if (group == NULL) return; //если группа топовая - то данные если не записать - сотрутся if (!impl_->current_drawing_state_.name_.empty()) @@ -595,7 +595,7 @@ void odf_drawing_context::end_drawing() draw_base* draw = impl_->current_drawing_state_.elements_.empty() ? NULL : dynamic_cast(impl_->current_drawing_state_.elements_[index].elm.get()); if (draw) { - if (impl_->current_drawing_state_.presentation_class_ || impl_->current_drawing_state_.presentation_placeholder_) + if (impl_->current_drawing_state_.presentation_class_ || impl_->current_drawing_state_.presentation_placeholder_id_) { _CP_OPT(std::wstring) draw_layer; if (impl_->is_presentation_.get() > 0) @@ -695,7 +695,7 @@ void odf_drawing_context::end_drawing() draw->common_draw_attlists_.rel_size_.common_draw_size_attlist_.svg_width_ = impl_->current_drawing_state_.svg_width_; } /////////////////////////////////////////////////////// - presentation_placeholder * placeholder = impl_->current_drawing_state_.elements_.empty() ? NULL : dynamic_cast(impl_->current_drawing_state_.elements_[index].elm.get()); + presentation_placeholder *placeholder = impl_->current_drawing_state_.elements_.empty() ? NULL : dynamic_cast(impl_->current_drawing_state_.elements_[index].elm.get()); if (placeholder) { placeholder->presentation_object_ = impl_->current_drawing_state_.presentation_class_; @@ -890,6 +890,14 @@ bool odf_drawing_context::is_wordart() return false; } +bool odf_drawing_context::is_placeholder() +{ + if (!impl_->current_level_.empty() && typeStylePresentationPlaceholder == impl_->current_level_[0].elm->get_type()) + return true; + + return false; +} + bool odf_drawing_context::change_text_box_2_wordart() { if (impl_->current_drawing_state_.oox_shape_preset_ > 2000 && impl_->current_drawing_state_.oox_shape_preset_ < 3000) @@ -1310,7 +1318,7 @@ void odf_drawing_context::end_frame() end_element(); } ///////////////////// -void odf_drawing_context::start_element(office_element_ptr elm, office_element_ptr style_elm) +void odf_drawing_context::start_element(office_element_ptr elm, office_element_ptr style_elm) { size_t level = impl_->current_level_.size(); @@ -1460,7 +1468,7 @@ void odf_drawing_context::set_placeholder_id (std::wstring val) { if (!impl_->is_presentation_) return; - impl_->current_drawing_state_.presentation_placeholder_ = val; + impl_->current_drawing_state_.presentation_placeholder_id_ = val; } void odf_drawing_context::set_placeholder_type (int val) { @@ -2506,6 +2514,16 @@ void odf_drawing_context::set_text_properties(style_text_properties *text_proper set_text_properties(&text_properties->content_); } +void odf_drawing_context::set_placeholder_style(const std::wstring& style_name) +{ + if (impl_->current_drawing_state_.elements_.empty()) return; + + presentation_placeholder* placeholder = dynamic_cast(impl_->current_drawing_state_.elements_[0].elm.get()); + if (placeholder) + { + placeholder->text_style_name_ = style_name; + } +} void odf_drawing_context::set_paragraph_properties(paragraph_format_properties *paragraph_properties) { if (impl_->current_drawing_state_.elements_.empty()) return; @@ -2515,7 +2533,7 @@ void odf_drawing_context::set_paragraph_properties(paragraph_format_properties * draw_base* draw = dynamic_cast(impl_->current_drawing_state_.elements_[0].elm.get()); if (draw) { - if(!draw->common_draw_attlists_.shape_with_text_and_styles_.common_shape_draw_attlist_.draw_text_style_name_) + if (!draw->common_draw_attlists_.shape_with_text_and_styles_.common_shape_draw_attlist_.draw_text_style_name_) { impl_->styles_context_->create_style(L"", style_family::Paragraph, true, false, -1); @@ -2680,7 +2698,7 @@ void odf_drawing_context::set_textarea_writing_mode(int mode) if (draw) { style* style_ = NULL; - if(!draw->common_draw_attlists_.shape_with_text_and_styles_.common_shape_draw_attlist_.draw_text_style_name_) + if (!draw->common_draw_attlists_.shape_with_text_and_styles_.common_shape_draw_attlist_.draw_text_style_name_) { impl_->styles_context_->create_style(L"", style_family::Paragraph, true, false, -1); diff --git a/OdfFile/Writer/Format/odf_drawing_context.h b/OdfFile/Writer/Format/odf_drawing_context.h index 0582aa5067..a417484a08 100644 --- a/OdfFile/Writer/Format/odf_drawing_context.h +++ b/OdfFile/Writer/Format/odf_drawing_context.h @@ -151,6 +151,7 @@ public: bool change_text_box_2_wordart(); bool is_wordart(); bool is_text_box(); + bool is_placeholder(); graphic_format_properties* get_graphic_properties(); @@ -158,6 +159,8 @@ public: void set_paragraph_properties (paragraph_format_properties *paragraph_properties); void set_text_properties (style_text_properties *text_properties); void set_text_properties (text_format_properties* text_properties); + + void set_placeholder_style(const std::wstring& style_name); void start_text_box (); void set_text_box_min_size (bool val); diff --git a/OdfFile/Writer/Format/odp_slide_context.cpp b/OdfFile/Writer/Format/odp_slide_context.cpp index 1210212f01..091945ee7b 100644 --- a/OdfFile/Writer/Format/odp_slide_context.cpp +++ b/OdfFile/Writer/Format/odp_slide_context.cpp @@ -191,7 +191,7 @@ void odp_slide_context::start_table_row (bool styled) if (styled) { - styles_context_->create_style(L"",odf_types::style_family::TableRow, true, false, -1); + styles_context_->create_style(L"", odf_types::style_family::TableRow, true, false, -1); odf_style_state_ptr style_state = styles_context_->last_state(style_family::TableRow); if (style_state) diff --git a/OdfFile/Writer/Format/style_presentation.cpp b/OdfFile/Writer/Format/style_presentation.cpp index 64fb1b722a..ae1311b095 100644 --- a/OdfFile/Writer/Format/style_presentation.cpp +++ b/OdfFile/Writer/Format/style_presentation.cpp @@ -58,7 +58,7 @@ void presentation_placeholder::serialize(std::wostream & strm) CP_XML_ATTR_OPT(L"svg:width", svg_width_); CP_XML_ATTR_OPT(L"svg:x", svg_x_); CP_XML_ATTR_OPT(L"svg:y", svg_y_); - + CP_XML_ATTR_OPT(L"draw:text-style-name", text_style_name_); } } } diff --git a/OdfFile/Writer/Format/style_presentation.h b/OdfFile/Writer/Format/style_presentation.h index 30225dad3e..eccda39622 100644 --- a/OdfFile/Writer/Format/style_presentation.h +++ b/OdfFile/Writer/Format/style_presentation.h @@ -47,7 +47,7 @@ namespace cpdoccore { namespace odf_writer { -class presentation_placeholder : public office_element_impl +class presentation_placeholder : public office_element_impl //draw_base ?? { public: static const wchar_t * ns; @@ -55,22 +55,20 @@ public: static const ElementType type = typeStylePresentationPlaceholder; - - virtual void create_child_element(const std::wstring & Ns, const std::wstring & Name){} virtual void add_child_element( const office_element_ptr & child){} virtual void serialize(std::wostream & strm); - + _CP_OPT(odf_types::length) svg_x_; _CP_OPT(odf_types::length) svg_y_; _CP_OPT(odf_types::length) svg_width_; _CP_OPT(odf_types::length) svg_height_; _CP_OPT(odf_types::presentation_class) presentation_object_; - +//additional + _CP_OPT(std::wstring) text_style_name_; }; - CP_REGISTER_OFFICE_ELEMENT2(presentation_placeholder); //---------------------------------------------------------------------------------- From ccfaa64cc1a8622629ad7b53bab454f48cd86963 Mon Sep 17 00:00:00 2001 From: "Elena.Subbotina" Date: Fri, 1 Dec 2023 16:48:52 +0300 Subject: [PATCH 51/54] fix bug #65340 --- MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp b/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp index e8b589aeef..5dfd3d5a86 100644 --- a/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp +++ b/MsBinaryFile/PptFile/Reader/PPTDocumentInfoOneUser.cpp @@ -2634,7 +2634,7 @@ void CPPTUserInfo::AddAudioTransition(_UINT32 refID, CTransition* pTransition, c std::vector sound; m_oDocument.GetRecordsByType(&sound, false); - if (sound.empty() || sound[0]->m_arRecords.size() < refID) + if (sound.empty() || sound[0]->m_arRecords.size() <= refID) return; auto audio = dynamic_cast(sound[0]->m_arRecords[refID]); From 7ca14893b9ba3608c6b173bfccd6dae0fb775a62 Mon Sep 17 00:00:00 2001 From: Mikhail Lobotskiy Date: Fri, 1 Dec 2023 18:33:16 +0400 Subject: [PATCH 52/54] JSC: Added Dispose() to ~CJSContext() --- .../doctrenderer/js_internal/jsc/jsc_base.mm | 3 ++- DesktopEditor/doctrenderer/test/json/main.cpp | 19 ++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm index b304a6aab1..fb8a097e73 100644 --- a/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm +++ b/DesktopEditor/doctrenderer/js_internal/jsc/jsc_base.mm @@ -205,7 +205,8 @@ namespace NSJSBase } CJSContext::~CJSContext() { - m_internal->context = nil; + if (m_internal->context) + Dispose(); RELEASEOBJECT(m_internal); } diff --git a/DesktopEditor/doctrenderer/test/json/main.cpp b/DesktopEditor/doctrenderer/test/json/main.cpp index 03d03df1d3..30fb4eb1b4 100644 --- a/DesktopEditor/doctrenderer/test/json/main.cpp +++ b/DesktopEditor/doctrenderer/test/json/main.cpp @@ -216,12 +216,6 @@ public: return true; } - JSSmart getObject(const std::string& objLiteral) - { - JSSmart jsObj = m_pContext->runScript("(() => { return " + objLiteral + ";})();")->toObject(); - return jsObj; - } - public: JSSmart m_pContext; }; @@ -845,14 +839,13 @@ TEST_F(CJSONTest, serialization_with_script) " return 2;" " if (obj['parameters']['arr'][2][0] !== 42)" " return 3;" - " if (obj['parameters']['arr'][4] === undefined)" + " if (obj['parameters']['arr'][4] !== undefined)" " return 4;" - " if (obj['parameters']['0'] === 0)" + " if (obj['parameters']['0'] !== 0)" " return 5;" - " if (obj['parameters']['typedArr']['data'] === null)" + " if (obj['parameters']['typedArr']['data'] !== null)" " return 6;" " return 0;" -// " return JSON.stringify(obj, null, 4);" "}" ); @@ -863,11 +856,7 @@ TEST_F(CJSONTest, serialization_with_script) JSSmart jsCheckResult = global->call_func("test", 1, args); EXPECT_TRUE(jsCheckResult->isNumber()); -// EXPECT_EQ(jsCheckResult->toInt32(), 0); - - -// EXPECT_TRUE(jsCheckResult->isString()); -// std::cout << jsCheckResult->toStringA() << std::endl; + EXPECT_EQ(jsCheckResult->toInt32(), 0); EXPECT_TRUE(compare(obj, args[0])); } From 1a47ad9c3120cdd1abc37bba74e4f6f1f7df19c6 Mon Sep 17 00:00:00 2001 From: "Elena.Subbotina" Date: Sun, 3 Dec 2023 14:08:13 +0300 Subject: [PATCH 53/54] fix bug #65352 --- OdfFile/Writer/Format/odf_drawing_context.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OdfFile/Writer/Format/odf_drawing_context.cpp b/OdfFile/Writer/Format/odf_drawing_context.cpp index 66dd77734e..90a96d24c6 100644 --- a/OdfFile/Writer/Format/odf_drawing_context.cpp +++ b/OdfFile/Writer/Format/odf_drawing_context.cpp @@ -1384,8 +1384,10 @@ void odf_drawing_context::end_area_properties() } void odf_drawing_context::start_line_properties(bool reset) { + if (!impl_->current_graphic_properties) return; + impl_->current_drawing_part_ = Line; - if (reset) + if (reset ) impl_->current_graphic_properties->draw_stroke_ = boost::none; } void odf_drawing_context::end_line_properties() @@ -1419,7 +1421,7 @@ void odf_drawing_context::set_hidden (bool bVal) } void odf_drawing_context::set_opacity(double percent_) { - if (!impl_->current_graphic_properties)return; + if (!impl_->current_graphic_properties) return; switch(impl_->current_drawing_part_) { From 54efbc22fc9cfe709fa58fb191ec35ff5a81012b Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Sun, 3 Dec 2023 22:04:47 +0300 Subject: [PATCH 54/54] Fix indents --- DesktopEditor/graphics/GraphicsLayer.h | 9 +++-- DesktopEditor/graphics/pro/graphics.pro | 40 +++++++++---------- .../graphics/tests/graphicsLayers/main.cpp | 6 ++- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/DesktopEditor/graphics/GraphicsLayer.h b/DesktopEditor/graphics/GraphicsLayer.h index c6dd6cad45..e26838018a 100644 --- a/DesktopEditor/graphics/GraphicsLayer.h +++ b/DesktopEditor/graphics/GraphicsLayer.h @@ -42,13 +42,16 @@ namespace Aggplus value_type* pDstBuffer = NULL; BYTE uchAlpha; - for (unsigned int unY = 0; unY < oSrc.height(); ++unY) + unsigned int unSrcW = oSrc.width(); + unsigned int unSrcH = oSrc.height(); + + for (unsigned int unY = 0; unY < unSrcH; ++unY) { pDstBuffer = oSrc.row_ptr(unY); - for (unsigned int unX = 0; unX < oSrc.width(); ++unX) + for (unsigned int unX = 0; unX < unSrcW; ++unX) { uchAlpha = (pSrcBuffer[order_type::A] * ((value_type)(m_oSettings.m_dOpacity * 255.)) + 1) >> 8; - if(uchAlpha) + if (uchAlpha) { if(uchAlpha == SrcPixelFormatRenderer::base_mask) { diff --git a/DesktopEditor/graphics/pro/graphics.pro b/DesktopEditor/graphics/pro/graphics.pro index 04483815a7..096c52db19 100644 --- a/DesktopEditor/graphics/pro/graphics.pro +++ b/DesktopEditor/graphics/pro/graphics.pro @@ -1,4 +1,4 @@ -QT -= core gui +QT -= core gui TARGET = graphics TEMPLATE = lib @@ -7,12 +7,12 @@ CONFIG += graphics_dynamic_library DEFINES += _QT graphics_dynamic_library { - CONFIG += shared + CONFIG += shared CONFIG += plugin - DEFINES += GRAPHICS_USE_DYNAMIC_LIBRARY_BUILDING + DEFINES += GRAPHICS_USE_DYNAMIC_LIBRARY_BUILDING } else { - DEFINES += GRAPHICS_NO_USE_DYNAMIC_LIBRARY + DEFINES += GRAPHICS_NO_USE_DYNAMIC_LIBRARY CONFIG += static } @@ -23,7 +23,7 @@ include(../../../Common/base.pri) ADD_DEPENDENCY(UnicodeConverter, kernel) core_windows { - LIBS += -lAdvapi32 + LIBS += -lAdvapi32 LIBS += -lShell32 } @@ -32,35 +32,35 @@ HEADERS += ./../config.h GRAPHICS_AGG_PATH = $$PWD/../../agg-2.4 INCLUDEPATH += \ - $$GRAPHICS_AGG_PATH/include + $$GRAPHICS_AGG_PATH/include # matrix HEADERS += \ - $$GRAPHICS_AGG_PATH/include/test_grads/custom_gradients.h \ - ./../Matrix_private.h \ + $$GRAPHICS_AGG_PATH/include/test_grads/custom_gradients.h \ + ./../Matrix_private.h \ ./../Matrix.h SOURCES += \ - ./../Matrix.cpp + ./../Matrix.cpp SOURCES += \ - $$GRAPHICS_AGG_PATH/src/agg_trans_affine.cpp + $$GRAPHICS_AGG_PATH/src/agg_trans_affine.cpp # paths HEADERS += \ - ./../GraphicsPath_private.h \ + ./../GraphicsPath_private.h \ ./../GraphicsPath.h SOURCES += \ - ./../GraphicsPath.cpp + ./../GraphicsPath.cpp # alpha mask HEADERS += \ - ./../AlphaMask_private.h \ + ./../AlphaMask_private.h \ ./../AlphaMask.h SOURCES += \ - ./../AlphaMask_private.cpp \ + ./../AlphaMask_private.cpp \ ./../AlphaMask.cpp # grapgics layer @@ -71,7 +71,7 @@ SOURCES += \ ./../GraphicsLayer.cpp SOURCES += \ - $$GRAPHICS_AGG_PATH/src/agg_arc.cpp \ + $$GRAPHICS_AGG_PATH/src/agg_arc.cpp \ $$GRAPHICS_AGG_PATH/src/agg_bezier_arc.cpp \ $$GRAPHICS_AGG_PATH/src/agg_curves.cpp \ $$GRAPHICS_AGG_PATH/src/agg_bspline.cpp \ @@ -83,9 +83,9 @@ include(raster.pri) #CONFIG += graphics_disable_metafile graphics_disable_metafile { - DEFINES += GRAPHICS_DISABLE_METAFILE + DEFINES += GRAPHICS_DISABLE_METAFILE } else { - include(metafile.pri) + include(metafile.pri) } CONFIG += support_font_converter @@ -97,7 +97,7 @@ SOURCES += ./officedrawingfile.cpp # graphics SOURCES += \ - $$GRAPHICS_AGG_PATH/src/agg_arrowhead.cpp \ + $$GRAPHICS_AGG_PATH/src/agg_arrowhead.cpp \ $$GRAPHICS_AGG_PATH/src/agg_image_filters.cpp \ $$GRAPHICS_AGG_PATH/src/agg_line_aa_basics.cpp \ $$GRAPHICS_AGG_PATH/src/agg_line_profile_aa.cpp \ @@ -106,7 +106,7 @@ SOURCES += \ $$GRAPHICS_AGG_PATH/src/agg_vcgen_smooth_poly1.cpp HEADERS += \ - ./../ArrowHead.h \ + ./../ArrowHead.h \ ./../Brush.h \ ./../Clip.h \ ./../Color.h \ @@ -122,7 +122,7 @@ HEADERS += \ ./Image.h SOURCES += \ - ./../ArrowHead.cpp \ + ./../ArrowHead.cpp \ ./../Brush.cpp \ ./../Clip.cpp \ ./../Graphics.cpp \ diff --git a/DesktopEditor/graphics/tests/graphicsLayers/main.cpp b/DesktopEditor/graphics/tests/graphicsLayers/main.cpp index 9be43dc456..34d875eae6 100644 --- a/DesktopEditor/graphics/tests/graphicsLayers/main.cpp +++ b/DesktopEditor/graphics/tests/graphicsLayers/main.cpp @@ -51,10 +51,11 @@ int main(int argc, char *argv[]) pRasterRenderer->EndCommand(c_nPathType); // Отрисовываем второй слой + pRasterRenderer->BeginCommand(c_nLayerType); + pRasterRenderer->BeginCommand(c_nPathType); pRasterRenderer->PathCommandStart(); - pRasterRenderer->BeginCommand(c_nLayerType); pRasterRenderer->PathCommandRect(300, 300, 300, 300); pRasterRenderer->put_BrushAlpha1(255); @@ -72,10 +73,11 @@ int main(int argc, char *argv[]) pRasterRenderer->EndCommand(c_nPathType); //Отрисовываем третий слой + pRasterRenderer->BeginCommand(c_nLayerType); + pRasterRenderer->BeginCommand(c_nPathType); pRasterRenderer->PathCommandStart(); - pRasterRenderer->BeginCommand(c_nLayerType); pRasterRenderer->PathCommandRect(500, 400, 300, 300); pRasterRenderer->put_BrushAlpha1(150);