diff --git a/CMakeLists.txt b/CMakeLists.txt index e1dfd60b8ff040ecaa0e3a29e6bf07d1517049fe..3feb433be94d72e58fd2f41f8a7b02ff1de0a10c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,49 +1,49 @@ cmake_minimum_required(VERSION 3.17) - -# Alpha Vivy, CXX only project(Vivy VERSION 0.1 LANGUAGES CXX) cmake_policy(SET CMP0100 NEW) # Let cmake use moc and uic for .hh files cmake_policy(SET CMP0009 NEW) # Do not follow symlinks with GLOB_RECURSE -if(CMAKE_BUILD_TYPE STREQUAL "Release") - set(CMAKE_BUILD_TYPE RelWithDebInfo) +if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + set(CMAKE_BUILD_TYPE RelWithDebInfo) + set(CARGO_RELEASE_BUILD "--release") +else() + set(CMAKE_BUILD_TYPE Debug) endif() message(STATUS "The installation prefix is ${CMAKE_INSTALL_PREFIX}") message(STATUS "The build type is ${CMAKE_BUILD_TYPE}") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Pass -fPIC +set(CMAKE_COLOR_MAKEFILE ON) +set(CMAKE_COLOR_DIAGNOSTICS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Always to that... +set(THREADS_PREFER_PTHREAD_FLAG ON) # Pthread ftw +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +# Dependencies +find_package(Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED) +find_library(AVCODEC_LIBRARY avcodec 4.0 REQUIRED) +find_library(AVUTIL_LIBRARY avutil 4.0 REQUIRED) +find_library(SWRESAMPLE_LIBRARY swresample REQUIRED) +find_library(AVFORMAT_LIBRARY avformat REQUIRED) +find_library(MPV_LIBRARY mpv REQUIRED) + # Don't forget for specific things -if(WIN32) - message(STATUS "You are building on windows, pay attenion to the dependencies") -endif() if(MSVC OR MSYS OR MINGW) - message(STATUS "You are building with a windows compiler") + set(Qt6_USE_STATIC_LIBS ON) + set(Qt6_USE_STATIC_RUNTIME ON) + find_package(dlfcn-win32 REQUIRED) + add_compile_definitions(TERMIWIN_DONOTREDEFINE) + message(STATUS "You are cross-compiling for windows") elseif(APPLE) message(STATUS "You are building on MacOS X") elseif(UNIX AND NOT APPLE) message(STATUS "You are building on Linux, FreeBSD or any other toaster OS") else() - message(FATAL_ERROR "The OS is not recognized") + message(FATAL_ERROR "The OS is not recognized or not supported, if you are building on windows use a cross-compiler from a toaster OS") endif() -set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Pass -fPIC -set(CMAKE_COLOR_MAKEFILE ON) -set(CMAKE_COLOR_DIAGNOSTICS ON) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(THREADS_PREFER_PTHREAD_FLAG ON) # Pthread ftw - -# For Qt -find_package(Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED) -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - -# Find others dependencies -find_library(AVCODEC_LIBRARY avcodec 4.0 REQUIRED) -find_library(AVUTIL_LIBRARY avutil 4.0 REQUIRED) -find_library(SWRESAMPLE_LIBRARY swresample REQUIRED) -find_library(AVFORMAT_LIBRARY avformat REQUIRED) -find_library(MPV_LIBRARY mpv REQUIRED) - # Grab all files file(GLOB_RECURSE Vivy_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc") file(GLOB_RECURSE Vivy_INC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hh") @@ -52,55 +52,45 @@ if(APPLE) endif() set(PROJECT_SOURCES ${Vivy_SRC} ${Vivy_INC} ${Vivy_APPLE_SRC}) +# The Rust lib +add_custom_target(libvvs + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/utils/scripts/build-libvvs.bash" + "${CMAKE_CURRENT_BINARY_DIR}" ${CARGO_RELEASE_BUILD} + BYPRODUCTS vvcc libvvs.a + COMMENT "Rust library to embed into Vivy" + USES_TERMINAL +) +set_property(TARGET libvvs PROPERTY ADDITIONAL_CLEAN_FILES "vvcc;libvvs.a") +install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/vvcc" DESTINATION bin) + # Add the Vivy executable qt_add_executable(Vivy ${PROJECT_SOURCES} rsc/VivyRessources.qrc) qt_set_finalizer_mode(Vivy ENABLE MODES static_plugins) +add_dependencies(Vivy libvvs) +install(TARGETS Vivy RUNTIME DESTINATION bin) -set(Vivy_PRECOMPILED_INC PRIVATE src/PreCompiledHeaders.hh) - -set_property(TARGET Vivy PROPERTY CXX_STANDARD 20) +set_property(TARGET Vivy PROPERTY CXX_STANDARD 20) set_property(TARGET Vivy PROPERTY AUTOSTATICPLUGINS ON) # Link dependencies to Vivy target_link_libraries(Vivy PRIVATE Qt6::Widgets Qt::OpenGL Qt::OpenGLWidgets) -target_link_libraries(Vivy PRIVATE ${AVCODEC_LIBRARY}) -target_link_libraries(Vivy PRIVATE ${AVUTIL_LIBRARY}) +target_link_libraries(Vivy PRIVATE ${AVCODEC_LIBRARY} ${AVUTIL_LIBRARY} ${AVFORMAT_LIBRARY}) target_link_libraries(Vivy PRIVATE ${SWRESAMPLE_LIBRARY}) -target_link_libraries(Vivy PRIVATE ${AVFORMAT_LIBRARY}) target_link_libraries(Vivy PRIVATE ${MPV_LIBRARY}) +target_link_libraries(Vivy PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/libvvs.a) # Headers related things target_include_directories(Vivy PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_precompile_headers(Vivy PRIVATE ${Vivy_PRECOMPILED_INC}) - -# Set Vivy's needed C++ features -target_compile_features(Vivy PRIVATE - cxx_std_20 - cxx_auto_type - cxx_deleted_functions - cxx_explicit_conversions - cxx_final - cxx_inline_namespaces - cxx_lambdas - cxx_noexcept - cxx_nonstatic_member_init - cxx_nullptr - cxx_override - cxx_range_for - cxx_strong_enums -) +target_precompile_headers(Vivy PRIVATE src/PreCompiledHeaders.hh) # More options and warnings target_compile_options(Vivy PRIVATE -Wall -Wextra -Wpedantic -Wshadow - -Wcast-align - -Wconversion - -Wsign-conversion + -Wcast-align -Wconversion -Wsign-conversion -Wdouble-promotion -Wunused-variable -Wmisleading-indentation -Wnull-dereference - -Wdouble-promotion -Wformat=2 -Woverloaded-virtual -Wnon-virtual-dtor @@ -110,22 +100,18 @@ target_compile_options(Vivy PRIVATE # Prepare for Qt6 target_compile_definitions(Vivy PRIVATE MPV_ENABLE_DEPRECATED=0 - QT_DISABLE_DEPRECATED_BEFORE=0x050F00 QT_NO_CAST_TO_ASCII QT_RESTRICTED_CAST_FROM_ASCII QTCREATOR_UTILS_STATIC_LIB ) # Some compiler specific warnings and options -if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") target_compile_options(Vivy PRIVATE -Weverything # Disable some things because we want C++20 and don't control some Qt generated files... - -Wno-c++98-compat - -Wno-c++98-compat-pedantic - -Wno-c++98-c++11-c++14-c++17-compat-pedantic - -Wno-c++20-compat + -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++98-c++11-c++14-c++17-compat-pedantic -Wno-c++20-compat # Different versions of MPV... -Wno-switch-enum @@ -137,7 +123,7 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") -Wno-global-constructors -Wno-exit-time-destructors ) -elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") +elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") target_compile_options(Vivy PRIVATE # Different versions of MPV... -Wno-switch @@ -149,29 +135,21 @@ elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") endif() set_target_properties(Vivy PROPERTIES - MACOSX_BUNDLE_GUI_IDENTIFIER kurisu.iiens.net - MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_GUI_IDENTIFIER kurisu.iiens.net + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} ) -# Set ASAN -if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") - if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") - target_compile_options(Vivy PRIVATE -g -O1 - -fsanitize=address - -fno-omit-frame-pointer - -fsanitize-address-use-after-return=always - ) - elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") - target_compile_options(Vivy PRIVATE -g -O1 -fsanitize=address -fno-omit-frame-pointer) - endif() - - target_link_libraries(Vivy PRIVATE -g -O1 -fsanitize=address) -endif() - -# Linking stuff +# Linking stuff & ASAN on UNIX if(UNIX) target_link_options(Vivy PRIVATE -Wl,-rpath,. -rdynamic) + if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + set(Clang_CO -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-return=always) + set(GNU_CO -fsanitize=address -fno-omit-frame-pointer) + target_compile_options(Vivy PRIVATE ${${CMAKE_CXX_COMPILER_ID}_CO}) + target_compile_options(Vivy PRIVATE -g -O1) + target_link_libraries( Vivy PRIVATE -g -O1 -fsanitize=address) + endif() elseif(WIN32) target_link_options(Vivy PRIVATE -static diff --git a/README.md b/README.md index a179e61ed95560827ceb8e0395535b37d9ccdcc7..9efaab231e39c45ab4c49c293612bde90beae24d 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,23 @@ - [mpv](https://mpv.io/) development library - [Qt6](https://www.qt.io/) development library: QtCore, QtWidgets, QtOpenGL, QtOpenGLWidgets. - The AV libraries: libavutil libavcodec libavformat -- [cbindgen](https://github.com/mozilla/cbindgen): `cargo install --force cbindgen` +- Some unix utils, the `jq` binary, the `bash` shell. ## Build Simply use cmake to build in another folder of the source folder: -``` -cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang + +```bash +cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++ -CDMAKE_INSTALL_PREFIX=$HOME/.local -GNinja +ninja -Cbuild +ninja -Cbuild install ``` -To do a debug build, use the debug switch with cmake: `-DCMAKE_BUILD_TYPE=Debug`. Note that the last -option is here to generate the `compile_commands.json`, you should copy it at the root of the -project. +To develop Vivy, you need to pass the following argument to cmake: `-DCMAKE_BUILD_TYPE=Debug`. Also, +don't forget to copy the compile_commands.json file from the build folder into the project's root. ## Licence -The C++ part of this software is licenced under the LGPL v3.0 or latter. The Rust part is under the -MIT license. - ---- - -# TODO! - -- Use the rust things for the ASS instead of the C++ thing. +- The C++ part of this software is licenced under [the LGPL v3.0 or latter](/LICENSE). +- The Rust part is under the [MIT license](/src/Rust/LICENSE.txt) +- The NotoSans fonts are distributed using the [OFL licence](/src/Rust/vvs_font/fonts/NotoSans-LICENCE-OFL.txt) diff --git a/src/Lib/Ass/Ass.hh b/src/Lib/Ass/Ass.hh deleted file mode 100644 index 051ea06210ba9691ee322f0035ae4d862353f5f6..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Ass.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef VIVY_ASS_ASS_H -#define VIVY_ASS_ASS_H - -#include "Lib/Ass/Line.hh" -#include "Lib/Ass/Syl.hh" -#include "Lib/Ass/Style.hh" -#include "Lib/Ass/AssPrivate.hh" -#include "Lib/Ass/AssFactory.hh" -#include "Lib/Ass/StyleProperties.hh" - -#endif // VIVY_ASS_ASS_H diff --git a/src/Lib/Ass/AssFactory.cc b/src/Lib/Ass/AssFactory.cc deleted file mode 100644 index aa56e403dfbf6b46bd1296ecb45f4344e4998341..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/AssFactory.cc +++ /dev/null @@ -1,169 +0,0 @@ -#include "PreCompiledHeaders.hh" -#include "Lib/Ass/AssFactory.hh" - -using namespace Vivy::Ass; - -bool -AssFactory::initFromStorage() noexcept -{ - QTextStream in(&diskStorage); - QString currentSection{}; - quint64 lineIndex = 0; - QStringList stylesContent{}; - QStringList eventsContent{}; - - while (!in.atEnd()) { - const QString line = in.readLine().trimmed(); - - // Dectect comment - if (line.startsWith(";") || line.isEmpty()) { - lineIndex++; - continue; - } - - // Dectect sections - else if (line.startsWith("[") && line.endsWith("]")) { - currentSection = line.mid(1, line.size() - 2); - logDebug() << "Parsing section " << VIVY_LOG_QUOTED(currentSection); - if (!validSections.contains(currentSection)) { - logWarning() << "The current section " << VIVY_LOG_QUOTED(currentSection) - << " is invalid, ignoring it"; - currentSection = ""; - } - } - - // Other lines - else if (!currentSection.isEmpty()) { - const int separatorIndex = line.indexOf(": "); - const int baseValueIndex = separatorIndex + 2; - - // Easy way to see if the line was invalid - if (separatorIndex < 0) - logWarning() << "Invalid line #" << lineIndex << ": " << line; - - // Script's info - else if (currentSection == sectionScriptInfo) { - assInfo.insert(line.mid(0, separatorIndex), line.mid(baseValueIndex)); - logDebug() << "Got line #" << lineIndex << ": " << line; - } - - // Skip the headers and the comment lines - else if ((currentSection == sectionStyles) && line.startsWith("Style: ")) { - stylesContent.append(line); - } else if ((currentSection == sectionEvents) && line.startsWith("Dialogue: ")) { - eventsContent.append(line); - } else if ((currentSection == sectionEvents) && line.startsWith("Comment: ")) { - eventsContent.append(line); - } - } - - lineIndex++; - } - - // Construct the styles and the lines - try { - for (const auto &styleLine : stylesContent) - assStyles.push_back(std::make_shared<Style>(styleLine)); - for (const auto &assLine : eventsContent) - assLines.push_back(std::make_shared<Line>(this, assLine)); - } catch (const std::runtime_error &e) { - logError() << "Failed to create ASS style or events with error: " << e.what(); - } - - logDebug() << "Got " << assLines.size() << " ASS dialog lines"; - - return true; -} - -bool -AssFactory::checkValidity() const noexcept -{ - if (assInfo.isEmpty()) { - logError() << "Empty info section"; - return false; - } - - // Check for fields that must be integers - SectionContent::const_iterator it = assInfo.begin(); - const SectionContent::const_iterator end = assInfo.end(); - while (it != end) { - bool ok = false; - if (intTypeFields.contains(it.key()) && (static_cast<void>(it.value().toInt(&ok)), !ok)) { - logError() << it.key() << " is not an integer: " << it.value(); - return false; - } - ++it; - } - - // Check for fixed values fields - for (const auto &fixedValues : checkedValues) { - if (const auto &first = fixedValues.first; - assInfo.contains(first) && assInfo[first] != fixedValues.second) { - logError() << "Invalid " << first << " as it should be equal to " << fixedValues.second - << " but was " << assInfo[first]; - return false; - } - } - - return true; -} - -AssFactory::AssFactory(const QString &fileName) - : diskStorage(fileName) -{ - if (!diskStorage.open(QIODevice::ReadOnly | QIODevice::Text)) - throw std::runtime_error("failed to open file for reading"); - - if (!initFromStorage()) - throw std::runtime_error("failed to init ass factory from file"); - - if (!checkValidity()) - throw std::runtime_error("the loaded ass is invalid"); -} - -void -AssFactory::getStyles(QVector<StylePtr> &ret) const noexcept -{ - ret.clear(); - for (const auto &style : assStyles) - ret.push_back(style); -} - -void -AssFactory::getLines(QVector<LinePtr> &ret) const noexcept -{ - ret.clear(); - for (const auto &line : assLines) - ret.push_back(line); -} - -AssFactory::SectionContent -AssFactory::getInfoSection() const noexcept -{ - return assInfo; -} - -StyleWeakPtr -AssFactory::getStyle(const QString &name) const noexcept -{ - auto findByName = [&name](const StylePtr &style) noexcept -> bool { - return style->getElementName() == name; - }; - - auto styleIt = std::find_if(std::begin(assStyles), std::end(assStyles), findByName); - if (styleIt != std::end(assStyles)) - return StyleWeakPtr(*styleIt); - - // Will be unable to lock - return StyleWeakPtr(spareNullStylePtr); -} - -bool -AssFactory::hasStyle(const QString &name) const noexcept -{ - for (const auto &stylePtr : assStyles) { - if (stylePtr->getElementName() == name) - return true; - } - return false; -} diff --git a/src/Lib/Ass/AssFactory.hh b/src/Lib/Ass/AssFactory.hh deleted file mode 100644 index d8f753f5d97665144c53294aa21c3d4d9943a63f..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/AssFactory.hh +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "VivyApplication.hh" -#include "Lib/Log.hh" -#include "Lib/Utils.hh" -#include "Lib/Ass/Style.hh" -#include "Lib/Ass/Line.hh" -#include "Lib/Ass/AssPrivate.hh" - -// An ASS file is basically an INI file, but some keys are present multiple -// times (V4+ Styles/Style, Events/Dialogue, Events/Comment). - -namespace Vivy::Ass -{ -class AssFactory final { - VIVY_UNMOVABLE_OBJECT(AssFactory) - VIVY_APP_LOGGABLE_OBJECT(AssFactory, logger) - -public: - enum class Section { ScriptInfo = 1, Styles = 2, Events = 3 }; - - using SectionContent = QMap<QString, QVariant>; - -private: - QFile diskStorage; - SectionContent assInfo{}; - QVector<LinePtr> assLines{}; - QVector<StylePtr> assStyles{}; - - StylePtr spareNullStylePtr{ nullptr }; - - static inline const QString sectionScriptInfo = "Script Info"; - static inline const QString sectionStyles = "V4+ Styles"; - static inline const QString sectionEvents = "Events"; - static inline const QStringList validSections = { sectionEvents, sectionScriptInfo, - sectionStyles }; - - static inline const QStringList intTypeFields{ "PlayResX", "PlayResY", "WrapStyle" }; - static inline const QVector<QPair<QString, QString>> checkedValues{ - { "ScriptType", "v4.00+" }, - { "WrapStyle", "0" }, - // { "YCbCr Matrix", "TV.601" }, - { "ScaledBorderAndShadow", "yes" } - }; - - bool initFromStorage() noexcept; - bool checkValidity() const noexcept; - -public: - explicit AssFactory(const QString &); - ~AssFactory() noexcept = default; - - bool hasStyle(const QString &) const noexcept; - StyleWeakPtr getStyle(const QString &) const noexcept; - - SectionContent getInfoSection() const noexcept; - void getStyles(QVector<StylePtr> &) const noexcept; - void getLines(QVector<LinePtr> &) const noexcept; -}; -} diff --git a/src/Lib/Ass/AssPrivate.hh b/src/Lib/Ass/AssPrivate.hh deleted file mode 100644 index b25192cfe7b50b2ea8b584ff33fd0699db02fed3..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/AssPrivate.hh +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "PreCompiledHeaders.hh" - -namespace Vivy::Ass -{ -class Style; -class Line; - -using StylePtr = std::shared_ptr<Style>; -using LinePtr = std::shared_ptr<Line>; - -using StyleWeakPtr = std::weak_ptr<Style>; -using LineWeakPtr = std::weak_ptr<Line>; -} diff --git a/src/Lib/Ass/Line.cc b/src/Lib/Ass/Line.cc deleted file mode 100644 index 91f8601c2a21c697abf4b3eba71320c6092e8e89..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Line.cc +++ /dev/null @@ -1,137 +0,0 @@ -#include "PreCompiledHeaders.hh" -#include "Lib/Ass/Line.hh" -#include "Lib/Ass/AssFactory.hh" - -using namespace Vivy::Ass; - -Line::Line(AssFactory *const factory, const QString &lineString) - : assFactory(factory) -{ - enum LineIndex : int { - Layer = 0, // int - Start = 1, // time - End = 2, // time - Style = 3, // text - Name = 4, // text - MarginL = 5, // int - MarginR = 6, // int - MarginV = 7, // int - Effect = 8, // text - Text = 9, // text - PastLastCode - - // NOTE: time is of the form: `h:mm:ss.cc` - }; - - const QString lineHeader = QStringLiteral("Dialogue: "); - isComment = !lineString.startsWith(lineHeader); - - const QString lineContent = lineString.mid(lineString.indexOf(": ") + 2 /* strlen ": " */); - QStringList contentList = lineContent.split(",", Qt::KeepEmptyParts, Qt::CaseInsensitive); - - if (contentList.size() < LineIndex::PastLastCode) - throw std::runtime_error(("invalid number of items " + QString::number(contentList.size()) + - " instead of something superiror or equal to " + - QString::number(PastLastCode) + " for line: " + lineContent) - .toStdString()); - - layer = Utils::decodeLineToInteger(contentList[LineIndex::Layer], "Layer is not an integer"); - effect = contentList[LineIndex::Effect]; - nameOrActor = contentList[LineIndex::Name]; - start = Utils::Time::fromString(contentList[LineIndex::Start]).toUInt(); - end = Utils::Time::fromString(contentList[LineIndex::End]).toUInt(); - - styleProperties.marginL = - Utils::decodeLineToInteger(contentList[LineIndex::MarginL], "MarginL is not an integer"); - styleProperties.marginR = - Utils::decodeLineToInteger(contentList[LineIndex::MarginR], "MarginR is not an integer"); - styleProperties.marginV = - Utils::decodeLineToInteger(contentList[LineIndex::MarginV], "MarginV is not an integer"); - - const QString style = contentList[LineIndex::Style]; - if (!assFactory->hasStyle(style)) - throw std::runtime_error(("Invalid or not declared style name: " + style).toStdString()); - lineStyle = assFactory->getStyle(style); - - // Pop all but the text, it may contains `,` characters - for (int i = 0; i < LineIndex::Text; ++i) - contentList.removeFirst(); - ___contentAsText = contentList.join(""); - initSylFromString(___contentAsText); -} - -void -Line::initSylFromString(const QString &line) noexcept -{ - // Matches syllabes like: `{\toto}{\alpha&HFF}content` - QRegularExpression re("((?:{[^}]*})+[^{]*)"); - if (!re.isValid()) - logFatal() << "The regex " << VIVY_LOG_QUOTED(re.pattern().toStdString().c_str()) - << " is not valid..."; - - bool once = false; - try { - QRegularExpressionMatchIterator it = re.globalMatch(line); - - while (it.hasNext()) { - QRegularExpressionMatch match = it.next(); - content.append(Syl(this, match.captured(1))); - once |= true; - } - } catch (const std::runtime_error &e) { - qCritical() << "Failed to init syllabes with line: " << VIVY_LOG_QUOTED(line) - << ". Error was: " << e.what() << ". Fallback to all line is one syllabe"; - once = false; - } - - if (!once) { - content.clear(); - content.append(Syl(this, line, Syl::ConstructMode::Raw)); - } -} - -void -Line::setStart(quint64 s) noexcept -{ - start = s; - if (s > end) - end = s; -} - -void -Line::setEnd(quint64 s) noexcept -{ - end = s; - if (start > s) - start = s; -} - -quint64 -Line::getDuration() const noexcept -{ - return end - start; -} - -StyleProperties -Line::getStyleProperties() const noexcept -{ - return styleProperties; -} - -StyleWeakPtr -Line::getStyle() const noexcept -{ - return lineStyle; -} - -const QVector<Syl> & -Line::getContent() const noexcept -{ - return content; -} - -bool -Line::getIsComment() const noexcept -{ - return isComment; -} diff --git a/src/Lib/Ass/Line.hh b/src/Lib/Ass/Line.hh deleted file mode 100644 index ba0c30e068639a81ba73c1648c4ea31a208cb9d6..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Line.hh +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "PreCompiledHeaders.hh" -#include "VivyApplication.hh" -#include "Lib/Log.hh" -#include "Lib/Ass/Syl.hh" -#include "Lib/Ass/StyleProperties.hh" -#include "Lib/Ass/Style.hh" - -namespace Vivy::Ass -{ -class AssFactory; - -class Line final { - VIVY_APP_LOGGABLE_OBJECT(Line, logger) - - quint64 start{ 0 }; - quint64 end{ 0 }; - int layer{ 0 }; - bool isComment{ true }; - - QVector<Syl> content{}; - StyleProperties styleProperties{}; - QString effect{}; - QString nameOrActor{}; - StyleWeakPtr lineStyle; - - QString ___contentAsText; - - AssFactory *assFactory; - -public: - explicit Line(AssFactory *const, const QString &); - - void setStart(quint64 s) noexcept; - void setEnd(quint64 s) noexcept; - quint64 getDuration() const noexcept; - bool getIsComment() const noexcept; - - StyleProperties getStyleProperties() const noexcept; - StyleWeakPtr getStyle() const noexcept; - const QVector<Syl> &getContent() const noexcept; - -private: - void initSylFromString(const QString &) noexcept; -}; -} diff --git a/src/Lib/Ass/Style.cc b/src/Lib/Ass/Style.cc deleted file mode 100644 index 0a78af9537991cd7d4f8d123ea79b3034967bcc8..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Style.cc +++ /dev/null @@ -1,198 +0,0 @@ -#include "PreCompiledHeaders.hh" -#include "Lib/Ass/Style.hh" -#include "Lib/Utils.hh" - -using namespace Vivy::Ass; - -Style::Style(const QString &styleString) -{ - // Some usefull defines only needed in that function - - enum StyleIndex : int { - Name = 0, - FontName = 1, - FontSize = 2, - - ColorPrimary = 3, - ColorSecondary = 4, - ColorOutline = 5, - ColorBack = 6, - - Bold = 7, - Italic = 8, - Underline = 9, - StrikeOut = 10, - - ScaleX = 11, - ScaleY = 12, - Spacing = 13, - Angle = 14, - - BorderStyle = 15, - - Outline = 16, - Shadow = 17, - - Alignement = 18, - MarginL = 19, - MarginR = 20, - MarginV = 21, - - Encoding = 22, - - PastLastCode - }; - - const QString lineHeader = QStringLiteral("Style: "); - - // Check line header and content items number - - if (!styleString.startsWith(lineHeader)) - throw std::runtime_error(("invalid style line header: " + styleString).toStdString()); - - const QString lineContent = styleString.mid(styleString.indexOf(": ") + 2 /* strlen ": " */); - const QStringList content = lineContent.split(",", Qt::KeepEmptyParts, Qt::CaseInsensitive); - - if (content.size() != StyleIndex::PastLastCode) - throw std::runtime_error(("invalid number of items " + QString::number(content.size()) + - " instead of " + QString::number(PastLastCode) + - " for line: " + lineContent) - .toStdString()); - - // Unpack data from the line - - styleName = content[StyleIndex::Name]; - fontName = content[StyleIndex::FontName]; - fontSize = - Utils::decodeLineToInteger(content[StyleIndex::FontSize], "FontSize is not an integer"); - - primaryColor = Color::fromString(content[StyleIndex::ColorPrimary]); - secondaryColor = Color::fromString(content[StyleIndex::ColorSecondary]); - outlineColor = Color::fromString(content[StyleIndex::ColorOutline]); - backColor = Color::fromString(content[StyleIndex::ColorBack]); - - bold = Utils::decodeLineToBoolean(content[StyleIndex::Bold], "Bold is not a boolean"); - italic = Utils::decodeLineToBoolean(content[StyleIndex::Italic], "Italic is not a boolean"); - underline = - Utils::decodeLineToBoolean(content[StyleIndex::Underline], "Underline is not a boolean"); - strikeOut = - Utils::decodeLineToBoolean(content[StyleIndex::StrikeOut], "StrikeOut is not a boolean"); - - scaleX = Utils::decodeLineToFloating(content[StyleIndex::ScaleX], "ScaleX is not a floating"); - scaleY = Utils::decodeLineToFloating(content[StyleIndex::ScaleY], "ScaleY is not a floating"); - spacing = Utils::decodeLineToFloating(content[StyleIndex::ScaleY], "Spacing is not a floating"); - angle = Utils::decodeLineToFloating(content[StyleIndex::Angle], "Angle is not a floating"); - borderStyle = Utils::decodeLineToFloating(content[StyleIndex::BorderStyle], - "BorderStyle is not a floating"); - outline = - Utils::decodeLineToFloating(content[StyleIndex::Outline], "Outline is not a floating"); - shadow = Utils::decodeLineToFloating(content[StyleIndex::Shadow], "Shadow is not a floating"); - - alignment = - Utils::decodeLineToInteger(content[StyleIndex::Alignement], "Alignement is not an integer"); - if (alignment < 1 || alignment > 9) - throw std::runtime_error( - ("invalid line content: Alignement must be between 1 and 9 included, it was " + - QString::number(alignment)) - .toStdString()); - - marginL = Utils::decodeLineToInteger(content[StyleIndex::MarginL], "MarginL is not an integer"); - marginR = Utils::decodeLineToInteger(content[StyleIndex::MarginR], "MarginR is not an integer"); - marginV = Utils::decodeLineToInteger(content[StyleIndex::MarginV], "MarginV is not an integer"); - encoding = - Utils::decodeLineToInteger(content[StyleIndex::Encoding], "Encoding is not an integer"); - - if (encoding != 1) - logWarning() << "Encoding is not '1' in the ASS Style"; -} - -QString -Color::toString(const QColor &c) noexcept -{ - return "&H" + QString::number(c.blue(), 16).toUpper() + - QString::number(c.green(), 16).toUpper() + QString::number(c.red(), 16).toUpper(); -} - -QColor -Color::fromString(const QString &colorString) noexcept -{ - // Ignore the '&H' at the begeing of the color if needed - int startIndex = 0; - if (colorString[startIndex] == '&') - startIndex++; - if (colorString[startIndex] == 'H' || colorString[startIndex] == 'h') - startIndex++; - - // In some cases, the color can begin by a '#' - if (colorString[startIndex] == '#') - startIndex++; - - // A valid string color is like 'AARRGGBB' for now (skipped 'aH') - if (colorString.size() - startIndex != 8) - return Color::defaultValue; - - bool ok_alpha = false; - bool ok_red = false; - bool ok_green = false; - bool ok_blue = false; - int alpha = colorString.mid(startIndex, 2).toInt(&ok_alpha, 16); - int red = colorString.mid(startIndex + 2, 2).toInt(&ok_red, 16); - int green = colorString.mid(startIndex + 4, 2).toInt(&ok_green, 16); - int blue = colorString.mid(startIndex + 6, 2).toInt(&ok_blue, 16); - - if (!(ok_alpha && ok_red && ok_green && ok_blue)) - return Color::defaultValue; - - return QColor(red, green, blue, alpha); -} - -QString -Style::getElementName() const noexcept -{ - return styleName; -} - -QJsonDocument -Style::getProperties() const noexcept -{ - QJsonDocument ret; - - QJsonObject styleFont{ - { "Font name", fontName }, { "Font size", fontSize }, { "Bold", bold }, - { "Italic", italic }, { "Underline", underline }, { "Strike Out", strikeOut }, - }; - - QJsonObject styleColors{ - { "Primary", Color::toString(primaryColor) }, - { "Secondary", Color::toString(secondaryColor) }, - { "Outline", Color::toString(outlineColor) }, - { "Back", Color::toString(backColor) }, - }; - - QJsonObject styleFontProperties{ - { "Scale X", static_cast<double>(scaleX) }, - { "Scale Y", static_cast<double>(scaleY) }, - { "Spacing", static_cast<double>(spacing) }, - { "Angle", static_cast<double>(angle) }, - { "Border Style", static_cast<double>(borderStyle) }, - { "Outline", static_cast<double>(outline) }, - { "Shadow", static_cast<double>(shadow) }, - }; - - QJsonObject styleMargins{ - { "Left", marginL }, - { "Right", marginR }, - { "Vertical", marginV }, - }; - - QJsonObject object{ { "Name", styleName }, - { "Font", styleFont }, - { "Font properties", styleFontProperties }, - { "Colors", styleColors }, - { "Margin", styleMargins }, - { "Alignement", alignment }, - { "Encoding", encoding } }; - - ret.setObject(object); - return ret; -} diff --git a/src/Lib/Ass/Style.hh b/src/Lib/Ass/Style.hh deleted file mode 100644 index 6712368c054861e3f03368a3f27c4002f7166da6..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Style.hh +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "PreCompiledHeaders.hh" -#include "VivyApplication.hh" -#include "Lib/Log.hh" -#include "Lib/Ass/AssPrivate.hh" - -namespace Vivy::Ass -{ -struct Color { - static QColor fromString(const QString &) noexcept; - static QString toString(const QColor &) noexcept; - - static inline const QColor defaultValue = QColor(0, 0, 0, 0); - -private: - Color() = default; -}; - -class Style final { - VIVY_APP_LOGGABLE_OBJECT(Style, logger) - - QString styleName; - QString fontName; - int fontSize{}; - - QColor primaryColor{ Color::defaultValue }, secondaryColor{ Color::defaultValue }, - outlineColor{ Color::defaultValue }, backColor{ Color::defaultValue }; - - bool bold{ false }, italic{ false }, underline{ false }, strikeOut{ false }; - - float scaleX{ 0.0 }, scaleY{ 0.0 }; - float spacing{ 0.0 }, angle{ 0.0 }, borderStyle{ 0.0 }; - float outline{ 0.0 }, shadow{ 0.0 }; - - int alignment{ 2 }; // Alignement is bottom center - int marginL{ 0 }, marginR{ 0 }, marginV{ 0 }; // No margin by default - int encoding{ 1 }; // Encoding is set to 1 in most ASS files by default (at least in Aegisub) - -public: - // Should grab and copy a user-changeable default style - explicit Style(const Style &) = default; - explicit Style(const QString &); - - Style &operator=(const Style &) = delete; - ~Style() noexcept = default; - - QString getElementName() const noexcept; - QJsonDocument getProperties() const noexcept; -}; -} diff --git a/src/Lib/Ass/StyleProperties.hh b/src/Lib/Ass/StyleProperties.hh deleted file mode 100644 index eb7c04cdeaa10b215ef46a95a80ebe119ebcf5f0..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/StyleProperties.hh +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "PreCompiledHeaders.hh" -#include "Lib/Ass/Style.hh" - -namespace Vivy::Ass -{ -// Overrides some properties of the Style of an Ass::Line, Ass::Char, Ass::Syl - -struct StyleProperties final { - // Colors - QColor primaryColor{ Color::defaultValue }, secondaryColor{ Color::defaultValue }, - outlineColor{ Color::defaultValue }, backColor{ Color::defaultValue }; - - QString fontName{}; // Can override the font's name - int fontSize{}; // The font size != the font scaling - - bool bold{ false }, italic{ false }, underline{ false }, strikeOut{ false }; - - // Usefull for rotations - float angle{ 0.0 }; - - // No margin by default - int marginL{ 0 }, marginR{ 0 }, marginV{ 0 }; - - float scaleX{ 0.0 }, scaleY{ 0.0 }; // Font scaling - float outline{ 0.0 }, shadow{ 0.0 }; // Outline sizes - - // Alignement is bottom center - int alignment{ 2 }; -}; -} diff --git a/src/Lib/Ass/Syl.cc b/src/Lib/Ass/Syl.cc deleted file mode 100644 index 20dc0ce44154185c31113789a598a9eb042da43c..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Syl.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include "PreCompiledHeaders.hh" -#include "Lib/Ass/Syl.hh" -#include "Lib/Ass/Line.hh" - -using namespace Vivy::Ass; - -Syl::Syl(Line *const line, const QString &lineString, ConstructMode mode) noexcept - : content(lineString) - , styleProperties(line->getStyleProperties()) - , duration(line->getDuration()) - , parentLine(line) -{ - // Will override the `content`, but will be heavy anyway - if (mode == ConstructMode::ReadAssTags) { - const int textBegin = lineString.lastIndexOf('}') + 1; - content = (textBegin >= lineString.size()) ? "" : lineString.mid(textBegin); - duration = getDurationFromString(lineString); - } -} - -quint64 -Syl::getDurationFromString(const QString &line) noexcept -{ - QRegularExpression re("\\\\(?:k|K|ko|kf)(\\d+)"); - quint64 duration = 0; - QRegularExpressionMatchIterator it = re.globalMatch(line); - - while (it.hasNext()) - duration += it.next().captured(1).toUInt(); - - return duration; -} - -QString -Syl::getContent() const noexcept -{ - return content; -} diff --git a/src/Lib/Ass/Syl.hh b/src/Lib/Ass/Syl.hh deleted file mode 100644 index 75da543cbf9ca1e9c188ff6a433b71b53b15ad4b..0000000000000000000000000000000000000000 --- a/src/Lib/Ass/Syl.hh +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "PreCompiledHeaders.hh" -#include "Lib/Ass/StyleProperties.hh" - -namespace Vivy::Ass -{ -class Line; - -class Syl final { -private: - QString content; - StyleProperties styleProperties; - quint64 duration{ 0 }; - -public: - Line *parentLine; - -public: - enum class ConstructMode { - Raw, // Don't read ASS tags - ReadAssTags // Read ass tags - }; - - explicit Syl(Line *const, const QString &, - ConstructMode mode = ConstructMode::ReadAssTags) noexcept; - - QString getContent() const noexcept; - -private: - static quint64 getDurationFromString(const QString &) noexcept; -}; -} diff --git a/src/Lib/Document/CRTPSubDocument.hh b/src/Lib/Document/CRTPSubDocument.hh index 3a3cf80b42b9878b34516df7e8e1137f3c6bc0da..22d9bf9b0ee67fed96692593126ca77260ba593c 100644 --- a/src/Lib/Document/CRTPSubDocument.hh +++ b/src/Lib/Document/CRTPSubDocument.hh @@ -10,7 +10,7 @@ #include "Lib/Utils.hh" #include "Lib/Audio.hh" #include "Lib/Video.hh" -#include "Lib/Ass/Ass.hh" +#include "Rust/VVLib.hh" #define VIVY_ENABLE_IF_TYPE(Type) \ template <typename = typename std::enable_if<!std::is_same<Type, void>::value>> @@ -135,14 +135,17 @@ class AssSubDocument final : public CRTPSubDocument<AssDocumentType, AssSubDocum friend CRTPSubDocument<AssDocumentType, AssSubDocument, void>; public: - QString getElementName() const noexcept; + ~AssSubDocument() noexcept; + + QString getElementName() const noexcept { return "AssSubDocument"; } QJsonDocument getProperties() const noexcept; - const QVector<Ass::LinePtr> &getLines() const noexcept; - const QVector<Ass::StylePtr> &getStyles() const noexcept; + const QVector<VVLib::ASSLine *> &getLines() const noexcept { return lines; } + const QVector<VVLib::ASSStyle *> &getStyles() const noexcept { return styles; } private: - QVector<Ass::StylePtr> styles; - QVector<Ass::LinePtr> lines; + VVLib::ASSContainer *ass_container{ nullptr }; + QVector<VVLib::ASSStyle *> styles; + QVector<VVLib::ASSLine *> lines; }; } diff --git a/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc b/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc index 96fc6dbea03b14b0b69285ea007bb3a4a1a78db4..ccd73b2a350cc1efecc3977d32a5aa992f3688e1 100644 --- a/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc +++ b/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc @@ -1,5 +1,5 @@ #include "PreCompiledHeaders.hh" -#include "Lib/Document//CRTPSubDocument.hh" +#include "Lib/Document/CRTPSubDocument.hh" #include "Lib/JsonBuilder.hh" using namespace Vivy; @@ -8,35 +8,26 @@ using namespace Vivy; void AssSubDocument::initFromPath(const QString &path) { - Ass::AssFactory factory(path); - factory.getStyles(styles); - factory.getLines(lines); -} - -QString -AssSubDocument::getElementName() const noexcept -{ - return "AssSubDocument"; -} - -const QVector<Ass::LinePtr> & -AssSubDocument::getLines() const noexcept -{ - return lines; + this->ass_container = VVLib::ASSContainerFromFile(path.toUtf8().data()); + for (size_t i = 0; i < VVLib::ASSContainerGetLinesCount(this->ass_container); i += 1) { + this->lines.push_back(VVLib::ASSContainerGetLineAt(this->ass_container, i)); + } + for (size_t i = 0; i < VVLib::ASSContainerGetStylesCount(this->ass_container); i += 1) { + this->styles.push_back(VVLib::ASSContainerGetStyleAt(this->ass_container, i)); + } } -const QVector<Ass::StylePtr> & -AssSubDocument::getStyles() const noexcept -{ - return styles; -} +AssSubDocument::~AssSubDocument() noexcept { VVLib::ASSContainerDrop(this->ass_container); } QJsonDocument AssSubDocument::getProperties() const noexcept { QJsonObject styleObject; - for (const Ass::StylePtr &style : styles) { - styleObject.insert(style->getElementName(), style->getProperties().object()); + for (size_t i = 0; i < VVLib::ASSContainerGetStylesCount(this->ass_container); i += 1) { + const auto view = + VVLib::ASSStyleGetName(VVLib::ASSContainerGetStyleAt(this->ass_container, i)); + styleObject.insert(QString::number(i), + QString::fromUtf8(view.str, static_cast<qsizetype>(view.len))); } return JsonBuilder::createOrderedJsonDocument({ diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock index 438b9cce5e2c3acb9b7aecd42b68361435637657..55a9cd7a64a9379ee95029ebd0118e7a92c0c751 100644 --- a/src/Rust/Cargo.lock +++ b/src/Rust/Cargo.lock @@ -57,6 +57,29 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.4.1" @@ -69,12 +92,46 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" +[[package]] +name = "cbindgen" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49" +dependencies = [ + "clap 3.2.25", + "heck", + "indexmap 1.9.3", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 1.0.109", + "tempfile", + "toml 0.5.11", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "strsim", + "termcolor", + "textwrap", +] + [[package]] name = "clap" version = "4.4.7" @@ -92,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstyle", - "clap_lex", + "clap_lex 0.6.0", "strsim", "terminal_size", ] @@ -103,7 +160,7 @@ version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" dependencies = [ - "clap", + "clap 4.4.7", ] [[package]] @@ -115,7 +172,16 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.38", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", ] [[package]] @@ -130,7 +196,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3be86020147691e1d2ef58f75346a3d4d94807bfc473e377d52f09f0f7d77f7" dependencies = [ - "clap", + "clap 4.4.7", "roff", ] @@ -150,6 +216,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.2" @@ -166,6 +244,25 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.0.2" @@ -173,9 +270,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.2", ] +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + [[package]] name = "libc" version = "0.2.149" @@ -233,6 +336,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "owned_ttf_parser" version = "0.19.0" @@ -260,6 +369,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "regex" version = "1.10.2" @@ -301,13 +419,19 @@ version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", "windows-sys", ] +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + [[package]] name = "serde" version = "1.0.190" @@ -325,7 +449,18 @@ checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", ] [[package]] @@ -343,6 +478,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.38" @@ -354,6 +500,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.3.0" @@ -364,6 +532,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thiserror" version = "1.0.50" @@ -381,7 +555,16 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", ] [[package]] @@ -411,7 +594,7 @@ version = "0.20.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "782bf6c2ddf761c1e7855405e8975472acf76f7f36d0d4328bd3b7a2fae12a85" dependencies = [ - "indexmap", + "indexmap 2.0.2", "serde", "serde_spanned", "toml_datetime", @@ -461,13 +644,13 @@ name = "vvs_cli" version = "0.5.0" dependencies = [ "anyhow", - "clap", + "clap 4.4.7", "clap_complete", "clap_mangen", "log", "serde", "thiserror", - "toml", + "toml 0.8.5", "vvs_font", "vvs_utils", ] @@ -487,7 +670,7 @@ name = "vvs_lang" version = "0.5.0" dependencies = [ "anyhow", - "hashbrown", + "hashbrown 0.14.2", "log", "nom", "nom_locate", @@ -497,13 +680,22 @@ dependencies = [ "vvs_utils", ] +[[package]] +name = "vvs_lib" +version = "0.5.0" +dependencies = [ + "cbindgen", + "log", + "vvs_ass", +] + [[package]] name = "vvs_procmacro" version = "0.5.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -515,6 +707,37 @@ dependencies = [ "thiserror", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" @@ -607,5 +830,5 @@ checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml index aeba7e5ad0f4da0a66977cef64410c516894ec9d..7cfb804b33b601230a3e7fb2a18848960ffbe9de 100644 --- a/src/Rust/Cargo.toml +++ b/src/Rust/Cargo.toml @@ -1,13 +1,6 @@ [workspace] resolver = "2" -members = [ - "vvs_cli", - "vvs_ass", - "vvs_font", - "vvs_lang", - "vvs_utils", - "vvs_procmacro", -] +members = ["vvs_*"] [workspace.package] version = "0.5.0" @@ -20,11 +13,11 @@ license = "MIT" # Utils thiserror = "1" anyhow = "1" -paste = "1" log = "0.4" bitflags = { version = "2", default-features = false } unicode-segmentation = "1" hashbrown = "0.14" +cbindgen = "0.26" # Parsing regex = { version = "1", default-features = false, features = ["std"] } diff --git a/src/Rust/VVLib.hh b/src/Rust/VVLib.hh new file mode 100644 index 0000000000000000000000000000000000000000..a3e8f3b729c42914ffd4edee86de3d13ec0b7581 --- /dev/null +++ b/src/Rust/VVLib.hh @@ -0,0 +1,82 @@ +/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ + +#pragma once + +/* Generated with cbindgen:0.26.0 */ + +namespace VVLib { + +struct ASSContainer; + +struct ASSLine; + +/// Type used to describe an ASS style. +struct ASSStyle; + +struct ASSSyllabe; + +/// Represents a string slice, the user may not modify this slice, never! Note that the string is +/// not null terminated and may contains null bytes in it, use the len attribute to get the length +/// of this string and convert it to your linking. +struct StringSlice +{ + uintptr_t len; + const char *str; +}; + +extern "C" { + +/// Get the name of the style. +/// +/// # Safety +/// It is up to the user to ensure that the style is not dropped before the returned pointer. +StringSlice ASSStyleGetName(const ASSStyle *this_); + +/// Get the number of lines in the container. +uintptr_t ASSContainerGetLinesCount(const ASSContainer *this_); + +/// Get the number of syllabes in the line. +uintptr_t ASSLineGetSyllabesCount(const ASSLine *this_); + +/// # Safety +/// It is up to the user to ensure that no aliasing is done or that the line is not removed +/// from the container before the pointer is dropped, or that the container is not dropped... +ASSLine *ASSContainerGetLineAt(ASSContainer *this_, uintptr_t idx); + +/// # Safety +/// It is up to the user to ensure that no aliasing is done or that the syllabe is not removed +/// from the line before the pointer is dropped, or that the line is not removed from the +/// container... +ASSSyllabe *ASSLineGetSyllabeAt(ASSLine *this_, uintptr_t idx); + +/// Tells whever a line is commented or not. +bool ASSLineIsCommented(const ASSLine *this_); + +/// Gets the style of the line, or 'Default' if it was not found/specified. +StringSlice ASSLineGetStyle(const ASSLine *this_); + +/// # Safety +/// The returned pointer must be freed +StringSlice ASSSyllabeGetContent(const ASSSyllabe *this_); + +/// Load the ASS from a file, returns nullptr if an error was encountred. +ASSContainer *ASSContainerFromFile(char *path); + +ASSStyle *ASSContainerGetStyleByName(ASSContainer *this_, const char *name); + +ASSStyle *ASSContainerGetStyleAt(ASSContainer *this_, uintptr_t idx); + +uintptr_t ASSContainerGetStylesCount(ASSContainer *this_); + +void ASSLineSetStartTime(ASSLine *this_, int64_t time); + +void ASSLineSetFiniTime(ASSLine *this_, int64_t time); + +/// Drop the container. It is file to pass a null pointer to this function. +/// # Safety +/// The use must ensure that no dangling references remains... +void ASSContainerDrop(ASSContainer *this_); + +} // extern "C" + +} // namespace VVLib diff --git a/src/Rust/vvs_ass/src/elements/line.rs b/src/Rust/vvs_ass/src/elements/line.rs index 63df87f09256b591a6ed13421f264e77b0585aff..c62d983ba7753438b81f92a2b5b602b2d07911d6 100644 --- a/src/Rust/vvs_ass/src/elements/line.rs +++ b/src/Rust/vvs_ass/src/elements/line.rs @@ -2,11 +2,12 @@ use crate::{ASSAuxTable, ASSPosition, ASSSyllabePtr}; #[derive(Debug, Default, Clone, PartialEq)] pub struct ASSLine { + pub is_comment: bool, + pub start: i64, + pub fini: i64, pub position: ASSPosition, pub content: Vec<ASSSyllabePtr>, pub aux: ASSAuxTable, - pub start: i64, - pub fini: i64, } #[derive(Debug, Default, Clone)] @@ -43,6 +44,10 @@ impl From<ASSLine> for ASSLinePtr { } impl ASSLines { + pub fn get(&self, idx: usize) -> Option<ASSLinePtr> { + self.0.get(idx).cloned() + } + pub fn len(&self) -> usize { self.0.len() } diff --git a/src/Rust/vvs_ass/src/elements/syllabe.rs b/src/Rust/vvs_ass/src/elements/syllabe.rs index 4c098045cfe2de182e5e9b54e8c20922cec6435e..6f66cdebefb24268dab775cc9b9db706f3116b90 100644 --- a/src/Rust/vvs_ass/src/elements/syllabe.rs +++ b/src/Rust/vvs_ass/src/elements/syllabe.rs @@ -43,6 +43,10 @@ impl From<ASSSyllabe> for ASSSyllabePtr { } impl ASSSyllabes { + pub fn get(&self, idx: usize) -> Option<ASSSyllabePtr> { + self.0.get(idx).cloned() + } + pub fn len(&self) -> usize { self.0.len() } diff --git a/src/Rust/vvs_ass/src/lib.rs b/src/Rust/vvs_ass/src/lib.rs index 59575219123c8918200d5218621b456152507680..6dd7470fbd2ba75ce5a530dcda46709ca647e242 100644 --- a/src/Rust/vvs_ass/src/lib.rs +++ b/src/Rust/vvs_ass/src/lib.rs @@ -1,4 +1,5 @@ //! ASS objects for Vivy. + #![forbid(unsafe_code)] mod colors; diff --git a/src/Rust/vvs_ass/src/styles.rs b/src/Rust/vvs_ass/src/styles.rs index 81252927a34c624b9c392c61bd352438f1d9073b..c80e382b9adbf128c403caf5bd6281f0db612cc9 100644 --- a/src/Rust/vvs_ass/src/styles.rs +++ b/src/Rust/vvs_ass/src/styles.rs @@ -1,6 +1,9 @@ use crate::{ASSAlign, ASSColor}; +/// cbindgen:derive-eq +/// cbindgen:prefix-with-name #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[repr(C)] pub enum ASSBorderStyle { #[default] OutlineAndDropShadow = 1, diff --git a/src/Rust/vvs_lib/Cargo.toml b/src/Rust/vvs_lib/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..77b27a26befd71c76263c68dc3dcc623bf3b5c42 --- /dev/null +++ b/src/Rust/vvs_lib/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "vvs_lib" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +description = "A C library to expose functionalities to C/C++" + +[lib] +name = "vvs" +crate-type = ["staticlib"] + +[dependencies] +log.workspace = true + +vvs_ass = { path = "../vvs_ass" } + +[build-dependencies] +cbindgen.workspace = true diff --git a/src/Rust/vvs_lib/build.rs b/src/Rust/vvs_lib/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..e5c1757049178e066234d76fa0a3e2c119a5f1fd --- /dev/null +++ b/src/Rust/vvs_lib/build.rs @@ -0,0 +1,23 @@ +use cbindgen::{Braces, Language, Style}; + +fn main() { + cbindgen::Builder::new() + .with_crate(std::env::var("CARGO_MANIFEST_DIR").unwrap()) + .with_parse_deps(true) + .with_parse_include(&["vvs_ass"]) + .with_documentation(true) + .with_header("/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */") + .with_language(Language::Cxx) + .with_no_includes() + .with_include_version(true) + .with_line_length(120) + .with_style(Style::Both) + .with_cpp_compat(true) + .with_pragma_once(true) + .with_namespace("VVLib") + .with_tab_width(4) + .with_braces(Braces::NextLine) + .generate() + .expect("Failed to generate config") + .write_to_file("../VVLib.hh"); +} diff --git a/src/Rust/vvs_lib/src/ass.rs b/src/Rust/vvs_lib/src/ass.rs new file mode 100644 index 0000000000000000000000000000000000000000..6fb01408756cdc6c29960db1b01a14b092a07909 --- /dev/null +++ b/src/Rust/vvs_lib/src/ass.rs @@ -0,0 +1,166 @@ +use std::{ + ffi::{c_char, CStr}, + ptr::NonNull, +}; +use vvs_ass::{ass_container_from_file, ASSContainer, ASSLine, ASSStyle, ASSSyllabe}; + +/// Represents a string slice, the user may not modify this slice, never! Note that the string is +/// not null terminated and may contains null bytes in it, use the len attribute to get the length +/// of this string and convert it to your linking. +#[repr(C)] +pub struct StringSlice { + len: usize, + str: *const c_char, +} + +impl<S: AsRef<str>> From<S> for StringSlice { + fn from(value: S) -> Self { + let value = value.as_ref(); + StringSlice { len: value.len(), str: value.as_ptr() as *const _ } + } +} + +/// Contains wrappers for the styles. +pub mod style { + use super::*; + + /// Get the name of the style. + /// + /// # Safety + /// It is up to the user to ensure that the style is not dropped before the returned pointer. + #[no_mangle] + pub extern "C" fn ASSStyleGetName(this: &ASSStyle) -> StringSlice { + StringSlice::from(&this.name) + } +} + +/// Contains wrappers for the container, the line, syllabes, etc... +pub mod elements { + use super::*; + + /// Get the number of lines in the container. + #[no_mangle] + pub extern "C" fn ASSContainerGetLinesCount(this: &ASSContainer) -> usize { + this.lines.len() + } + + /// Get the number of syllabes in the line. + #[no_mangle] + pub extern "C" fn ASSLineGetSyllabesCount(this: &ASSLine) -> usize { + this.content.len() + } + + /// # Safety + /// It is up to the user to ensure that no aliasing is done or that the line is not removed + /// from the container before the pointer is dropped, or that the container is not dropped... + #[no_mangle] + pub unsafe extern "C" fn ASSContainerGetLineAt(this: &mut ASSContainer, idx: usize) -> *mut ASSLine { + match this.lines.get(idx) { + Some(line) => match line.0.write() { + Ok(mut line) => (&mut *line) as *mut _, + Err(err) => { + log::error!("failed to get line n°{idx}: {err}"); + std::ptr::null_mut() + } + }, + None => { + log::error!("failed to get line n°{idx}"); + std::ptr::null_mut() + } + } + } + + /// # Safety + /// It is up to the user to ensure that no aliasing is done or that the syllabe is not removed + /// from the line before the pointer is dropped, or that the line is not removed from the + /// container... + #[no_mangle] + pub unsafe extern "C" fn ASSLineGetSyllabeAt(this: &mut ASSLine, idx: usize) -> *mut ASSSyllabe { + match this.content.get(idx) { + Some(s) => match s.0.write() { + Ok(mut s) => (&mut *s) as *mut _, + Err(err) => { + log::error!("failed to get syllabe n°{idx}: {err}"); + std::ptr::null_mut() + } + }, + None => { + log::error!("failed to get syllabe n°{idx}"); + std::ptr::null_mut() + } + } + } + + /// Tells whever a line is commented or not. + #[no_mangle] + pub extern "C" fn ASSLineIsCommented(this: &ASSLine) -> bool { + this.is_comment + } + + /// Gets the style of the line, or 'Default' if it was not found/specified. + #[no_mangle] + pub extern "C" fn ASSLineGetStyle(this: &ASSLine) -> StringSlice { + this.aux + .get("style") + .map(|style| match style { + vvs_ass::ASSAuxValue::String(str) => StringSlice::from(str), + _ => StringSlice::from("Default"), + }) + .unwrap_or_else(|| StringSlice::from("Default")) + } + + /// # Safety + /// The returned pointer must be freed + #[no_mangle] + pub extern "C" fn ASSSyllabeGetContent(this: &ASSSyllabe) -> StringSlice { + StringSlice::from(&this.content) + } + + /// Load the ASS from a file, returns nullptr if an error was encountred. + #[no_mangle] + pub extern "C" fn ASSContainerFromFile(path: NonNull<c_char>) -> *mut ASSContainer { + match unsafe { CStr::from_ptr(path.as_ptr() as *const _) }.to_str() { + Ok(path) => ass_container_from_file(path) + .map(|ass| Box::into_raw(Box::new(ass))) + .unwrap_or_else(|err| { + log::error!("failed to load file: {err}"); + std::ptr::null_mut() + }), + Err(err) => { + log::error!("invalid utf8 filename: {err}"); + return std::ptr::null_mut(); + } + } + } + + #[no_mangle] + pub extern "C" fn ASSContainerGetStyleByName(this: &mut ASSContainer, name: *const c_char) -> *mut ASSStyle { + todo!() + } + + #[no_mangle] + pub extern "C" fn ASSContainerGetStyleAt(this: &mut ASSContainer, idx: usize) -> *mut ASSStyle { + todo!() + } + + #[no_mangle] + pub extern "C" fn ASSContainerGetStylesCount(this: &mut ASSContainer) -> usize { + todo!() + } + + #[no_mangle] + pub extern "C" fn ASSLineSetStartTime(this: &mut ASSLine, time: i64) {} + + #[no_mangle] + pub extern "C" fn ASSLineSetFiniTime(this: &mut ASSLine, time: i64) {} + + /// Drop the container. It is file to pass a null pointer to this function. + /// # Safety + /// The use must ensure that no dangling references remains... + #[no_mangle] + pub extern "C" fn ASSContainerDrop(this: *mut ASSContainer) { + if !this.is_null() { + drop(unsafe { Box::from_raw(this) }); + } + } +} diff --git a/src/Rust/vvs_lib/src/lib.rs b/src/Rust/vvs_lib/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..18305b8b8cc3fc613fa62a9de2bb7c053a5a0c04 --- /dev/null +++ b/src/Rust/vvs_lib/src/lib.rs @@ -0,0 +1,7 @@ +//! Here we define the things that will be exported to C/C++ code. We use PascalCase as it is not +//! very common and getters must be of the form `{StructName}{Get,Set}{TheField}` and methods of +//! the form `{StructName}{FunctionName}`. For free functions we use `{TheCrate}{FunctionName}`. + +#![allow(non_snake_case)] + +pub mod ass; diff --git a/src/UI/AboutWindow.cc b/src/UI/AboutWindow.cc index 307c09a2b4c48a84c098257b47756b25a7e9b070..b31788aedb0d2fa724a1605a8895e24eda8ec43a 100644 --- a/src/UI/AboutWindow.cc +++ b/src/UI/AboutWindow.cc @@ -9,12 +9,9 @@ using namespace Vivy; static const char *aboutContent = "<body>" - " <p>Vivy is a replacement for Aegisub, writen in Qt5+and with less" - " segfaults - hopefully.</p>" - " <p>This software is licenced under the LGPL v3.0 or latter. The" - " FakeVim part is imported from QtCreator, © 2016 The Qt" - " Company Ltd. and other contributors. Vivy is © Vivy" - " contributors.</p>" + " <p>Vivy is a replacement for Aegisub, writen in Qt6 and with less segfaults - hopefully.</p>" + " <p>This software (Vivy) is licenced under the LGPL v3.0 or latter and is © Vivy contributors." + " The libvvs library and vvcc compiler are MIT licenced and are © 2023 Vivy contributors.</p>" " <p>Contributors:<ul>" " <li>Elliu</li>" " <li>Kubat</li>" @@ -25,8 +22,7 @@ static const char *libContent = "<body>" " <p>Here are the libraries that where used to create the software:</p>" " <ul>" - " <li><a href=https://doc.qt.io/qt-5/index.html>Qt5</a> © <i>2018 The Qt Company Ltd. and other contributors. (LGPL-V3)</i></li>" - " <li><a href=https://www.lua.org>Lua 5.4</a> © <i>1994–2021 Lua.org, PUC-Rio. (MIT)</i></li>" + " <li><a href=https://doc.qt.io/qt-6/index.html>Qt6</a> © <i>2023 The Qt Company Ltd. and other contributors. (LGPL-V3)</i></li>" " <li><a href=https://libav.org>Libav</a> © <i>Libav contributors. (LGPL-V2.1+)</i></li>" " </ul>" " <p>Other external dependencies where used:</p>" diff --git a/src/UI/DocumentViews/AssLinesModel.cc b/src/UI/DocumentViews/AssLinesModel.cc index 52d2490c87169dcfdfc1f7cc69275f237b35e211..a59240df393d5232e18c49d0444860508fa698d1 100644 --- a/src/UI/DocumentViews/AssLinesModel.cc +++ b/src/UI/DocumentViews/AssLinesModel.cc @@ -1,9 +1,10 @@ #include "PreCompiledHeaders.hh" +#include "Rust/VVLib.hh" #include "UI/DocumentViews/AssLinesModel.hh" using namespace Vivy; -AssLinesModel::Item::Item(Ass::LineWeakPtr linePtr) noexcept +AssLinesModel::Item::Item(VVLib::ASSLine *linePtr) noexcept : line(linePtr) { } @@ -18,11 +19,10 @@ QString AssLinesModel::Item::getLineText() const noexcept { QString ret; - if (auto ptr = line.lock()) { - for (const auto &syl : ptr->getContent()) { - ret.append(syl.getContent()); - ret.append("|"); - } + for (size_t i = 0; i < VVLib::ASSLineGetSyllabesCount(line); i += 1) { + const auto str = VVLib::ASSSyllabeGetContent(VVLib::ASSLineGetSyllabeAt(line, i)); + ret.append(std::string_view(str.str, str.len)); + ret.append("|"); } ret.remove(ret.size() - 1, 1); return ret; @@ -31,28 +31,22 @@ AssLinesModel::Item::getLineText() const noexcept bool AssLinesModel::Item::getIsComment() const noexcept { - if (auto ptr = line.lock()) - return ptr->getIsComment(); - return false; + return VVLib::ASSLineIsCommented(line); } QString AssLinesModel::Item::getLineStyle() const noexcept { - if (auto ptr = line.lock()) { - if (auto style = ptr->getStyle().lock()) { - return style->getElementName(); - } - } - return ""; + const auto str = VVLib::ASSLineGetStyle(line); + return QString::fromUtf8(str.str, static_cast<qsizetype>(str.len)); } -AssLinesModel::AssLinesModel(const QVector<Ass::LinePtr> &lines) noexcept +AssLinesModel::AssLinesModel(const QVector<VVLib::ASSLine *> &lines) noexcept : lineRealData(lines) { childs.reserve(lines.count()); - for (const Ass::LinePtr &line : lines) - childs.append(new Item(Ass::LineWeakPtr{ line })); + for (VVLib::ASSLine *line : lines) + childs.append(new Item(line)); } AssLinesModel::~AssLinesModel() noexcept { qDeleteAll(childs); } diff --git a/src/UI/DocumentViews/AssLinesModel.hh b/src/UI/DocumentViews/AssLinesModel.hh index bd55c1beadb52f7af47aeb3fd4475adba0abebe2..10a4b10c9427e83a31df6118382ec9c45bd22f72 100644 --- a/src/UI/DocumentViews/AssLinesModel.hh +++ b/src/UI/DocumentViews/AssLinesModel.hh @@ -2,7 +2,7 @@ #include "PreCompiledHeaders.hh" #include "Lib/Utils.hh" -#include "Lib/Ass/Ass.hh" +#include "Rust/VVLib.hh" namespace Vivy { @@ -15,7 +15,7 @@ private: VIVY_UNMOVABLE_OBJECT(Item) public: - Item(Ass::LineWeakPtr linePtr) noexcept; + Item(VVLib::ASSLine *linePtr) noexcept; ~Item() noexcept = default; enum class Field : int { @@ -29,13 +29,13 @@ private: QString getLineStyle() const noexcept; private: - Ass::LineWeakPtr line; + VVLib::ASSLine *line; }; static inline const QStringList headers{ "", "Style", "Text" }; public: - explicit AssLinesModel(const QVector<Ass::LinePtr> &) noexcept; + explicit AssLinesModel(const QVector<VVLib::ASSLine *> &) noexcept; ~AssLinesModel() noexcept override; QVariant data(const QModelIndex &, int role) const noexcept override; @@ -52,6 +52,6 @@ public: private: QVector<Item *> childs; - const QVector<Ass::LinePtr> &lineRealData; + const QVector<VVLib::ASSLine *> &lineRealData; }; } diff --git a/src/UI/DocumentViews/TimingScene.cc b/src/UI/DocumentViews/TimingScene.cc index c438efa4f83e847cce97d96cb084fb77c6039d79..268bc0f627e85aeccef1fcab5aa40ac8b7c3d3cf 100644 --- a/src/UI/DocumentViews/TimingScene.cc +++ b/src/UI/DocumentViews/TimingScene.cc @@ -23,11 +23,12 @@ TimingScene::TimingScene(QWidget *parent) noexcept TimingScene::TimingScene(QImage img_, quint64 soundLength_, QWidget *parent) noexcept : QGraphicsScene(parent) + , backgroundImg(addPixmap(QPixmap::fromImage(img_))) , img(img_) - , soundLength(soundLength_) + , soundLength( + static_cast<qint64>(std::clamp(soundLength_, static_cast<quint64>(0), + static_cast<quint64>(std::numeric_limits<qint64>::max())))) { - QPixmap pixmap(QPixmap::fromImage(img)); - backgroundImg = addPixmap(pixmap); } void @@ -35,52 +36,49 @@ TimingScene::mousePressEvent(QGraphicsSceneMouseEvent *event) noexcept { QPointF pos = event->scenePos(); QGraphicsItem *got = itemAt(pos, QTransform()); - Ass::LinePtr p = currentLine.lock(); - if (p && (got == nullptr || got == backgroundImg)) [[likely]] { + if (currentLine && (got == nullptr || got == backgroundImg)) [[likely]] { // Handle the different cases if (timingMode == TimingMode::Line) - handleMousePressEventLine(event, p); + handleMousePressEventLine(event, currentLine); else if (timingMode == TimingMode::Syl) - handleMousePressEventSyl(event, p); + handleMousePressEventSyl(event, currentLine); else if (timingMode == TimingMode::Char) - handleMousePressEventChar(event, p); + handleMousePressEventChar(event, currentLine); } QGraphicsScene::mousePressEvent(event); } void -TimingScene::handleMousePressEventLine(QGraphicsSceneMouseEvent *event, Ass::LinePtr p) noexcept +TimingScene::handleMousePressEventLine(QGraphicsSceneMouseEvent *event, VVLib::ASSLine p[]) noexcept { - QPointF pos = event->scenePos(); - quint64 time = timeFromPos(pos.x()); - + const qint64 time = timeFromPos(event->scenePos().x()); if (const auto &btn = event->button(); btn == Qt::LeftButton) { - p->setStart(time); + VVLib::ASSLineSetStartTime(p, static_cast<int64_t>(time)); } else if (btn == Qt::RightButton) { - p->setEnd(time); + VVLib::ASSLineSetFiniTime(p, static_cast<int64_t>(time)); } } void -TimingScene::handleMousePressEventSyl(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept +TimingScene::handleMousePressEventSyl(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept { } void -TimingScene::handleMousePressEventChar(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept +TimingScene::handleMousePressEventChar(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept { } -quint64 +qint64 TimingScene::timeFromPos(qreal x) { if (const qreal w = width(); x <= 0 || w <= 0) { qCritical() << "Try avoid possible divide by zero in the time from position"; return 0; } else { - return static_cast<quint64>(x) * soundLength / static_cast<quint64>(w); + return static_cast<qint64>(x) * soundLength / static_cast<qint64>(w); } } diff --git a/src/UI/DocumentViews/TimingScene.hh b/src/UI/DocumentViews/TimingScene.hh index 1d28e61afaf136d08260e2970b679260672f986a..7bb841cbdcead04be41e603d9f28db525764d477 100644 --- a/src/UI/DocumentViews/TimingScene.hh +++ b/src/UI/DocumentViews/TimingScene.hh @@ -1,7 +1,7 @@ #pragma once #include "Lib/Utils.hh" -#include "Lib/Ass/Ass.hh" +#include "Rust/VVLib.hh" #include "UI/DocumentViews/TimingBar.hh" namespace Vivy @@ -23,8 +23,8 @@ public: private: QGraphicsPixmapItem *backgroundImg{ nullptr }; QImage img; - quint64 soundLength{ 0 }; - Ass::LineWeakPtr currentLine{}; + qint64 soundLength{ 0 }; + VVLib::ASSLine *currentLine{ nullptr }; TimingMode timingMode{ TimingMode::Line }; public: @@ -32,10 +32,10 @@ public: void mousePressEvent(QGraphicsSceneMouseEvent *event) noexcept override; private: - quint64 timeFromPos(qreal x); - void handleMousePressEventLine(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept; - void handleMousePressEventSyl(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept; - void handleMousePressEventChar(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept; + qint64 timeFromPos(qreal x); + void handleMousePressEventLine(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept; + void handleMousePressEventSyl(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept; + void handleMousePressEventChar(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept; public slots: }; diff --git a/utils/scripts/build-libvvs.bash b/utils/scripts/build-libvvs.bash new file mode 100755 index 0000000000000000000000000000000000000000..0dd55e638cbeba2e0b1c85752c45a9ea1f09e2a3 --- /dev/null +++ b/utils/scripts/build-libvvs.bash @@ -0,0 +1,13 @@ +#!/bin/sh +set -e +exec 5>&1 +cd "$(git rev-parse --show-toplevel)" + +FILES=$(cargo build --manifest-path src/Rust/Cargo.toml --workspace ${2} --message-format=json \ + | jq -r 'select( .reason == "compiler-artifact" and ((.target.kind | index("staticlib")) or (.target.kind | index("bin"))) ) .filenames[0]' \ + | tee >(cat - >&5)) + +for FILE in ${FILES}; do + FILE=${FILE} + cp -u ${FILE} "${1}/$(basename ${FILE})" +done diff --git a/utils/scripts/count-lines.bash b/utils/scripts/count-lines.bash new file mode 100755 index 0000000000000000000000000000000000000000..f52e7367c600dbe109c13b936ad4cf02607ff09a --- /dev/null +++ b/utils/scripts/count-lines.bash @@ -0,0 +1,4 @@ +#!/bin/bash +set -xe +cd "$(git rev-parse --show-toplevel)" +cloc --vcs=git diff --git a/utils/scripts/count-lines.sh b/utils/scripts/count-lines.sh deleted file mode 100755 index 4971cb7efaf75756eee35cf14fdc94818e52e90a..0000000000000000000000000000000000000000 --- a/utils/scripts/count-lines.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -set -xe -_ROOT="$(git rev-parse --show-toplevel)" -cd "$_ROOT" -cloc --vcs=git diff --git a/utils/scripts/icons.bash b/utils/scripts/icons.bash index 91f277df4a4c2ae5ce3da2f131b21afe01200ae3..a453d1b10c51b6f79c590e19b522c7e1fe678b03 100755 --- a/utils/scripts/icons.bash +++ b/utils/scripts/icons.bash @@ -1,5 +1,7 @@ #!/bin/bash +cd "$(git rev-parse --show-toplevel)" + COUNTER=0 FILE=utils/rsc/VivyPartialIcons.tmp diff --git a/utils/scripts/tidy.bash b/utils/scripts/tidy.bash deleted file mode 100755 index 5873d272f01c7ac212cc9f2b84bc4a11deda2b53..0000000000000000000000000000000000000000 --- a/utils/scripts/tidy.bash +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -if [ ! -f compile_commands.json ] -then - echo "Did you use cmake with the '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON'" - echo "option and copy the 'compile_commands.json' into the project's" - echo "root folder?" - exit 1 -fi - -INCLUDES="" -UNAME=$(uname -a) - -# Detect Qt headers, you may add support for your distribution -uname -a | egrep -i 'ubuntu|debian' 2>/dev/null >/dev/null -if [ $? -eq 0 ] -then - INCLUDES="-I/usr/include/x86_64-linux-gnu/qt5/QtCore -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets" - echo "Using debian/ubuntu Qt header locations" -fi - -find src -name '*.cc' -exec clang-tidy {} -fix-errors -checks=modernize-* -- -std=c++20 $INCLUDES \; -find src -name '*.cc' -exec clang-tidy {} -fix-errors -checks=abseil-* -- -std=c++20 $INCLUDES \; -find src -name '*.cc' -exec clang-tidy {} -fix-errors -checks=bugprone-* -- -std=c++20 $INCLUDES \; diff --git a/vendor/README.md b/vendor/README.md deleted file mode 100644 index 6928ae7fd0650d5c8f39742727df2faa12558325..0000000000000000000000000000000000000000 --- a/vendor/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# How to add new third party libraries - -1. Check the licence compatibility -2. Extract the archive in this folder -3. Add a `CMakeLists.txt` to be able to compile and link this library - with Vivy. - -Here is a sample `CMakeLists.txt` file for lua: - -```cmake -cmake_minimum_required(VERSION 3.5) -project(lua VERSION 5.4.3 LANGUAGES C) - -if(WIN32) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) -endif() - -# Lua static library -add_library(lualib STATIC - lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c - llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c - ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c - lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c - lstrlib.c ltablib.c loadlib.c linit.c -) -set_target_properties(lualib PROPERTIES OUTPUT_NAME "lua") - -# Lua interpreter -link_directories(${LUA_BINARY_DIR}) -add_executable(lua lua.c) -target_link_libraries(lua PRIVATE lualib) -if(UNIX) - target_link_libraries(lua m) -endif() - -# Lua compiler -link_directories(${LUA_BINARY_DIR}) -add_executable(luac luac.c) -target_link_libraries(luac lualib) -if(UNIX) - target_link_libraries(luac m) -endif() -```