summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Repository.mk3
-rw-r--r--RepositoryExternal.mk16
-rw-r--r--RepositoryModule_host.mk1
-rw-r--r--android/source/res/values-ab/strings.xml118
-rw-r--r--bin/find-can-be-private-symbols.functions.results1
-rw-r--r--canvas/inc/pch/precompiled_vclcanvas.hxx1
-rw-r--r--canvas/source/vcl/canvashelper.cxx1
-rw-r--r--codemaker/Executable_rustmaker.mk33
-rw-r--r--codemaker/Module_codemaker.mk1
-rw-r--r--codemaker/source/rustmaker/cpp_include_manager.cxx174
-rw-r--r--codemaker/source/rustmaker/cpp_include_manager.hxx86
-rw-r--r--codemaker/source/rustmaker/cpproduce.cxx2739
-rw-r--r--codemaker/source/rustmaker/cpproduce.hxx225
-rw-r--r--codemaker/source/rustmaker/rustfile.cxx664
-rw-r--r--codemaker/source/rustmaker/rustfile.hxx112
-rw-r--r--codemaker/source/rustmaker/rustmaker.cxx64
-rw-r--r--codemaker/source/rustmaker/rustoptions.cxx196
-rw-r--r--codemaker/source/rustmaker/rustoptions.hxx27
-rw-r--r--codemaker/source/rustmaker/rustproduce.cxx1234
-rw-r--r--codemaker/source/rustmaker/rustproduce.hxx92
-rw-r--r--codemaker/source/rustmaker/type_analyzer.cxx188
-rw-r--r--codemaker/source/rustmaker/type_analyzer.hxx94
-rw-r--r--codemaker/source/rustmaker/unoproduce.cxx376
-rw-r--r--codemaker/source/rustmaker/unoproduce.hxx109
-rw-r--r--comphelper/source/misc/date.cxx8
-rw-r--r--compilerplugins/clang/nullptr.cxx6
-rw-r--r--config_host.mk.in1
-rw-r--r--configure.ac46
-rw-r--r--cui/source/dialogs/about.cxx3
-rw-r--r--desktop/Executable_soffice_bin.mk1
-rw-r--r--desktop/qa/data/formulabar.odsbin0 -> 9288 bytes
-rw-r--r--desktop/qa/desktop_lib/test_desktop_lib.cxx59
-rw-r--r--download.lst16
-rw-r--r--editeng/source/editeng/editview.cxx9
-rw-r--r--editeng/source/editeng/impedit3.cxx11
-rw-r--r--emfio/inc/mtftools.hxx6
-rw-r--r--emfio/qa/cppunit/emf/EmfImportTest.cxx51
-rw-r--r--emfio/source/reader/emfreader.cxx16
-rw-r--r--emfio/source/reader/mtftools.cxx4
-rw-r--r--external/boost/Module_boost.mk1
-rw-r--r--external/boost/StaticLibrary_boost_system.mk29
-rw-r--r--external/curl/0001-cookie-don-t-treat-the-leading-slash-as-trailing.patch54
-rw-r--r--external/curl/0001-ws-get-a-new-mask-for-each-new-outgoing-frame.patch61
-rw-r--r--external/curl/UnpackedTarball_curl.mk2
-rw-r--r--external/liborcus/ExternalProject_liborcus.mk3
-rw-r--r--external/liborcus/Library_orcus-parser.mk1
-rw-r--r--external/liborcus/Library_orcus.mk1
-rw-r--r--external/mariadb-connector-c/UnpackedTarball_mariadb-connector-c.mk1
-rw-r--r--external/mariadb-connector-c/c23.patch.011
-rw-r--r--forms/source/component/FormComponent.cxx6
-rw-r--r--forms/source/xforms/convert.cxx2
-rw-r--r--include/sfx2/lokhelper.hxx2
-rw-r--r--include/sfx2/viewsh.hxx3
-rw-r--r--include/tools/date.hxx3
-rw-r--r--include/vcl/IDialogRenderable.hxx3
-rw-r--r--include/vcl/accessibility/AccessibleBrowseBox.hxx35
-rw-r--r--include/vcl/metaact.hxx51
-rw-r--r--include/vcl/settings.hxx2
-rw-r--r--include/vcl/svapp.hxx3
-rw-r--r--include/vcl/toolkit/MenuButton.hxx2
-rw-r--r--include/vcl/toolkit/button.hxx1
-rw-r--r--include/vcl/window.hxx9
-rw-r--r--m4/ax_boost_system.m4121
-rw-r--r--odk/examples/DevelopersGuide/FirstSteps/FirstLoadComponent/csharp/Makefile3
-rw-r--r--odk/examples/DevelopersGuide/FirstSteps/FirstUnoContact/csharp/Makefile3
-rw-r--r--odk/examples/DevelopersGuide/FirstSteps/HelloTextTableShape/csharp/Makefile3
-rw-r--r--odk/examples/DevelopersGuide/OfficeDev/PathSettings/csharp/Makefile3
-rw-r--r--odk/examples/DevelopersGuide/OfficeDev/PathSubstitution/csharp/Makefile3
-rw-r--r--odk/examples/DevelopersGuide/OfficeDev/TerminationTest/csharp/Makefile3
-rw-r--r--odk/examples/dotnet/WriterDemo/csharp/Makefile3
-rw-r--r--odk/examples/dotnet/WriterDemo/fsharp/Makefile3
-rw-r--r--odk/examples/dotnet/WriterDemo/vbasic/Makefile3
-rw-r--r--rust_uno/.gitignore3
-rw-r--r--rust_uno/Cargo.toml20
-rw-r--r--rust_uno/CustomTarget_cargo.mk18
-rw-r--r--rust_uno/CustomTarget_rustmaker.mk31
-rw-r--r--rust_uno/Extension_rust_uno-example.mk26
-rw-r--r--rust_uno/Library_rust_uno-cpp.mk41
-rw-r--r--rust_uno/Library_rust_uno-example.mk37
-rw-r--r--rust_uno/Makefile14
-rw-r--r--rust_uno/Module_rust_uno.mk22
-rw-r--r--rust_uno/build.rs39
-rw-r--r--rust_uno/example/Addons.xcu43
-rw-r--r--rust_uno/example/META-INF/manifest.xml28
-rw-r--r--rust_uno/example/ProtocolHandler.xcu29
-rw-r--r--rust_uno/example/description.xml26
-rw-r--r--rust_uno/example/example.component28
-rw-r--r--rust_uno/example/example.cxx243
-rw-r--r--rust_uno/example/rust_uno_hook.hxx (renamed from include/vcl/bitmap/BitmapAlphaClampFilter.hxx)22
-rw-r--r--rust_uno/src/core/any.rs257
-rw-r--r--rust_uno/src/core/mod.rs37
-rw-r--r--rust_uno/src/core/oustring.rs256
-rw-r--r--rust_uno/src/core/sequence.rs245
-rw-r--r--rust_uno/src/core/tests/string_tests.rs387
-rw-r--r--rust_uno/src/core/tests/type_tests.rs520
-rw-r--r--rust_uno/src/core/type.rs328
-rw-r--r--rust_uno/src/core/uno_wrapper.rs59
-rw-r--r--rust_uno/src/examples/any_example.rs158
-rw-r--r--rust_uno/src/examples/basic_example.rs120
-rw-r--r--rust_uno/src/examples/load_writer.rs124
-rw-r--r--rust_uno/src/examples/mod.rs41
-rw-r--r--rust_uno/src/examples/string_example.rs131
-rw-r--r--rust_uno/src/examples/type_example.rs324
-rw-r--r--rust_uno/src/ffi/mod.rs27
-rw-r--r--rust_uno/src/ffi/rtl_string.rs87
-rw-r--r--rust_uno/src/ffi/sal_types.rs50
-rw-r--r--rust_uno/src/ffi/tests/integration_tests.rs828
-rw-r--r--rust_uno/src/ffi/type_ffi.rs173
-rw-r--r--rust_uno/src/ffi/uno_any.rs108
-rw-r--r--rust_uno/src/ffi/uno_bridge.rs37
-rw-r--r--rust_uno/src/ffi/uno_sequence.rs54
-rw-r--r--rust_uno/src/lib.rs24
-rw-r--r--rust_uno/uno_bootstrap.cxx86
-rw-r--r--sc/inc/SheetView.hxx3
-rw-r--r--sc/inc/document.hxx3
-rw-r--r--sc/qa/unit/tiledrendering/SheetViewTest.cxx87
-rw-r--r--sc/qa/unit/tiledrendering/data/autofilter.odsbin0 -> 11730 bytes
-rw-r--r--sc/qa/unit/tiledrendering/data/pivotTableFilter.odsbin0 -> 11929 bytes
-rw-r--r--sc/qa/unit/tiledrendering/data/shape-textbox.odsbin0 -> 10126 bytes
-rw-r--r--sc/qa/unit/tiledrendering/tiledrendering.cxx68
-rw-r--r--sc/qa/unit/ucalc_sort.cxx61
-rw-r--r--sc/source/core/data/SheetView.cxx6
-rw-r--r--sc/source/core/data/document10.cxx10
-rw-r--r--sc/source/core/data/table3.cxx40
-rw-r--r--sc/source/core/tool/interpr2.cxx9
-rw-r--r--sc/source/ui/app/inputwin.cxx2
-rw-r--r--sc/source/ui/drawfunc/fuins1.cxx12
-rw-r--r--sc/source/ui/inc/colrowba.hxx1
-rw-r--r--sc/source/ui/inc/gridwin.hxx1
-rw-r--r--sc/source/ui/inc/hdrcont.hxx1
-rw-r--r--sc/source/ui/inc/viewfunc.hxx2
-rw-r--r--sc/source/ui/view/colrowba.cxx6
-rw-r--r--sc/source/ui/view/gridwin.cxx19
-rw-r--r--sc/source/ui/view/gridwin2.cxx21
-rw-r--r--sc/source/ui/view/hdrcont.cxx5
-rw-r--r--sc/source/ui/view/viewfun3.cxx7
-rw-r--r--sc/source/ui/view/viewfunc.cxx200
-rw-r--r--schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng40
-rw-r--r--sd/qa/uitest/impress_tests2/tdf146019.py4
-rw-r--r--sd/source/ui/func/fuinsert.cxx13
-rw-r--r--sd/source/ui/view/sdview3.cxx13
-rw-r--r--sfx2/source/doc/guisaveas.cxx3
-rw-r--r--sfx2/source/view/classificationhelper.cxx14
-rw-r--r--sfx2/source/view/lokhelper.cxx10
-rw-r--r--sfx2/source/view/viewsh.cxx5
-rw-r--r--solenv/gbuild/DotnetTest.mk2
-rw-r--r--solenv/gbuild/platform/com_GCC_defs.mk1
-rw-r--r--solenv/gbuild/platform/com_MSC_defs.mk1
-rw-r--r--svtools/source/brwbox/brwbox3.cxx8
-rw-r--r--sw/CppunitTest_sw_filter_md.mk1
-rw-r--r--sw/inc/init.hxx2
-rw-r--r--sw/inc/pagedesc.hxx3
-rw-r--r--sw/inc/swatrset.hxx3
-rw-r--r--sw/inc/swmodule.hxx7
-rw-r--r--sw/inc/view.hxx4
-rw-r--r--sw/qa/extras/mailmerge/data/mm-single-date.fodt25
-rw-r--r--sw/qa/extras/mailmerge/data/single-date.odsbin0 -> 7118 bytes
-rw-r--r--sw/qa/extras/mailmerge/mailmerge2.cxx14
-rw-r--r--sw/qa/filter/md/md.cxx44
-rw-r--r--sw/source/core/attr/hints.cxx5
-rw-r--r--sw/source/core/attr/swatrset.cxx4
-rw-r--r--sw/source/core/bastyp/init.cxx8
-rw-r--r--sw/source/core/doc/docdesc.cxx2
-rw-r--r--sw/source/core/doc/docnew.cxx3
-rw-r--r--sw/source/core/fields/dbfld.cxx2
-rw-r--r--sw/source/core/layout/pagedesc.cxx54
-rw-r--r--sw/source/core/text/EnhancedPDFExportHelper.cxx9
-rw-r--r--sw/source/core/text/inftxt.cxx4
-rw-r--r--sw/source/filter/md/wrtmd.cxx35
-rw-r--r--sw/source/filter/md/wrtmd.hxx3
-rw-r--r--sw/source/ui/chrdlg/numpara.cxx6
-rw-r--r--sw/source/ui/dbui/dbinsdlg.cxx10
-rw-r--r--sw/source/uibase/app/docst.cxx3
-rw-r--r--sw/source/uibase/app/docstyle.cxx7
-rw-r--r--sw/source/uibase/app/swdll.cxx8
-rw-r--r--sw/source/uibase/app/swmodule.cxx18
-rw-r--r--sw/source/uibase/dochdl/swdtflvr.cxx22
-rw-r--r--sw/source/uibase/docvw/HeaderFooterWin.cxx8
-rw-r--r--sw/source/uibase/docvw/PageBreakWin.cxx14
-rw-r--r--sw/source/uibase/docvw/edtwin.cxx14
-rw-r--r--sw/source/uibase/docvw/edtwin2.cxx4
-rw-r--r--sw/source/uibase/inc/uitool.hxx3
-rw-r--r--sw/source/uibase/uiview/view0.cxx6
-rw-r--r--sw/source/uibase/utlui/uitool.cxx35
-rw-r--r--toolkit/source/controls/table/cellvalueconversion.cxx50
-rw-r--r--toolkit/source/controls/table/cellvalueconversion.hxx28
-rw-r--r--tools/source/datetime/tdate.cxx19
-rw-r--r--vcl/Library_vcl.mk3
-rw-r--r--vcl/commonfuzzer.mk1
-rw-r--r--vcl/inc/accessibility/accessibletablistbox.hxx7
-rw-r--r--vcl/inc/graphic/GraphicFormatDetector.hxx2
-rw-r--r--vcl/inc/menutogglebutton.hxx3
-rw-r--r--vcl/inc/qt5/QtInstancePopover.hxx2
-rw-r--r--vcl/inc/qt5/QtWidget.hxx3
-rw-r--r--vcl/inc/salwtype.hxx1
-rw-r--r--vcl/inc/skia/gdiimpl.hxx9
-rw-r--r--vcl/inc/window.h4
-rw-r--r--vcl/qa/cppunit/BitmapFilterTest.cxx18
-rw-r--r--vcl/qa/cppunit/GraphicFormatDetectorTest.cxx34
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample.dxf4184
-rw-r--r--vcl/qa/cppunit/data/TypeDetectionExample2.dxf4186
-rw-r--r--vcl/qt5/QtInstancePopover.cxx18
-rw-r--r--vcl/qt5/QtWidget.cxx85
-rw-r--r--vcl/skia/gdiimpl.cxx22
-rw-r--r--vcl/source/accessibility/AccessibleBrowseBox.cxx30
-rw-r--r--vcl/source/accessibility/accessibletablistbox.cxx6
-rw-r--r--vcl/source/app/scheduler.cxx4
-rw-r--r--vcl/source/app/settings.cxx6
-rw-r--r--vcl/source/app/svapp.cxx4
-rw-r--r--vcl/source/bitmap/BitmapAlphaClampFilter.cxx43
-rw-r--r--vcl/source/control/MenuButton.cxx21
-rw-r--r--vcl/source/control/button.cxx14
-rw-r--r--vcl/source/edit/vclmedit.cxx9
-rw-r--r--vcl/source/filter/graphicfilter.cxx14
-rw-r--r--vcl/source/filter/png/PngImageReader.cxx44
-rw-r--r--vcl/source/filter/png/PngImageWriter.cxx4
-rw-r--r--vcl/source/gdi/metaact.cxx235
-rw-r--r--vcl/source/pdf/pdfbuildin_fonts.cxx (renamed from vcl/source/gdi/pdfbuildin_fonts.cxx)0
-rw-r--r--vcl/source/treelist/svtabbx.cxx6
-rw-r--r--vcl/source/window/accessibility.cxx40
-rw-r--r--vcl/source/window/cursor.cxx88
-rw-r--r--vcl/source/window/paint.cxx6
-rw-r--r--vcl/source/window/window.cxx43
-rw-r--r--vcl/source/window/window2.cxx11
-rw-r--r--vcl/source/window/winproc.cxx47
-rw-r--r--vcl/unx/gtk3/fpicker/SalGtkPicker.cxx2
226 files changed, 21527 insertions, 1254 deletions
diff --git a/Repository.mk b/Repository.mk
index 0cb81f699ba4..3f5d69b0ddc4 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -97,6 +97,7 @@ $(eval $(call gb_Helper_register_executables_for_install,SDK,sdk, \
javamaker \
netmaker \
pythonmaker \
+ $(if $(ENABLE_RUST_UNO),rustmaker) \
$(call gb_CondExeSp2bv,sp2bv) \
$(if $(filter ODK,$(BUILD_TYPE)),unoapploader) \
unoidl-read \
@@ -458,6 +459,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,ooo, \
passwordcontainer \
pcr \
pdffilter \
+ $(if $(ENABLE_RUST_UNO),rust_uno-cpp) \
$(call gb_Helper_optional,SCRIPTING,protocolhandler) \
sax \
sb \
@@ -777,6 +779,7 @@ $(eval $(call gb_Helper_register_libraries,EXTENSIONLIBS, \
active_native \
passive_native \
crashextension \
+ rust_uno-example \
))
ifneq ($(ENABLE_JAVA),)
diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk
index e5683f408009..432a8ff16b3f 100644
--- a/RepositoryExternal.mk
+++ b/RepositoryExternal.mk
@@ -659,13 +659,6 @@ endef
gb_ExternalProject__use_boost_iostreams :=
-define gb_LinkTarget__use_boost_system
-$(call gb_LinkTarget__use_boost_lib,$(1),$(BOOST_SYSTEM_LIB))
-
-endef
-
-gb_ExternalProject__use_boost_system :=
-
define gb_LinkTarget__use_boost_headers
$(call gb_LinkTarget_set_include,$(1),\
$$(INCLUDE) \
@@ -718,15 +711,6 @@ define gb_ExternalProject__use_boost_iostreams
$(call gb_ExternalProject_use_static_libraries,$(1),boost_iostreams)
endef
-define gb_LinkTarget__use_boost_system
-$(call gb_LinkTarget__use_boost_lib,$(1),boost_system)
-
-endef
-
-define gb_ExternalProject__use_boost_system
-$(call gb_ExternalProject_use_static_libraries,$(1),boost_system)
-endef
-
define gb_LinkTarget__use_boost_headers
$(call gb_LinkTarget_use_unpacked,$(1),boost)
$(call gb_LinkTarget_set_include,$(1),\
diff --git a/RepositoryModule_host.mk b/RepositoryModule_host.mk
index 8d23ee960f68..bb5add564c0c 100644
--- a/RepositoryModule_host.mk
+++ b/RepositoryModule_host.mk
@@ -126,6 +126,7 @@ $(eval $(call gb_Module_add_moduledirs,libreoffice,\
reportbuilder \
$(call gb_Helper_optional,DBCONNECTIVITY,reportdesign) \
ridljar \
+ rust_uno \
sal \
salhelper \
sax \
diff --git a/android/source/res/values-ab/strings.xml b/android/source/res/values-ab/strings.xml
index 4a4cb755f153..185c1c978b45 100644
--- a/android/source/res/values-ab/strings.xml
+++ b/android/source/res/values-ab/strings.xml
@@ -1,3 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- </resources>
+ <string name="app_name">LibreOffice Ахәаԥшыга</string>
+ <string name="app_version">Аверсиа: %1$s&lt;br&gt;Build ID: &lt;a href=https://hub.libreoffice.org/git-core/%2$s&gt;%2$s&lt;/a&gt;</string>
+ <string name="new_textdocument">Атексттә документ ҿыц</string>
+ <string name="title_recents">Ааигәатәи афаилқәа</string>
+ <string name="calc_optimal_length">Иоптималу аура</string>
+ <string name="action_keyboard">Аклавиатура аарԥштәуп</string>
+ <string name="message_saving_failed">Иамуӡеит адокумент аиқәырхара</string>
+ <string name="calc_show">Иаарԥштәуп</string>
+ <string name="pdf_export_finished">PDF аекспорт хыркәшоуп</string>
+ <string name="highlight_color">Алкаара аԥштәы</string>
+ <string name="select_insert_options">Иалышәх аҭаргылара апараметрқәа:</string>
+ <string name="calc_optimal_width">Иоптималу аҭбаара</string>
+ <string name="font_color">Ашрифт аԥштәы</string>
+ <string name="action_pwd_dialog_OK">ОК</string>
+ <string name="save_alert_dialog_title">Еиқәырхатәума адокумент аркра аԥхьа?</string>
+ <string name="action_copy">Икопиатәуп</string>
+ <string name="UNO_commands_string_type_hint">Атип</string>
+ <string name="pref_experimental_editing_summary">Иаҿактәуп аексперименталтә редакциазура арежим. Ара, иҟалар зылшо агхақәа рзы аҭакԥхықәра шәара ишәыдлоит.</string>
+ <string name="app_vendor">Ари аверсиа аԥҵара $VENDOR иабзоуроуп.</string>
+ <string name="action_delete_worksheet">Ианыхтәуп аусуратә бӷьыц</string>
+ <string name="action_presentation">Апрезентациа арбара</string>
+ <string name="compress_photo_title">Ишәҭахума афото аиҵацалара?</string>
+ <string name="action_add_worksheet">Аусуратә бӷьыц ацҵатәуп</string>
+ <string name="calc_alert_double_click_optimal_length">Аҵаҳәара: ахы ҩынтә ақәыӷәӷәара иқәнаргылоит иоптималу аҭбаара/аҳаракыра.</string>
+ <string name="about_license">Иаарԥштәуп алицензиа</string>
+ <string name="action_cut">Игәылԥҟатәуп</string>
+ <string name="app_name_settings">LibreOffice Ахәаԥшыга архиара</string>
+ <string name="app_credits">https://www.libreoffice.org</string>
+ <string name="app_description">LibreOffice ахәаԥшыга — ари апрограмма LibreOffice аҟны иаԥҵаз адокументқәа рыхәаԥшра иазкуп.</string>
+ <string name="readonly_file">Ари афаил аԥхьара мацара иазкуп.</string>
+ <string name="create_file">Иаԥҵатәуп афаил ҿыц</string>
+ <string name="new_presentation">Апрезентациа ҿыц</string>
+ <string name="new_spreadsheet">Алектронтә таблица ҿыц</string>
+ <string name="new_drawing">Асахьа ҿыц</string>
+ <string name="search_find_next">Иԥшаатәуп анаҩс</string>
+ <string name="title_browser">Афаилқәа зегьы</string>
+ <string name="pref_experimental_editing">Аексперименталтә режим</string>
+ <string name="pref_developer_mode">Аԥҵаҩы ирежим</string>
+ <string name="action_settings">Архиарақәа</string>
+ <string name="action_save">Еиқәырхатәуп</string>
+ <string name="action_save_as">Еиқәырхатәуп абас…</string>
+ <string name="action_fromat">Иаҿактәуп аформат</string>
+ <string name="action_search">Аԥшаара</string>
+ <string name="message_saving">Адокумент аиқәырхара…</string>
+ <string name="password">Ажәамаӡа</string>
+ <string name="action_undo">Иаҟәыхтәуп</string>
+ <string name="save_document">ЕИҚӘЫРХАТӘУП</string>
+ <string name="action_cancel">Аҟәыхра</string>
+ <string name="no_save_document">МАП</string>
+ <string name="action_add_slide">Аслаид ацҵатәуп</string>
+ <string name="slideshow_action_back">Шьҭахьҟа</string>
+ <string name="calc_insert_before">Иҭаргылатәуп</string>
+ <string name="calc_delete">Ианыхтәуп</string>
+ <string name="calc_hide">Иҵәахтәуп</string>
+ <string name="calc_optimal_height">Иоптималу аҳаракыра</string>
+ <string name="about_notice">Иаарԥштәуп ардырра</string>
+ <string name="about_privacy_policy">Аконфиденциалра аполитика</string>
+ <string name="select_file_to_open">Иалышәх иаарттәу афаил</string>
+ <string name="search_find_previous">Иԥшаатәуп аԥхьатәи</string>
+ <string name="pref_category_general">Азеиԥшқәа</string>
+ <string name="default_document_name">ахьӡ змам</string>
+ <string name="file_icon_desc">афаил адыргаҷ</string>
+ <string name="action_about">Апрограмма иазкны</string>
+ <string name="action_parts">Ахәҭақәа</string>
+ <string name="action_UNO_commands">Ишьҭтәуп UNO акоманда</string>
+ <string name="message_saved">Аиқәырхара нагӡоуп</string>
+ <string name="pref_developer_mode_summary">Иаҿашәк аԥҵаҩы ирежим, ара иауеит UNO акомандақәа апрограмма аҩныҵҟа рышьҭра. Ара, иҟалар зылшо агхақәа рзы аҭакԥхықәра шәара ишәыдлоит.</string>
+ <string name="action_redo">Шьҭахьҟа архынҳәра</string>
+ <string name="calc_adjust_length">Ишәырманшәал аура</string>
+ <string name="calc_adjust_height">Ишәырманшәал аҳаракыра</string>
+ <string name="calc_adjust_width">Ишәырманшәал аҭбаара</string>
+ <string name="calc_optimal_length_confirm">ОК</string>
+ <string name="alert_ok">ОК</string>
+ <string name="alert_cancel">Аҟәыхра</string>
+ <string name="unable_to_export_pdf">PDF ахь аекспорт ауам</string>
+ <string name="unable_to_save">Иамуӡеит афаил аиқәырхара</string>
+ <string name="error">Агха</string>
+ <string name="page">Адаҟьа</string>
+ <string name="sheet">Абӷьыц</string>
+ <string name="slide">Аслаид</string>
+ <string name="action_pwd_dialog_cancel">Аҟәыхра</string>
+ <string name="action_pwd_dialog_title">Иҭажәгал ажәамаӡа</string>
+ <string name="no_camera_found">Акамера ԥшаам</string>
+ <string name="compress_photo_max_quality">Имаксималу ахаҭабзиара</string>
+ <string name="compress_photo_no_compress">Еиҵацалатәӡам</string>
+ <string name="action_paste">Иҭаргылатәуп</string>
+ <string name="action_back">Шьҭахьҟа</string>
+ <string name="insert_table">Иҭаргылатәуп атаблица</string>
+ <string name="select_delete_options">Иалышәх аныхра апараметрқәа:</string>
+ <string name="action_delete_slide">Ианыхтәуп аслаид</string>
+ <string name="UNO_commands_string_hint">UNO акоманда</string>
+ <string name="UNO_commands_string_value_hint">Аҵакы</string>
+ <string name="action_exportToPDF">PDF ахь аекспорт</string>
+ <string name="action_print">Акьыԥхьра</string>
+ <string name="tabhost_character">Асимвол</string>
+ <string name="tabhost_paragraph">Абзац</string>
+ <string name="tabhost_insert">Иҭаргылатәуп</string>
+ <string name="tabhost_style">Астиль</string>
+ <string name="select_photo">Иалхтәуп афото</string>
+ <string name="select_photo_title">Иалхтәуп асахьа</string>
+ <string name="compress_photo_smallest_size">Иреиҵаӡоу ашәагаа</string>
+ <string name="compress_photo_medium_size">Абжьаратә шәагаа</string>
+ <string name="action_text_copied">Атекст аиҭныԥсахларатә буфер ахь акопиа</string>
+ <string name="action_rename_worksheet">Аусуратә бӷьыц ахьӡ ԥсахтәуп</string>
+ <string name="name_already_used">Ари ахьӡ ахархәара амоуп.</string>
+ <string name="part_name_changed">Ахәҭа ахьӡ ԥсахуп.</string>
+ <string name="part_deleted">Ахәҭа аныхуп.</string>
+ <string name="current_uno_command">Уажәтәи UNO акоманда</string>
+ <string name="enter_part_name">Иҭажәгал ахәҭа ахьӡ</string>
+ <string name="bmp_null">Bmp ашәагаа нульуп</string>
+ <string name="part">Ахәҭа</string>
+ <string name="take_photo">Афото ҟаҵатәуп</string>
+ <string name="calc_optimal_length_default_text">Иҭажәгал иацҵоу аура 1/100 мм ахәҭа ала</string>
+ <string name="UNO_commands_string_parent_value_hint">Излыҵыз аҵакы</string>
+ <string name="action_rename_slide">Аслаид ахьӡ ԥсахтәуп</string>
+ <string name="automatic">Автоматикала</string>
+</resources>
diff --git a/bin/find-can-be-private-symbols.functions.results b/bin/find-can-be-private-symbols.functions.results
index fd2aebafc784..0646ae702adf 100644
--- a/bin/find-can-be-private-symbols.functions.results
+++ b/bin/find-can-be-private-symbols.functions.results
@@ -32,7 +32,6 @@ BasicManager::SetLibraryContainerInfo(LibraryContainerInfo const&)
BasicManager::~BasicManager()
BigInt::BigInt(unsigned int)
BigInt::operator%=(BigInt const&)
-BitmapAlphaClampFilter::execute(BitmapEx const&) const
BitmapBasicMorphologyFilter::filter(Bitmap const&) const
BitmapColorQuantizationFilter::execute(BitmapEx const&) const
BitmapConvolutionMatrixFilter::execute(BitmapEx const&) const
diff --git a/canvas/inc/pch/precompiled_vclcanvas.hxx b/canvas/inc/pch/precompiled_vclcanvas.hxx
index d8a0e367643f..dee8538d638d 100644
--- a/canvas/inc/pch/precompiled_vclcanvas.hxx
+++ b/canvas/inc/pch/precompiled_vclcanvas.hxx
@@ -35,7 +35,6 @@
#include <vcl/BitmapReadAccess.hxx>
#include <vcl/BitmapTools.hxx>
#include <vcl/alpha.hxx>
-#include <vcl/bitmap/BitmapAlphaClampFilter.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/dibtools.hxx>
#include <vcl/gradient.hxx>
diff --git a/canvas/source/vcl/canvashelper.cxx b/canvas/source/vcl/canvashelper.cxx
index ac182c7ae73a..909f25b979fc 100644
--- a/canvas/source/vcl/canvashelper.cxx
+++ b/canvas/source/vcl/canvashelper.cxx
@@ -40,7 +40,6 @@
#include <vcl/bitmap.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <vcl/canvastools.hxx>
-#include <vcl/bitmap/BitmapAlphaClampFilter.hxx>
#include <vcl/skia/SkiaHelper.hxx>
#include <canvas/canvastools.hxx>
diff --git a/codemaker/Executable_rustmaker.mk b/codemaker/Executable_rustmaker.mk
new file mode 100644
index 000000000000..1fb006b23e83
--- /dev/null
+++ b/codemaker/Executable_rustmaker.mk
@@ -0,0 +1,33 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Executable_Executable,rustmaker))
+
+$(eval $(call gb_Executable_use_libraries,rustmaker,\
+ salhelper \
+ sal \
+ unoidl \
+))
+
+$(eval $(call gb_Executable_use_static_libraries,rustmaker,\
+ codemaker \
+))
+
+$(eval $(call gb_Executable_add_exception_objects,rustmaker,\
+ codemaker/source/rustmaker/rustmaker \
+ codemaker/source/rustmaker/rustoptions \
+ codemaker/source/rustmaker/rustproduce \
+ codemaker/source/rustmaker/rustfile \
+ codemaker/source/rustmaker/cpproduce \
+ codemaker/source/rustmaker/unoproduce \
+ codemaker/source/rustmaker/type_analyzer \
+ codemaker/source/rustmaker/cpp_include_manager \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/codemaker/Module_codemaker.mk b/codemaker/Module_codemaker.mk
index 36f44f231195..495400366539 100644
--- a/codemaker/Module_codemaker.mk
+++ b/codemaker/Module_codemaker.mk
@@ -19,6 +19,7 @@ $(eval $(call gb_Module_add_targets,codemaker,\
Executable_cppumaker \
Executable_netmaker \
Executable_pythonmaker \
+ $(if $(ENABLE_RUST_UNO),Executable_rustmaker) \
))
endif
diff --git a/codemaker/source/rustmaker/cpp_include_manager.cxx b/codemaker/source/rustmaker/cpp_include_manager.cxx
new file mode 100644
index 000000000000..bbf4b98bb777
--- /dev/null
+++ b/codemaker/source/rustmaker/cpp_include_manager.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "cpp_include_manager.hxx"
+#include "rustfile.hxx"
+#include <filesystem>
+#include <algorithm>
+#include <sal/log.hxx>
+
+CppIncludeManager::CppIncludeManager(const TypeAnalyzer::TypeInfo& typeInfo)
+ : m_typeInfo(typeInfo)
+{
+}
+
+void CppIncludeManager::dumpIncludes(CppFile& file, std::string_view interfaceName)
+{
+ // Write file header comment
+ file.beginLine()
+ .append("// Auto-generated C++ bridge functions for ")
+ .append(interfaceName)
+ .endLine()
+ .beginLine()
+ .append("// Generated by rustmaker with dynamic includes")
+ .endLine()
+ .endLine();
+
+ // Write pragma once directive to prevent multiple inclusions (only for header files)
+ if (file.getExtension() == ".hxx")
+ {
+ file.beginLine().append("#pragma once").endLine().endLine();
+ }
+
+ // Write standard includes
+ writeStandardIncludes(file);
+
+ // Write UNO-specific includes based on type analysis
+ writeUnoIncludes(file);
+
+ // Write interface-specific includes
+ writeInterfaceIncludes(file, interfaceName);
+
+ file.endLine();
+}
+
+void CppIncludeManager::dumpNamespaces(CppFile& file)
+{
+ // Generate specific namespace using declarations for only what we need
+ for (const auto& ns : m_typeInfo.namespaces)
+ {
+ file.beginLine().append("using namespace ").append(ns).append(";").endLine();
+ }
+ file.endLine();
+}
+
+void CppIncludeManager::writeStandardIncludes(CppFile& file)
+{
+ // Always needed for UNO operations
+ if (m_typeInfo.needsUnoInterface)
+ {
+ file.beginLine().append("#include <com/sun/star/uno/XInterface.hpp>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/Reference.hxx>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/Exception.hpp>").endLine();
+ file.beginLine().append("#include <sal/log.hxx>").endLine(); // For SAL_WARN macro
+ }
+
+ // Basic type includes
+ if (m_typeInfo.needsSalTypes)
+ {
+ file.beginLine().append("#include <sal/types.h>").endLine();
+ }
+
+ if (m_typeInfo.needsRtlUstring)
+ {
+ file.beginLine().append("#include <rtl/ustring.hxx>").endLine();
+ }
+}
+
+void CppIncludeManager::writeUnoIncludes(CppFile& file)
+{
+ // Core UNO types - implemented: Any
+ if (m_typeInfo.needsAny)
+ {
+ file.beginLine().append("#include <com/sun/star/uno/Any.hxx>").endLine();
+ file.beginLine().append("#include <uno/data.h>").endLine();
+ file.beginLine().append("#include <cppu/unotype.hxx>").endLine();
+ }
+
+ if (m_typeInfo.needsSequence)
+ {
+ file.beginLine().append("#include <com/sun/star/uno/Sequence.hxx>").endLine();
+ file.beginLine().append("#include <uno/sequence2.h>").endLine();
+ file.beginLine().append("#include <typelib/typedescription.h>").endLine();
+ }
+
+ if (m_typeInfo.needsPropertyValue)
+ {
+ // TODO: implement PropertyValue handling
+ file.beginLine().append("// TODO: Add PropertyValue includes").endLine();
+ file.beginLine().append("#include <com/sun/star/beans/PropertyValue.hpp>").endLine();
+ }
+}
+
+void CppIncludeManager::writeInterfaceIncludes(CppFile& file, std::string_view interfaceName)
+{
+ // Include the interface being processed
+ OString selfInclude = "<" + OString(interfaceName).replaceAll("."_ostr, "/"_ostr) + ".hpp>";
+ file.beginLine().append("#include ").append(selfInclude).endLine();
+
+ // Include headers for all interface types found in the analysis
+ for (const auto& interfaceType : m_typeInfo.interfaceTypes)
+ {
+ // Don't include ourselves twice
+ if (interfaceType != interfaceName)
+ {
+ OString includeFile = "<" + interfaceType.replaceAll("."_ostr, "/"_ostr) + ".hpp>";
+ file.beginLine().append("#include ").append(includeFile).endLine();
+ }
+ }
+}
+
+OString CppIncludeManager::calculateRelativeIncludePath(const CppFile& file,
+ const OString& targetType,
+ const std::string& extension)
+{
+ namespace fs = std::filesystem;
+
+ // Get the current file's directory
+ fs::path currentFilePath = file.getPath();
+ fs::path currentDir = currentFilePath.parent_path();
+
+ // Convert target type name to path (dots to slashes)
+ std::string targetTypeStr = std::string(targetType);
+ std::replace(targetTypeStr.begin(), targetTypeStr.end(), '.', '/');
+
+ // Find the base directory (cpp)
+ fs::path baseDir = currentDir;
+ while (baseDir.has_parent_path() && baseDir.filename() != "cpp")
+ {
+ baseDir = baseDir.parent_path();
+ }
+
+ // Create target file path
+ fs::path target = (baseDir / (targetTypeStr + extension)).lexically_normal();
+
+ // If they're in the same directory, just use the filename
+ if (target.parent_path() == currentDir)
+ {
+ std::string result = target.filename().string();
+ return OString("\"" + result + "\"");
+ }
+
+ // Otherwise calculate relative path from current directory to target file
+ fs::path rel;
+ try
+ {
+ rel = fs::relative(target, currentDir);
+ }
+ catch (const std::exception&)
+ {
+ // Fallback: use the path relative to base directory
+ rel = fs::relative(target, baseDir);
+ }
+
+ std::string result = rel.generic_string();
+ return OString("\"" + result + "\"");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/cpp_include_manager.hxx b/codemaker/source/rustmaker/cpp_include_manager.hxx
new file mode 100644
index 000000000000..ea9a190b1680
--- /dev/null
+++ b/codemaker/source/rustmaker/cpp_include_manager.hxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "type_analyzer.hxx"
+#include <rtl/string.hxx>
+
+// Forward declaration
+class CppFile;
+
+/**
+ * Manages dynamic generation of C++ includes and namespace declarations
+ * based on type analysis results.
+ */
+class CppIncludeManager
+{
+public:
+ /**
+ * Constructor that takes type analysis results.
+ *
+ * @param typeInfo The type analysis results from TypeAnalyzer.
+ */
+ explicit CppIncludeManager(const TypeAnalyzer::TypeInfo& typeInfo);
+
+ /**
+ * Writes the necessary #include directives to the C++ file.
+ *
+ * @param file The CppFile to write to.
+ * @param interfaceName The name of the interface being processed (for self-include).
+ */
+ void dumpIncludes(CppFile& file, std::string_view interfaceName);
+
+ /**
+ * Writes the necessary using namespace declarations to the C++ file.
+ *
+ * @param file The CppFile to write to.
+ */
+ void dumpNamespaces(CppFile& file);
+
+private:
+ const TypeAnalyzer::TypeInfo& m_typeInfo;
+
+ /**
+ * Writes standard system includes that are always needed.
+ *
+ * @param file The CppFile to write to.
+ */
+ void writeStandardIncludes(CppFile& file);
+
+ /**
+ * Writes UNO-specific includes based on type analysis.
+ *
+ * @param file The CppFile to write to.
+ */
+ void writeUnoIncludes(CppFile& file);
+
+ /**
+ * Writes interface-specific includes.
+ *
+ * @param file The CppFile to write to.
+ * @param interfaceName The name of the interface being processed.
+ */
+ void writeInterfaceIncludes(CppFile& file, std::string_view interfaceName);
+
+ /**
+ * Calculates relative include paths like cppumaker does.
+ * This generates the proper relative path from the current file being generated
+ * to the target dependency file.
+ *
+ * @param file The current file being generated (provides context for relative path)
+ * @param targetType The UNO type name (e.g., "com.sun.star.beans.Property")
+ * @param extension The file extension to use (e.g., ".hxx", ".hpp")
+ * @return Properly formatted include statement with quotes
+ */
+ static OString calculateRelativeIncludePath(const CppFile& file, const OString& targetType,
+ const std::string& extension);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/cpproduce.cxx b/codemaker/source/rustmaker/cpproduce.cxx
new file mode 100644
index 000000000000..cf8af02c0950
--- /dev/null
+++ b/codemaker/source/rustmaker/cpproduce.cxx
@@ -0,0 +1,2739 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "cpproduce.hxx"
+#include <rtl/string.hxx>
+#include "rustfile.hxx"
+#include "type_analyzer.hxx"
+#include "cpp_include_manager.hxx"
+#include <codemaker/typemanager.hxx>
+#include <codemaker/unotype.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <iostream>
+#include <filesystem>
+#include <string_view>
+#include <algorithm>
+
+CppProducer::CppProducer(const OString& outputDir, bool verbose, bool dryRun,
+ const rtl::Reference<TypeManager>& typeManager)
+ : m_outputDir(outputDir)
+ , m_verbose(verbose)
+ , m_dryRun(dryRun)
+ , m_typeManager(typeManager)
+ , m_combinedSourceFile()
+ , m_combinedHeaderFile()
+{
+}
+
+void CppProducer::initializeCombinedFile()
+{
+ if (m_dryRun)
+ return;
+
+ // Create the combined source file (.cxx)
+ m_combinedSourceFile = std::make_unique<CppFile>(m_outputDir, "rust_uno_bindings", ".cxx");
+ std::filesystem::path sourceFilePath = m_combinedSourceFile->getPath();
+ if (std::filesystem::exists(sourceFilePath))
+ {
+ std::filesystem::remove(sourceFilePath);
+ }
+ m_combinedSourceFile->openFile();
+
+ // Include the header file
+ m_combinedSourceFile->beginLine().append("#include \"rust_uno_bindings.hxx\"").endLine();
+ m_combinedSourceFile->beginLine().append("").endLine();
+
+ // Create the combined header file (.hxx)
+ m_combinedHeaderFile = std::make_unique<CppFile>(m_outputDir, "rust_uno_bindings", ".hxx");
+ std::filesystem::path headerFilePath = m_combinedHeaderFile->getPath();
+ if (std::filesystem::exists(headerFilePath))
+ {
+ std::filesystem::remove(headerFilePath);
+ }
+ m_combinedHeaderFile->openFile();
+
+ // Add header guard
+ m_combinedHeaderFile->beginLine().append("#pragma once").endLine();
+ m_combinedHeaderFile->beginLine().append("").endLine();
+
+ // Add only sal/types.h which definitely exists
+ m_combinedHeaderFile->beginLine().append("#include <sal/types.h>").endLine();
+ m_combinedHeaderFile->beginLine().append("").endLine();
+}
+
+void CppProducer::finalizeCombinedFile()
+{
+ if (m_combinedSourceFile)
+ {
+ m_combinedSourceFile->closeFile();
+ m_combinedSourceFile.reset();
+ }
+
+ if (m_combinedHeaderFile)
+ {
+ m_combinedHeaderFile->closeFile();
+ m_combinedHeaderFile.reset();
+ }
+}
+
+void CppProducer::produceEnum(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity)
+{
+ if (m_verbose)
+ std::cout << "[cpp-opaque-enum] " << name << " -> enum bridge functions" << '\n';
+
+ generateEnumBridge(name, entity);
+}
+
+void CppProducer::produceStruct(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ if (m_verbose)
+ std::cout << "[cpp-opaque-struct] " << name
+ << " -> constructor/destructor + getter/setter functions" << '\n';
+
+ generateStructWrapper(name, entity);
+ // generateStructBridge(name, entity);
+}
+
+void CppProducer::produceInterface(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ if (m_verbose)
+ std::cout << "[cpp-opaque-interface] " << name
+ << " -> opaque handle + method wrapper functions" << '\n';
+
+ generateInterfaceHeader(name, entity);
+ generateInterfaceSource(name, entity);
+}
+
+void CppProducer::produceService(
+ std::string_view name, const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity)
+{
+ if (m_verbose)
+ std::cout << "[cpp-opaque-service] " << name << " -> service creation bridge functions"
+ << '\n';
+
+ generateServiceHeader(name, entity);
+ generateServiceSource(name, entity);
+}
+
+void CppProducer::generateEnumBridge(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity)
+{
+ generateEnumHeader(name, entity);
+ generateEnumSource(name, entity);
+}
+
+void CppProducer::generateStructWrapper(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ generateStructHeader(name, entity);
+ generateStructSource(name, entity);
+}
+
+void CppProducer::generateStructBridge(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>&)
+{
+ CppFile file(m_outputDir, name);
+
+ if (m_dryRun)
+ return;
+
+ file.openFile();
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Simple opaque struct bridge functions (like old FFI approach)
+ OString className = getInterfaceClassName(name);
+ OString functionPrefix = getCFunctionPrefix(name);
+
+ file.beginLine()
+ .append("// Opaque struct creation")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void* ")
+ .append(functionPrefix)
+ .append("_create()")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("return new ")
+ .append(className)
+ .append("();")
+ .endLine()
+ .endBlock();
+
+ file.beginLine().append("").endLine();
+ file.endBlock().append(" // extern \"C\"");
+
+ file.closeFile();
+}
+
+void CppProducer::generateCBridgeIncludes(CppFile& file, std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ // Use existing infrastructure for includes
+ TypeAnalyzer analyzer(m_typeManager);
+ TypeAnalyzer::TypeInfo typeInfo = analyzer.analyzeInterface(entity);
+ CppIncludeManager includeManager(typeInfo);
+
+ includeManager.dumpIncludes(file, name);
+}
+
+void CppProducer::generateCBridgeTypeDefinitions(CppFile& file, const OString& handleTypeName)
+{
+ // Opaque handle typedef for type safety
+ file.beginLine()
+ .append("// Opaque handle for type-safe C FFI")
+ .endLine()
+ .beginLine()
+ .append("typedef void* ")
+ .append(handleTypeName)
+ .append(";")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine();
+}
+
+void CppProducer::generateCBridgeConstructors(CppFile& file, const OString& className,
+ const OString& functionPrefix,
+ const OString& handleTypeName)
+{
+ // Opaque constructor function - creates interface instance from existing Reference
+ file.beginLine()
+ .append("// Opaque constructor - creates interface wrapper from UNO Reference")
+ .endLine()
+ .beginLine()
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_create_from_reference(void* xInterface)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (!xInterface) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Cast void* back to Reference<")
+ .append(className)
+ .append(">")
+ .endLine()
+ .beginLine()
+ .append("Reference<")
+ .append(className)
+ .append(">* pRef = static_cast<Reference<")
+ .append(className)
+ .append(">*>(xInterface);")
+ .endLine()
+ .beginLine()
+ .append("if (!pRef->is()) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Create wrapper with interface reference")
+ .endLine()
+ .beginLine()
+ .append("return new ")
+ .append(className)
+ .append("Wrapper(*pRef);")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Opaque service creation - attempts to create UNO service")
+ .endLine()
+ .beginLine()
+ .append("// Note: This is a simplified approach - real service creation")
+ .endLine()
+ .beginLine()
+ .append("// would need ComponentContext and service name resolution")
+ .endLine()
+ .beginLine()
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_create_service(void* xContext, const char* serviceName)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (!xContext || !serviceName) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("try")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("// Cast context")
+ .endLine()
+ .beginLine()
+ .append("Reference<XComponentContext>* pContext =")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("static_cast<Reference<XComponentContext>*>(xContext);")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Create service")
+ .endLine()
+ .beginLine()
+ .append("OUString svcName = OUString::createFromAscii(serviceName);")
+ .endLine()
+ .beginLine()
+ .append("Reference<")
+ .append(className)
+ .append("> xService(")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("pContext->getServiceManager()->createInstanceWithContext(")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("svcName, *pContext), UNO_QUERY);")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!xService.is()) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Return wrapper")
+ .endLine()
+ .beginLine()
+ .append("return new ")
+ .append(className)
+ .append("Wrapper(xService);")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("catch (const Exception& ex)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("// TODO: Log exception details")
+ .endLine()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"UNO exception in interface method\");")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .endBlock();
+}
+
+void CppProducer::generateCBridgeDestructor(CppFile& file, const OString& className,
+ const OString& functionPrefix,
+ const OString& handleTypeName)
+{
+ // Opaque destructor function - destroys interface instance
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Opaque destructor - destroys interface wrapper")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_destroy(")
+ .append(handleTypeName)
+ .append(" handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("delete static_cast<")
+ .append(className)
+ .append("Wrapper*>(handle);")
+ .endLine()
+ .endBlock();
+}
+
+void CppProducer::generateCBridgeValidation(CppFile& file, const OString& className,
+ const OString& functionPrefix,
+ const OString& handleTypeName)
+{
+ // Opaque validity check function
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Opaque validity check - tests if interface is valid")
+ .endLine()
+ .beginLine()
+ .append("bool ")
+ .append(functionPrefix)
+ .append("_is_valid(")
+ .append(handleTypeName)
+ .append(" handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (!handle) return false;")
+ .endLine()
+ .beginLine()
+ .append("return static_cast<")
+ .append(className)
+ .append("Wrapper*>(handle)->isValid();")
+ .endLine()
+ .endBlock();
+}
+
+void CppProducer::generateCBridgeMethods(CppFile& file, const OString& className,
+ const OString& functionPrefix,
+ const OString& handleTypeName,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ // Opaque method bridge functions - each method gets unique extern "C" function
+ for (const auto& method : entity->getDirectMethods())
+ {
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Opaque method bridge for ")
+ .append(method.name)
+ .endLine()
+ .beginLine()
+ .append(getMethodReturnType(method.returnType))
+ .append(" ")
+ .append(functionPrefix)
+ .append("_")
+ .append(method.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle");
+
+ // Use proper types instead of void* for parameters
+ for (const auto& param : method.parameters)
+ {
+ file.append(", ").append(getCppTypeName(param.type)).append(" ").append(param.name);
+ }
+
+ file.append(")")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (!handle) return ")
+ .append(getMethodDefaultReturn(method.returnType))
+ .append(";")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("auto* wrapper = static_cast<")
+ .append(className)
+ .append("Wrapper*>(handle);")
+ .endLine()
+ .beginLine()
+ .append("return wrapper->")
+ .append(method.name)
+ .append("(");
+
+ // Pass through all opaque parameters
+ bool first = true;
+ for (const auto& param : method.parameters)
+ {
+ if (!first)
+ file.append(", ");
+ first = false;
+ file.append(param.name);
+ }
+
+ file.append(");").endLine().endBlock();
+ }
+}
+
+void CppProducer::generateCBridge(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ CppFile file(m_outputDir, name);
+
+ if (m_dryRun)
+ return;
+
+ file.openFile();
+
+ // Generate file setup and includes
+ generateCBridgeIncludes(file, name, entity);
+
+ // Generate type definitions
+ OString className = getInterfaceClassName(name);
+ OString functionPrefix = getCFunctionPrefix(name);
+ OString handleTypeName = functionPrefix + "Handle";
+
+ generateCBridgeTypeDefinitions(file, handleTypeName);
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Generate constructor functions
+ generateCBridgeConstructors(file, className, functionPrefix, handleTypeName);
+
+ // Generate destructor function
+ generateCBridgeDestructor(file, className, functionPrefix, handleTypeName);
+
+ // Generate validation function
+ generateCBridgeValidation(file, className, functionPrefix, handleTypeName);
+
+ // Generate method bridge functions
+ generateCBridgeMethods(file, className, functionPrefix, handleTypeName, entity);
+
+ file.beginLine().append("").endLine();
+ file.endBlock().append(" // extern \"C\"");
+
+ file.closeFile();
+}
+
+void CppProducer::generateStructHeader(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ if (m_dryRun || !m_combinedHeaderFile)
+ return;
+
+ // Use combined file instead of individual file
+ CppFile& file = *m_combinedHeaderFile;
+ file.openFileAppend();
+
+ // Generate includes following the pattern used in generateStructSource
+ file.beginLine().append("#include <sal/types.h>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/Reference.hxx>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/Any.hxx>").endLine();
+ // Include the struct definition
+ std::string headerName(name);
+ std::replace(headerName.begin(), headerName.end(), '.', '/');
+ file.beginLine().append("#include <").append(headerName).append(".hpp>").endLine();
+ file.beginLine().append("").endLine();
+ file.beginLine().append("using namespace com::sun::star::uno;").endLine();
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+ // Add struct-specific namespace
+ std::string cppNamespace(name);
+ size_t lastDot = cppNamespace.rfind('.');
+ if (lastDot != std::string::npos)
+ {
+ cppNamespace = cppNamespace.substr(0, lastDot);
+ // Convert dots to double colons for C++ namespace syntax
+ size_t pos = 0;
+ while ((pos = cppNamespace.find('.', pos)) != std::string::npos)
+ {
+ cppNamespace.replace(pos, 1, "::");
+ pos += 2;
+ }
+ }
+
+ // Simple opaque struct bridge functions
+ OString functionPrefix = getCFunctionPrefix(name);
+ OString handleTypeName = functionPrefix + "Handle";
+ file.beginLine()
+ .append("// Opaque handle for type-safe C FFI")
+ .endLine()
+ .beginLine()
+ .append("typedef void* ")
+ .append(handleTypeName)
+ .append(";")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine();
+
+ file.beginLine()
+ .append("// Opaque struct creation")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_constructor();")
+ .endLine();
+
+ file.beginLine()
+ .append("// Opaque handle destruction")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_destroy(")
+ .append(handleTypeName)
+ .append(" handle);")
+ .endLine();
+
+ file.beginLine()
+ .append("// Struct from_ptr type casting")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_from_ptr(void* ptr);")
+ .endLine();
+
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("// Getters/setters for direct struct members")
+ .endLine();
+
+ // Opaque member access functions - each member gets getter/setter
+ for (const auto& member : entity->getDirectMembers())
+ {
+ file.beginLine()
+ .append("// Opaque getter for ")
+ .append(member.name)
+ .append(" (type: ")
+ .append(member.type)
+ .append(")")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void* ")
+ .append(functionPrefix)
+ .append("_get_")
+ .append(member.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle);")
+ .endLine();
+
+ file.beginLine()
+ .append("// Opaque setter for ")
+ .append(member.name)
+ .append(" (type: ")
+ .append(member.type)
+ .append(")")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_set_")
+ .append(member.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle, void* value);")
+ .endLine();
+ }
+ file.endBlock().append("// extern \"C\"").endLine();
+ file.closeFile();
+}
+
+// Unified include generation function to eliminate duplication
+void CppProducer::generateCommonIncludes(CppFile& file, std::string_view name, bool needsLogging,
+ bool needsUnoTypes)
+{
+ // Always include sal/types.h
+ file.beginLine().append("#include <sal/types.h>").endLine();
+
+ // Include logging if needed
+ if (needsLogging)
+ {
+ file.beginLine().append("#include <sal/log.hxx>").endLine();
+ }
+
+ // Include UNO types if needed
+ if (needsUnoTypes)
+ {
+ file.beginLine().append("#include <com/sun/star/uno/Reference.hxx>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/Any.hxx>").endLine();
+ }
+
+ // Include the type-specific header
+ std::string headerName(name);
+ std::replace(headerName.begin(), headerName.end(), '.', '/');
+ file.beginLine().append("#include <").append(headerName).append(".hpp>").endLine();
+ file.beginLine().append("").endLine();
+}
+
+void CppProducer::generateStructSourceIncludes(CppFile& file, std::string_view name)
+{
+ generateCommonIncludes(file, name, false, true);
+}
+
+void CppProducer::generateEnumIncludes(CppFile& file, std::string_view name)
+{
+ generateCommonIncludes(file, name, false, false);
+}
+
+void CppProducer::generateEnumSourceIncludes(CppFile& file, std::string_view name)
+{
+ generateCommonIncludes(file, name, true, false);
+}
+
+void CppProducer::generateEnumHeader(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>&)
+{
+ if (m_dryRun || !m_combinedHeaderFile)
+ return;
+
+ // Use combined file instead of individual file
+ CppFile& file = *m_combinedHeaderFile;
+ file.openFileAppend();
+
+ // Add separator comment for this enum
+ file.beginLine().append("").endLine();
+ file.beginLine().append("// === ").append(name).append(" ===").endLine();
+
+ // Generate includes in combined file
+ generateEnumIncludes(file, name);
+
+ // Generate extern "C" declarations
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Opaque enum conversion functions - treat enums as opaque values
+ OString enumName = convertUnoTypeToCpp(OUString::createFromAscii(std::string(name)));
+ OString functionPrefix = getCFunctionPrefix(name); // Use consistent double-underscore naming
+ file.beginLine()
+ .append(" SAL_DLLPUBLIC_EXPORT ")
+ .append(enumName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_from_i32(sal_Int32 value);")
+ .endLine();
+
+ file.beginLine()
+ .append(" SAL_DLLPUBLIC_EXPORT sal_Int32 ")
+ .append(functionPrefix)
+ .append("_to_i32(")
+ .append(enumName)
+ .append(" value);")
+ .endLine();
+
+ file.beginLine().append("}").endLine();
+
+ file.closeFile();
+}
+
+void CppProducer::generateEnumSource(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>&)
+{
+ if (m_dryRun || !m_combinedSourceFile)
+ return;
+
+ // Use combined file instead of individual file
+ CppFile& file = *m_combinedSourceFile;
+ file.openFileAppend();
+
+ // Add separator comment for this enum
+ file.beginLine().append("").endLine();
+ file.beginLine().append("// === ").append(name).append(" ===").endLine();
+
+ // Generate includes for source file
+ generateEnumSourceIncludes(file, name);
+
+ // Generate extern "C" implementations
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Opaque enum conversion functions implementations
+ OString enumName = convertUnoTypeToCpp(OUString::createFromAscii(std::string(name)));
+ OString functionPrefix = getCFunctionPrefix(name); // Use consistent double-underscore naming
+
+ // from_i32 implementation
+ file.beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(enumName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_from_i32(sal_Int32 value)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("return static_cast<")
+ .append(enumName)
+ .append(">(value);")
+ .endLine()
+ .endBlock();
+
+ // to_i32 implementation
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT sal_Int32 ")
+ .append(functionPrefix)
+ .append("_to_i32(")
+ .append(enumName)
+ .append(" value)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("return static_cast<sal_Int32>(value);")
+ .endLine()
+ .endBlock();
+
+ file.beginLine().append("}").endLine();
+
+ file.closeFile();
+}
+
+// Unified namespace generation function to eliminate duplication
+void CppProducer::generateSourceNamespaces(CppFile& file, std::string_view name)
+{
+ file.beginLine().append("using namespace com::sun::star::uno;").endLine();
+
+ // Add type-specific namespace
+ std::string cppNamespace(name);
+ size_t lastDot = cppNamespace.rfind('.');
+ if (lastDot != std::string::npos)
+ {
+ cppNamespace = cppNamespace.substr(0, lastDot);
+ // Convert dots to double colons for C++ namespace syntax
+ size_t pos = 0;
+ while ((pos = cppNamespace.find('.', pos)) != std::string::npos)
+ {
+ cppNamespace.replace(pos, 1, "::");
+ pos += 2;
+ }
+ file.beginLine().append("using namespace ").append(cppNamespace).append(";").endLine();
+ }
+ file.beginLine().append("").endLine();
+}
+
+void CppProducer::generateStructSourceNamespaces(CppFile& file, std::string_view name)
+{
+ generateSourceNamespaces(file, name);
+}
+
+void CppProducer::generateStructSourceBasicFunctions(CppFile& file, const OString& functionPrefix,
+ const OString& handleTypeName,
+ const std::string& className)
+{
+ // Generate struct creation function
+ file.beginLine()
+ .append("// Opaque struct creation")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_constructor()")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("return new ")
+ .append(className)
+ .append("();")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine();
+
+ // Generate struct destroy function
+ file.beginLine()
+ .append("// Opaque handle destruction")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_destroy(")
+ .append(handleTypeName)
+ .append(" handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("delete static_cast<")
+ .append(className)
+ .append("*>(handle);")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine();
+
+ // Generate from_ptr function for struct type casting
+ file.beginLine()
+ .append("// Struct from_ptr type casting")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_from_ptr(void* ptr)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (ptr == nullptr) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("// For structs, we assume the pointer is already the correct type")
+ .endLine()
+ .beginLine()
+ .append("// Create a copy of the struct")
+ .endLine()
+ .beginLine()
+ .append("")
+ .append(className)
+ .append("* source = static_cast<")
+ .append(className)
+ .append("*>(ptr);")
+ .endLine()
+ .beginLine()
+ .append("return new ")
+ .append(className)
+ .append("(*source);")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine();
+}
+
+void CppProducer::generateStructSourceBaseMembers(
+ CppFile& file, const OString& functionPrefix, const OString& handleTypeName,
+ const std::string& className, const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ // Generate getters/setters for base type members (if struct has a base)
+ if (!entity->getDirectBase().isEmpty())
+ {
+ file.beginLine()
+ .append("// Getters/setters for base type members (")
+ .append(entity->getDirectBase())
+ .append(")")
+ .endLine();
+
+ // Get base type entity to access its members
+ rtl::Reference<unoidl::Entity> baseEntity;
+ codemaker::UnoType::Sort baseSort
+ = m_typeManager->getSort(entity->getDirectBase(), &baseEntity);
+
+ if (baseSort == codemaker::UnoType::Sort::PlainStruct)
+ {
+ rtl::Reference<unoidl::PlainStructTypeEntity> baseStruct(
+ static_cast<unoidl::PlainStructTypeEntity*>(baseEntity.get()));
+
+ for (const auto& baseMember : baseStruct->getDirectMembers())
+ {
+ generateStructMemberAccessors(file, functionPrefix, handleTypeName, className,
+ baseMember);
+ }
+ }
+ }
+}
+
+void CppProducer::generateStructSourceDirectMembers(
+ CppFile& file, const OString& functionPrefix, const OString& handleTypeName,
+ const std::string& className, const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ // Generate getters/setters for direct struct members
+ file.beginLine().append("// Getters/setters for direct struct members").endLine();
+
+ for (const auto& member : entity->getDirectMembers())
+ {
+ generateStructMemberAccessors(file, functionPrefix, handleTypeName, className, member);
+ }
+}
+
+void CppProducer::generateStructMemberAccessors(CppFile& file, const OString& functionPrefix,
+ const OString& handleTypeName,
+ const std::string& className,
+ const unoidl::PlainStructTypeEntity::Member& member)
+{
+ // Generate getter implementation
+ file.beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void* ")
+ .append(functionPrefix)
+ .append("_get_")
+ .append(member.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append(className)
+ .append("* obj = static_cast<")
+ .append(className)
+ .append("*>(handle);")
+ .endLine()
+ .beginLine()
+ .append("return &(obj->")
+ .append(member.name)
+ .append(");")
+ .endLine()
+ .endBlock();
+
+ // Generate setter implementation
+ file.beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_set_")
+ .append(member.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle, void* value)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append(className)
+ .append("* obj = static_cast<")
+ .append(className)
+ .append("*>(handle);")
+ .endLine()
+ .beginLine()
+ .append("obj->")
+ .append(member.name);
+
+ // Check if this is a UNO interface type by checking the UNO type string
+ OUString unoType = member.type;
+ SAL_INFO("codemaker", "Struct member " << member.name << " UNO type: " << unoType);
+
+ // UNO interface types start with "com.sun.star" and end with an interface name (typically starting with "X")
+ // Examples: "com.sun.star.uno.XInterface", "com.sun.star.text.XText"
+ bool isInterfaceType = (unoType.startsWith("com.sun.star.") && (unoType.lastIndexOf('.') != -1)
+ && (unoType.copy(unoType.lastIndexOf('.') + 1).startsWith("X")));
+
+ if (isInterfaceType)
+ {
+ SAL_INFO("codemaker", "Detected UNO interface type, using pointer assignment");
+ // For interface types, assign the pointer directly without dereferencing
+ // The C++ struct expects Reference<Interface>, but we assign the raw interface pointer
+ file.append(" = reinterpret_cast<")
+ .append(convertUnoTypeToCpp(unoType))
+ .append("*>(value);");
+ }
+ else
+ {
+ SAL_INFO("codemaker", "Non-interface type, using dereferenced assignment");
+ // For non-interface types, dereference the pointer as before
+ file.append(" = *reinterpret_cast<const ")
+ .append(convertUnoTypeToCpp(unoType))
+ .append("*>(value);");
+ }
+ file.endLine().endBlock().beginLine().append("").endLine();
+}
+
+void CppProducer::generateStructSource(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ if (m_dryRun || !m_combinedSourceFile)
+ return;
+
+ // Use combined file instead of individual file
+ CppFile& file = *m_combinedSourceFile;
+ file.openFileAppend();
+
+ // Add separator comment for this struct
+ file.beginLine().append("").endLine();
+ file.beginLine().append("// === ").append(name).append(" ===").endLine();
+
+ // Start isolated block for this struct to avoid namespace conflicts
+ file.beginLine().append("namespace");
+ file.beginBlock();
+
+ // Generate includes
+ generateStructSourceIncludes(file, name);
+
+ // Generate namespaces (now in isolated scope)
+ generateStructSourceNamespaces(file, name);
+
+ OString functionPrefix = getCFunctionPrefix(name);
+ OString handleTypeName = functionPrefix + "Handle";
+ // Use fully qualified C++ type name to avoid namespace ambiguity
+ OString className = convertUnoTypeToCpp(OUString::createFromAscii(std::string(name)));
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Generate basic functions (creation/destruction)
+ generateStructSourceBasicFunctions(file, functionPrefix, handleTypeName, className.getStr());
+
+ // Generate accessors for base type members
+ generateStructSourceBaseMembers(file, functionPrefix, handleTypeName, className.getStr(),
+ entity);
+
+ // Generate accessors for direct members
+ generateStructSourceDirectMembers(file, functionPrefix, handleTypeName, className.getStr(),
+ entity);
+
+ file.endBlock().append(" // extern \"C\"").endLine();
+
+ // End isolated block for this struct
+ file.endBlock().append(" // End isolated block for ").append(name).endLine();
+
+ file.closeFile();
+}
+
+// Helper functions
+std::string_view CppProducer::splitName(std::string_view name)
+{
+ size_t split = name.find_last_of(".::");
+ if (split != std::string_view::npos)
+ return name.substr(split + 1);
+ else
+ return name;
+}
+
+OString CppProducer::getInterfaceClassName(std::string_view unoName)
+{
+ return OString(splitName(unoName));
+}
+
+OString CppProducer::getCFunctionPrefix(std::string_view unoName)
+{
+ // Convert com.sun.star.lang.XMain to com__sun__star__lang__XMain for function names
+ OString temp(unoName);
+ return temp.replaceAll(".", "__");
+}
+
+OString CppProducer::getMethodReturnType(std::u16string_view returnType) const
+{
+ // Use the sophisticated type mapping from the old FFI producer
+ return getCppTypeName(returnType);
+}
+
+OString CppProducer::getMethodDefaultReturn(std::u16string_view returnType) const
+{
+ // First resolve any typedefs to their underlying types
+ OUString resolvedType = resolveTypedef(returnType);
+
+ // Handle void vs non-void return types properly
+ if (resolvedType == u"void")
+ return ""; // void methods don't return anything
+
+ // Return appropriate default values for different types
+ if (resolvedType == u"double")
+ return "0.0";
+ else if (resolvedType == u"float")
+ return "0.0f";
+ else if (resolvedType == u"sal_Int32" || resolvedType == u"long" || resolvedType == u"sal_Int16"
+ || resolvedType == u"short" || resolvedType == u"sal_Int8" || resolvedType == u"byte"
+ || resolvedType == u"sal_uInt8" || resolvedType == u"sal_uInt16"
+ || resolvedType == u"sal_uInt32" || resolvedType == u"sal_Int64"
+ || resolvedType == u"sal_uInt64" || resolvedType == u"sal_Unicode"
+ || resolvedType == u"unsigned short" || resolvedType == u"unsigned long"
+ || resolvedType == u"unsigned hyper" || resolvedType == u"hyper")
+ return "0";
+ else if (resolvedType == u"sal_Bool" || resolvedType == u"boolean")
+ return "false";
+ else
+ {
+ // Check if it's an enum type
+ if (isUnoType(resolvedType) && isUnoEnum(resolvedType))
+ {
+ // Return default enum value (first enum value, typically 0)
+ OString returnTypeStr = u2b(resolvedType);
+ size_t lastDot = returnTypeStr.lastIndexOf('.');
+ std::string_view enumName = (lastDot != std::string_view::npos)
+ ? returnTypeStr.subView(lastDot + 1)
+ : returnTypeStr;
+ return "static_cast<"_ostr + enumName + "_>(0)"_ostr;
+ }
+ // Check if it's a struct type
+ else if (isUnoType(resolvedType) && isUnoStruct(resolvedType))
+ {
+ // Return empty struct for struct types
+ return OString("{}"); // Empty struct literal
+ }
+ else
+ {
+ return "nullptr"; // For pointer/interface/any types
+ }
+ }
+}
+
+OString CppProducer::convertUnoTypeToCpp(std::u16string_view unoType) const
+{
+ std::string result(unoType.begin(), unoType.end());
+
+ // Handle sequences: []type -> Sequence<type>
+ int sequenceDepth = 0;
+ while (result.starts_with("[]"))
+ {
+ result = result.substr(2);
+ sequenceDepth++;
+ }
+
+ // Check if the inner type is an interface and wrap with Reference<> if needed for sequences
+ bool needsReferenceWrapper = false;
+ if (sequenceDepth > 0 && result.find(".") != std::string::npos)
+ {
+ // For UNO types with namespaces, check if it's an interface (before namespace conversion)
+ rtl::Reference<unoidl::Entity> entity;
+ OUString unoTypeName = OUString::createFromAscii(result);
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(unoTypeName, &entity);
+
+ if (sort == codemaker::UnoType::Sort::Interface)
+ {
+ needsReferenceWrapper = true;
+ }
+ }
+
+ // Handle template arguments recursively (before namespace conversion)
+ result = convertTemplateArguments(result);
+
+ // Convert dots to double colons for C++ namespace syntax
+ size_t pos = 0;
+ while ((pos = result.find('.', pos)) != std::string::npos)
+ {
+ result.replace(pos, 1, "::");
+ pos += 2;
+ }
+
+ // Handle primitive types (only for non-template contexts)
+ if (result.find('<') == std::string::npos)
+ {
+ if (result == "boolean")
+ result = "sal_Bool";
+ else if (result == "byte")
+ result = "sal_Int8";
+ else if (result == "short")
+ result = "sal_Int16";
+ else if (result == "unsigned short")
+ result = "sal_uInt16";
+ else if (result == "long")
+ result = "sal_Int32";
+ else if (result == "unsigned long")
+ result = "sal_uInt32";
+ else if (result == "hyper")
+ result = "sal_Int64";
+ else if (result == "unsigned hyper")
+ result = "sal_uInt64";
+ else if (result == "float")
+ result = "float";
+ else if (result == "double")
+ result = "double";
+ else if (result == "char")
+ result = "sal_Unicode";
+ else if (result == "string")
+ result = "OUString";
+ else if (result == "type")
+ result = "Type";
+ else if (result == "any")
+ result = "Any";
+ // else: keep as-is for UNO types like com::sun::star::...
+ }
+
+ // Apply Reference<> wrapper if needed
+ if (needsReferenceWrapper)
+ {
+ result = "Reference<" + result + ">";
+ }
+
+ // Wrap with Sequence<> for each nesting level
+ for (int i = 0; i < sequenceDepth; i++)
+ {
+ result = "Sequence<" + result + ">";
+ }
+
+ return OString(result.c_str());
+}
+
+std::string CppProducer::convertTemplateArguments(const std::string& unoType) const
+{
+ std::string result = unoType;
+
+ // Find template arguments within < >
+ size_t start = result.find('<');
+ if (start == std::string::npos)
+ return result; // No template arguments
+
+ size_t end = result.rfind('>');
+ if (end == std::string::npos || end <= start)
+ return result; // Malformed template
+
+ // Extract and process template arguments
+ std::string prefix = result.substr(0, start + 1);
+ std::string suffix = result.substr(end);
+ std::string args = result.substr(start + 1, end - start - 1);
+
+ // Split arguments by comma (simple split for now)
+ std::string processedArgs = "";
+ size_t argStart = 0;
+ size_t comma = 0;
+
+ while (true)
+ {
+ comma = args.find(',', argStart);
+ std::string arg;
+ if (comma == std::string::npos)
+ {
+ arg = args.substr(argStart);
+ }
+ else
+ {
+ arg = args.substr(argStart, comma - argStart);
+ }
+
+ // Trim whitespace
+ arg.erase(0, arg.find_first_not_of(" \t"));
+ arg.erase(arg.find_last_not_of(" \t") + 1);
+
+ // Recursively process nested template arguments first
+ arg = convertTemplateArguments(arg);
+
+ // Handle sequence types first: []type -> Sequence<type>
+ if (arg.starts_with("[]"))
+ {
+ std::string innerType = arg.substr(2);
+ arg = "Sequence<" + innerType + ">";
+ }
+
+ // Convert basic types
+ if (arg == "string")
+ arg = "OUString";
+ else if (arg == "boolean")
+ arg = "sal_Bool";
+ else if (arg == "byte")
+ arg = "sal_Int8";
+ else if (arg == "short")
+ arg = "sal_Int16";
+ else if (arg == "long")
+ arg = "sal_Int32";
+ else if (arg == "hyper")
+ arg = "sal_Int64";
+ else if (arg == "float")
+ arg = "float";
+ else if (arg == "double")
+ arg = "double";
+ else if (arg == "char")
+ arg = "sal_Unicode";
+ else if (arg == "type")
+ arg = "Type";
+ else if (arg == "any")
+ arg = "Any";
+ // For complex types, convert dots to ::
+ else if (arg.find('.') != std::string::npos)
+ {
+ size_t pos = 0;
+ while ((pos = arg.find('.', pos)) != std::string::npos)
+ {
+ arg.replace(pos, 1, "::");
+ pos += 2;
+ }
+ }
+
+ if (!processedArgs.empty())
+ processedArgs += ",";
+ processedArgs += arg;
+
+ if (comma == std::string::npos)
+ break;
+ argStart = comma + 1;
+ }
+
+ return prefix + processedArgs + suffix;
+}
+
+void CppProducer::generateInterfaceHeader(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ if (m_dryRun || !m_combinedHeaderFile)
+ return;
+
+ // Use combined file instead of individual file
+ CppFile& file = *m_combinedHeaderFile;
+ file.openFileAppend();
+
+ // Add separator comment for this interface
+ file.beginLine().append("").endLine();
+ file.beginLine().append("// === ").append(name).append(" ===").endLine();
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Generate opaque handle typedef
+ OString functionPrefix = getCFunctionPrefix(name);
+ OString handleTypeName = functionPrefix + "Handle";
+
+ file.beginLine()
+ .append("// Opaque handle for type-safe C FFI")
+ .endLine()
+ .beginLine()
+ .append("typedef void* ")
+ .append(handleTypeName)
+ .append(";")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine();
+
+ // Generate create/destroy functions
+ file.beginLine()
+ .append("// Interface lifecycle")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_constructor();")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_destructor(")
+ .append(handleTypeName)
+ .append(" handle);")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_from_ptr(void* ptr);")
+ .endLine();
+
+ file.beginLine().append("").endLine();
+
+ // Generate method wrappers for all methods
+ file.beginLine().append("// Method wrappers").endLine();
+
+ // TODO: Add interface inheritance support in the future
+ // For now, only process direct methods from this interface
+
+ // Process only this interface's direct methods (no inheritance)
+ for (const auto& method : entity->getDirectMethods())
+ {
+ // Generate method signature
+ file.beginLine();
+
+ // Return type - use void* for all non-void returns (keep it simple)
+ OString returnType = getMethodReturnType(method.returnType);
+ if (returnType == "void")
+ {
+ file.append("SAL_DLLPUBLIC_EXPORT void ");
+ }
+ else
+ {
+ file.append("SAL_DLLPUBLIC_EXPORT void* ");
+ }
+
+ // Function name: com__sun__star__lang__XMain__methodName
+ file.append(functionPrefix)
+ .append("_")
+ .append(method.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle");
+
+ // Add parameters
+ for (const auto& param : method.parameters)
+ {
+ file.append(", void* ").append(param.name);
+ }
+
+ file.append(");");
+ file.endLine();
+ }
+
+ file.endBlock().beginLine().append("// extern \"C\"").endLine();
+
+ file.closeFile();
+}
+
+void CppProducer::generateInterfaceSourceIncludes(CppFile& file, std::string_view name)
+{
+ generateCommonIncludes(file, name, true, true);
+}
+
+void CppProducer::generateInterfaceSourceNamespaces(CppFile& file, std::string_view name)
+{
+ generateSourceNamespaces(file, name);
+}
+
+void CppProducer::generateInterfaceSourceBasicFunctions(CppFile& file,
+ const OString& functionPrefix,
+ const OString& className,
+ const OString& handleTypeName)
+{
+ // Interface creation
+ file.beginLine()
+ .append("// Interface creation - creates empty Reference (to be populated by Rust)")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_constructor()")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("//Debug: Interface constructor called for ")
+ .append(className)
+ .endLine()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"Debug: Creating interface ")
+ .append(className)
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("// Create empty Reference - actual interface will be set from Rust side")
+ .endLine()
+ .beginLine()
+ .append("auto res = new Reference<")
+ .append(className)
+ .append(">();")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!res)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rust_uno_ffi\", \"Failed to allocate Reference<")
+ .append(className)
+ .append("> wrapper\");")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append(
+ "// Note: Empty Reference is expected here - is() will be false until set from Rust")
+ .endLine()
+ .beginLine()
+ .append("SAL_INFO(\"rust_uno_ffi\", \"✅ Successfully created empty Reference<")
+ .append(className)
+ .append("> wrapper\");")
+ .endLine()
+ .beginLine()
+ .append("return res;")
+ .endLine()
+ .endBlock();
+
+ file.beginLine().append("").endLine();
+
+ // Interface destruction
+ file.beginLine()
+ .append("// Interface destruction")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void ")
+ .append(functionPrefix)
+ .append("_destructor(")
+ .append(handleTypeName)
+ .append(" handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("delete static_cast<Reference<")
+ .append(className)
+ .append(">*>(handle);")
+ .endLine()
+ .endBlock();
+ file.beginLine().append("").endLine();
+
+ // Interface casting from void* to typed Reference using UNO_QUERY
+ file.beginLine()
+ .append("// Interface casting - casts void* to typed Reference using UNO_QUERY")
+ .endLine()
+ .beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT ")
+ .append(handleTypeName)
+ .append(" ")
+ .append(functionPrefix)
+ .append("_from_ptr(void* ptr)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("if (ptr == nullptr) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("try")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("// Convert XInterface* to ")
+ .append(className)
+ .append(" via UNO_QUERY")
+ .endLine()
+ .beginLine()
+ .append("Reference<XInterface>* interfacePtr = static_cast<Reference<XInterface>*>(ptr);")
+ .endLine()
+ .beginLine()
+ .append("Reference<")
+ .append(className)
+ .append("> queryResult(interfacePtr->get(), UNO_QUERY);")
+ .endLine()
+ .beginLine()
+ .append("if (!queryResult.is()) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("Reference<")
+ .append(className)
+ .append(">* refPtr = new Reference<")
+ .append(className)
+ .append(">(queryResult);")
+ .endLine()
+ .beginLine()
+ .append("if (refPtr && refPtr->is())")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_INFO(\"rust_uno_ffi\", \"Successfully created Reference<")
+ .append(className)
+ .append("> in from_ptr\");")
+ .endLine()
+ .beginLine()
+ .append("return refPtr;")
+ .endBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rust_uno_ffi\", \"Reference is invalid in from_ptr for ")
+ .append(className)
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("delete refPtr;")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("catch (const Exception& e)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"UNO exception in ")
+ .append(functionPrefix)
+ .append("_from_ptr: \" << e.Message);")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .endBlock();
+
+ file.beginLine().append("").endLine();
+}
+
+void CppProducer::generateInterfaceSourceMethodImplementations(
+ CppFile& file, const OString& functionPrefix, const OString& className,
+ const OString& handleTypeName, const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ // Generate method implementations
+ file.beginLine().append("// Method implementations").endLine();
+
+ // TODO: Add interface inheritance support in the future
+ // For now, only process direct methods from this interface (no inheritance)
+
+ // Process only this interface's direct methods
+ for (const auto& method : entity->getDirectMethods())
+ {
+ generateSingleInterfaceMethod(file, functionPrefix, className, handleTypeName, method);
+ }
+}
+
+void CppProducer::generateSingleInterfaceMethod(CppFile& file, const OString& functionPrefix,
+ const OString& className,
+ const OString& handleTypeName,
+ const unoidl::InterfaceTypeEntity::Method& method)
+{
+ file.beginLine();
+
+ // Use void* for all non-void returns (keep it simple)
+ OString returnType = getMethodReturnType(method.returnType);
+ if (returnType == "void")
+ {
+ file.append("SAL_DLLPUBLIC_EXPORT void ");
+ }
+ else
+ {
+ file.append("SAL_DLLPUBLIC_EXPORT void* ");
+ }
+
+ file.append(functionPrefix)
+ .append("_")
+ .append(method.name)
+ .append("(")
+ .append(handleTypeName)
+ .append(" handle");
+
+ // Add parameters
+ for (const auto& param : method.parameters)
+ {
+ file.append(", void* ").append(param.name);
+ }
+
+ file.append(")").endLine().beginBlock();
+
+ // Implementation body
+ file.beginLine()
+ .append("//Debug: Method ")
+ .append(method.name)
+ .append(" called")
+ .endLine()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"Debug: Method ")
+ .append(className)
+ .append("::")
+ .append(method.name)
+ .append(" called\");")
+ .endLine()
+ .beginLine()
+ .append("Reference<")
+ .append(className)
+ .append(">* ref = static_cast<Reference<")
+ .append(className)
+ .append(">*>(handle);")
+ .endLine()
+ .beginLine()
+ .append("//Debug: Checking reference validity")
+ .endLine()
+ .beginLine()
+ .append("if (!ref) { SAL_WARN(\"rustmaker\", \"Debug: ref is null\"); ")
+ .append(method.returnType == u"void" ? "return;" : "return nullptr;")
+ .append(" }")
+ .endLine()
+ .beginLine()
+ .append("if (!ref->is()) { SAL_WARN(\"rustmaker\", \"Debug: ref->is() is false\"); ")
+ .append(method.returnType == u"void" ? "return;" : "return nullptr;")
+ .append(" }")
+ .endLine();
+
+ // Generate try-catch block for UNO exceptions
+ file.beginLine().append("try").endLine().beginBlock();
+
+ // Generate actual UNO method call
+ generateActualMethodCall(file, method);
+
+ // Note: Return value conversion is now handled inside generateActualMethodCall()
+
+ // Exception handling
+ file.endBlock()
+ .beginLine()
+ .append("catch (const Exception& ex)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"UNO exception in ")
+ .append(className)
+ .append("_")
+ .append(method.name)
+ .append(": \" << ex.Message);")
+ .endLine();
+
+ // Return appropriate error value based on return type
+ if (method.returnType == u"void")
+ {
+ file.beginLine().append("return; // void method - no return on exception").endLine();
+ }
+ else
+ {
+ file.beginLine().append("return nullptr; // error return for non-void method").endLine();
+ }
+
+ file.endBlock().endBlock();
+
+ file.beginLine().append("").endLine();
+}
+
+void CppProducer::generateInterfaceSource(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ if (m_dryRun || !m_combinedSourceFile)
+ return;
+
+ // Use combined file instead of individual file
+ CppFile& file = *m_combinedSourceFile;
+ file.openFileAppend();
+
+ // Add separator comment for this interface
+ file.beginLine().append("").endLine();
+ file.beginLine().append("// === ").append(name).append(" ===").endLine();
+
+ // Generate includes
+ generateInterfaceSourceIncludes(file, name);
+
+ // Add namespaces
+ generateInterfaceSourceNamespaces(file, name);
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+
+ // Generate implementation
+ OString functionPrefix = getCFunctionPrefix(name);
+ OString handleTypeName = functionPrefix + "Handle";
+ // Use fully qualified C++ type name to avoid namespace ambiguity
+ OString className = convertUnoTypeToCpp(OUString::createFromAscii(std::string(name)));
+
+ // Generate basic functions (creation/destruction)
+ generateInterfaceSourceBasicFunctions(file, functionPrefix, className, handleTypeName);
+
+ // Generate method implementations
+ generateInterfaceSourceMethodImplementations(file, functionPrefix, className, handleTypeName,
+ entity);
+
+ file.endBlock().append(" // extern \"C\"");
+ file.beginLine().append("").endLine();
+
+ file.closeFile();
+}
+
+void CppProducer::generateActualMethodCall(CppFile& file,
+ const unoidl::InterfaceTypeEntity::Method& method)
+{
+ // Generate actual UNO method call based on method signature
+ file.beginLine()
+ .append("//Debug: About to call UNO method ")
+ .append(method.name)
+ .endLine()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"Debug: Calling UNO method ")
+ .append(method.name)
+ .append(" with ")
+ .append(OString::number(static_cast<sal_Int32>(method.parameters.size())))
+ .append(" parameters\");")
+ .endLine();
+
+ if (method.returnType != u"void")
+ {
+ // Method with return value
+ file.beginLine()
+ .append("// Call actual UNO method with return value")
+ .endLine()
+ .beginLine();
+
+ file.append("auto result = (*ref)->").append(method.name).append("(");
+ }
+ else
+ {
+ // Void method
+ file.beginLine().append("// Call actual UNO method (void return)").endLine().beginLine();
+
+ file.append("(*ref)->").append(method.name).append("(");
+ }
+
+ // Add parameters with proper type conversion
+ bool first = true;
+ for (const auto& param : method.parameters)
+ {
+ if (!first)
+ file.append(", ");
+ first = false;
+
+ // Convert void* parameters to proper UNO types based on parameter type
+ std::u16string_view paramType = param.type;
+
+ // Determine if parameter is input-only (needs const) or output/inout (needs non-const reference)
+ bool isInputOnly
+ = (param.direction == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN);
+
+ if (paramType == u"string")
+ {
+ if (isInputOnly)
+ {
+ // Input parameter: convert rtl_uString* to OUString object
+ file.append("OUString(static_cast<rtl_uString*>(").append(param.name).append("))");
+ }
+ else
+ {
+ // Output parameter: needs OUString reference for binding
+ file.append("*reinterpret_cast<OUString*>(").append(param.name).append(")");
+ }
+ }
+ else if (paramType == u"any")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const Any*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<Any*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"boolean")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const sal_Bool*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<sal_Bool*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"byte")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const sal_Int8*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<sal_Int8*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"short")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const sal_Int16*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<sal_Int16*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"long")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const sal_Int32*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<sal_Int32*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"hyper")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const sal_Int64*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<sal_Int64*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"float")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const float*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<float*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"double")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const double*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<double*>(").append(param.name).append(")");
+ }
+ else if (paramType == u"type")
+ {
+ if (isInputOnly)
+ file.append("*reinterpret_cast<const Type*>(").append(param.name).append(")");
+ else
+ file.append("*reinterpret_cast<Type*>(").append(param.name).append(")");
+ }
+ else if (paramType.starts_with(u"[]"))
+ {
+ // Sequence type - convert with null pointer safety
+ OString cppTypeName = convertUnoTypeToCpp(paramType);
+
+ if (isInputOnly)
+ {
+ // Input parameter - can use temporary empty sequence
+ file.append("(")
+ .append(param.name)
+ .append(" ? *reinterpret_cast<const ")
+ .append(cppTypeName)
+ .append("*>(")
+ .append(param.name)
+ .append(") : ")
+ .append(cppTypeName)
+ .append("())");
+ }
+ else
+ {
+ // Output/InOut parameter - needs reference, must dereference non-null pointer
+ file.append("*reinterpret_cast<")
+ .append(cppTypeName)
+ .append("*>(")
+ .append(param.name)
+ .append(")");
+ }
+ }
+ else
+ {
+ // For interfaces and other complex types
+ // Check if it's an interface type that needs Reference<> wrapper
+ rtl::Reference<unoidl::Entity> entity;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(paramType), &entity);
+
+ if (sort == codemaker::UnoType::Sort::Interface)
+ {
+ // Interface parameters: void* from Rust points to Reference<ActualType>*
+ // We need to dereference and cast via UNO_QUERY to the expected interface type
+ OString cppTypeName = convertUnoTypeToCpp(paramType);
+ if (isInputOnly)
+ {
+ // For input interface parameters, we assume the Rust code passes Reference<SomeInterface>*
+ // We dereference it and cast via UNO_QUERY to the expected interface type
+ file.append("Reference<")
+ .append(cppTypeName)
+ .append(">(static_cast<Reference<XInterface>*>(")
+ .append(param.name)
+ .append(")->get(), UNO_QUERY)");
+ }
+ else
+ file.append("*reinterpret_cast<Reference<")
+ .append(cppTypeName)
+ .append(">*>(")
+ .append(param.name)
+ .append(")");
+ }
+ else
+ {
+ // For structs and other complex types, assume proper type cast
+ OString cppTypeName = convertUnoTypeToCpp(paramType);
+ if (isInputOnly)
+ {
+ file.append("(")
+ .append(param.name)
+ .append(" == nullptr ? ")
+ .append(cppTypeName)
+ .append("() : *reinterpret_cast<const ")
+ .append(cppTypeName)
+ .append("*>(")
+ .append(param.name)
+ .append("))");
+ }
+ else
+ {
+ file.append("*reinterpret_cast<")
+ .append(cppTypeName)
+ .append("*>(")
+ .append(param.name)
+ .append(")");
+ }
+ }
+ }
+ }
+
+ file.append(");").endLine();
+
+ // Handle return value conversion for non-void methods
+ if (method.returnType != u"void")
+ {
+ file.beginLine().append("// Convert result to opaque void* return").endLine();
+
+ std::u16string_view returnType = method.returnType;
+
+ if (returnType == u"string")
+ {
+ file.beginLine().append("return new OUString(result);").endLine();
+ }
+ else if (returnType == u"any")
+ {
+ file.beginLine().append("return new Any(result);").endLine();
+ }
+ else if (returnType == u"boolean")
+ {
+ file.beginLine().append("return new sal_Bool(result);").endLine();
+ }
+ else if (returnType == u"byte")
+ {
+ file.beginLine().append("return new sal_Int8(result);").endLine();
+ }
+ else if (returnType == u"short")
+ {
+ file.beginLine().append("return new sal_Int16(result);").endLine();
+ }
+ else if (returnType == u"long")
+ {
+ file.beginLine().append("return new sal_Int32(result);").endLine();
+ }
+ else if (returnType == u"hyper")
+ {
+ file.beginLine().append("return new sal_Int64(result);").endLine();
+ }
+ else if (returnType == u"float")
+ {
+ file.beginLine().append("return new float(result);").endLine();
+ }
+ else if (returnType == u"double")
+ {
+ file.beginLine().append("return new double(result);").endLine();
+ }
+ else if (returnType == u"type")
+ {
+ file.beginLine().append("return new Type(result);").endLine();
+ }
+ else if (returnType.starts_with(u"[]"))
+ {
+ // Sequence return type
+ file.beginLine()
+ .append("return new ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("(result);")
+ .endLine();
+ }
+ else
+ {
+ // For interfaces and other complex types, create appropriate wrapper
+ // Check if it's an interface type
+ rtl::Reference<unoidl::Entity> entity;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(returnType), &entity);
+
+ if (sort == codemaker::UnoType::Sort::Interface)
+ {
+ // Add debug output for interface return values
+ file.beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"Debug: UNO method ")
+ .append(method.name)
+ .append(
+ " completed, result.is() = \" << (result.is() ? \"true\" : \"false\"));")
+ .endLine()
+ .beginLine()
+ .append("SAL_INFO(\"rust_uno_ffi\", \"Creating new Reference<")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("> wrapper for method ")
+ .append(method.name)
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("auto res = new Reference<")
+ .append(convertUnoTypeToCpp(returnType))
+ .append(">(result);")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!res)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rust_uno_ffi\", \"Failed to create Reference wrapper for ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append(" in method ")
+ .append(method.name)
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!res->is())")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rust_uno_ffi\", \"Reference wrapper is invalid (is() = "
+ "false) for ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append(" in method ")
+ .append(method.name)
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("delete res;")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("SAL_INFO(\"rust_uno_ffi\", \"✅ Successfully created valid Reference "
+ "wrapper for ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append(" in method ")
+ .append(method.name)
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("return res;")
+ .endLine();
+ }
+ else
+ {
+ // For structs and other types
+ file.beginLine()
+ .append("return new ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("(result);")
+ .endLine();
+ }
+ }
+ }
+}
+
+void CppProducer::generateReturnValueConversion(CppFile& file,
+ const unoidl::InterfaceTypeEntity::Method& method)
+{
+ file.beginLine().append("// Convert result to opaque void* return").endLine();
+
+ std::u16string_view returnType = method.returnType;
+
+ if (returnType == u"string")
+ {
+ file.beginLine().append("return new OUString(result);").endLine();
+ }
+ else if (returnType == u"any")
+ {
+ file.beginLine().append("return new Any(result);").endLine();
+ }
+ else if (returnType == u"boolean")
+ {
+ file.beginLine().append("return new sal_Bool(result);").endLine();
+ }
+ else if (returnType == u"byte")
+ {
+ file.beginLine().append("return new sal_Int8(result);").endLine();
+ }
+ else if (returnType == u"short")
+ {
+ file.beginLine().append("return new sal_Int16(result);").endLine();
+ }
+ else if (returnType == u"long")
+ {
+ file.beginLine().append("return new sal_Int32(result);").endLine();
+ }
+ else if (returnType == u"hyper")
+ {
+ file.beginLine().append("return new sal_Int64(result);").endLine();
+ }
+ else if (returnType == u"float")
+ {
+ file.beginLine().append("return new float(result);").endLine();
+ }
+ else if (returnType == u"double")
+ {
+ file.beginLine().append("return new double(result);").endLine();
+ }
+ else if (returnType == u"type")
+ {
+ file.beginLine().append("return new Type(result);").endLine();
+ }
+ else if (returnType.starts_with(u"[]"))
+ {
+ // Sequence return type - return void* to new sequence
+ file.beginLine()
+ .append("return new ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("(result);")
+ .endLine();
+ }
+ else
+ {
+ // For interfaces - return Reference<> to avoid instantiating abstract types
+ rtl::Reference<unoidl::Entity> entity;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(returnType), &entity);
+
+ if (sort == codemaker::UnoType::Sort::Interface)
+ {
+ // Interface return type - return new Reference<Interface>(result)
+ file.beginLine()
+ .append("SAL_INFO(\"rust_uno_ffi\", \"Creating Reference wrapper for return type ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("auto res = new Reference<")
+ .append(convertUnoTypeToCpp(returnType))
+ .append(">(result);")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!res)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rust_uno_ffi\", \"Failed to create Reference wrapper for ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!res->is())")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append(
+ "SAL_WARN(\"rust_uno_ffi\", \"Reference wrapper is invalid (is() = false) for ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("delete res;")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("SAL_INFO(\"rust_uno_ffi\", \"✅ Successfully created valid Reference "
+ "wrapper for ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("\");")
+ .endLine()
+ .beginLine()
+ .append("return res;")
+ .endLine();
+ }
+ else
+ {
+ // For structs, enums and other types - return void* to new object
+ file.beginLine()
+ .append("return new ")
+ .append(convertUnoTypeToCpp(returnType))
+ .append("(result);")
+ .endLine();
+ }
+ }
+}
+
+// Type mapping functions (from old FFI producer)
+
+OUString CppProducer::resolveTypedef(std::u16string_view unoType) const
+{
+ // Recursively resolve typedefs to their underlying types
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(unoType), &entity, &cursor);
+
+ if (sort == codemaker::UnoType::Sort::Typedef)
+ {
+ rtl::Reference<unoidl::TypedefEntity> typedefEntity(
+ static_cast<unoidl::TypedefEntity*>(entity.get()));
+ if (typedefEntity.is())
+ {
+ // Recursively resolve in case of nested typedefs
+ OUString resolvedType = typedefEntity->getType();
+ return resolveTypedef(resolvedType);
+ }
+ }
+
+ // If not a typedef or resolution failed, return the original type
+ return OUString(unoType);
+}
+
+OString CppProducer::mapUnoPrimitiveToSal(std::u16string_view unoType) const
+{
+ // Common primitive type mappings from UNO to SAL types
+ if (unoType == u"boolean")
+ return "sal_Bool"_ostr;
+ else if (unoType == u"byte")
+ return "sal_Int8"_ostr;
+ else if (unoType == u"short")
+ return "sal_Int16"_ostr;
+ else if (unoType == u"unsigned short")
+ return "sal_uInt16"_ostr;
+ else if (unoType == u"long")
+ return "sal_Int32"_ostr;
+ else if (unoType == u"unsigned long")
+ return "sal_uInt32"_ostr;
+ else if (unoType == u"hyper")
+ return "sal_Int64"_ostr;
+ else if (unoType == u"unsigned hyper")
+ return "sal_uInt64"_ostr;
+ else if (unoType == u"float")
+ return "float"_ostr;
+ else if (unoType == u"double")
+ return "double"_ostr;
+ else
+ return OString(); // Not a primitive type
+}
+
+OString CppProducer::getCppTypeName(std::u16string_view unoType) const
+{
+ // First, resolve any typedefs to their underlying types
+ OUString resolvedType = resolveTypedef(unoType);
+
+ // Map UNO types to C++ types for extern "C" functions
+ if (resolvedType == u"void")
+ return "void"_ostr;
+ else if (resolvedType == u"string")
+ return "rtl_uString*"_ostr;
+ else if (resolvedType == u"any" || resolvedType == u"com.sun.star.uno.Any")
+ return "uno_Any*"_ostr;
+
+ // Try primitive type mapping
+ OString primitiveType = mapUnoPrimitiveToSal(resolvedType);
+ if (!primitiveType.isEmpty())
+ return primitiveType;
+
+ // Handle complex types
+ if (resolvedType.startsWith(u"[]"))
+ return "uno_Sequence*"_ostr;
+ else if (isUnoStruct(resolvedType))
+ {
+ // For structs, return the FFI struct name with underscore (value type, not pointer)
+ OString type = u2b(resolvedType);
+ size_t lastDot = type.lastIndexOf('.');
+ if (lastDot != std::string_view::npos)
+ return OString::Concat(type.subView(lastDot + 1)) + "_";
+ else
+ return type + "_";
+ }
+ else if (isUnoEnum(resolvedType))
+ {
+ // For enums, return the enum name with underscore to match generated FFI enums
+ OString type = u2b(resolvedType);
+ size_t lastDot = type.lastIndexOf('.');
+ if (lastDot != std::string_view::npos)
+ return OString::Concat(type.subView(lastDot + 1)) + "_";
+ else
+ return type + "_";
+ }
+ else if (isUnoConstantGroup(resolvedType))
+ {
+ // For constant groups, return the FFI name with underscore
+ OString type = u2b(resolvedType);
+ size_t lastDot = type.lastIndexOf('.');
+ if (lastDot != std::string_view::npos)
+ return OString::Concat(type.subView(lastDot + 1)) + "_";
+ else
+ return type + "_";
+ }
+ else if (isUnoType(resolvedType))
+ {
+ // For interfaces and other types, return XInterface* pointer
+ return "XInterface*"_ostr;
+ }
+ else
+ return "void*"_ostr; // Default to void* for unknown types
+}
+
+OString CppProducer::getRustFFITypeName(std::u16string_view unoType) const
+{
+ // Map UNO types to Rust FFI types
+ if (unoType == u"string")
+ return "*mut rtl_uString"_ostr;
+ else if (unoType == u"boolean")
+ return "u8"_ostr; // sal_Bool is typedef'd to u8 (unsigned char)
+ else if (unoType == u"byte")
+ return "i8"_ostr;
+ else if (unoType == u"short")
+ return "i16"_ostr;
+ else if (unoType == u"unsigned short")
+ return "u16"_ostr;
+ else if (unoType == u"long")
+ return "i32"_ostr;
+ else if (unoType == u"unsigned long")
+ return "u32"_ostr;
+ else if (unoType == u"hyper")
+ return "i64"_ostr;
+ else if (unoType == u"unsigned hyper")
+ return "u64"_ostr;
+ else if (unoType == u"float")
+ return "f32"_ostr;
+ else if (unoType == u"double")
+ return "f64"_ostr;
+ else if (unoType == u"void")
+ return "()"_ostr;
+ else if (unoType == u"any" || unoType == u"com.sun.star.uno.Any")
+ return "*mut uno_Any"_ostr; // UNO Any type
+ else if (isUnoStruct(unoType))
+ {
+ // For structs, return just the struct name with underscore since we import it
+ OString type = u2b(unoType);
+ size_t lastDot = type.lastIndexOf('.');
+ if (lastDot != std::string_view::npos)
+ return OString::Concat(type.subView(lastDot + 1)) + "_";
+ else
+ return type + "_";
+ }
+ else if (isUnoEnum(unoType))
+ {
+ // For enums, return just the enum name since we import it
+ OString type = u2b(unoType);
+ size_t lastDot = type.lastIndexOf('.');
+ if (lastDot != std::string_view::npos)
+ return OString(type.subView(lastDot + 1));
+ else
+ return type;
+ }
+ else if (isUnoConstantGroup(unoType))
+ {
+ // For constant groups, return the constant group name with underscore to match C++ side
+ OString type = u2b(unoType);
+ size_t lastDot = type.lastIndexOf('.');
+ if (lastDot != std::string_view::npos)
+ return OString::Concat(type.subView(lastDot + 1)) + "_";
+ else
+ return type + "_";
+ }
+ else if (isUnoType(unoType))
+ {
+ // For interfaces, return *mut XInterface pointer
+ return "*mut XInterface"_ostr;
+ }
+ else
+ return "*mut std::ffi::c_void"_ostr; // Default for unknown types
+}
+
+OString CppProducer::convertBasicType(const OString& typeName) const
+{
+ OString result = typeName;
+
+ // Convert UNO primitive types to C++ types
+ if (result == "long")
+ result = "sal_Int32";
+ else if (result == "short")
+ result = "sal_Int16";
+ else if (result == "byte")
+ result = "sal_Int8";
+ else if (result == "boolean")
+ result = "sal_Bool";
+ else if (result == "double")
+ result = "double";
+ else if (result == "float")
+ result = "float";
+ else if (result == "string")
+ result = "OUString";
+ else if (result == "any")
+ result = "Any";
+ else if (result.indexOf('.') != -1)
+ {
+ // For UNO types with namespace, convert dots to double colons
+ result = result.replaceAll(".", "::");
+ }
+
+ return result;
+}
+
+// Type classification helper methods
+
+bool CppProducer::isUnoType(std::u16string_view typeName) const
+{
+ // Check if this is a valid UNO type using TypeManager
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+
+ // Return true for any valid UNO type (not just interfaces/structs/enums)
+ return sort != codemaker::UnoType::Sort::Void && sort != codemaker::UnoType::Sort::Boolean
+ && sort != codemaker::UnoType::Sort::Byte && sort != codemaker::UnoType::Sort::Short
+ && sort != codemaker::UnoType::Sort::UnsignedShort
+ && sort != codemaker::UnoType::Sort::Long
+ && sort != codemaker::UnoType::Sort::UnsignedLong
+ && sort != codemaker::UnoType::Sort::Hyper
+ && sort != codemaker::UnoType::Sort::UnsignedHyper
+ && sort != codemaker::UnoType::Sort::Float && sort != codemaker::UnoType::Sort::Double
+ && sort != codemaker::UnoType::Sort::Char && sort != codemaker::UnoType::Sort::String
+ && sort != codemaker::UnoType::Sort::Type && sort != codemaker::UnoType::Sort::Any;
+}
+
+bool CppProducer::isUnoStruct(std::u16string_view typeName) const
+{
+ // Check the type sort using TypeManager
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+
+ // Return true if it's a plain struct or polymorphic struct template
+ return (sort == codemaker::UnoType::Sort::PlainStruct);
+}
+
+bool CppProducer::isUnoEnum(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::Enum;
+}
+
+bool CppProducer::isUnoPolymorphicStruct(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::PolymorphicStructTemplate;
+}
+
+bool CppProducer::isUnoConstantGroup(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::ConstantGroup;
+}
+
+bool CppProducer::isUnoInterface(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::Interface;
+}
+
+OString CppProducer::convertUnoTypeToHandle(std::u16string_view unoType) const
+{
+ // Convert UNO type name to typedef handle name
+ // com.sun.star.lang.XMain -> com__sun__star__lang__XMainHandle
+ OString functionPrefix = getCFunctionPrefix(std::string(unoType.begin(), unoType.end()));
+ return functionPrefix + "Handle";
+}
+
+void CppProducer::generateServiceHeader(
+ std::string_view name, const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity)
+{
+ if (m_dryRun || !m_combinedHeaderFile)
+ return;
+
+ CppFile& file = *m_combinedHeaderFile;
+ file.openFileAppend();
+
+ // Add pragma once for header guard
+ file.beginLine().append("#pragma once").endLine().endLine();
+
+ // Include the service's interface
+ OUString interfaceType = entity->getBase();
+ std::string includePath(u2b(interfaceType));
+ std::replace(includePath.begin(), includePath.end(), '.', '/');
+ file.beginLine().append("#include <").append(includePath).append(".hpp>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/XComponentContext.hpp>").endLine();
+ file.beginLine().append("#include <com/sun/star/uno/Reference.hxx>").endLine();
+ file.endLine();
+
+ // Generate extern "C" declarations for service creation
+ OString functionPrefix = getCFunctionPrefix(name); // Use consistent double-underscore naming
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+ file.beginLine().append(" // Service creation functions for ").append(name).endLine();
+ file.beginLine()
+ .append(" SAL_DLLPUBLIC_EXPORT void* ")
+ .append(functionPrefix)
+ .append("_create(void* context_handle);")
+ .endLine();
+ file.beginLine().append("}").endLine();
+
+ file.closeFile();
+}
+
+void CppProducer::generateServiceSource(
+ std::string_view name, const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity)
+{
+ if (m_dryRun || !m_combinedSourceFile)
+ return;
+
+ CppFile& file = *m_combinedSourceFile;
+ file.openFileAppend();
+
+ // Include the header
+ std::string headerPath(name);
+ std::replace(headerPath.begin(), headerPath.end(), '.', '/');
+ file.beginLine().append("#include <com/sun/star/lang/XMultiComponentFactory.hpp>").endLine();
+ file.beginLine().append("#include <sal/log.hxx>").endLine();
+ file.endLine();
+
+ // Services don't need namespace declarations - use fully qualified names instead
+
+ // Generate service creation function
+ OString functionPrefix = getCFunctionPrefix(name); // Use consistent double-underscore naming
+ OUString interfaceType = entity->getBase();
+ std::string interfaceCppType(u2b(interfaceType));
+ std::replace(interfaceCppType.begin(), interfaceCppType.end(), '.', ':');
+ // Fix single colons to double colons for C++ namespace syntax
+ size_t colonPos = 0;
+ while ((colonPos = interfaceCppType.find(":", colonPos)) != std::string::npos)
+ {
+ if (colonPos == 0 || interfaceCppType[colonPos - 1] != ':')
+ {
+ interfaceCppType.insert(colonPos, ":");
+ colonPos += 2;
+ }
+ else
+ {
+ colonPos++;
+ }
+ }
+ if (!interfaceCppType.empty() && interfaceCppType.substr(0, 2) != "::")
+ {
+ interfaceCppType = "::" + interfaceCppType;
+ }
+
+ file.beginLine().append("extern \"C\"").endLine().beginBlock();
+ file.beginLine()
+ .append("SAL_DLLPUBLIC_EXPORT void* ")
+ .append(functionPrefix)
+ .append("_create(void* context_handle)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("try")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("Reference<com::sun::star::uno::XComponentContext>* ctx = "
+ "static_cast<Reference<com::sun::star::uno::XComponentContext>*>(context_handle);")
+ .endLine()
+ .beginLine()
+ .append("if (!ctx || !ctx->is()) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("Reference<com::sun::star::lang::XMultiComponentFactory> factory = "
+ "(*ctx)->getServiceManager();")
+ .endLine()
+ .beginLine()
+ .append("if (!factory.is()) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("Reference<")
+ .append("com::sun::star::uno::XInterface")
+ .append("> service = Reference<")
+ .append("com::sun::star::uno::XInterface")
+ .append(">(")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("factory->createInstanceWithContext(\"")
+ .append(name)
+ .append("\", *ctx), UNO_QUERY);")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("if (!service.is()) return nullptr;")
+ .endLine()
+ .beginLine()
+ .append("return new Reference<")
+ .append("com::sun::star::uno::XInterface")
+ .append(">(service);")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("catch (const Exception& ex)")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("SAL_WARN(\"rustmaker\", \"Service creation failed for ")
+ .append(name)
+ .append(": \" << ex.Message);")
+ .endLine()
+ .beginLine()
+ .append("return nullptr;")
+ .endLine()
+ .endBlock()
+ .endBlock();
+ file.beginLine().append("}").endLine();
+
+ file.closeFile();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/cpproduce.hxx b/codemaker/source/rustmaker/cpproduce.hxx
new file mode 100644
index 000000000000..8c9aa50447da
--- /dev/null
+++ b/codemaker/source/rustmaker/cpproduce.hxx
@@ -0,0 +1,225 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+#include <unoidl/unoidl.hxx>
+#include <codemaker/typemanager.hxx>
+#include <rtl/string.hxx>
+
+// Forward declarations
+class CppFile;
+
+/**
+ * CppProducer generates C++-side opaque pointer implementations.
+ *
+ * This is the C-side generator in the opaque pointer approach.
+ * It creates C++ wrapper classes and extern "C" bridge functions
+ * that the Rust-side can call through opaque pointers.
+ *
+ * Architecture:
+ * - C++ wrapper classes that hide UNO complexity
+ * - extern "C" bridge functions with unique names
+ * - Simple void* pointer casting for opaque compatibility
+ * - All UNO complexity isolated in C++ side
+ */
+class CppProducer
+{
+public:
+ /**
+ * Constructor
+ * @param outputDir Directory for generated C++ files
+ * @param verbose Enable verbose output
+ * @param dryRun Don't actually write files
+ * @param typeManager UNO type manager for accessing type information
+ */
+ CppProducer(const OString& outputDir, bool verbose, bool dryRun,
+ const rtl::Reference<TypeManager>& typeManager);
+
+ /**
+ * Initialize the single combined output file
+ */
+ void initializeCombinedFile();
+
+ /**
+ * Finalize and close the single combined output file
+ */
+ void finalizeCombinedFile();
+
+ /**
+ * Generate C++ opaque enum bridge
+ * Creates conversion functions between enum and integers
+ */
+ void produceEnum(std::string_view name, const rtl::Reference<unoidl::EnumTypeEntity>& entity);
+
+ /**
+ * Generate C++ opaque struct bridge
+ * Creates wrapper class and field accessor functions
+ */
+ void produceStruct(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+
+ /**
+ * Generate C++ opaque interface bridge
+ * Creates wrapper class and method bridge functions
+ */
+ void produceInterface(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+
+ /**
+ * Generate C++ opaque service bridge
+ * Creates service creation bridge functions
+ */
+ void produceService(std::string_view name,
+ const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity);
+
+private:
+ // Configuration
+ OString m_outputDir;
+ bool m_verbose;
+ bool m_dryRun;
+ rtl::Reference<TypeManager> m_typeManager;
+
+ // Combined output files
+ std::unique_ptr<CppFile> m_combinedSourceFile; // .cxx file
+ std::unique_ptr<CppFile> m_combinedHeaderFile; // .hxx file
+
+ // ========================================================================
+ // CORE TYPE GENERATION METHODS
+ // ========================================================================
+ void generateStructWrapper(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+ void generateEnumBridge(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity);
+ void generateStructBridge(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+ void generateCBridge(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+
+ void generateStructHeader(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+ void generateStructSource(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+
+ void generateInterfaceHeader(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+ void generateInterfaceSource(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+
+ void generateEnumHeader(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity);
+ void generateEnumSource(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity);
+
+ void
+ generateServiceHeader(std::string_view name,
+ const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity);
+ void
+ generateServiceSource(std::string_view name,
+ const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity);
+
+ // ========================================================================
+ // FILE GENERATION UTILITIES
+ // ========================================================================
+ // Unified include and namespace generation (eliminates duplication)
+ void generateCommonIncludes(CppFile& file, std::string_view name, bool needsLogging = false,
+ bool needsUnoTypes = false);
+ void generateSourceNamespaces(CppFile& file, std::string_view name);
+
+ // Legacy functions (maintained for existing calls)
+ void generateStructSourceIncludes(CppFile& file, std::string_view name);
+ void generateStructSourceNamespaces(CppFile& file, std::string_view name);
+ void generateEnumIncludes(CppFile& file, std::string_view name);
+ void generateEnumSourceIncludes(CppFile& file, std::string_view name);
+ void generateInterfaceSourceIncludes(CppFile& file, std::string_view name);
+ void generateInterfaceSourceNamespaces(CppFile& file, std::string_view name);
+
+ // ========================================================================
+ // TYPE SYSTEM & CONVERSION UTILITIES
+ // ========================================================================
+ // Type conversion and mapping
+ OString convertUnoTypeToCpp(std::u16string_view unoType) const;
+ std::string convertTemplateArguments(const std::string& unoType) const;
+ OString getCppTypeName(std::u16string_view unoType) const;
+ OString getRustFFITypeName(std::u16string_view unoType) const;
+ OString mapUnoPrimitiveToSal(std::u16string_view unoType) const;
+ OUString resolveTypedef(std::u16string_view unoType) const;
+ OString convertBasicType(const OString& typeName) const;
+ OString convertUnoTypeToHandle(std::u16string_view unoType) const;
+
+ // Type classification
+ bool isUnoType(std::u16string_view typeName) const;
+ bool isUnoStruct(std::u16string_view typeName) const;
+ bool isUnoEnum(std::u16string_view typeName) const;
+ bool isUnoInterface(std::u16string_view typeName) const;
+ bool isUnoPolymorphicStruct(std::u16string_view typeName) const;
+ bool isUnoConstantGroup(std::u16string_view typeName) const;
+
+ // Method return type handling
+ OString getMethodReturnType(std::u16string_view returnType) const;
+ OString getMethodDefaultReturn(std::u16string_view returnType) const;
+
+ // ========================================================================
+ // CODE GENERATION HELPERS
+ // ========================================================================
+ // C Bridge generation helpers
+ void generateCBridgeIncludes(CppFile& file, std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+ void generateCBridgeTypeDefinitions(CppFile& file, const OString& handleTypeName);
+ void generateCBridgeConstructors(CppFile& file, const OString& className,
+ const OString& functionPrefix, const OString& handleTypeName);
+ void generateCBridgeDestructor(CppFile& file, const OString& className,
+ const OString& functionPrefix, const OString& handleTypeName);
+ void generateCBridgeValidation(CppFile& file, const OString& className,
+ const OString& functionPrefix, const OString& handleTypeName);
+ void generateCBridgeMethods(CppFile& file, const OString& className,
+ const OString& functionPrefix, const OString& handleTypeName,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+
+ // Interface generation helpers
+ void generateInterfaceSourceBasicFunctions(CppFile& file, const OString& functionPrefix,
+ const OString& className,
+ const OString& handleTypeName);
+ void generateInterfaceSourceMethodImplementations(
+ CppFile& file, const OString& functionPrefix, const OString& className,
+ const OString& handleTypeName, const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+ void generateSingleInterfaceMethod(CppFile& file, const OString& functionPrefix,
+ const OString& className, const OString& handleTypeName,
+ const unoidl::InterfaceTypeEntity::Method& method);
+ void generateActualMethodCall(CppFile& file, const unoidl::InterfaceTypeEntity::Method& method);
+ void generateReturnValueConversion(CppFile& file,
+ const unoidl::InterfaceTypeEntity::Method& method);
+
+ // Struct generation helpers
+ void generateStructSourceBasicFunctions(CppFile& file, const OString& functionPrefix,
+ const OString& handleTypeName,
+ const std::string& className);
+ void
+ generateStructSourceBaseMembers(CppFile& file, const OString& functionPrefix,
+ const OString& handleTypeName, const std::string& className,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+ void
+ generateStructSourceDirectMembers(CppFile& file, const OString& functionPrefix,
+ const OString& handleTypeName, const std::string& className,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+ void generateStructMemberAccessors(CppFile& file, const OString& functionPrefix,
+ const OString& handleTypeName, const std::string& className,
+ const unoidl::PlainStructTypeEntity::Member& member);
+
+ // ========================================================================
+ // UTILITY FUNCTIONS
+ // ========================================================================
+ static std::string_view splitName(std::string_view name);
+ static OString getInterfaceClassName(std::string_view unoName);
+ static OString getCFunctionPrefix(std::string_view unoName);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustfile.cxx b/codemaker/source/rustmaker/rustfile.cxx
new file mode 100644
index 000000000000..0b2b863d87ed
--- /dev/null
+++ b/codemaker/source/rustmaker/rustfile.cxx
@@ -0,0 +1,664 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+// Implementation of Rust file generation and module management
+
+#include "rustfile.hxx"
+#include <algorithm>
+#include <filesystem>
+#include <iostream>
+#include <vector>
+#include <functional>
+#include <codemaker/global.hxx>
+
+RustFile::RustFile(std::string_view directory, std::string_view typeName)
+ : m_filePath(createFilePath(directory, typeName))
+ , m_indentLevel(0)
+{
+}
+
+std::string RustFile::getPath() const { return m_filePath.string(); }
+
+void RustFile::openFile()
+{
+ std::filesystem::create_directories(m_filePath.parent_path());
+ createModFiles();
+ addFileToModDeclaration();
+ m_fileStream.open(m_filePath, std::fstream::out | std::fstream::trunc);
+ m_indentLevel = 0;
+}
+
+void RustFile::closeFile() { m_fileStream.close(); }
+
+void RustFile::createLibFile(const std::filesystem::path& outputDir)
+{
+ // Create generated/rustmaker directory first, then src directory inside it
+ std::filesystem::path generatedDir = outputDir / "generated";
+ std::filesystem::path rustmakerDir = generatedDir / "rustmaker";
+ std::filesystem::path srcDir = rustmakerDir / "src";
+ std::filesystem::create_directories(srcDir);
+
+ std::filesystem::path libFile = srcDir / "lib.rs";
+ if (!std::filesystem::exists(libFile))
+ {
+ std::ofstream libStream(libFile);
+ libStream << "//! Generated Rust bindings for LibreOffice UNO types\n";
+ libStream << "//! \n";
+ libStream << "//! This crate contains automatically generated Rust bindings\n";
+ libStream << "//! for LibreOffice UNO (Universal Network Objects) types.\n\n";
+ libStream.close();
+ }
+}
+
+void RustFile::createCargoFile(const std::filesystem::path& outputDir, const std::string& crateName)
+{
+ // Create Cargo.toml in the generated/rustmaker directory
+ std::filesystem::path generatedDir = outputDir / "generated";
+ std::filesystem::path rustmakerDir = generatedDir / "rustmaker";
+ std::filesystem::path cargoFile = rustmakerDir / "Cargo.toml";
+ if (!std::filesystem::exists(cargoFile))
+ {
+ std::ofstream cargoStream(cargoFile);
+ cargoStream << "[package]\n";
+ cargoStream << "name = \"" << crateName << "\"\n";
+ cargoStream << "version = \"0.1.0\"\n";
+ cargoStream << "edition = \"2024\"\n";
+ cargoStream << "\n";
+ cargoStream << "[lib]\n";
+ cargoStream << "name = \"rustmaker\"\n";
+ // Support both dynamic and static linking
+ cargoStream << "crate-type = [\"cdylib\", \"rlib\"]\n";
+ cargoStream << "description = \"Generated Rust bindings for LibreOffice UNO types\"\n\n";
+ cargoStream << "[dependencies]\n";
+ cargoStream << "# UNO runtime dependencies\n";
+ cargoStream << "rust_uno = { path = \"../../../../rust_uno\" }\n";
+ cargoStream.close();
+ }
+}
+
+void RustFile::createGeneratedModFile(const std::filesystem::path& outputDir)
+{
+ // Create generated directory and its mod.rs file
+ std::filesystem::path generatedDir = outputDir / "generated";
+ std::filesystem::create_directories(generatedDir);
+
+ std::filesystem::path modFile = generatedDir / "mod.rs";
+ if (!std::filesystem::exists(modFile))
+ {
+ std::ofstream modStream(modFile);
+ modStream << "//! Generated opaque bindings for LibreOffice UNO types\n";
+ modStream << "//!\n";
+ modStream << "//! This module contains both Rust and C++ opaque bindings\n";
+ modStream << "//! auto-generated by rustmaker\n\n";
+ modStream << "// Include the generated rustmaker bindings directly\n";
+ modStream << "// The rustmaker directory contains a complete Rust project structure\n";
+ modStream << "// We include its lib.rs as a module here\n";
+ modStream << "#[path = \"rustmaker/src/lib.rs\"]\n";
+ modStream << "pub mod rustmaker;\n\n";
+ modStream << "// Re-export the UNO namespace for easier access\n";
+ modStream << "pub use rustmaker::com;\n\n";
+ modStream << "// Note: cpp_rustmaker directory contains C++ bridge files\n";
+ modStream << "// These are compiled separately and linked via build.rs\n";
+ modStream.close();
+ }
+}
+
+void RustFile::finalizeModFiles(const std::filesystem::path& outputDir)
+{
+ // Find all directories in the rustmaker source tree and update their mod.rs files
+ std::filesystem::path rustmakerSrc = outputDir / "generated" / "rustmaker" / "src";
+
+ if (!std::filesystem::exists(rustmakerSrc))
+ {
+ return;
+ }
+
+ // Start processing from the rustmaker src directory
+ processDirectoryRecursively(rustmakerSrc);
+}
+
+RustFile& RustFile::beginBlock()
+{
+ beginLine();
+ append("{");
+ endLine();
+ ++m_indentLevel;
+ return *this;
+}
+
+RustFile& RustFile::endBlock()
+{
+ --m_indentLevel;
+ beginLine();
+ append("}");
+ endLine();
+ return *this;
+}
+
+// Text output methods
+RustFile& RustFile::beginLine()
+{
+ for (int i = 0; i < m_indentLevel; i++)
+ {
+ m_fileStream << " ";
+ }
+ return *this;
+}
+
+RustFile& RustFile::extraIndent()
+{
+ m_fileStream << " ";
+ return *this;
+}
+
+RustFile& RustFile::append(std::string_view item)
+{
+ m_fileStream << item;
+ return *this;
+}
+
+RustFile& RustFile::append(std::u16string_view item)
+{
+ m_fileStream << u2b(item);
+ return *this;
+}
+
+RustFile& RustFile::endLine()
+{
+ m_fileStream << '\n';
+ return *this;
+}
+
+void RustFile::createModFiles()
+{
+ std::filesystem::path outputRoot = findOutputRoot();
+
+ // Create lib and cargo files only once at the proper root level
+ // outputRoot should be the rustmaker directory, so we pass its parent to the create functions
+ // which will then create the rustmaker directory and put files inside it
+ createGeneratedModFile(
+ outputRoot.parent_path().parent_path()); // Create generated/mod.rs at top level
+ createLibFile(
+ outputRoot.parent_path().parent_path()); // Create in the directory containing generated/
+ createCargoFile(outputRoot.parent_path().parent_path(), "rustmaker");
+
+ // Build path hierarchy from file location up to project root
+ std::filesystem::path workingPath = m_filePath.parent_path();
+ std::vector<std::filesystem::path> pathsToProcess;
+
+ // Collect all directory paths from current file up to root
+ while (workingPath != outputRoot && workingPath.has_parent_path())
+ {
+ pathsToProcess.push_back(workingPath);
+ workingPath = workingPath.parent_path();
+ }
+
+ // Process paths from root down to ensure proper mod.rs structure
+ std::reverse(pathsToProcess.begin(), pathsToProcess.end());
+ for (const auto& path : pathsToProcess)
+ {
+ ensureModFileExists(path);
+ }
+}
+
+// Complex path resolution - walks up directory tree to find project root
+std::filesystem::path RustFile::findOutputRoot()
+{
+ std::filesystem::path currentPath = m_filePath.parent_path();
+
+ // Walk up until we find a directory structure indicating project root
+ while (currentPath.has_parent_path() && currentPath != currentPath.parent_path())
+ {
+ if (currentPath.filename() == "src")
+ {
+ return currentPath.parent_path(); // Return rustmaker directory
+ }
+
+ // Look for rustmaker directory as the project root
+ if (currentPath.filename() == "rustmaker")
+ {
+ return currentPath;
+ }
+
+ // Look for existing src/ subdirectory as root indicator
+ std::filesystem::path srcDir = currentPath / "src";
+ if (std::filesystem::exists(srcDir))
+ {
+ return currentPath;
+ }
+
+ currentPath = currentPath.parent_path();
+ }
+
+ // Fallback: find parent of src directory (which should be rustmaker)
+ std::filesystem::path result = m_filePath.parent_path();
+ while (result.has_parent_path() && result.filename() != "src")
+ {
+ result = result.parent_path();
+ }
+
+ if (result.filename() == "src")
+ {
+ return result.parent_path(); // Return rustmaker directory
+ }
+
+ return result; // Default case
+}
+
+void RustFile::addFileToModDeclaration()
+{
+ std::filesystem::path parentDir = m_filePath.parent_path();
+ std::filesystem::path modFile = parentDir / "mod.rs";
+ std::string fileName = m_filePath.stem().string(); // Get filename without extension
+
+ if (std::filesystem::exists(modFile))
+ {
+ addModuleDeclaration(modFile, fileName);
+ }
+}
+
+void RustFile::ensureModFileExists(const std::filesystem::path& dirPath)
+{
+ // Skip mod.rs creation for the src directory itself
+ if (dirPath.filename() == "src")
+ {
+ return;
+ }
+
+ std::filesystem::path modFile = dirPath / "mod.rs";
+ if (!std::filesystem::exists(modFile))
+ {
+ // Create mod.rs file with proper structure
+ std::ofstream modStream(modFile);
+ modStream << "// Generated mod.rs file\n\n";
+ modStream << "#[allow(non_snake_case)]\n";
+ modStream.close();
+ }
+
+ // After ensuring the mod.rs exists, collect all subdirectories and modules
+ // to automatically add pub use ::* patterns
+ std::vector<std::string> childModules;
+
+ // Scan directory for subdirectories (modules) and .rs files
+ if (std::filesystem::exists(dirPath))
+ {
+ try
+ {
+ for (const auto& entry : std::filesystem::directory_iterator(dirPath))
+ {
+ if (entry.is_directory())
+ {
+ std::string dirName = entry.path().filename().string();
+ childModules.push_back(dirName);
+ }
+ else if (entry.is_regular_file() && entry.path().extension() == ".rs")
+ {
+ std::string fileName = entry.path().stem().string();
+ if (fileName != "mod") // Don't include mod.rs itself
+ {
+ childModules.push_back(fileName);
+ }
+ }
+ }
+ }
+ catch (const std::filesystem::filesystem_error&)
+ {
+ // Handle permission errors gracefully
+ }
+ }
+
+ // Add module declarations and pub use statements for all child modules
+ for (const std::string& moduleName : childModules)
+ {
+ addModuleDeclaration(modFile, moduleName);
+ }
+
+ // Recursively ensure parent modules are properly declared
+ if (dirPath.has_parent_path())
+ {
+ std::filesystem::path parentDir = dirPath.parent_path();
+ std::filesystem::path outputRoot = findOutputRoot();
+
+ if (parentDir >= outputRoot)
+ {
+ std::string moduleName = dirPath.filename().string();
+
+ if (parentDir.filename() == "src")
+ {
+ std::filesystem::path libFile = parentDir / "lib.rs";
+ if (std::filesystem::exists(libFile))
+ {
+ addModuleDeclaration(libFile, moduleName);
+ }
+ }
+ else if (parentDir == outputRoot)
+ {
+ std::filesystem::path libFile = parentDir / "src" / "lib.rs";
+ if (std::filesystem::exists(libFile))
+ {
+ addModuleDeclaration(libFile, moduleName);
+ }
+ }
+ else
+ {
+ ensureModFileExists(parentDir);
+ std::filesystem::path parentModFile = parentDir / "mod.rs";
+ if (std::filesystem::exists(parentModFile))
+ {
+ addModuleDeclaration(parentModFile, moduleName);
+ }
+ }
+ }
+ }
+}
+
+void RustFile::addModuleDeclaration(const std::filesystem::path& modFile,
+ const std::string& moduleName)
+{
+ // Read existing content to check for duplicates and organize sections
+ std::ifstream inFile(modFile);
+ std::string line;
+ std::vector<std::string> pubModLines;
+ std::vector<std::string> otherLines;
+ bool foundModDeclaration = false;
+
+ while (std::getline(inFile, line))
+ {
+ if (line.find("pub mod " + moduleName + ";") != std::string::npos)
+ {
+ foundModDeclaration = true;
+ }
+
+ if (line.find("pub mod ") == 0)
+ {
+ pubModLines.push_back(line);
+ }
+ else if (!(line.find("pub use ") == 0 && line.find("::*;") != std::string::npos))
+ {
+ // Skip old pub use re-export lines, include everything else
+ otherLines.push_back(line);
+ }
+ }
+ inFile.close();
+
+ // If module declaration is already declared, return
+ if (foundModDeclaration)
+ {
+ return;
+ }
+
+ // Add new declarations if not found
+ if (!foundModDeclaration)
+ {
+ pubModLines.push_back("pub mod " + moduleName + ";");
+ }
+ // Re-export generation removed - causes unused import warnings
+
+ // Rewrite the file with organized structure
+ std::ofstream outFile(modFile, std::ios::trunc);
+
+ // Write other lines first (comments, etc.)
+ for (const auto& otherLine : otherLines)
+ {
+ // Skip re-export comment lines
+ if (otherLine.find("// Re-export all items from child modules") == std::string::npos)
+ {
+ outFile << otherLine << "\n";
+ }
+ }
+
+ // Write all pub mod declarations
+ for (const auto& modLine : pubModLines)
+ {
+ outFile << modLine << "\n";
+ }
+
+ // Re-export section removed - causes unused import warnings
+
+ outFile.close();
+}
+
+// Converts UNO type name to file path (dots become path separators)
+std::filesystem::path RustFile::createFilePath(std::string_view dir, std::string_view type)
+{
+ std::string subdir(type);
+ for (char& c : subdir)
+ if (c == '.')
+ c = '/';
+
+ std::filesystem::path path(dir);
+ path /= "rustmaker"; // Add rustmaker subdirectory for generated types
+ path /= "src";
+ path /= subdir + ".rs";
+ return path;
+}
+
+// CppFile implementation
+CppFile::CppFile(std::string_view directory, std::string_view typeName)
+ : m_filePath(createCppFilePath(directory, typeName))
+ , m_indentLevel(0)
+{
+}
+
+CppFile::CppFile(std::string_view directory, std::string_view typeName, std::string_view extension)
+ : m_filePath(createCppFilePath(directory, typeName, extension))
+ , m_indentLevel(0)
+{
+}
+
+std::string CppFile::getPathString() const { return m_filePath.string(); }
+std::filesystem::path CppFile::getPath() const { return m_filePath; }
+std::string CppFile::getExtension() const { return m_filePath.extension().string(); }
+
+void CppFile::openFile()
+{
+ std::filesystem::create_directories(m_filePath.parent_path());
+ m_fileStream.open(m_filePath, std::fstream::out | std::fstream::trunc);
+ m_indentLevel = 0;
+}
+
+void CppFile::openFileAppend()
+{
+ std::filesystem::create_directories(m_filePath.parent_path());
+ m_fileStream.open(m_filePath, std::fstream::out | std::fstream::app);
+ m_indentLevel = 0;
+}
+
+void CppFile::closeFile() { m_fileStream.close(); }
+
+CppFile& CppFile::beginBlock()
+{
+ beginLine();
+ append("{");
+ endLine();
+ ++m_indentLevel;
+ return *this;
+}
+
+CppFile& CppFile::endBlock()
+{
+ --m_indentLevel;
+ beginLine();
+ append("}");
+ endLine();
+ return *this;
+}
+
+CppFile& CppFile::beginLine()
+{
+ m_fileStream << std::string(4 * m_indentLevel, ' ');
+ return *this;
+}
+
+CppFile& CppFile::extraIndent()
+{
+ m_fileStream << " ";
+ return *this;
+}
+
+CppFile& CppFile::append(std::string_view item)
+{
+ m_fileStream << item;
+ return *this;
+}
+
+CppFile& CppFile::append(std::u16string_view item)
+{
+ m_fileStream << u2b(item);
+ return *this;
+}
+
+CppFile& CppFile::endLine()
+{
+ m_fileStream << std::endl;
+ return *this;
+}
+
+CppFile& CppFile::writeIncludes(const std::vector<std::string>& includes)
+{
+ for (const auto& include : includes)
+ {
+ beginLine().append("#include ").append(include).endLine();
+ }
+ endLine();
+ return *this;
+}
+
+CppFile& CppFile::writeNamespaceBegin(const std::vector<std::string>& namespaces)
+{
+ for (const auto& ns : namespaces)
+ {
+ beginLine().append("namespace ").append(ns).append(" {").endLine();
+ }
+ endLine();
+ return *this;
+}
+
+CppFile& CppFile::writeNamespaceEnd(const std::vector<std::string>& namespaces)
+{
+ endLine();
+ for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it)
+ {
+ beginLine().append("} // namespace ").append(*it).endLine();
+ }
+ return *this;
+}
+
+std::filesystem::path CppFile::createCppFilePath(std::string_view dir, std::string_view type,
+ std::string_view extension)
+{
+ std::filesystem::path outputDir(dir);
+
+ // For the special case of "rust_uno_bindings", create it directly in the output directory
+ if (type == "rust_uno_bindings")
+ {
+ return outputDir / (std::string(type) + std::string(extension));
+ }
+
+ std::filesystem::path basePath = outputDir;
+
+ std::string typeName(type);
+
+ // Extract interface name (part after last dot)
+ size_t lastDot = typeName.find_last_of('.');
+ std::string interfaceName
+ = (lastDot != std::string::npos) ? typeName.substr(lastDot + 1) : typeName;
+
+ // Create namespace directory path from the full type name
+ if (lastDot != std::string::npos)
+ {
+ // Convert namespace dots to path separators: com.sun.star.frame -> com/sun/star/frame/
+ std::string namespacePath = typeName.substr(0, lastDot);
+
+ // Replace dots with path separators
+ std::replace(namespacePath.begin(), namespacePath.end(), '.', '/');
+
+ // Build full path: cpp_rustmaker/com/sun/star/frame/XComponentLoader.hxx
+ return basePath / namespacePath / (interfaceName + std::string(extension));
+ }
+ else
+ {
+ // No namespace, put directly in cpp_rustmaker directory
+ return basePath / (interfaceName + std::string(extension));
+ }
+}
+
+void RustFile::processDirectoryRecursively(const std::filesystem::path& currentDir)
+{
+ if (!std::filesystem::exists(currentDir) || !std::filesystem::is_directory(currentDir))
+ {
+ return;
+ }
+
+ // Skip the root src directory
+ if (currentDir.filename() == "src" && currentDir.parent_path().filename() == "rustmaker")
+ {
+ // Process subdirectories but don't create mod.rs for src itself
+ for (const auto& entry : std::filesystem::directory_iterator(currentDir))
+ {
+ if (entry.is_directory())
+ {
+ processDirectoryRecursively(entry.path());
+ }
+ }
+ return;
+ }
+
+ std::vector<std::string> childModules;
+
+ try
+ {
+ // Collect all subdirectories and .rs files
+ for (const auto& entry : std::filesystem::directory_iterator(currentDir))
+ {
+ if (entry.is_directory())
+ {
+ std::string dirName = entry.path().filename().string();
+ childModules.push_back(dirName);
+ // Recursively process subdirectory
+ processDirectoryRecursively(entry.path());
+ }
+ else if (entry.is_regular_file() && entry.path().extension() == ".rs")
+ {
+ std::string fileName = entry.path().stem().string();
+ if (fileName != "mod" && fileName != "lib") // Don't include mod.rs or lib.rs
+ {
+ childModules.push_back(fileName);
+ }
+ }
+ }
+ }
+ catch (const std::filesystem::filesystem_error&)
+ {
+ // Handle permission errors gracefully
+ return;
+ }
+
+ // Create/update mod.rs file if there are child modules
+ if (!childModules.empty())
+ {
+ std::filesystem::path modFile = currentDir / "mod.rs";
+
+ // Create the mod.rs file with all declarations
+ std::ofstream modStream(modFile, std::ios::trunc);
+ modStream << "// Generated mod.rs file\n\n";
+ modStream << "#[allow(non_snake_case)]\n";
+
+ for (const std::string& moduleName : childModules)
+ {
+ modStream << "pub mod " << moduleName << ";\n";
+ }
+
+ // Re-export section removed per request
+
+ modStream.close();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustfile.hxx b/codemaker/source/rustmaker/rustfile.hxx
new file mode 100644
index 000000000000..a5ecd307a902
--- /dev/null
+++ b/codemaker/source/rustmaker/rustfile.hxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <filesystem>
+#include <fstream>
+#include <set>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include <codemaker/typemanager.hxx>
+
+/**
+ * Generates Rust source files from UNO type definitions
+ */
+class RustFile
+{
+public:
+ RustFile(std::string_view directory, std::string_view typeName);
+
+ std::string getPath() const;
+ void openFile();
+ void closeFile();
+
+ // Static methods for project setup
+ static void createLibFile(const std::filesystem::path& outputDir);
+ static void createCargoFile(const std::filesystem::path& outputDir,
+ const std::string& crateName = "rustmaker");
+ static void createGeneratedModFile(const std::filesystem::path& outputDir);
+ static void finalizeModFiles(const std::filesystem::path& outputDir);
+
+ // Code generation helpers
+ RustFile& beginBlock();
+ RustFile& endBlock();
+ RustFile& beginLine();
+ RustFile& extraIndent();
+ RustFile& append(std::string_view item);
+ RustFile& append(std::u16string_view item);
+ RustFile& endLine();
+
+private:
+ // Complex path resolution - walks up directory tree to find project root
+ std::filesystem::path findOutputRoot();
+
+ // Module management - handles mod.rs creation and declarations
+ void createModFiles();
+ void addFileToModDeclaration();
+ void ensureModFileExists(const std::filesystem::path& dirPath);
+ static void addModuleDeclaration(const std::filesystem::path& modFile,
+ const std::string& moduleName);
+
+ // Converts UNO type name to file path (dots become path separators)
+ static std::filesystem::path createFilePath(std::string_view dir, std::string_view type);
+
+private:
+ std::filesystem::path m_filePath;
+ std::ofstream m_fileStream;
+ int m_indentLevel;
+
+ // Helper function for recursive directory processing
+ static void processDirectoryRecursively(const std::filesystem::path& currentDir);
+};
+
+/**
+ * Generates C++ bridge files for UNO opaque functions
+ */
+class CppFile
+{
+public:
+ CppFile(std::string_view directory, std::string_view typeName);
+ CppFile(std::string_view directory, std::string_view typeName, std::string_view extension);
+
+ std::string getPathString() const;
+ std::filesystem::path getPath() const;
+ std::string getExtension() const;
+ void openFile();
+ void openFileAppend(); // Open for appending (continue writing)
+ void closeFile();
+
+ // Code generation helpers
+ CppFile& beginBlock();
+ CppFile& endBlock();
+ CppFile& beginLine();
+ CppFile& extraIndent();
+ CppFile& append(std::string_view item);
+ CppFile& append(std::u16string_view item);
+ CppFile& endLine();
+
+ // C++ specific helpers
+ CppFile& writeIncludes(const std::vector<std::string>& includes);
+ CppFile& writeNamespaceBegin(const std::vector<std::string>& namespaces);
+ CppFile& writeNamespaceEnd(const std::vector<std::string>& namespaces);
+
+private:
+ static std::filesystem::path createCppFilePath(std::string_view dir, std::string_view type,
+ std::string_view extension = ".hxx");
+
+private:
+ std::filesystem::path m_filePath;
+ std::ofstream m_fileStream;
+ int m_indentLevel;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustmaker.cxx b/codemaker/source/rustmaker/rustmaker.cxx
new file mode 100644
index 000000000000..f17bef9e2442
--- /dev/null
+++ b/codemaker/source/rustmaker/rustmaker.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <iostream>
+
+#include <sal/main.h>
+#include <unoidl/unoidl.hxx>
+
+#include "rustoptions.hxx"
+#include "unoproduce.hxx"
+
+// coverity[tainted_data] - this is a build time tool
+SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
+{
+ try
+ {
+ RustOptions options;
+ UnoProducer producer;
+
+ // Parse command line arguments and generate code if successful
+ if (options.initOptions(argc, argv))
+ {
+ producer.initProducer(options);
+ producer.produceAll();
+ // Finalize opaque pointer generation
+ producer.finalizeGeneration();
+ }
+ }
+ catch (const ::IllegalArgument& e)
+ {
+ std::cerr << "ERROR: Illegal option " << e.m_message << '\n';
+ return EXIT_FAILURE;
+ }
+ catch (const ::CannotDumpException& e)
+ {
+ std::cerr << "ERROR: Could not dump as " << e.getMessage() << '\n';
+ return EXIT_FAILURE;
+ }
+ catch (const unoidl::NoSuchFileException& e)
+ {
+ std::cerr << "ERROR: No such file " << e.getUri() << '\n';
+ return EXIT_FAILURE;
+ }
+ catch (const unoidl::FileFormatException& e)
+ {
+ std::cerr << "ERROR: Bad format of " << e.getUri() << ", '" << e.getDetail() << "'\n";
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "ERROR: " << e.what() << '\n';
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustoptions.cxx b/codemaker/source/rustmaker/rustoptions.cxx
new file mode 100644
index 000000000000..b92aba9c5565
--- /dev/null
+++ b/codemaker/source/rustmaker/rustoptions.cxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <iostream>
+
+#include "rustoptions.hxx"
+
+bool RustOptions::initOptions(int argc, char* argv[], bool)
+{
+ if (argc < 2)
+ {
+ std::cerr << prepareHelp();
+ return false;
+ }
+
+ for (int i = 1; i < argc; i++)
+ {
+ OString argument = argv[i];
+
+ if (argument == "-h"_ostr || argument == "--help"_ostr)
+ {
+ std::cout << prepareHelp();
+ return false;
+ }
+ else if (argument == "-v"_ostr || argument == "--verbose"_ostr)
+ {
+ m_options["--verbose"_ostr] = ""_ostr;
+ }
+ else if (argument == "-n"_ostr || argument == "--dry-run"_ostr)
+ {
+ m_options["--dry-run"_ostr] = ""_ostr;
+ m_options["--verbose"_ostr] = "--dry-run"_ostr; // dry run implies verbose
+ }
+ else if (argument == "-T"_ostr || argument == "--types"_ostr)
+ {
+ if (i + 1 < argc)
+ {
+ if (m_options.count("--types"_ostr) == 0)
+ {
+ m_options["--types"_ostr] = argv[++i];
+ }
+ else
+ {
+ // Allow multiple -T options by joining with semicolon
+ m_options["--types"_ostr] += ";"_ostr + argv[++i];
+ }
+ }
+ else
+ {
+ throw IllegalArgument("-T/--types must be followed by type name or wildcard"_ostr);
+ }
+ }
+ else if (argument == "-X"_ostr || argument == "--extra-types"_ostr)
+ {
+ if (i + 1 < argc)
+ {
+ m_extra_input_files.emplace_back(argv[++i]);
+ }
+ else
+ {
+ throw IllegalArgument("-X/--extra-types must be followed by .rdb file"_ostr);
+ }
+ }
+ else if (argument == "-Ocpp"_ostr)
+ {
+ if (i + 1 < argc)
+ {
+ m_options["--cpp-output-dir"_ostr] = argv[++i];
+ }
+ else
+ {
+ throw IllegalArgument("-Ocpp must be followed by directory"_ostr);
+ }
+ }
+ else if (argument == "-Orust"_ostr)
+ {
+ if (i + 1 < argc)
+ {
+ m_options["--rust-output-dir"_ostr] = argv[++i];
+ }
+ else
+ {
+ throw IllegalArgument("-Orust must be followed by directory"_ostr);
+ }
+ }
+ else if (argument == "-O"_ostr || argument == "--output-dir"_ostr)
+ {
+ if (i + 1 < argc)
+ {
+ // Legacy support: set both cpp and rust output to same directory
+ m_options["--cpp-output-dir"_ostr]
+ = OString::Concat(argv[++i]) + "/generated/cpp_rustmaker";
+ m_options["--rust-output-dir"_ostr] = OString::Concat(argv[i]) + "/generated";
+ }
+ else
+ {
+ throw IllegalArgument("-O/--output-dir must be followed by directory"_ostr);
+ }
+ }
+ else
+ {
+ // Any non-option argument is treated as input .rdb file
+ m_inputFiles.emplace_back(argument);
+ }
+ }
+
+ // Validate required arguments
+ if (m_inputFiles.empty())
+ {
+ throw IllegalArgument("at least one .rdb file must be provided"_ostr);
+ }
+
+ if (m_options.count("--cpp-output-dir"_ostr) == 0
+ || m_options.count("--rust-output-dir"_ostr) == 0)
+ {
+ throw IllegalArgument(
+ "Both -Ocpp and -Orust must be provided (or use -O for legacy mode)"_ostr);
+ }
+
+ return true;
+}
+
+OString RustOptions::prepareHelp()
+{
+ return R"(
+
+About:
+ rustmaker is a tool for generating Rust files from a type library generated by the UNOIDL compiler unoidl-write.
+ The generated code files require the implemented Rust types from rust_uno.
+
+Usage:
+ rustmaker [-v|--verbose] [-n|--dry-run]
+ [-T|--types <type name or wildcard>]
+ [-X|--extra-types <.rdb file>]
+ -Ocpp <cpp output directory> -Orust <rust output directory>
+ <rdb file(s)>
+
+ OR (legacy mode):
+ rustmaker [-v|--verbose] [-n|--dry-run]
+ [-T|--types <type name or wildcard>]
+ [-X|--extra-types <.rdb file>]
+ -O|--output-dir <output directory>
+ <rdb file(s)>
+
+Options:
+ -h, --help
+ Display this help message.
+
+ -v, --verbose
+ Log the name of every file created and type generated to stdout.
+
+ -n, --dry-run
+ Do not write generated files to disk. Implies --verbose.
+
+ -T, --types <type name or wildcard>
+ Specify a type name or a wildcard pattern to generate code for. This option can be specified multiple times. If not specified, all types in the given .rdb files are generated.
+
+ -X, --extra-types <.rdb file>
+ Use an .rdb file containing types to be taken into account without generating output for them. This option can be specified multiple times.
+
+ -Ocpp <directory>
+ Specify the directory to write generated C++ files to.
+
+ -Orust <directory>
+ Specify the directory to write generated Rust files to.
+
+ -O, --output-dir <directory> (legacy mode)
+ Specify the directory to write generated files to. Creates subdirectories for C++ and Rust files.
+
+Examples:
+ rustmaker --verbose -T com.acme.XSomething \
+ -X types.rdb -Ocpp acme/cpp -Orust acme/src acmetypes.rdb
+
+ rustmaker --dry-run -T com.acme.* -X types.rdb \
+ -X offapi.rdb -Ocpp acme/cpp -Orust acme/src acmetypes.rdb
+
+ rustmaker -X types.rdb -Ocpp acme/cpp -Orust acme/src \
+ acmetypes.rdb moretypes.rdb
+
+ # Generate opaque pointer bindings for all UNO types
+ rustmaker -T com.sun.star.frame.XComponentLoader \
+ -X offapi.rdb -Ocpp cpp/ -Orust src/generated/ offapi.rdb
+
+ # Legacy mode (backward compatibility)
+ rustmaker --verbose -T com.acme.XSomething \
+ -X types.rdb -O acme/ acmetypes.rdb
+)"_ostr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustoptions.hxx b/codemaker/source/rustmaker/rustoptions.hxx
new file mode 100644
index 000000000000..7300613ea8ad
--- /dev/null
+++ b/codemaker/source/rustmaker/rustoptions.hxx
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <rtl/string.hxx>
+#include <codemaker/options.hxx>
+
+/**
+ * Command line options parser for rustmaker
+ */
+class RustOptions : public Options
+{
+public:
+ RustOptions() { m_program = "rustmaker"_ostr; }
+
+ bool initOptions(int argc, char* argv[], bool bCmdFile = false) override;
+ OString prepareHelp() override;
+};
+
+/* vim:set shiftwidth=2 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustproduce.cxx b/codemaker/source/rustmaker/rustproduce.cxx
new file mode 100644
index 000000000000..100827f0936a
--- /dev/null
+++ b/codemaker/source/rustmaker/rustproduce.cxx
@@ -0,0 +1,1234 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rustproduce.hxx"
+#include "rustfile.hxx"
+#include <codemaker/typemanager.hxx>
+#include <sal/log.hxx>
+#include <iostream>
+#include <set>
+
+RustProducer::RustProducer(const OString& outputDir, bool verbose, bool dryRun,
+ const rtl::Reference<TypeManager>& typeManager)
+ : m_outputDir(outputDir)
+ , m_verbose(verbose)
+ , m_dryRun(dryRun)
+ , m_typeManager(typeManager)
+{
+}
+
+void RustProducer::produceEnum(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity)
+{
+ RustFile file(m_outputDir, name);
+
+ if (m_verbose)
+ std::cout << "[rust-opaque-enum] " << name << " -> " << file.getPath() << '\n';
+ if (m_dryRun)
+ return;
+
+ file.openFile();
+
+ OString typeName(splitName(name)); // Simple name for Rust enum
+ OString externFunctionPrefix = getRustTypeName(name); // Full name for extern "C" functions
+
+ file.beginLine()
+ .append("/// Opaque Rust enum wrapper for ")
+ .append(name)
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("#[repr(C)]")
+ .endLine()
+ .beginLine()
+ .append("#[allow(non_camel_case_types)]")
+ .endLine()
+ .beginLine()
+ .append("#[derive(Debug, Clone, Copy, PartialEq, Eq)]")
+ .endLine()
+ .beginLine()
+ .append("pub enum ")
+ .append(typeName)
+ .endLine()
+ .beginBlock();
+
+ // Track used discriminant values to avoid duplicates
+ std::set<sal_Int32> usedValues;
+
+ for (const auto& member : entity->getMembers())
+ {
+ // Only include members with unique discriminant values
+ if (usedValues.find(member.value) == usedValues.end())
+ {
+ usedValues.insert(member.value);
+ file.beginLine()
+ .append(member.name)
+ .append(" = ")
+ .append(OString::number(member.value))
+ .append(",")
+ .endLine();
+ }
+ }
+
+ file.endBlock();
+
+ // Add conversion functions using extern "C" bridge
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("impl ")
+ .append(typeName)
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("pub fn from_i32(value: i32) -> Self {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_from_i32(value) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn to_i32(self) -> i32 {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_to_i32(self) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .endBlock();
+
+ // Extern "C" declarations
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("unsafe extern \"C\" {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_from_i32(value: i32) -> ")
+ .append(typeName)
+ .append(";")
+ .endLine()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_to_i32(value: ")
+ .append(typeName)
+ .append(") -> i32;")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine();
+
+ file.closeFile();
+}
+
+void RustProducer::produceStruct(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ RustFile file(m_outputDir, name);
+
+ if (m_verbose)
+ std::cout << "[rust-opaque-struct] " << name << " -> " << file.getPath() << '\n';
+ if (m_dryRun)
+ return;
+
+ file.openFile();
+
+ OString typeName(splitName(name)); // Simple name for Rust struct
+ OString externFunctionPrefix = getRustTypeName(name); // Full name for extern "C" functions
+
+ file.beginLine()
+ .append("/// Opaque Rust struct wrapper for ")
+ .append(name)
+ .endLine()
+ .beginLine()
+ .append("use std::ffi::c_void;")
+ .endLine()
+ .beginLine()
+ .append("#[allow(non_camel_case_types)]")
+ .endLine()
+ .beginLine()
+ .append("pub struct ")
+ .append(typeName)
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("ptr: *mut c_void,")
+ .endLine()
+ .endBlock();
+
+ // Implementation with opaque field accessors
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("impl ")
+ .append(typeName)
+ .endLine()
+ .beginBlock();
+
+ // Constructor
+ file.beginLine()
+ .append("pub fn new() -> Option<Self> {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("let ptr = unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_constructor() };")
+ .endLine()
+ .beginLine()
+ .append("if ptr.is_null() {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("None")
+ .endLine()
+ .beginLine()
+ .append("} else {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("Some(Self { ptr })")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine();
+
+ // from_ptr method for creating wrapper from existing pointer with C++ type casting
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn from_ptr(ptr: *mut c_void) -> Option<Self>")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("let casted_ptr = unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_from_ptr(ptr) };")
+ .endLine()
+ .beginLine()
+ .append("if casted_ptr.is_null()")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("None")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("else")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("Some(Self { ptr: casted_ptr })")
+ .endLine()
+ .endBlock()
+ .endBlock();
+
+ // Opaque field accessors
+ for (const auto& member : entity->getDirectMembers())
+ {
+ OString memberName = u2b(member.name); // Use original case, not snake_case
+
+ // Getter
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn get_")
+ .append(memberName)
+ .append("(&self) -> *mut c_void {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_get_")
+ .append(memberName)
+ .append("(self.ptr) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine();
+
+ // Setter
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn set_")
+ .append(memberName)
+ .append("(&mut self, value: *mut c_void) {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_set_")
+ .append(memberName)
+ .append("(self.ptr, value) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine();
+ }
+
+ file.endBlock();
+
+ // Drop implementation
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("impl Drop for ")
+ .append(typeName)
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("fn drop(&mut self) {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("if !self.ptr.is_null() {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_destroy(self.ptr) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .endBlock();
+
+ // Extern "C" declarations for opaque operations
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("unsafe extern \"C\" {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_constructor() -> *mut c_void;")
+ .endLine()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_destroy(ptr: *mut c_void);")
+ .endLine()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_from_ptr(ptr: *mut c_void) -> *mut c_void;")
+ .endLine();
+
+ for (const auto& member : entity->getDirectMembers())
+ {
+ OString memberName = u2b(member.name); // Use original case, not snake_case
+ file.beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_get_")
+ .append(memberName)
+ .append("(ptr: *mut c_void) -> *mut c_void;")
+ .endLine()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_set_")
+ .append(memberName)
+ .append("(ptr: *mut c_void, value: *mut c_void);")
+ .endLine();
+ }
+
+ file.beginLine().append("}").endLine();
+
+ file.closeFile();
+}
+
+void RustProducer::produceInterface(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ RustFile file(m_outputDir, name);
+
+ if (m_verbose)
+ std::cout << "[rust-opaque-interface] " << name << " -> " << file.getPath() << '\n';
+ if (m_dryRun)
+ return;
+
+ file.openFile();
+
+ OString typeName(splitName(name)); // Simple name for Rust interface
+ OString externFunctionPrefix = getRustTypeName(name); // Full name for extern "C" functions
+
+ file.beginLine()
+ .append("/// Opaque Rust interface wrapper for ")
+ .append(name)
+ .endLine()
+ .beginLine()
+ .append("use std::ffi::c_void;")
+ .endLine()
+ .beginLine()
+ .append("#[allow(non_camel_case_types)]")
+ .endLine()
+ .beginLine()
+ .append("pub struct ")
+ .append(typeName)
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("ptr: *mut c_void,")
+ .endLine()
+ .endBlock();
+
+ // Implementation block
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("impl ")
+ .append(typeName)
+ .endLine()
+ .beginBlock();
+
+ // Constructor
+ file.beginLine()
+ .append("pub fn new() -> Option<Self> {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("let ptr = unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_constructor() };")
+ .endLine()
+ .beginLine()
+ .append("if ptr.is_null() {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("None")
+ .endLine()
+ .beginLine()
+ .append("} else {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("Some(Self { ptr })")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine();
+
+ // from_ptr method for creating wrapper from existing pointer with C++ type casting
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn from_ptr(ptr: *mut c_void) -> Option<Self>")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("let casted_ptr = unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_from_ptr(ptr) };")
+ .endLine()
+ .beginLine()
+ .append("if casted_ptr.is_null()")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("None")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append("else")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("Some(Self { ptr: casted_ptr })")
+ .endLine()
+ .endBlock()
+ .endBlock();
+
+ // as_ptr method for getting the raw pointer
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn as_ptr(&self) -> *mut c_void")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("self.ptr")
+ .endLine()
+ .endBlock();
+
+ // Validity check - only add if there's no conflicting isValid method
+ bool hasIsValidMethod = false;
+ for (const auto& method : entity->getDirectMethods())
+ {
+ if (u2b(method.name).equalsIgnoreAsciiCase("isValid"))
+ {
+ hasIsValidMethod = true;
+ break;
+ }
+ }
+
+ if (!hasIsValidMethod)
+ {
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn is_valid(&self) -> bool {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_is_valid(self.ptr) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine();
+ }
+
+ // Method wrappers - all methods return opaque pointers
+ for (const auto& method : entity->getDirectMethods())
+ {
+ OString rustMethodName = getRustFunctionName(u2b(method.name));
+
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub fn ")
+ .append(rustMethodName)
+ .append("(&self");
+
+ // All parameters are opaque void pointers
+ for (const auto& param : method.parameters)
+ {
+ file.append(", ").append(param.name).append(": *mut c_void");
+ }
+
+ file.append(") -> ")
+ .append(getRustReturnType(method.returnType))
+ .append(" {")
+ .endLine()
+ .extraIndent();
+
+ // Handle return value conversion based on return type
+ if (method.returnType == u"void")
+ {
+ // Void methods - just call the function with semicolon (no return)
+ file.beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_")
+ .append(method.name)
+ .append("(self.ptr");
+
+ for (const auto& param : method.parameters)
+ {
+ file.append(", ").append(param.name);
+ }
+
+ file.append(") };").endLine();
+ }
+ else
+ {
+ // Non-void methods - call function and convert result
+ file.beginLine()
+ .append("let ptr = unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_")
+ .append(method.name)
+ .append("(self.ptr");
+
+ for (const auto& param : method.parameters)
+ {
+ file.append(", ").append(param.name);
+ }
+
+ file.append(") };").endLine();
+
+ // Convert result based on return type
+ if (isUnoInterface(method.returnType) || isUnoStruct(method.returnType)
+ || isUnoEnum(method.returnType))
+ {
+ // For interface/struct/enum returns - use service-style conversion
+ OString rustType = u2b(method.returnType);
+ if (rustType.indexOf('.') != -1)
+ {
+ sal_Int32 lastDot = rustType.lastIndexOf('.');
+ if (lastDot != -1)
+ {
+ OString simpleName = rustType.copy(lastDot + 1);
+ OString modulePath = rustType.replaceAll("."_ostr, "::"_ostr);
+
+ file.beginLine().append("if ptr.is_null() {").endLine();
+ file.extraIndent().beginLine().append("None").endLine();
+ file.beginLine().append("} else {").endLine();
+ // Check if this is an enum type
+ if (isUnoEnum(method.returnType))
+ {
+ // Enum types - cast from void* to i32 and use from_i32
+ file.extraIndent()
+ .beginLine()
+ .append("Some(crate::generated::rustmaker::")
+ .append(modulePath)
+ .append("::")
+ .append(simpleName)
+ .append("::from_i32(unsafe { *(ptr as *const i32) }))")
+ .endLine();
+ }
+ else
+ {
+ // Interface and struct types - use from_ptr
+ file.extraIndent()
+ .beginLine()
+ .append("crate::generated::rustmaker::")
+ .append(modulePath)
+ .append("::")
+ .append(simpleName)
+ .append("::from_ptr(ptr)")
+ .endLine();
+ }
+ file.beginLine().append("}").endLine();
+ }
+ }
+ }
+ else
+ {
+ // Convert raw pointer to wrapper type for other types
+ OString rustType = u2b(method.returnType);
+
+ // Handle special types that need conversion
+ if (rustType == "string")
+ {
+ file.beginLine().append("if ptr.is_null() {").endLine();
+ file.extraIndent().beginLine().append("None").endLine();
+ file.beginLine().append("} else {").endLine();
+ file.extraIndent()
+ .beginLine()
+ .append("Some(unsafe { crate::core::OUString::from_raw(ptr as *mut "
+ "crate::ffi::rtl_string::rtl_uString) })")
+ .endLine();
+ file.beginLine().append("}").endLine();
+ }
+ else if (rustType == "any" || rustType == "com.sun.star.uno.Any")
+ {
+ file.beginLine().append("if ptr.is_null() {").endLine();
+ file.extraIndent().beginLine().append("None").endLine();
+ file.beginLine().append("} else {").endLine();
+ file.extraIndent()
+ .beginLine()
+ .append("Some(unsafe { crate::core::Any::from_raw(std::ptr::read(ptr as "
+ "*mut crate::ffi::uno_any::uno_Any)) })")
+ .endLine();
+ file.beginLine().append("}").endLine();
+ }
+ else
+ {
+ // Check for typedef resolution first
+ OString resolvedType = resolveTypedef(method.returnType);
+ if (resolvedType != rustType)
+ {
+ // It's a typedef - handle based on resolved type
+ if (resolvedType == "boolean")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u8) }").endLine();
+ }
+ else if (resolvedType == "byte")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i8) }").endLine();
+ }
+ else if (resolvedType == "short")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i16) }").endLine();
+ }
+ else if (resolvedType == "unsigned short")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u16) }").endLine();
+ }
+ else if (resolvedType == "long")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i32) }").endLine();
+ }
+ else if (resolvedType == "unsigned long")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u32) }").endLine();
+ }
+ else if (resolvedType == "hyper")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i64) }").endLine();
+ }
+ else if (resolvedType == "unsigned hyper")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u64) }").endLine();
+ }
+ else if (resolvedType == "float")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const f32) }").endLine();
+ }
+ else if (resolvedType == "double")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const f64) }").endLine();
+ }
+ else if (resolvedType == "char")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u16) }").endLine();
+ }
+ else
+ {
+ // Typedef resolves to other types - return raw pointer
+ file.beginLine().append("ptr").endLine();
+ }
+ }
+ else
+ {
+ // Not a typedef - check for primitive types that need dereferencing
+ if (rustType == "boolean")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u8) }").endLine();
+ }
+ else if (rustType == "byte")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i8) }").endLine();
+ }
+ else if (rustType == "short")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i16) }").endLine();
+ }
+ else if (rustType == "unsigned short")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u16) }").endLine();
+ }
+ else if (rustType == "long")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i32) }").endLine();
+ }
+ else if (rustType == "unsigned long")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u32) }").endLine();
+ }
+ else if (rustType == "hyper")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const i64) }").endLine();
+ }
+ else if (rustType == "unsigned hyper")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u64) }").endLine();
+ }
+ else if (rustType == "float")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const f32) }").endLine();
+ }
+ else if (rustType == "double")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const f64) }").endLine();
+ }
+ else if (rustType == "char")
+ {
+ file.beginLine().append("unsafe { *(ptr as *const u16) }").endLine();
+ }
+ else
+ {
+ // For other types (sequences, templates, etc), return the raw pointer
+ file.beginLine().append("ptr").endLine();
+ }
+ }
+ }
+ }
+ }
+
+ file.beginLine().append("}").endLine();
+ }
+
+ file.endBlock();
+
+ // Drop implementation for automatic cleanup
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("impl Drop for ")
+ .append(typeName)
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("fn drop(&mut self) {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("if !self.ptr.is_null() {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_destructor(self.ptr) }")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .beginLine()
+ .append("}")
+ .endLine()
+ .endBlock();
+
+ // Thread safety markers
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("unsafe impl Send for ")
+ .append(typeName)
+ .append(" {}")
+ .endLine()
+ .beginLine()
+ .append("unsafe impl Sync for ")
+ .append(typeName)
+ .append(" {}")
+ .endLine();
+
+ // Extern "C" declarations - connects to C-side bridge
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("unsafe extern \"C\" {")
+ .endLine()
+ .extraIndent()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_constructor() -> *mut c_void;")
+ .endLine()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_destructor(ptr: *mut c_void);")
+ .endLine()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_from_ptr(ptr: *mut c_void) -> *mut c_void;")
+ .endLine();
+
+ // Only declare _is_valid if we don't have a conflicting isValid method
+ if (!hasIsValidMethod)
+ {
+ file.beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_is_valid(ptr: *mut c_void) -> bool;")
+ .endLine();
+ }
+
+ for (const auto& method : entity->getDirectMethods())
+ {
+ file.beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_")
+ .append(method.name)
+ .append("(ptr: *mut c_void");
+
+ for (const auto& param : method.parameters)
+ {
+ file.append(", ").append(param.name).append(": *mut c_void");
+ }
+
+ file.append(") -> ");
+
+ if (method.returnType == u"void")
+ {
+ file.append("()");
+ }
+ else
+ {
+ file.append("*mut c_void");
+ }
+
+ file.append(";").endLine();
+ }
+
+ file.beginLine().append("}").endLine();
+
+ file.closeFile();
+}
+
+void RustProducer::produceService(
+ std::string_view name, const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity)
+{
+ RustFile file(m_outputDir, name);
+
+ if (m_verbose)
+ std::cout << "[rust-opaque-service] " << name << " -> " << file.getPath() << '\n';
+ if (m_dryRun)
+ return;
+
+ file.openFile();
+
+ OString serviceName(splitName(name)); // Simple name for Rust service
+ OString externFunctionPrefix = getRustTypeName(name); // Full name for extern "C" functions
+ OUString interfaceType = entity->getBase();
+
+ // Generate proper module path for the interface
+ OString interfaceTypeStr = u2b(interfaceType);
+ std::string_view interfaceTypeName = splitName(interfaceTypeStr);
+
+ // Convert interface type to full module path
+ OString path = interfaceTypeStr;
+ path = path.replaceAll("."_ostr, "::"_ostr);
+ OString interfaceModulePath
+ = "crate::generated::rustmaker::"_ostr + path + "::" + interfaceTypeName;
+
+ file.beginLine()
+ .append("/// Opaque Rust service wrapper for ")
+ .append(name)
+ .endLine()
+ .beginLine()
+ .append("use std::ffi::c_void;")
+ .endLine()
+ .beginLine()
+ .append("#[allow(non_camel_case_types)]")
+ .endLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("pub struct ")
+ .append(serviceName)
+ .append(";")
+ .endLine();
+
+ // Implementation block
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("impl ")
+ .append(serviceName)
+ .endLine()
+ .beginBlock();
+
+ // Service creation method
+ file.beginLine()
+ .append("/// Create a new instance of ")
+ .append(name)
+ .endLine()
+ .beginLine()
+ .append("pub fn create(context: *mut c_void) -> Option<")
+ .append(interfaceModulePath)
+ .append("> ")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("let ptr = unsafe { ")
+ .append(externFunctionPrefix)
+ .append("_create(context) };")
+ .endLine()
+ .beginLine()
+ .append("if ptr.is_null() ")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("None")
+ .endLine()
+ .endBlock()
+ .beginLine()
+ .append(" else ")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append(interfaceModulePath)
+ .append("::from_ptr(ptr)")
+ .endLine()
+ .endBlock()
+ .endBlock();
+
+ file.endBlock();
+
+ // Extern "C" declarations
+ file.beginLine()
+ .append("")
+ .endLine()
+ .beginLine()
+ .append("unsafe extern \"C\" ")
+ .endLine()
+ .beginBlock()
+ .beginLine()
+ .append("fn ")
+ .append(externFunctionPrefix)
+ .append("_create(context: *mut c_void) -> *mut c_void;")
+ .endLine()
+ .endBlock();
+
+ file.closeFile();
+}
+
+// Helper functions
+std::string_view RustProducer::splitName(std::string_view name)
+{
+ size_t split = name.find_last_of(".::");
+ if (split != std::string_view::npos)
+ return name.substr(split + 1);
+ else
+ return name;
+}
+
+OString RustProducer::getRustFunctionName(std::string_view methodName)
+{
+ // Keep original UNO method name (no snake_case conversion)
+ std::string result(methodName);
+
+ // Handle Rust reserved keywords by prefixing with r#
+ if (result == "move" || result == "type" || result == "ref" || result == "mut"
+ || result == "impl" || result == "fn" || result == "let" || result == "const"
+ || result == "static" || result == "match" || result == "if" || result == "else"
+ || result == "for" || result == "while" || result == "loop" || result == "break"
+ || result == "continue" || result == "return" || result == "self" || result == "Self"
+ || result == "super" || result == "crate" || result == "mod" || result == "pub"
+ || result == "use" || result == "extern" || result == "struct" || result == "enum"
+ || result == "trait" || result == "async" || result == "await" || result == "where"
+ || result == "unsafe" || result == "dyn" || result == "true" || result == "false")
+ {
+ result = "r#" + result;
+ }
+
+ return OString(result.c_str());
+}
+
+OString RustProducer::getRustTypeName(std::string_view unoName)
+{
+ // Convert com.sun.star.lang.XMain to com__sun__star__lang__XMain
+ OString result(unoName);
+ result = result.replaceAll("."_ostr, "__"_ostr);
+ return result;
+}
+
+OString RustProducer::getRustWrapperTypeName(std::u16string_view unoType) const
+{
+ OString rustType = u2b(unoType);
+
+ // Handle void returns
+ if (rustType == "void")
+ {
+ return "()"_ostr;
+ }
+
+ // Handle primitive types
+ if (rustType == "boolean")
+ return "u8";
+ if (rustType == "byte")
+ return "i8";
+ if (rustType == "short")
+ return "i16";
+ if (rustType == "unsigned short")
+ return "u16";
+ if (rustType == "long")
+ return "i32";
+ if (rustType == "unsigned long")
+ return "u32";
+ if (rustType == "hyper")
+ return "i64";
+ if (rustType == "unsigned hyper")
+ return "u64";
+ if (rustType == "float")
+ return "f32";
+ if (rustType == "double")
+ return "f64";
+ if (rustType == "char")
+ return "u16";
+
+ // Handle special UNO types
+ if (rustType == "string")
+ return "Option<crate::core::OUString>";
+ if (rustType == "any" || rustType == "com.sun.star.uno.Any")
+ return "Option<crate::core::Any>";
+
+ // Handle sequence types (arrays) - return raw pointer for now
+ if (rustType.startsWith("[]"))
+ {
+ return "*mut c_void";
+ }
+
+ // Handle template types like Pair<T,U> - return raw pointer for now to avoid parsing issues
+ if (rustType.indexOf('<') != -1 && rustType.indexOf('>') != -1)
+ {
+ return "*mut c_void";
+ }
+
+ // Handle generated UNO types (interface, struct, enum)
+ if (rustType.indexOf('.') != -1)
+ {
+ // Skip types that look malformed or have invalid characters
+ if (rustType.indexOf('[') != -1 || rustType.indexOf('<') != -1)
+ {
+ return "*mut c_void";
+ }
+
+ // First resolve typedefs
+ OString resolvedType = resolveTypedef(unoType);
+ if (resolvedType != rustType)
+ {
+ // It's a typedef - recursively get wrapper type for resolved type
+ return getRustWrapperTypeName(b2u(resolvedType));
+ }
+
+ // Not a typedef - convert dots to :: for module path
+ OString modulePath = rustType.replaceAll("."_ostr, "::"_ostr);
+
+ // Extract simple type name
+ sal_Int32 lastDot = rustType.lastIndexOf('.');
+ if (lastDot != -1)
+ {
+ OString simpleName = rustType.copy(lastDot + 1);
+ return "Option<crate::generated::rustmaker::" + modulePath + "::" + simpleName + ">";
+ }
+ }
+
+ // Default to raw pointer for unknown types
+ return "*mut c_void";
+}
+
+OString RustProducer::resolveTypedef(std::u16string_view unoType) const
+{
+ // Recursively resolve typedefs to underlying types
+ rtl::Reference<unoidl::Entity> entity;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(unoType), &entity);
+
+ if (sort == codemaker::UnoType::Sort::Typedef)
+ {
+ rtl::Reference<unoidl::TypedefEntity> typedefEntity(
+ static_cast<unoidl::TypedefEntity*>(entity.get()));
+ if (typedefEntity.is())
+ {
+ // Recursively resolve typedefs
+ return resolveTypedef(typedefEntity->getType());
+ }
+ }
+
+ // Return original type if not a typedef
+ return u2b(unoType);
+}
+
+OString RustProducer::getRustReturnType(std::u16string_view unoType) const
+{
+ // Handle void returns
+ if (unoType == u"void")
+ {
+ return "()";
+ }
+
+ // For interfaces, structs, enums - return Option<TypeWrapper> like services
+ if (isUnoInterface(unoType) || isUnoStruct(unoType) || isUnoEnum(unoType))
+ {
+ OString rustType = u2b(unoType);
+ if (rustType.indexOf('.') != -1)
+ {
+ // Convert dots to :: for module path
+ OString modulePath = rustType.replaceAll(".", "::");
+
+ // Extract simple type name
+ sal_Int32 lastDot = rustType.lastIndexOf('.');
+ if (lastDot != -1)
+ {
+ OString simpleName = rustType.copy(lastDot + 1);
+ return "Option<crate::generated::rustmaker::" + modulePath + "::" + simpleName
+ + ">";
+ }
+ }
+ }
+
+ // For primitive and other types, use the existing logic
+ return getRustWrapperTypeName(unoType);
+}
+
+OString RustProducer::getRustFFIReturnType(std::u16string_view unoType) const
+{
+ // Handle void returns
+ if (unoType == u"void")
+ {
+ return "()";
+ }
+
+ // For interfaces, structs, enums - return their opaque handle typedef
+ if (isUnoInterface(unoType) || isUnoStruct(unoType) || isUnoEnum(unoType))
+ {
+ // Convert UNO type name to typedef handle name
+ // com.sun.star.lang.XMain -> com__sun__star__lang__XMainHandle
+ OString functionPrefix = getRustTypeName(std::string(unoType.begin(), unoType.end()));
+ return functionPrefix + "Handle";
+ }
+
+ // For other types (primitives, sequences, etc) - use void*
+ return "*mut c_void";
+}
+
+bool RustProducer::isUnoInterface(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::Interface;
+}
+
+bool RustProducer::isUnoStruct(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::PlainStruct;
+}
+
+bool RustProducer::isUnoEnum(std::u16string_view typeName) const
+{
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(OUString(typeName), &entity, &cursor);
+ return sort == codemaker::UnoType::Sort::Enum;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/rustproduce.hxx b/codemaker/source/rustmaker/rustproduce.hxx
new file mode 100644
index 000000000000..3c2d0fb2cbfe
--- /dev/null
+++ b/codemaker/source/rustmaker/rustproduce.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string_view>
+#include <unoidl/unoidl.hxx>
+#include <codemaker/typemanager.hxx>
+#include <rtl/string.hxx>
+
+/**
+ * RustProducer generates Rust-side opaque pointer wrappers.
+ *
+ * This is the Rust-side generator in the opaque pointer approach.
+ * It creates Rust structs that use void* pointers and call extern "C"
+ * bridge functions generated by the C-side (CppProducer).
+ *
+ * Architecture:
+ * - Rust structs with opaque void* pointers
+ * - Safe RAII wrappers with Drop trait
+ * - extern "C" function declarations matching C-side bridge
+ * - All parameters/returns are void* for maximum simplicity
+ */
+class RustProducer
+{
+public:
+ /**
+ * Constructor
+ * @param outputDir Directory for generated Rust files
+ * @param verbose Enable verbose output
+ * @param dryRun Don't actually write files
+ * @param typeManager UNO type manager for accessing type information
+ */
+ RustProducer(const OString& outputDir, bool verbose, bool dryRun,
+ const rtl::Reference<TypeManager>& typeManager);
+
+ /**
+ * Generate Rust opaque enum wrapper
+ * Creates simple enum with conversion functions via extern "C"
+ */
+ void produceEnum(std::string_view name, const rtl::Reference<unoidl::EnumTypeEntity>& entity);
+
+ /**
+ * Generate Rust opaque struct wrapper
+ * Creates struct with void* pointer and field accessor methods
+ */
+ void produceStruct(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+
+ /**
+ * Generate Rust opaque interface wrapper
+ * Creates struct with void* pointer and method wrappers
+ */
+ void produceInterface(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+
+ /**
+ * Generate Rust opaque service wrapper
+ * Creates service creation wrapper methods
+ */
+ void produceService(std::string_view name,
+ const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity);
+
+private:
+ // Configuration
+ OString m_outputDir;
+ bool m_verbose;
+ bool m_dryRun;
+ rtl::Reference<TypeManager> m_typeManager;
+
+ // Helper functions
+ static std::string_view splitName(std::string_view name);
+ static OString getRustFunctionName(std::string_view methodName);
+ static OString getRustTypeName(std::string_view unoName);
+ OString getRustWrapperTypeName(std::u16string_view unoType) const;
+ OString getRustReturnType(std::u16string_view unoType) const;
+ OString getRustFFIReturnType(std::u16string_view unoType) const;
+ OString resolveTypedef(std::u16string_view unoType) const;
+
+ // Type classification helpers
+ bool isUnoInterface(std::u16string_view typeName) const;
+ bool isUnoStruct(std::u16string_view typeName) const;
+ bool isUnoEnum(std::u16string_view typeName) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/type_analyzer.cxx b/codemaker/source/rustmaker/type_analyzer.cxx
new file mode 100644
index 000000000000..75eb4323e89e
--- /dev/null
+++ b/codemaker/source/rustmaker/type_analyzer.cxx
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "type_analyzer.hxx"
+#include <codemaker/unotype.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <unoidl/unoidl.hxx>
+#include <vector>
+
+TypeAnalyzer::TypeAnalyzer(const rtl::Reference<TypeManager>& typeManager)
+ : m_typeManager(typeManager)
+{
+}
+
+TypeAnalyzer::TypeInfo
+TypeAnalyzer::analyzeInterface(const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ TypeInfo typeInfo;
+
+ // Always need XInterface for base type operations
+ typeInfo.needsUnoInterface = true;
+ typeInfo.namespaces.insert("com::sun::star::uno"_ostr);
+
+ // Analyze all methods in the interface
+ for (const auto& method : entity->getDirectMethods())
+ {
+ // Analyze return type
+ if (method.returnType != u"void")
+ {
+ analyzeType(typeInfo, method.returnType);
+ }
+
+ // Analyze parameter types
+ for (const auto& param : method.parameters)
+ {
+ analyzeType(typeInfo, param.type);
+ }
+ }
+
+ return typeInfo;
+}
+
+void TypeAnalyzer::analyzeType(TypeInfo& typeInfo, std::u16string_view unoType)
+{
+ // Use cppumaker's approach: recursively insert dependencies
+ insertDependency(typeInfo, unoType);
+}
+
+void TypeAnalyzer::insertDependency(TypeInfo& typeInfo, std::u16string_view unoType)
+{
+ // Decompose sequence/template types like cppumaker does
+ sal_Int32 sequenceDepth;
+ std::vector<OString> templateArgs;
+ OString baseType = codemaker::UnoType::decompose(u2b(unoType), &sequenceDepth, &templateArgs);
+ OUString baseTypeU = b2u(baseType);
+
+ if (sequenceDepth != 0)
+ {
+ typeInfo.needsSequence = true;
+ }
+
+ // Get the type sort to determine how to handle it
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+ codemaker::UnoType::Sort sort = m_typeManager->getSort(baseTypeU, &entity, &cursor);
+
+ switch (sort)
+ {
+ case codemaker::UnoType::Sort::Void:
+ // No special handling needed
+ break;
+ case codemaker::UnoType::Sort::Boolean:
+ case codemaker::UnoType::Sort::Byte:
+ case codemaker::UnoType::Sort::Short:
+ case codemaker::UnoType::Sort::UnsignedShort:
+ case codemaker::UnoType::Sort::Long:
+ case codemaker::UnoType::Sort::UnsignedLong:
+ case codemaker::UnoType::Sort::Hyper:
+ case codemaker::UnoType::Sort::UnsignedHyper:
+ case codemaker::UnoType::Sort::Float:
+ case codemaker::UnoType::Sort::Double:
+ case codemaker::UnoType::Sort::Char:
+ typeInfo.needsSalTypes = true;
+ break;
+ case codemaker::UnoType::Sort::String:
+ typeInfo.needsString = true;
+ typeInfo.needsRtlUstring = true;
+ break;
+ case codemaker::UnoType::Sort::Type:
+ typeInfo.needsUnoInterface = true; // Type needs XInterface includes
+ break;
+ case codemaker::UnoType::Sort::Any:
+ typeInfo.needsAny = true;
+ break;
+ case codemaker::UnoType::Sort::PlainStruct:
+ {
+ // Add this struct to dependencies and recursively analyze its members
+ typeInfo.structTypes.insert(baseType);
+
+ rtl::Reference<unoidl::PlainStructTypeEntity> structEntity(
+ static_cast<unoidl::PlainStructTypeEntity*>(entity.get()));
+ if (structEntity.is())
+ {
+ // Recursively analyze base struct
+ if (!structEntity->getDirectBase().isEmpty())
+ {
+ insertDependency(typeInfo, structEntity->getDirectBase());
+ }
+
+ // Recursively analyze member types
+ for (const auto& member : structEntity->getDirectMembers())
+ {
+ insertDependency(typeInfo, member.type);
+ }
+ }
+ break;
+ }
+ case codemaker::UnoType::Sort::Enum:
+ typeInfo.enumTypes.insert(baseType);
+ typeInfo.needsEnum = true;
+ typeInfo.needsSalTypes = true;
+ break;
+ case codemaker::UnoType::Sort::Interface:
+ typeInfo.interfaceTypes.insert(baseType);
+ typeInfo.needsUnoInterface = true;
+ typeInfo.namespaces.insert("com::sun::star::uno"_ostr);
+ break;
+ case codemaker::UnoType::Sort::ConstantGroup:
+ typeInfo.constantGroupTypes.insert(baseType);
+ typeInfo.needsConstantGroup = true;
+ break;
+ case codemaker::UnoType::Sort::PolymorphicStructTemplate:
+ {
+ // Handle template arguments recursively
+ for (const OString& arg : templateArgs)
+ {
+ insertDependency(typeInfo, b2u(arg));
+ }
+ // Note: Don't add polymorphic struct templates to structTypes
+ // since they don't have concrete header files to include
+ break;
+ }
+ default:
+ // For unknown types, ensure basic includes
+ typeInfo.needsUnoInterface = true;
+ break;
+ }
+
+ // Extract namespace from UNO type name (for any valid UNO type)
+ if (sort != codemaker::UnoType::Sort::Void && sort != codemaker::UnoType::Sort::Boolean
+ && sort != codemaker::UnoType::Sort::Byte && sort != codemaker::UnoType::Sort::Short
+ && sort != codemaker::UnoType::Sort::UnsignedShort && sort != codemaker::UnoType::Sort::Long
+ && sort != codemaker::UnoType::Sort::UnsignedLong && sort != codemaker::UnoType::Sort::Hyper
+ && sort != codemaker::UnoType::Sort::UnsignedHyper
+ && sort != codemaker::UnoType::Sort::Float && sort != codemaker::UnoType::Sort::Double
+ && sort != codemaker::UnoType::Sort::Char && sort != codemaker::UnoType::Sort::String
+ && sort != codemaker::UnoType::Sort::Type && sort != codemaker::UnoType::Sort::Any
+ && baseType.indexOf('.') != sal_Int32(std::string::npos))
+ {
+ typeInfo.namespaces.insert(extractNamespace(baseTypeU));
+ }
+}
+
+OString TypeAnalyzer::extractNamespace(std::u16string_view unoType)
+{
+ OString typeStr = u2b(unoType);
+
+ // Convert dots to double colons for C++ namespace
+ OString cppNamespace = typeStr.replaceAll("."_ostr, "::"_ostr);
+
+ // Remove the last component (the actual type name) to get just the namespace
+ sal_Int32 lastColon = cppNamespace.lastIndexOf("::");
+ if (lastColon != -1)
+ {
+ return cppNamespace.copy(0, lastColon);
+ }
+
+ return cppNamespace;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/type_analyzer.hxx b/codemaker/source/rustmaker/type_analyzer.hxx
new file mode 100644
index 000000000000..e0b9f177e51c
--- /dev/null
+++ b/codemaker/source/rustmaker/type_analyzer.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <set>
+#include <string>
+#include <unoidl/unoidl.hxx>
+#include <codemaker/typemanager.hxx>
+#include <rtl/string.hxx>
+
+/**
+ * Analyzes UNO interface entities to identify type dependencies for dynamic include generation.
+ */
+class TypeAnalyzer
+{
+public:
+ TypeAnalyzer(const rtl::Reference<TypeManager>& typeManager);
+
+private:
+ rtl::Reference<TypeManager> m_typeManager;
+
+public:
+ /**
+ * Container for type analysis results.
+ */
+ struct TypeInfo
+ {
+ std::set<OString> interfaceTypes; // UNO interface types (e.g., "com.sun.star.text.XText")
+ std::set<OString> structTypes; // UNO struct types (e.g., "com.sun.star.beans.Property")
+ std::set<OString> enumTypes; // UNO enum types (e.g., "com.sun.star.uno.TypeClass")
+ std::set<OString>
+ constantGroupTypes; // UNO constant groups (e.g., "com.sun.star.awt.FontWeight")
+ std::set<OString> namespaces; // Required namespaces (e.g., "com::sun::star::text")
+
+ // Core UNO types - implemented first: Any
+ bool needsAny = false;
+
+ // Core UNO types - TODO: implement in future
+ bool needsString = false; // TODO: implement string type handling
+ bool needsSequence = false; // TODO: implement sequence type handling
+ bool needsPropertyValue = false; // TODO: implement PropertyValue handling
+
+ // Basic types
+ bool needsSalTypes = false; // For sal_Int32, sal_Bool, etc.
+ bool needsRtlUstring = false; // For rtl_uString*
+ bool needsUnoInterface = false; // For XInterface base type
+ bool needsEnum = false; // For enum type handling
+ bool needsConstantGroup = false; // For constant group handling
+ };
+
+ /**
+ * Analyzes the given interface entity and returns type dependency information.
+ *
+ * @param entity The interface entity to analyze.
+ * @return TypeInfo containing all identified dependencies.
+ */
+ TypeInfo analyzeInterface(const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+
+ /**
+ * Analyzes a single UNO type string and updates the TypeInfo accordingly.
+ *
+ * @param typeInfo The TypeInfo to update.
+ * @param unoType The UNO type string to analyze (e.g., "com.sun.star.uno.Any").
+ */
+ void analyzeType(TypeInfo& typeInfo, std::u16string_view unoType);
+
+private:
+ /**
+ * Recursively inserts type dependencies following cppumaker's pattern.
+ * This method handles decomposition of sequences and templates, and recursively
+ * analyzes struct members and base types.
+ *
+ * @param typeInfo The TypeInfo to update with dependencies.
+ * @param unoType The UNO type to analyze recursively.
+ */
+ void insertDependency(TypeInfo& typeInfo, std::u16string_view unoType);
+
+ /**
+ * Extracts namespace from a UNO type name.
+ *
+ * @param unoType The UNO type name (e.g., "com.sun.star.text.XText").
+ * @return The corresponding C++ namespace (e.g., "com::sun::star::text").
+ */
+ static OString extractNamespace(std::u16string_view unoType);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/unoproduce.cxx b/codemaker/source/rustmaker/unoproduce.cxx
new file mode 100644
index 000000000000..ec873466a012
--- /dev/null
+++ b/codemaker/source/rustmaker/unoproduce.cxx
@@ -0,0 +1,376 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <iostream>
+#include <set>
+#include <memory>
+
+#include <o3tl/string_view.hxx>
+#include <string_view>
+
+#include "unoproduce.hxx"
+#include "rustproduce.hxx"
+#include "cpproduce.hxx"
+#include <rtl/strbuf.hxx>
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+#include "rustfile.hxx"
+#include <unoidl/unoidl.hxx>
+#include <codemaker/unotype.hxx>
+
+const std::unordered_set<std::string_view> UnoProducer::m_reservedKeywords
+ // Rust keywords that need special handling to avoid naming conflicts
+ = { "as", "break", "const", "continue", "crate", "else", "enum", "extern",
+ "false", "fn", "for", "if", "impl", "in", "let", "loop",
+ "match", "mod", "move", "mut", "pub", "ref", "return", "Result",
+ "self", "Self", "static", "struct", "super", "trait", "true", "type",
+ "unsafe", "use", "where", "while", "async", "await", "dyn", "try" };
+
+const std::unordered_map<std::string_view, OString> UnoProducer::m_baseTypes
+ // Maps UNO basic types to their Rust equivalents
+ // TODO: need to edit the core types Implemented manauly
+ = { { "boolean", "bool"_ostr },
+ { "char", "char"_ostr },
+ { "byte", "i8"_ostr },
+ { "short", "i16"_ostr },
+ { "unsigned short", "u16"_ostr },
+ { "long", "i32"_ostr },
+ { "unsigned long", "u32"_ostr },
+ { "hyper", "i64"_ostr },
+ { "unsigned hyper", "u64"_ostr },
+ { "float", "f32"_ostr },
+ { "double", "f64"_ostr },
+ { "string", "String"_ostr },
+ { "void", "()"_ostr },
+ { "type", "uno::type"_ostr }, // TODO:
+ { "any", "uno::any"_ostr }, // TODO:
+ // TODO: These exception types need proper implementation
+ { "com.sun.star.uno.Exception", "com::sun::star::uno::Exception"_ostr } };
+// Note: XInterface removed from baseTypes so it can be generated like other interfaces
+
+std::string_view UnoProducer::splitName(std::string_view name)
+{
+ size_t split = name.find_last_of(".::");
+ if (split != std::string_view::npos)
+ return name.substr(split + 1);
+ else
+ return name;
+}
+
+OString UnoProducer::handleName(std::string_view name, bool istype)
+{
+ // Convert UNO dotted names to Rust double-colon syntax
+ OString temp(name);
+ OString result = temp.replaceAll("."_ostr, "::"_ostr);
+ temp = result;
+ if (istype)
+ result = "crate::"_ostr + temp + "::" + splitName(name);
+ return result;
+}
+
+OString UnoProducer::handleName(std::u16string_view name, bool istype)
+{
+ return handleName(u2b(name), istype);
+}
+
+OString UnoProducer::getBaseUnoName(std::string_view name)
+{
+ // Extract base type name by removing array brackets and template parameters
+ size_t start = name.find_first_not_of("[]");
+ if (start == std::string_view::npos)
+ start = 0;
+
+ size_t end = name.find_first_of('<');
+ if (end == std::string_view::npos)
+ end = name.size();
+
+ return OString(name.substr(start, end - start));
+}
+OString UnoProducer::getBaseUnoName(std::u16string_view name) { return getBaseUnoName(u2b(name)); }
+
+OString UnoProducer::getSafeIdentifier(std::string_view name, bool istype = false)
+{
+ // Add underscore suffix to avoid Rust keyword conflicts
+ OString temp = handleName(name, istype);
+ return m_reservedKeywords.contains(temp) ? temp + "_"_ostr : temp;
+}
+
+OString UnoProducer::getSafeIdentifier(std::u16string_view name, bool istype = false)
+{
+ return getSafeIdentifier(u2b(name), istype);
+}
+
+void UnoProducer::separatedForeach(const auto& items, auto&& sepFunc, auto&& itemFunc)
+{
+ for (auto it = items.begin(); it != items.end(); ++it)
+ {
+ if (it != items.begin())
+ sepFunc();
+ itemFunc(*it);
+ }
+}
+
+void UnoProducer::initProducer(const RustOptions& options)
+{
+ m_manager = rtl::Reference<TypeManager>(new TypeManager());
+
+ // Load type providers from input files (following old approach pattern)
+ for (const OString& file : options.getInputFiles())
+ m_manager->loadProvider(convertToFileUrl(file), true);
+ for (const OString& file : options.getExtraInputFiles())
+ m_manager->loadProvider(convertToFileUrl(file), false);
+
+ // Get separate output directories for C++ and Rust files
+ OString cppOutputDir = options.getOption("--cpp-output-dir"_ostr);
+ m_rustOutputDir = options.getOption("--rust-output-dir"_ostr);
+ // Enable dry-run mode (don't actually write files)
+ m_dryRun = options.isValid("--dry-run"_ostr);
+ // Enable verbose output for debugging
+ m_verbose = options.isValid("--verbose"_ostr);
+
+ // Initialize both producers with separate output directories
+ m_rustProducer
+ = std::make_unique<RustProducer>(m_rustOutputDir, m_verbose, m_dryRun, m_manager);
+ m_cppProducer = std::make_unique<CppProducer>(cppOutputDir, m_verbose, m_dryRun, m_manager);
+
+ // Initialize combined C++ output file
+ m_cppProducer->initializeCombinedFile();
+
+ // Parse type selection criteria (following old approach exactly)
+ if (options.isValid("--types"_ostr))
+ {
+ const OString& names(options.getOption("--types"_ostr));
+ // Process semicolon-separated list of type names/patterns
+ for (size_t i = 0; i != std::string_view::npos;)
+ {
+ std::string_view name(o3tl::getToken(names, ';', i));
+ if (name == "*")
+ // "*" means generate all types
+ m_startingTypes.insert(""_ostr);
+ else if (name.ends_with(".*"))
+ // "namespace.*" means generate all types in namespace
+ m_startingTypes.emplace(name.substr(0, name.size() - 2));
+ else
+ // Specific type name
+ m_startingTypes.emplace(name);
+ }
+ }
+ else
+ {
+ // Default: generate all types
+ m_startingTypes.insert(""_ostr);
+ }
+}
+
+void UnoProducer::produceAll()
+{
+ for (const OString& name : m_startingTypes)
+ produceType(name);
+}
+
+void UnoProducer::finalizeGeneration()
+{
+ // Finalize combined C++ output file
+ if (m_cppProducer)
+ {
+ m_cppProducer->finalizeCombinedFile();
+ }
+
+ // Always finalize mod.rs files in opaque mode
+ if (!m_dryRun)
+ {
+ if (m_verbose)
+ std::cout << "Finalizing mod.rs files with complete module information...\n";
+
+ RustFile::finalizeModFiles(std::filesystem::path(m_rustOutputDir.getStr()));
+
+ if (m_verbose)
+ std::cout << "Module finalization complete\n";
+ }
+}
+
+void UnoProducer::produceType(const OString& name)
+{
+ // Skip already processed types to avoid duplicates
+ if (m_typesProduced.contains(name))
+ return;
+
+ m_typesProduced.insert(name);
+
+ // Skip built-in types that don't need code generation
+ if (m_baseTypes.contains(name))
+ return;
+
+ OUString uname(b2u(name));
+
+ rtl::Reference<unoidl::Entity> entity;
+ rtl::Reference<unoidl::MapCursor> cursor;
+
+ // Only generate code for types from primary providers (not dependencies)
+ if (m_manager->foundAtPrimaryProvider(uname))
+ {
+ // Dispatch to appropriate generator based on UNO type kind
+ switch (m_manager->getSort(uname, &entity, &cursor))
+ {
+ case codemaker::UnoType::Sort::Module:
+ produceModule(name, cursor);
+ break;
+
+ case codemaker::UnoType::Sort::Enum:
+ produceEnum(name, dynamic_cast<unoidl::EnumTypeEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::PlainStruct:
+ produceStruct(name, dynamic_cast<unoidl::PlainStructTypeEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::PolymorphicStructTemplate:
+ producePolyStruct(
+ name, dynamic_cast<unoidl::PolymorphicStructTypeTemplateEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::Exception:
+ produceException(name, dynamic_cast<unoidl::ExceptionTypeEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::Interface:
+ produceInterface(name, dynamic_cast<unoidl::InterfaceTypeEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::Typedef:
+ produceTypedef(name, dynamic_cast<unoidl::TypedefEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::ConstantGroup:
+ produceConstantGroup(name,
+ dynamic_cast<unoidl::ConstantGroupEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::SingleInterfaceBasedService:
+ produceService(
+ name, dynamic_cast<unoidl::SingleInterfaceBasedServiceEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::InterfaceBasedSingleton:
+ produceSingleton(
+ name, dynamic_cast<unoidl::InterfaceBasedSingletonEntity*>(entity.get()));
+ break;
+
+ case codemaker::UnoType::Sort::AccumulationBasedService:
+ case codemaker::UnoType::Sort::ServiceBasedSingleton:
+ // old-style services and singletons not supported
+ break;
+
+ default:
+ throw CannotDumpException(u"entity '"_ustr + uname + u"' has unexpected type"_ustr);
+ }
+ }
+ else
+ {
+ // type from --extra-types
+ switch (m_manager->getSort(uname, &entity, &cursor))
+ {
+ case codemaker::UnoType::Sort::Typedef:
+ produceTypedef(name, dynamic_cast<unoidl::TypedefEntity*>(entity.get()));
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void UnoProducer::produceModule(std::string_view name,
+ const rtl::Reference<unoidl::MapCursor>& cursor)
+{
+ OUString moduleName;
+ while (cursor->getNext(&moduleName).is())
+ {
+ OString memberName = name.empty() ? u2b(moduleName) : name + "."_ostr + u2b(moduleName);
+ produceType(memberName);
+ }
+}
+void UnoProducer::produceEnum(std::string_view name,
+ const rtl::Reference<unoidl::EnumTypeEntity>& entity)
+{
+ // Coordinate both producers for complete opaque enum generation
+ m_cppProducer->produceEnum(name, entity); // C++ side: bridge functions
+ m_rustProducer->produceEnum(name, entity); // Rust side: wrapper with extern declarations
+}
+
+void UnoProducer::produceStruct(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
+{
+ // Coordinate both producers for complete struct generation
+ m_cppProducer->produceStruct(name, entity); // C++ side: wrapper class + bridge functions
+ m_rustProducer->produceStruct(name, entity); // Rust side: wrapper with extern declarations
+}
+
+void UnoProducer::producePolyStruct(
+ std::string_view name, const rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>&)
+{
+ // TODO: Implement polymorphic struct support
+ if (m_verbose)
+ std::cout << "[poly-struct] " << name << " -> skipping polymorphic structs for now\n";
+}
+
+void UnoProducer::produceException(std::string_view name,
+ const rtl::Reference<unoidl::ExceptionTypeEntity>&)
+{
+ // TODO: Handle exceptions as special structs
+ if (m_verbose)
+ std::cout << "[exception] " << name << " -> treating as struct\n";
+}
+
+void UnoProducer::produceInterface(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
+{
+ // Coordinate both producers for complete interface generation
+ m_cppProducer->produceInterface(name, entity); // C++ side: wrapper class + bridge functions
+ m_rustProducer->produceInterface(name, entity); // Rust side: wrapper with extern declarations
+}
+
+void UnoProducer::produceTypedef(std::string_view name,
+ const rtl::Reference<unoidl::TypedefEntity>&)
+{
+ // TODO: Handle typedefs properly
+ if (m_verbose)
+ std::cout << "[typedef] " << name << " -> skipping typedef resolution\n";
+}
+
+void UnoProducer::produceConstantGroup(std::string_view name,
+ const rtl::Reference<unoidl::ConstantGroupEntity>&)
+{
+ // TODO: Handle constant groups
+ if (m_verbose)
+ std::cout << "[constant-group] " << name << " -> skipping constants for now\n";
+}
+
+void UnoProducer::produceService(
+ std::string_view name, const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity)
+{
+ // Generate service creation wrappers that access services through their interfaces
+ if (m_verbose)
+ std::cout << "[service] " << name << " -> generating service creation methods\n";
+
+ // Coordinate both producers for complete service generation
+ m_cppProducer->produceService(name, entity); // C++ side: service creation bridge functions
+ m_rustProducer->produceService(name,
+ entity); // Rust side: service wrapper with creation methods
+}
+
+void UnoProducer::produceSingleton(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceBasedSingletonEntity>&)
+{
+ // Singletons are accessed through their interfaces
+ if (m_verbose)
+ std::cout << "[singleton] " << name << " -> use underlying interface instead\n";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/rustmaker/unoproduce.hxx b/codemaker/source/rustmaker/unoproduce.hxx
new file mode 100644
index 000000000000..61671c984643
--- /dev/null
+++ b/codemaker/source/rustmaker/unoproduce.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string_view>
+#include <unordered_set>
+#include <unordered_map>
+#include <memory>
+
+#include <codemaker/typemanager.hxx>
+#include <unoidl/unoidl.hxx>
+
+#include <rtl/string.hxx>
+#include "rustoptions.hxx"
+#include "rustfile.hxx"
+#include "rustproduce.hxx"
+#include "cpproduce.hxx"
+
+// Forward declarations
+class CppFile;
+
+/**
+ * Main class responsible for generating Rust code from UNO type definitions.
+ * Processes UNO IDL types and produces corresponding Rust bindings.
+ */
+class UnoProducer
+{
+public:
+ UnoProducer()
+ : m_manager(new TypeManager())
+ {
+ }
+
+public:
+ // Initialize the producer with command line options
+ void initProducer(const RustOptions& options);
+ // Generate code for all requested types
+ void produceAll();
+ // Finalize opaque pointer generation
+ void finalizeGeneration();
+
+ // Static lookup tables for Rust keyword conflicts and type mappings
+ static const std::unordered_set<std::string_view> m_reservedKeywords;
+ static const std::unordered_map<std::string_view, OString> m_baseTypes;
+
+private:
+ // Main UNO type processor - coordinates opaque generation for all types
+ void produceType(const OString& name);
+ void produceModule(std::string_view name, const rtl::Reference<unoidl::MapCursor>& cursor);
+
+ // Generation for all UNO types - coordinates RustProducer + CppProducer
+ void produceEnum(std::string_view name, const rtl::Reference<unoidl::EnumTypeEntity>& entity);
+ void produceStruct(std::string_view name,
+ const rtl::Reference<unoidl::PlainStructTypeEntity>& entity);
+ void
+ producePolyStruct(std::string_view name,
+ const rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>& entity);
+ void produceException(std::string_view name,
+ const rtl::Reference<unoidl::ExceptionTypeEntity>& entity);
+ void produceInterface(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceTypeEntity>& entity);
+ void produceTypedef(std::string_view name, const rtl::Reference<unoidl::TypedefEntity>& entity);
+ void produceConstantGroup(std::string_view name,
+ const rtl::Reference<unoidl::ConstantGroupEntity>& entity);
+ void produceService(std::string_view name,
+ const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity);
+ void produceSingleton(std::string_view name,
+ const rtl::Reference<unoidl::InterfaceBasedSingletonEntity>& entity);
+
+ // Type name conversion for Rust output
+ OString getRustName(std::string_view name, bool istype = false);
+ OString getRustName(std::u16string_view name, bool istype = false);
+
+ //
+ static OString getBaseUnoName(std::string_view name);
+ OString getBaseUnoName(std::u16string_view name);
+
+ // Core data members
+ rtl::Reference<TypeManager> m_manager;
+
+ std::unordered_set<OString> m_startingTypes; // Types requested by user
+ std::unordered_set<OString> m_typesProduced; // Prevent duplicate generation
+ std::unordered_map<OString, OString> m_typedefs;
+
+ // Runtime configuration
+ OString m_rustOutputDir;
+ bool m_verbose;
+ bool m_dryRun;
+ // Producer instances for coordinated opaque generation
+ std::unique_ptr<RustProducer> m_rustProducer;
+ std::unique_ptr<CppProducer> m_cppProducer;
+
+ // Name processing utilities
+ static std::string_view splitName(std::string_view name);
+ static OString handleName(std::string_view name, bool istype);
+ static OString handleName(std::u16string_view name, bool istype);
+ static OString getSafeIdentifier(std::string_view name, bool istype);
+ static OString getSafeIdentifier(std::u16string_view name, bool istype);
+ static void separatedForeach(const auto& items, auto&& sepFunc, auto&& itemFunc);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/comphelper/source/misc/date.cxx b/comphelper/source/misc/date.cxx
index b95f63f75c97..2625d32c1d2f 100644
--- a/comphelper/source/misc/date.cxx
+++ b/comphelper/source/misc/date.cxx
@@ -36,12 +36,14 @@ namespace comphelper::date
/* XXX can that dbconversion cope with years > 9999 or negative years at all?
* Database fields may be limited to positive 4 digits. */
-constexpr sal_Int32 MIN_DAYS = -11968265; // -32768-01-01
-constexpr sal_Int32 MAX_DAYS = 11967900; // 32767-12-31
-
constexpr sal_Int16 kYearMax = SAL_MAX_INT16;
constexpr sal_Int16 kYearMin = SAL_MIN_INT16;
+constexpr sal_Int32 MIN_DAYS = convertDateToDays(1, 1, kYearMin); // -32768-01-01
+static_assert(MIN_DAYS == -11968265);
+constexpr sal_Int32 MAX_DAYS = convertDateToDays(31, 12, kYearMax); // 32767-12-31
+static_assert(MAX_DAYS == 11967900);
+
constexpr sal_Int32 nNullDateDays = convertDateToDays(30, 12, 1899);
static_assert(nNullDateDays == 693594);
diff --git a/compilerplugins/clang/nullptr.cxx b/compilerplugins/clang/nullptr.cxx
index 04fb5bf0f9fd..3189013fbc69 100644
--- a/compilerplugins/clang/nullptr.cxx
+++ b/compilerplugins/clang/nullptr.cxx
@@ -137,9 +137,11 @@ bool Nullptr::VisitImplicitCastExpr(CastExpr const * expr) {
{
break; // POSIX locale_t is left unspecified
}
- // Hack to handle libc++ and stdlibc++ `std::strong_ordering x; x < 0` etc.:
+ // Hack to handle libc++ and libstdc++ (libstdc++ < 16: __unspec; libstdc++ >= 16:
+ // __literal_zero) `std::strong_ordering x; x < 0` etc.:
if (tc.MemberPointerOf().ClassOrStruct("_CmpUnspecifiedParam").StdNamespace()
- || tc.Pointer().ClassOrStruct("__unspec").Namespace("__cmp_cat").StdNamespace())
+ || tc.Pointer().ClassOrStruct("__unspec").Namespace("__cmp_cat").StdNamespace()
+ || tc.Pointer().ClassOrStruct("__literal_zero").Namespace("__cmp_cat").StdNamespace())
{
break;
}
diff --git a/config_host.mk.in b/config_host.mk.in
index 429a4610d9ee..48d2ed3d76dc 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -178,6 +178,7 @@ export ENABLE_DBUS=@ENABLE_DBUS@
export ENABLE_DCONF=@ENABLE_DCONF@
export ENABLE_DEBUG=@ENABLE_DEBUG@
ENABLE_DOTNET=@ENABLE_DOTNET@
+ENABLE_RUST_UNO=@ENABLE_RUST_UNO@
SYSTEM_DRAGONBOX=@SYSTEM_DRAGONBOX@
SYSTEM_FROZEN=@SYSTEM_FROZEN@
ENABLE_EMBINDTEST_UNO=@ENABLE_EMBINDTEST_UNO@
diff --git a/configure.ac b/configure.ac
index 99ccaf54f748..4eeeefc3c19e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3022,6 +3022,10 @@ AC_ARG_WITH(dotnet,
Requires .NET SDK 8 or higher. To disable building .NET components, use
--without-dotnet or --with-dotnet=no.]))
+AC_ARG_ENABLE(rust-uno,
+ AS_HELP_STRING([--enable-rust-uno],
+ [Enable experimental Rust UNO support.]))
+
dnl ===================================================================
dnl Branding
dnl ===================================================================
@@ -5926,6 +5930,16 @@ AC_SUBST(ENABLE_DOTNET)
AC_SUBST(DOTNET)
AC_SUBST(DOTNET_ROOT)
+AC_MSG_CHECKING([whether to enable Rust UNO support])
+if test "$enable_rust_uno" = "yes"; then
+ ENABLE_RUST_UNO=TRUE
+ AC_MSG_RESULT([yes])
+else
+ ENABLE_RUST_UNO=
+ AC_MSG_RESULT([no])
+fi
+AC_SUBST(ENABLE_RUST_UNO)
+
DISABLE_GUI=""
if test "$enable_gui" = "no"; then
if test "$using_x11" != yes; then
@@ -11587,18 +11601,9 @@ dnl ===================================================================
dnl Orcus
dnl ===================================================================
libo_CHECK_SYSTEM_MODULE([orcus],[ORCUS],[liborcus-0.20 >= 0.20.2])
-if test "$with_system_orcus" != "yes"; then
- if test "$SYSTEM_BOOST" = "TRUE"; then
- dnl Link with Boost.System
- dnl This seems to be necessary since boost 1.50 (1.48 does not need it,
- dnl 1.49 is untested). The macro BOOST_THREAD_DONT_USE_SYSTEM mentioned
- dnl in documentation has no effect.
- AX_BOOST_SYSTEM
- fi
-fi
+
dnl FIXME by renaming SYSTEM_LIBORCUS to SYSTEM_ORCUS in the build system world
SYSTEM_LIBORCUS=$SYSTEM_ORCUS
-AC_SUBST([BOOST_SYSTEM_LIB])
AC_SUBST(SYSTEM_LIBORCUS)
dnl ===================================================================
@@ -11651,7 +11656,7 @@ else
else
# autodetect, prefer meson.py / standalone version that can more likely be run
# by different python runtimes
- AC_PATH_PROGS(MESON,[meson.py meson],,[$LODE_HOME/packages/meson-1.7.2:$PATH])
+ AC_PATH_PROGS(MESON,[meson.py meson],,[$LODE_HOME/opt/bin:$PATH])
if test -z "$MESON"; then
AC_MSG_WARN([meson not found, using internal copy])
BUILD_TYPE="$BUILD_TYPE MESON"
@@ -11661,7 +11666,24 @@ else
MESON="$formatted_path"
AC_MSG_CHECKING([whether meson can be run with "$PYTHON_FOR_BUILD $MESON"])
if ($PYTHON_FOR_BUILD $MESON --version >/dev/null) ; then
- AC_MSG_RESULT([yes])
+ # Xcode 26 and higher need a newer version of meson so use
+ # the internal meson if the external meson's version is
+ # too old
+ if test $_os = Darwin -a $MACOSX_SDK_VERSION -ge 260000; then
+ _meson_minver=1.8.3
+ _meson_minmajmin=`echo $_meson_minver | $AWK -F. '{ print \$1*10000+\$2*100+\$3 }'`
+ _meson_version=`$PYTHON_FOR_BUILD $MESON --version 2>/dev/null`
+ _meson_majmin=`echo $_meson_version | $AWK -F. '{ print \$1*10000+\$2*100+\$3 }'`
+ if test "$_meson_majmin" -lt "$_meson_minmajmin"; then
+ AC_MSG_WARN([meson "$_meson_version" is too old, using internal copy])
+ BUILD_TYPE="$BUILD_TYPE MESON"
+ MESON='$(gb_UnpackedTarball_workdir)/meson/meson.py'
+ else
+ AC_MSG_RESULT([yes])
+ fi
+ else
+ AC_MSG_RESULT([yes])
+ fi
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([meson incompatible with the specified python. Try using a different python runtime or a plain release of meson by adding PYTHON=/other/python.version and/or MESON=/path/to/meson.py to autogen.input])
diff --git a/cui/source/dialogs/about.cxx b/cui/source/dialogs/about.cxx
index ca471ccf71f0..de52af0f8ce0 100644
--- a/cui/source/dialogs/about.cxx
+++ b/cui/source/dialogs/about.cxx
@@ -78,8 +78,7 @@ AboutDialog::AboutDialog(weld::Window *pParent)
OUString sbuildId = GetBuildString();
if (IsStringValidGitHash(sbuildId)) {
const tools::Long nMaxChar = 25;
- m_pBuildLabel->set_uri("https://gerrit.libreoffice.org/gitweb?p=core.git;a=log;h="
- + sbuildId);
+ m_pBuildLabel->set_uri("https://git.libreoffice.org/core/history/" + sbuildId);
m_pBuildLabel->set_label(sbuildId.getLength() > nMaxChar ? sbuildId.replaceAt(
nMaxChar, sbuildId.getLength() - nMaxChar, u"...")
: sbuildId);
diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk
index 5838572d16fa..5987a9a4d456 100644
--- a/desktop/Executable_soffice_bin.mk
+++ b/desktop/Executable_soffice_bin.mk
@@ -19,6 +19,7 @@ $(eval $(call gb_Executable_add_defs,soffice_bin,\
))
$(eval $(call gb_Executable_use_libraries,soffice_bin,\
+ $(if $(ENABLE_RUST_UNO),rust_uno-cpp) \
sal \
sofficeapp \
))
diff --git a/desktop/qa/data/formulabar.ods b/desktop/qa/data/formulabar.ods
new file mode 100644
index 000000000000..ea099e24077c
--- /dev/null
+++ b/desktop/qa/data/formulabar.ods
Binary files differ
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index d997d9e8f673..02ad4a2da30b 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -149,6 +149,7 @@ public:
void testGetFilterTypes();
void testGetPartPageRectangles();
void testSearchCalc();
+ void testPropertySettingOnFormulaBar();
void testSearchAllNotificationsCalc();
void testPaintTile();
void testSaveAs();
@@ -226,6 +227,7 @@ public:
CPPUNIT_TEST(testGetFilterTypes);
CPPUNIT_TEST(testGetPartPageRectangles);
CPPUNIT_TEST(testSearchCalc);
+ CPPUNIT_TEST(testPropertySettingOnFormulaBar);
CPPUNIT_TEST(testSearchAllNotificationsCalc);
CPPUNIT_TEST(testPaintTile);
CPPUNIT_TEST(testSaveAs);
@@ -2259,6 +2261,7 @@ public:
bool m_bEmptyTableSelection;
bool m_bTilesInvalidated;
bool m_bZeroCursor;
+ bool m_stateBold;
tools::Rectangle m_aOwnCursor;
boost::property_tree::ptree m_aCommentCallbackResult;
boost::property_tree::ptree m_aColorPaletteCallbackResult;
@@ -2269,7 +2272,8 @@ public:
m_nTableSelectionCount(0),
m_bEmptyTableSelection(false),
m_bTilesInvalidated(false),
- m_bZeroCursor(false)
+ m_bZeroCursor(false),
+ m_stateBold(false)
{
mnView = SfxLokHelper::getCurrentView();
mpDocument->m_pDocumentClass->registerCallback(pDocument, &ViewCallback::callback, this);
@@ -2357,6 +2361,13 @@ public:
m_aLastRedlineInfo = redlines[0];
}
break;
+ case LOK_CALLBACK_STATE_CHANGED:
+ {
+ if (aPayload.startsWith(".uno:Bold="))
+ {
+ m_stateBold = aPayload.copy(".uno:Bold="_ostr.getLength()).toBoolean();
+ }
+ }
}
}
};
@@ -3120,6 +3131,52 @@ void DesktopLOKTest::testCalcValidityDropdownInReadonlyMode()
CPPUNIT_ASSERT_EQUAL(true, aView.m_JSONDialog.empty());
}
+void DesktopLOKTest::testPropertySettingOnFormulaBar()
+{
+ LibLibreOffice_Impl aOffice;
+ LibLODocument_Impl* pDocument = loadDoc("formulabar.ods");
+ Scheduler::ProcessEventsToIdle();
+
+ pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}");
+ Scheduler::ProcessEventsToIdle();
+
+ ViewCallback aView(pDocument);
+ Scheduler::ProcessEventsToIdle();
+
+ // Go to A1. There are 2 words in the cell.
+ pDocument->pClass->postMouseEvent(pDocument, LOK_MOUSEEVENT_MOUSEBUTTONDOWN, 1000, 150, 1, 1, 0);
+ pDocument->pClass->postMouseEvent(pDocument, LOK_MOUSEEVENT_MOUSEBUTTONUP, 1000, 150, 1, 1, 0);
+ Scheduler::ProcessEventsToIdle();
+
+ // Set the focus to formulabar.
+ pDocument->pClass->sendDialogEvent(pDocument, 0, "{\"id\":\"sc_input_window\", \"cmd\": \"grab_focus\", \"data\": \"null\", \"type\": \"drawingarea\"}");
+ Scheduler::ProcessEventsToIdle();
+
+ // Select the first word.
+ pDocument->pClass->sendDialogEvent(pDocument, 0, "{\"id\":\"sc_input_window\", \"cmd\": \"textselection\", \"data\": \"0;3;0;0\", \"type\": \"drawingarea\"}");
+ Scheduler::ProcessEventsToIdle();
+
+ // Set bold property for the selected word.
+ pDocument->pClass->postUnoCommand(pDocument, ".uno:Bold", nullptr, false);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(true, aView.m_stateBold);
+
+ // Select the second word. Without the fix, this selection removes the "bold" attribute.
+ pDocument->pClass->sendDialogEvent(pDocument, 0, "{\"id\":\"sc_input_window\", \"cmd\": \"textselection\", \"data\": \"4;9;0;0\", \"type\": \"drawingarea\"}");
+ Scheduler::ProcessEventsToIdle();
+
+ // Select the first word again.
+ pDocument->pClass->sendDialogEvent(pDocument, 0, "{\"id\":\"sc_input_window\", \"cmd\": \"textselection\", \"data\": \"0;3;0;0\", \"type\": \"drawingarea\"}");
+ Scheduler::ProcessEventsToIdle();
+
+ // Unset bold property for the selected word.
+ pDocument->pClass->postUnoCommand(pDocument, ".uno:Bold", nullptr, false);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(false, aView.m_stateBold); // This line doesn't pass without the fix in this commit.
+}
+
void DesktopLOKTest::testRunMacro()
{
LibLibreOffice_Impl aOffice;
diff --git a/download.lst b/download.lst
index 480e930d9076..c30ccb1d6ed8 100644
--- a/download.lst
+++ b/download.lst
@@ -14,8 +14,8 @@ ARGON2_TARBALL := phc-winner-argon2-20190702.tar.gz
# so that git cherry-pick
# will not run into conflicts
# please repack the tarball using external/boost/repack_tarball.sh
-BOOST_SHA256SUM := 5c67a448c562f1606e38203ba7ed7e8d7453581b6b9ca324e96205eae0da5ff8
-BOOST_TARBALL := boost_1_88_0.tar.xz
+BOOST_SHA256SUM := b3a976c659961f1d7fae9a8e58d6729a11f5473abaf2ef0e623f53777c86475d
+BOOST_TARBALL := boost_1_89_0.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
@@ -302,8 +302,8 @@ FREEHAND_TARBALL := libfreehand-0.1.2.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
-FREETYPE_SHA256SUM := f8dfa8f15ef0576738dfb55b2e6e6b172fd5d09b6f03785a1df03239549f64d2
-FREETYPE_TARBALL := freetype-2.14.0.tar.xz
+FREETYPE_SHA256SUM := 32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc
+FREETYPE_TARBALL := freetype-2.14.1.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
@@ -482,8 +482,8 @@ LXML_TARBALL := lxml-6.0.1.tar.gz
# three static lines
# so that git cherry-pick
# will not run into conflicts
-MARIADB_CONNECTOR_C_SHA256SUM := b593fdd3d5b8964a9feec2bf57a13e6cc8f178a4fe948e89f60ede9c53d621fe
-MARIADB_CONNECTOR_C_TARBALL := mariadb-connector-c-3.3.15-src.tar.gz
+MARIADB_CONNECTOR_C_SHA256SUM := a5abb7331508988f7287b481c1839bd929261ce38352cd0fde6c002c300e0c01
+MARIADB_CONNECTOR_C_TARBALL := mariadb-connector-c-3.3.17-src.tar.gz
# three static lines
# so that git cherry-pick
# will not run into conflicts
@@ -497,8 +497,8 @@ MDNSRESPONDER_TARBALL := mDNSResponder-878.200.35.tar.gz
# three static lines
# so that git cherry-pick
# will not run into conflicts
-MESON_SHA256SUM := 0a9b23311271519bd03dca12d7d8b0eab582c3a2c5da433d465b6e519dc88e2f
-MESON_TARBALL := meson-1.8.0.tar.gz
+MESON_SHA256SUM := f118aa910fc0a137cc2dd0122232dbf82153d9a12fb5b0f5bb64896f6a157abf
+MESON_TARBALL := meson-1.8.3.tar.gz
# three static lines
# so that git cherry-pick
# will not run into conflicts
diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index ae94c4c9b3f0..0494d792fd33 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -1735,7 +1735,6 @@ OUString EditView::GetSurroundingText() const
Selection EditView::GetSurroundingTextSelection() const
{
ESelection aSelection( GetSelection() );
- aSelection.Adjust();
if( HasSelection() )
{
@@ -1745,7 +1744,13 @@ Selection EditView::GetSurroundingTextSelection() const
// Stop reconversion if the selected text includes a line break.
if ( aStr.indexOf( 0x0A ) == -1 )
- return Selection(0, aSelection.end.nIndex - aSelection.start.nIndex);
+ {
+ const tools::Long nLength = std::abs(aSelection.end.nIndex - aSelection.start.nIndex);
+ if (aSelection.start.nIndex < aSelection.end.nIndex)
+ return Selection(0, nLength);
+ else
+ return Selection(nLength, 0);
+ }
else
return Selection( 0, 0 );
}
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index f8a29522e5e2..e6b92171c974 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -569,6 +569,16 @@ void ImpEditEngine::populateRubyInfo(ParaPortion& rParaPortion, EditLine* pLine)
for (sal_Int32 nP = pLine->GetStartPortion(); pNextRubyAttr && nP <= pLine->GetEndPortion();
++nP)
{
+ const auto* pRuby = static_cast<const SvxRubyItem*>(pNextRubyAttr->GetItem());
+ if (pRuby->GetText().isEmpty())
+ {
+ // Skip processing blank ruby spans
+ pNextRubyAttr
+ = rParaPortion.GetNode()->GetCharAttribs().FindNextAttrib(EE_CHAR_RUBY, nTextPos);
+ pTPRubyStart = nullptr;
+ continue;
+ }
+
SeekCursor(pNode, nTextPos, aTmpFont);
TextPortion& rTP = rParaPortion.GetTextPortions()[nP];
@@ -596,7 +606,6 @@ void ImpEditEngine::populateRubyInfo(ParaPortion& rParaPortion, EditLine* pLine)
auto pRubyInfo = std::make_unique<RubyPortionInfo>();
// Get ruby text width
- const auto* pRuby = static_cast<const SvxRubyItem*>(pNextRubyAttr->GetItem());
// TODO: Style support is unimplemented. For now, use a hard-coded 50% scale
aRubyStartFont.SetFontSize(aRubyStartFont.GetFontSize() / 2);
diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx
index 91a7a461f84f..2230801ff288 100644
--- a/emfio/inc/mtftools.hxx
+++ b/emfio/inc/mtftools.hxx
@@ -204,6 +204,8 @@ namespace emfio
enum PenStyle : sal_uInt32
{
PS_COSMETIC = 0x00000000,
+ PS_GEOMETRIC = 0x00010000,
+
PS_SOLID = 0x00000000,
PS_DASH = 0x00000001,
PS_DOT = 0x00000002,
@@ -223,9 +225,7 @@ namespace emfio
PS_JOIN_ROUND = 0x00000000,
PS_JOIN_BEVEL = 0x00001000,
PS_JOIN_MITER = 0x00002000,
- PS_JOIN_STYLE_MASK = 0x0000F000,
-
- PS_GEOMETRIC = 0x00010000
+ PS_JOIN_STYLE_MASK = 0x0000F000
};
/* [MS-WMF] - v20210625 - pages 30, 82 */
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 37c42d4c2126..a59c95c1d8f9 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -87,19 +87,19 @@ CPPUNIT_TEST_FIXTURE(Test, testPolyPolygon)
assertXPath(pDocument, aXPathPrefix + "mask/polypolygoncolor[2]/polypolygon", "path",
u"m2574 13194v-12065h15303v12065z");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke", 44);
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke", 116);
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstroke[1]/polygon",
- u"2574,13194 2574,1129");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "color", u"#000000");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "width", u"0");
+ u"2574,13194 2574,1129 17877,1129 17877,13194");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "color", u"#ffffff");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "width", u"35");
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstroke[2]/polygon",
- u"2574,1129 2574,1129");
+ u"2574,13194 2574,1129");
assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "color", u"#000000");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "width", u"0");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "width", u"35");
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstroke[10]/polygon",
- u"8674,1129 8674,1129");
+ u"8674,13194 8674,1129");
assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[10]/line", "color", u"#000000");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[10]/line", "width", u"0");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[10]/line", "width", u"35");
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion", 28);
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[6]", "width", u"459");
@@ -556,14 +556,13 @@ CPPUNIT_TEST_FIXTURE(Test, testEnglishMapMode)
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[1]", "width", u"424");
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[1]", "height", u"424");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline", 3);
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline", 5);
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonhairline[1]/polygon",
u"-1,-1 29699,-1 29699,21000 -1,21000");
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonhairline[2]/polygon",
u"1058,7937 1058,13230 4233,13230 4233,12171 2115,12171 2115,7937");
- assertXPathContent(
- pDocument, aXPathPrefix + "mask/polygonhairline[3]/polygon",
- u"12699,1058 16933,1058 16933,2118 15346,2118 15346,6349 14287,6349 14287,2118 12699,2118");
+ assertXPathContent(pDocument, aXPathPrefix + "mask/polygonhairline[3]/polygon",
+ u"1058,7937 1058,13230 4233,13230 4233,12171 2115,12171 2115,7937");
}
CPPUNIT_TEST_FIXTURE(Test, testRectangleWithModifyWorldTransform)
@@ -910,7 +909,7 @@ CPPUNIT_TEST_FIXTURE(Test, testEmfPolydraw)
assertXPathContent(pDocument, aXPathPrefix + "polygonstroke[1]/polygon",
u"50,50 50,50 1000,1000 1000,1000 2000,2500 2000,1000");
assertXPath(pDocument, aXPathPrefix + "polygonstroke[1]/line", "color", u"#ff0000");
- assertXPath(pDocument, aXPathPrefix + "polygonstroke[1]/stroke", "dotDashArray", u"30 10 ");
+ assertXPath(pDocument, aXPathPrefix + "polygonstroke[1]/stroke", "dotDashArray", u"90 30 ");
}
CPPUNIT_TEST_FIXTURE(Test, testEmfPlusBrushPathGradientWithBlendColors)
@@ -1588,29 +1587,23 @@ CPPUNIT_TEST_FIXTURE(Test, testCreatePen)
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "path", u"m0 0h31250v18192h-31250z");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke", 3);
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke", 758);
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstroke[1]/polygon",
- u"17898,5693 20172,5693");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "color", u"#008000");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "width", u"0");
+ u"0,0 31225,0 31225,17742 0,17742");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "color", u"#ffffff");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line", "width", u"25");
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstroke[2]/polygon",
- u"17898,6959 20172,6959");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "color", u"#000080");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "width", u"0");
+ u"25,23 31200,23 31200,17719 25,17719");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "color", u"#ffffff");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line", "width", u"25");
assertXPathContent(pDocument, aXPathPrefix + "mask/polygonstroke[3]/polygon",
- u"17898,7381 20172,7381");
+ u"27875,16523 27875,1453");
assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[3]/line", "color", u"#ff0000");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[3]/line", "width", u"0");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[3]/line", "width", u"3");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline", 755);
- assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline[5]", "color", u"#ff0000");
- assertXPathContent(pDocument, aXPathPrefix + "mask/polygonhairline[5]/polygon",
- u"27925,16078 27875,16078");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline[10]", "color", u"#ff0000");
- assertXPathContent(pDocument, aXPathPrefix + "mask/polygonhairline[10]/polygon",
- u"27925,14180 27875,14180");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline", 0);
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion", 69);
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[1]", "width", u"374");
diff --git a/emfio/source/reader/emfreader.cxx b/emfio/source/reader/emfreader.cxx
index 9ecfe1a411d9..abd842e417da 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -1258,10 +1258,10 @@ namespace emfio
SAL_INFO("emfio", "\t\tIndex: " << nIndex << " Style: 0x" << std::hex
<< nPenStyle << std::dec
<< " PenWidth: " << nPenWidth);
- if ((nPenStyle & PS_STYLE_MASK) > PS_INSIDEFRAME)
- nPenStyle = PS_COSMETIC;
- if ((nPenStyle & PS_GEOMETRIC) == 0)
- nPenWidth = 0;
+ // PS_COSMETIC width is always fixed at one logical unit
+ // and is not affected by any geometric transformations like scaling
+ if (nPenStyle == PS_COSMETIC)
+ nPenWidth = 1;
CreateObjectIndexed(nIndex, std::make_unique<WinMtfLineStyle>(ReadColor(), nPenStyle, nPenWidth));
}
}
@@ -1284,10 +1284,10 @@ namespace emfio
else
{
SAL_INFO("emfio", "\t\tStyle: 0x" << std::hex << nPenStyle << std::dec);
- if ((nPenStyle & PS_STYLE_MASK) > PS_INSIDEFRAME)
- nPenStyle = PS_COSMETIC;
- if ((nPenStyle & PS_GEOMETRIC) == 0)
- nWidth = 0;
+ // PS_COSMETIC width is always fixed at one logical unit
+ // and is not affected by any geometric transformations like scaling
+ if (nPenStyle == PS_COSMETIC)
+ nWidth = 1;
SAL_INFO("emfio", "\t\tWidth: " << nWidth);
CreateObjectIndexed(nIndex, std::make_unique<WinMtfLineStyle>(aColorRef, nPenStyle, nWidth));
}
diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx
index f5467f88c923..b57c528b67f9 100644
--- a/emfio/source/reader/mtftools.cxx
+++ b/emfio/source/reader/mtftools.cxx
@@ -803,12 +803,12 @@ namespace emfio
break;
case StockObject::WHITE_PEN :
{
- maLineStyle = WinMtfLineStyle(COL_WHITE, PS_COSMETIC, 0);
+ maLineStyle = WinMtfLineStyle(COL_WHITE, PS_COSMETIC, 1);
}
break;
case StockObject::BLACK_PEN :
{
- maLineStyle = WinMtfLineStyle(COL_BLACK, PS_COSMETIC, 0);
+ maLineStyle = WinMtfLineStyle(COL_BLACK, PS_COSMETIC, 1);
}
break;
case StockObject::NULL_PEN :
diff --git a/external/boost/Module_boost.mk b/external/boost/Module_boost.mk
index 252bf1c9a3b3..f12e5dafa980 100644
--- a/external/boost/Module_boost.mk
+++ b/external/boost/Module_boost.mk
@@ -13,7 +13,6 @@ $(eval $(call gb_Module_add_targets,boost,\
StaticLibrary_boost_date_time \
StaticLibrary_boost_filesystem \
StaticLibrary_boost_locale \
- StaticLibrary_boost_system \
StaticLibrary_boost_iostreams \
UnpackedTarball_boost \
))
diff --git a/external/boost/StaticLibrary_boost_system.mk b/external/boost/StaticLibrary_boost_system.mk
deleted file mode 100644
index e4b05d7b5cde..000000000000
--- a/external/boost/StaticLibrary_boost_system.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
-#
-# This file is part of the LibreOffice project.
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-
-$(eval $(call gb_StaticLibrary_StaticLibrary,boost_system))
-
-$(eval $(call gb_StaticLibrary_use_unpacked,boost_system,boost))
-
-$(eval $(call gb_StaticLibrary_set_warnings_disabled,boost_system))
-
-# disable "auto link" "feature" on MSVC
-$(eval $(call gb_StaticLibrary_add_defs,boost_system,\
- -DBOOST_ALL_NO_LIB \
-))
-
-$(eval $(call gb_StaticLibrary_use_external,boost_system,boost_headers))
-
-$(eval $(call gb_StaticLibrary_set_generated_cxx_suffix,boost_system,cpp))
-
-$(eval $(call gb_StaticLibrary_add_generated_exception_objects,boost_system,\
- UnpackedTarball/boost/libs/system/src/error_code \
-))
-
-# vim: set noet sw=4 ts=4:
diff --git a/external/curl/0001-cookie-don-t-treat-the-leading-slash-as-trailing.patch b/external/curl/0001-cookie-don-t-treat-the-leading-slash-as-trailing.patch
new file mode 100644
index 000000000000..45fba1f8af4e
--- /dev/null
+++ b/external/curl/0001-cookie-don-t-treat-the-leading-slash-as-trailing.patch
@@ -0,0 +1,54 @@
+From c6ae07c6a541e0e96d0040afb62b45dd37711300 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Mon, 11 Aug 2025 20:23:05 +0200
+Subject: [PATCH] cookie: don't treat the leading slash as trailing
+
+If there is only a leading slash in the path, keep that. Also add an
+assert to make sure the path is never blank.
+
+Reported-by: Google Big Sleep
+Closes #18266
+---
+ lib/cookie.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/lib/cookie.c b/lib/cookie.c
+index 914a4aca1..b72dd99bc 100644
+--- a/lib/cookie.c
++++ b/lib/cookie.c
+@@ -296,9 +296,9 @@ static char *sanitize_cookie_path(const char *cookie_path)
+ /* Let cookie-path be the default-path. */
+ return strdup("/");
+
+- /* remove trailing slash */
++ /* remove trailing slash when path is non-empty */
+ /* convert /hoge/ to /hoge */
+- if(len && cookie_path[len - 1] == '/')
++ if(len > 1 && cookie_path[len - 1] == '/')
+ len--;
+
+ return Curl_memdup0(cookie_path, len);
+@@ -965,7 +965,7 @@ replace_existing(struct Curl_easy *data,
+ clist->spath && co->spath && /* both have paths */
+ clist->secure && !co->secure && !secure) {
+ size_t cllen;
+- const char *sep;
++ const char *sep = NULL;
+
+ /*
+ * A non-secure cookie may not overlay an existing secure cookie.
+@@ -974,8 +974,9 @@ replace_existing(struct Curl_easy *data,
+ * "/loginhelper" is ok.
+ */
+
+- sep = strchr(clist->spath + 1, '/');
+-
++ DEBUGASSERT(clist->spath[0]);
++ if(clist->spath[0])
++ sep = strchr(clist->spath + 1, '/');
+ if(sep)
+ cllen = sep - clist->spath;
+ else
+--
+2.39.5
+
diff --git a/external/curl/0001-ws-get-a-new-mask-for-each-new-outgoing-frame.patch b/external/curl/0001-ws-get-a-new-mask-for-each-new-outgoing-frame.patch
new file mode 100644
index 000000000000..99f497d26726
--- /dev/null
+++ b/external/curl/0001-ws-get-a-new-mask-for-each-new-outgoing-frame.patch
@@ -0,0 +1,61 @@
+From 84db7a9eae8468c0445b15aa806fa7fa806fa0f2 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Mon, 8 Sep 2025 14:14:15 +0200
+Subject: [PATCH] ws: get a new mask for each new outgoing frame
+
+Reported-by: Calvin Ruocco
+Closes #18496
+---
+ lib/ws.c | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/lib/ws.c b/lib/ws.c
+index e973409b6..3b6542816 100644
+--- a/lib/ws.c
++++ b/lib/ws.c
+@@ -875,6 +875,19 @@ static CURLcode ws_enc_add_frame(struct Curl_easy *data,
+ enc->payload_remain = enc->payload_len = payload_len;
+ ws_enc_info(enc, data, "sending");
+
++ /* 4 bytes random */
++
++ CURLcode result =
++ Curl_rand(data, (unsigned char *)&enc->mask, sizeof(enc->mask));
++ if(result)
++ return result;
++
++#ifdef DEBUGBUILD
++ if(getenv("CURL_WS_FORCE_ZERO_MASK"))
++ /* force the bit mask to 0x00000000, effectively disabling masking */
++ memset(&enc->mask, 0, sizeof(enc->mask));
++#endif
++
+ /* add 4 bytes mask */
+ memcpy(&head[hlen], &enc->mask, 4);
+ hlen += 4;
+@@ -1335,21 +1347,7 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
+ subprotocol not requested by the client), the client MUST Fail
+ the WebSocket Connection. */
+
+- /* 4 bytes random */
+-
+- result = Curl_rand(data, (unsigned char *)&ws->enc.mask,
+- sizeof(ws->enc.mask));
+- if(result)
+- return result;
+-
+-#ifdef DEBUGBUILD
+- if(getenv("CURL_WS_FORCE_ZERO_MASK"))
+- /* force the bit mask to 0x00000000, effectively disabling masking */
+- memset(ws->enc.mask, 0, sizeof(ws->enc.mask));
+-#endif
+-
+- infof(data, "[WS] Received 101, switch to WebSocket; mask %02x%02x%02x%02x",
+- ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]);
++ infof(data, "[WS] Received 101, switch to WebSocket");
+
+ /* Install our client writer that decodes WS frames payload */
+ result = Curl_cwriter_create(&ws_dec_writer, data, &ws_cw_decode,
+--
+2.39.5
+
diff --git a/external/curl/UnpackedTarball_curl.mk b/external/curl/UnpackedTarball_curl.mk
index 52861a50bed8..51bec9c4f659 100644
--- a/external/curl/UnpackedTarball_curl.mk
+++ b/external/curl/UnpackedTarball_curl.mk
@@ -28,6 +28,8 @@ $(eval $(call gb_UnpackedTarball_add_patches,curl,\
external/curl/zlib.patch.0 \
external/curl/configurable-z-option.patch.0 \
external/curl/0001-const-up-readonly-H2_NON_FIELD.patch.1 \
+ external/curl/0001-cookie-don-t-treat-the-leading-slash-as-trailing.patch \
+ external/curl/0001-ws-get-a-new-mask-for-each-new-outgoing-frame.patch \
))
ifeq ($(OS)-$(COM_IS_CLANG),WNT-TRUE)
diff --git a/external/liborcus/ExternalProject_liborcus.mk b/external/liborcus/ExternalProject_liborcus.mk
index a18026c13b6d..83fd8dea505e 100644
--- a/external/liborcus/ExternalProject_liborcus.mk
+++ b/external/liborcus/ExternalProject_liborcus.mk
@@ -15,7 +15,6 @@ $(eval $(call gb_ExternalProject_use_externals,liborcus, \
boost_headers \
boost_filesystem \
boost_iostreams \
- boost_system \
mdds_headers \
zlib \
))
@@ -41,7 +40,7 @@ endif
ifneq ($(SYSTEM_BOOST),)
liborcus_LIBS+=$(BOOST_SYSTEM_LIB) $(BOOST_IOSTREAMS_LIB) $(BOOST_FILESYSTEM_LIB)
else
-liborcus_LIBS+=-L$(gb_StaticLibrary_WORKDIR) -lboost_system -lboost_iostreams -lboost_filesystem
+liborcus_LIBS+=-L$(gb_StaticLibrary_WORKDIR) -lboost_iostreams -lboost_filesystem
endif
ifeq ($(OS),ANDROID)
liborcus_LIBS+=$(gb_STDLIBS)
diff --git a/external/liborcus/Library_orcus-parser.mk b/external/liborcus/Library_orcus-parser.mk
index 3680d57d41b4..5d8b5f08a74f 100644
--- a/external/liborcus/Library_orcus-parser.mk
+++ b/external/liborcus/Library_orcus-parser.mk
@@ -14,7 +14,6 @@ $(eval $(call gb_Library_use_unpacked,orcus-parser,liborcus))
$(eval $(call gb_Library_use_externals,orcus-parser,\
boost_headers \
boost_filesystem \
- boost_system \
mdds_headers \
zlib \
))
diff --git a/external/liborcus/Library_orcus.mk b/external/liborcus/Library_orcus.mk
index 582dc6b6e474..f6243e4e0fd2 100644
--- a/external/liborcus/Library_orcus.mk
+++ b/external/liborcus/Library_orcus.mk
@@ -15,7 +15,6 @@ $(eval $(call gb_Library_use_externals,orcus,\
boost_headers \
boost_filesystem \
boost_iostreams \
- boost_system \
mdds_headers \
zlib \
))
diff --git a/external/mariadb-connector-c/UnpackedTarball_mariadb-connector-c.mk b/external/mariadb-connector-c/UnpackedTarball_mariadb-connector-c.mk
index fb91af3e5a55..7c72bd807259 100644
--- a/external/mariadb-connector-c/UnpackedTarball_mariadb-connector-c.mk
+++ b/external/mariadb-connector-c/UnpackedTarball_mariadb-connector-c.mk
@@ -30,7 +30,6 @@ endif # $(OS),WNT
$(eval $(call gb_UnpackedTarball_add_patches,mariadb-connector-c,\
external/mariadb-connector-c/clang-cl.patch.0 \
- external/mariadb-connector-c/c23.patch.0 \
external/mariadb-connector-c/0001-const-up-my_uca1400_collation_definitions.patch \
external/mariadb-connector-c/0001-const-up-mariadb_defaults-and-MADB_OS_CHARSET.patch \
))
diff --git a/external/mariadb-connector-c/c23.patch.0 b/external/mariadb-connector-c/c23.patch.0
deleted file mode 100644
index d19d6be4cdae..000000000000
--- a/external/mariadb-connector-c/c23.patch.0
+++ /dev/null
@@ -1,11 +0,0 @@
---- include/ma_global.h
-+++ include/ma_global.h
-@@ -683,7 +683,7 @@
- typedef int myf; /* Type of MyFlags in my_funcs */
- typedef char my_bool; /* Small bool */
- typedef unsigned long long my_ulonglong;
--#if !defined(bool) && !defined(bool_defined) && (!defined(HAVE_BOOL) || !defined(__cplusplus))
-+#if !defined(bool) && !defined(bool_defined) && !(defined(__cplusplus) || __STDC_VERSION__ >= 202311L)
- typedef char bool; /* Ordinary boolean values 0 1 */
- #endif
- /* Macros for converting *constants* to the right type */
diff --git a/forms/source/component/FormComponent.cxx b/forms/source/component/FormComponent.cxx
index 97ac1280bd91..0492afa4817f 100644
--- a/forms/source/component/FormComponent.cxx
+++ b/forms/source/component/FormComponent.cxx
@@ -53,7 +53,8 @@
#include <sal/log.hxx>
#include <algorithm>
-
+#include <vcl/window.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
namespace frm
{
using namespace ::com::sun::star::uno;
@@ -270,6 +271,9 @@ void SAL_CALL OControl::createPeer(const Reference<XToolkit>& _rxToolkit, const
{
m_xControl->createPeer( _rxToolkit, _rxParent );
impl_resetStateGuard_nothrow();
+
+ VclPtr<vcl::Window> pVclPeer = VCLUnoHelper::GetWindow(getPeer());
+ pVclPeer->SetFormControl(true);
}
}
diff --git a/forms/source/xforms/convert.cxx b/forms/source/xforms/convert.cxx
index 98fd3391f220..8cf61cd2ac2c 100644
--- a/forms/source/xforms/convert.cxx
+++ b/forms/source/xforms/convert.cxx
@@ -118,7 +118,7 @@ namespace
css::util::Date lcl_toUNODate( std::u16string_view rString )
{
- css::util::Date aDate( 1, 1, 1900 );
+ css::util::Date aDate;
bool bWellformed = ISO8601parseDate(rString, aDate);
diff --git a/include/sfx2/lokhelper.hxx b/include/sfx2/lokhelper.hxx
index b32f775db14b..bee8f3178ae7 100644
--- a/include/sfx2/lokhelper.hxx
+++ b/include/sfx2/lokhelper.hxx
@@ -187,6 +187,8 @@ public:
static void notifyDocumentSizeChangedAllViews(vcl::ITiledRenderable* pDoc, bool bInvalidateAll = true);
/// Emits a LOK_CALLBACK_DOCUMENT_SIZE_CHANGED for all views of the same document with the same part
static void notifyPartSizeChangedAllViews(vcl::ITiledRenderable* pDoc, int nPart);
+ /// Emits a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR
+ static void notifyCursorInvalidation(SfxViewShell const* pThisView, tools::Rectangle const * pRect, bool bControlEvent);
/// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed.
static void notifyInvalidation(SfxViewShell const* pThisView, int nPart, tools::Rectangle const *);
/// Emits a LOK_CALLBACK_INVALIDATE_TILES, but tweaks it according to setOptionalFeatures() if needed
diff --git a/include/sfx2/viewsh.hxx b/include/sfx2/viewsh.hxx
index ee35c7195278..1748644dff75 100644
--- a/include/sfx2/viewsh.hxx
+++ b/include/sfx2/viewsh.hxx
@@ -434,6 +434,9 @@ public:
/// ILibreOfficeKitNotifier. Emits a LOK_CALLBACK_INVALIDATE_TILES.
virtual void notifyInvalidation(tools::Rectangle const *) const override;
+ /// ILibreOfficeKitNotifier.
+ virtual void notifyCursorInvalidation(tools::Rectangle const *, bool bControlEvent) const override;
+
/// See OutlinerViewShell::NotifyOtherViews().
void NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload) override;
/// See OutlinerViewShell::NotifyOtherView().
diff --git a/include/tools/date.hxx b/include/tools/date.hxx
index f2e492d8f15e..db6c1a9e7029 100644
--- a/include/tools/date.hxx
+++ b/include/tools/date.hxx
@@ -134,6 +134,9 @@ public:
*/
void AddDays( sal_Int32 nAddDays );
+ // Same as AddDays, but returns false on int overflow cases
+ [[nodiscard]] bool CheckedAddDays(sal_Int32 nAddDays);
+
/** Obtain the day of the week for the date.
Internally normalizes a copy of values.
diff --git a/include/vcl/IDialogRenderable.hxx b/include/vcl/IDialogRenderable.hxx
index 79ed78765212..aaa17cd7991c 100644
--- a/include/vcl/IDialogRenderable.hxx
+++ b/include/vcl/IDialogRenderable.hxx
@@ -40,6 +40,9 @@ public:
/// Emits a LOK_CALLBACK_INVALIDATE_TILES.
virtual void notifyInvalidation(tools::Rectangle const *) const = 0;
+ /// Emits a LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR.
+ virtual void notifyCursorInvalidation(tools::Rectangle const *, bool bControlEvent) const = 0;
+
/// Debugging
virtual OString dumpNotifyState() const = 0;
};
diff --git a/include/vcl/accessibility/AccessibleBrowseBox.hxx b/include/vcl/accessibility/AccessibleBrowseBox.hxx
index fd070e44e034..f1b0a63dbe60 100644
--- a/include/vcl/accessibility/AccessibleBrowseBox.hxx
+++ b/include/vcl/accessibility/AccessibleBrowseBox.hxx
@@ -33,7 +33,7 @@ class VCL_DLLPUBLIC AccessibleBrowseBox : public AccessibleBrowseBoxBase
public:
AccessibleBrowseBox(
- const css::uno::Reference< css::accessibility::XAccessible >& _rxParent,
+ const rtl::Reference<comphelper::OAccessible>& rpParent,
::vcl::IAccessibleTableProvider& _rBrowseBox
);
@@ -107,21 +107,11 @@ public:
/** returns the accessible object for the row or the column header bar
*/
- css::uno::Reference<
- css::accessibility::XAccessible >
- getHeaderBar( AccessibleBrowseBoxObjType _eObjType )
- {
- return implGetHeaderBar(_eObjType);
- }
+ rtl::Reference<comphelper::OAccessible> getHeaderBar(AccessibleBrowseBoxObjType eObjType);
/** returns the accessible object for the table representation
*/
- css::uno::Reference<
- css::accessibility::XAccessible >
- getTable( )
- {
- return implGetTable();
- }
+ rtl::Reference<comphelper::OAccessible> getTable();
protected:
// internal virtual methods
@@ -132,26 +122,11 @@ protected:
// internal helper methods
- /** This method creates (once) and returns the accessible data table child.
- @attention This method requires locked mutex's and a living object.
- @return The XAccessible interface of the data table. */
- css::uno::Reference<
- css::accessibility::XAccessible > implGetTable();
-
- /** This method creates (once) and returns the specified header bar.
- @attention This method requires locked mutex's and a living object.
- @return The XAccessible interface of the header bar. */
- css::uno::Reference<
- css::accessibility::XAccessible >
- implGetHeaderBar( AccessibleBrowseBoxObjType eObjType );
-
/** This method returns one of the children that are always present:
Data table, row and column header bar or corner control.
@attention This method requires locked mutex's and a living object.
- @return The XAccessible interface of the specified child. */
- css::uno::Reference<
- css::accessibility::XAccessible >
- implGetFixedChild( sal_Int64 nChildIndex );
+ @return The accessible object of the specified child. */
+ rtl::Reference<comphelper::OAccessible> implGetFixedChild(sal_Int64 nChildIndex);
/** This method creates and returns an accessible table.
@return An AccessibleBrowseBoxTable. */
diff --git a/include/vcl/metaact.hxx b/include/vcl/metaact.hxx
index 0ca9b1fe87ca..62655d770b49 100644
--- a/include/vcl/metaact.hxx
+++ b/include/vcl/metaact.hxx
@@ -104,7 +104,6 @@ private:
Color maColor;
public:
- SAL_DLLPRIVATE MetaPixelAction();
MetaPixelAction(MetaPixelAction const &) = default;
MetaPixelAction(MetaPixelAction &&) = default;
MetaPixelAction & operator =(MetaPixelAction const &) = delete; // due to MetaAction
@@ -130,7 +129,6 @@ private:
Point maPt;
public:
- SAL_DLLPRIVATE MetaPointAction();
MetaPointAction(MetaPointAction const &) = default;
MetaPointAction(MetaPointAction &&) = default;
MetaPointAction & operator =(MetaPointAction const &) = delete; // due to MetaAction
@@ -158,7 +156,6 @@ private:
Point maEndPt;
public:
- SAL_DLLPRIVATE MetaLineAction();
MetaLineAction(MetaLineAction const &) = default;
MetaLineAction(MetaLineAction &&) = default;
MetaLineAction & operator =(MetaLineAction const &) = delete; // due to MetaAction
@@ -188,7 +185,6 @@ private:
tools::Rectangle maRect;
public:
- SAL_DLLPRIVATE MetaRectAction();
MetaRectAction(MetaRectAction const &) = default;
MetaRectAction(MetaRectAction &&) = default;
MetaRectAction & operator =(MetaRectAction const &) = delete; // due to MetaAction
@@ -216,7 +212,6 @@ private:
sal_uInt32 mnVertRound;
public:
- SAL_DLLPRIVATE MetaRoundRectAction();
MetaRoundRectAction(MetaRoundRectAction const &) = default;
MetaRoundRectAction(MetaRoundRectAction &&) = default;
MetaRoundRectAction & operator =(MetaRoundRectAction const &) = delete; // due to MetaAction
@@ -245,7 +240,6 @@ private:
tools::Rectangle maRect;
public:
- SAL_DLLPRIVATE MetaEllipseAction();
MetaEllipseAction(MetaEllipseAction const &) = default;
MetaEllipseAction(MetaEllipseAction &&) = default;
MetaEllipseAction & operator =(MetaEllipseAction const &) = delete; // due to MetaAction
@@ -273,7 +267,6 @@ private:
Point maEndPt;
public:
- SAL_DLLPRIVATE MetaArcAction();
MetaArcAction(MetaArcAction const &) = default;
MetaArcAction(MetaArcAction &&) = default;
MetaArcAction & operator =(MetaArcAction const &) = delete; // due to MetaAction
@@ -304,7 +297,6 @@ private:
Point maEndPt;
public:
- SAL_DLLPRIVATE MetaPieAction();
MetaPieAction(MetaPieAction const &) = default;
MetaPieAction(MetaPieAction &&) = default;
MetaPieAction & operator =(MetaPieAction const &) = delete; // due to MetaAction
@@ -335,7 +327,6 @@ private:
Point maEndPt;
public:
- SAL_DLLPRIVATE MetaChordAction();
MetaChordAction(MetaChordAction const &) = default;
MetaChordAction(MetaChordAction &&) = default;
MetaChordAction & operator =(MetaChordAction const &) = delete; // due to MetaAction
@@ -365,7 +356,6 @@ private:
tools::Polygon maPoly;
public:
- SAL_DLLPRIVATE MetaPolyLineAction();
MetaPolyLineAction(MetaPolyLineAction const &) = default;
MetaPolyLineAction(MetaPolyLineAction &&) = default;
MetaPolyLineAction & operator =(MetaPolyLineAction const &) = delete; // due to MetaAction
@@ -393,7 +383,6 @@ private:
tools::Polygon maPoly;
public:
- SAL_DLLPRIVATE MetaPolygonAction();
MetaPolygonAction(MetaPolygonAction const &) = default;
MetaPolygonAction(MetaPolygonAction &&) = default;
MetaPolygonAction & operator =(MetaPolygonAction const &) = delete; // due to MetaAction
@@ -419,7 +408,6 @@ private:
tools::PolyPolygon maPolyPoly;
public:
- SAL_DLLPRIVATE MetaPolyPolygonAction();
MetaPolyPolygonAction(MetaPolyPolygonAction const &) = default;
MetaPolyPolygonAction(MetaPolyPolygonAction &&) = default;
MetaPolyPolygonAction & operator =(MetaPolyPolygonAction const &) = delete; // due to MetaAction
@@ -448,7 +436,6 @@ private:
sal_Int32 mnLen;
public:
- MetaTextAction();
MetaTextAction(MetaTextAction const &) = default;
MetaTextAction(MetaTextAction &&) = default;
MetaTextAction & operator =(MetaTextAction const &) = delete; // due to MetaAction
@@ -487,7 +474,6 @@ private:
SAL_DLLPRIVATE virtual ~MetaTextArrayAction() override;
public:
- SAL_DLLPRIVATE MetaTextArrayAction();
SAL_DLLPRIVATE MetaTextArrayAction( const MetaTextArrayAction& rAction );
SAL_DLLPRIVATE MetaTextArrayAction( const Point& rStartPt, OUString aStr,
KernArray rDXAry,
@@ -531,7 +517,6 @@ private:
sal_Int32 mnLen;
public:
- MetaStretchTextAction();
MetaStretchTextAction(MetaStretchTextAction const &) = default;
MetaStretchTextAction(MetaStretchTextAction &&) = default;
MetaStretchTextAction & operator =(MetaStretchTextAction const &) = delete; // due to MetaAction
@@ -565,7 +550,6 @@ private:
DrawTextFlags mnStyle;
public:
- MetaTextRectAction();
MetaTextRectAction(MetaTextRectAction const &) = default;
MetaTextRectAction(MetaTextRectAction &&) = default;
MetaTextRectAction & operator =(MetaTextRectAction const &) = delete; // due to MetaAction
@@ -598,7 +582,6 @@ private:
FontLineStyle meOverline;
public:
- MetaTextLineAction();
MetaTextLineAction(MetaTextLineAction const &) = default;
MetaTextLineAction(MetaTextLineAction &&) = default;
MetaTextLineAction & operator =(MetaTextLineAction const &) = delete; // due to MetaAction
@@ -631,7 +614,6 @@ private:
Point maPt;
public:
- SAL_DLLPRIVATE MetaBmpAction();
MetaBmpAction(MetaBmpAction const &) = default;
MetaBmpAction(MetaBmpAction &&) = default;
MetaBmpAction & operator =(MetaBmpAction const &) = delete; // due to MetaAction
@@ -660,7 +642,6 @@ private:
Size maSz;
public:
- SAL_DLLPRIVATE MetaBmpScaleAction();
MetaBmpScaleAction(MetaBmpScaleAction const &) = default;
MetaBmpScaleAction(MetaBmpScaleAction &&) = default;
MetaBmpScaleAction & operator =(MetaBmpScaleAction const &) = delete; // due to MetaAction
@@ -693,7 +674,6 @@ private:
Size maSrcSz;
public:
- SAL_DLLPRIVATE MetaBmpScalePartAction();
MetaBmpScalePartAction(MetaBmpScalePartAction const &) = default;
MetaBmpScalePartAction(MetaBmpScalePartAction &&) = default;
MetaBmpScalePartAction & operator =(MetaBmpScalePartAction const &) = delete; // due to MetaAction
@@ -726,7 +706,6 @@ private:
Point maPt;
public:
- SAL_DLLPRIVATE MetaBmpExAction();
MetaBmpExAction(MetaBmpExAction const &) = default;
MetaBmpExAction(MetaBmpExAction &&) = default;
MetaBmpExAction & operator =(MetaBmpExAction const &) = delete; // due to MetaAction
@@ -756,7 +735,6 @@ private:
Size maSz;
public:
- SAL_DLLPRIVATE MetaBmpExScaleAction();
MetaBmpExScaleAction(MetaBmpExScaleAction const &) = default;
MetaBmpExScaleAction(MetaBmpExScaleAction &&) = default;
MetaBmpExScaleAction & operator =(MetaBmpExScaleAction const &) = delete; // due to MetaAction
@@ -790,7 +768,6 @@ private:
Size maSrcSz;
public:
- SAL_DLLPRIVATE MetaBmpExScalePartAction();
MetaBmpExScalePartAction(MetaBmpExScalePartAction const &) = default;
MetaBmpExScalePartAction(MetaBmpExScalePartAction &&) = default;
MetaBmpExScalePartAction & operator =(MetaBmpExScalePartAction const &) = delete; // due to MetaAction
@@ -825,7 +802,6 @@ private:
Point maPt;
public:
- MetaMaskAction();
MetaMaskAction(MetaMaskAction const &) = default;
MetaMaskAction(MetaMaskAction &&) = default;
MetaMaskAction & operator =(MetaMaskAction const &) = delete; // due to MetaAction
@@ -858,7 +834,6 @@ private:
Size maSz;
public:
- MetaMaskScaleAction();
MetaMaskScaleAction(MetaMaskScaleAction const &) = default;
MetaMaskScaleAction(MetaMaskScaleAction &&) = default;
MetaMaskScaleAction & operator =(MetaMaskScaleAction const &) = delete; // due to MetaAction
@@ -894,7 +869,6 @@ private:
Size maSrcSz;
public:
- MetaMaskScalePartAction();
MetaMaskScalePartAction(MetaMaskScalePartAction const &) = default;
MetaMaskScalePartAction(MetaMaskScalePartAction &&) = default;
MetaMaskScalePartAction & operator =(MetaMaskScalePartAction const &) = delete; // due to MetaAction
@@ -929,7 +903,6 @@ private:
Gradient maGradient;
public:
- MetaGradientAction();
MetaGradientAction(MetaGradientAction const &) = default;
MetaGradientAction(MetaGradientAction &&) = default;
MetaGradientAction & operator =(MetaGradientAction const &) = delete; // due to MetaAction
@@ -957,7 +930,6 @@ private:
Gradient maGradient;
public:
- SAL_DLLPRIVATE MetaGradientExAction();
MetaGradientExAction(MetaGradientExAction const &) = default;
MetaGradientExAction(MetaGradientExAction &&) = default;
MetaGradientExAction & operator =(MetaGradientExAction const &) = delete; // due to MetaAction
@@ -985,7 +957,6 @@ private:
Hatch maHatch;
public:
- MetaHatchAction();
MetaHatchAction(MetaHatchAction const &) = default;
MetaHatchAction(MetaHatchAction &&) = default;
MetaHatchAction & operator =(MetaHatchAction const &) = delete; // due to MetaAction
@@ -1013,7 +984,6 @@ private:
Wallpaper maWallpaper;
public:
- SAL_DLLPRIVATE MetaWallpaperAction();
MetaWallpaperAction(MetaWallpaperAction const &) = default;
MetaWallpaperAction(MetaWallpaperAction &&) = default;
MetaWallpaperAction & operator =(MetaWallpaperAction const &) = delete; // due to MetaAction
@@ -1042,7 +1012,6 @@ private:
bool mbClip;
public:
- SAL_DLLPRIVATE MetaClipRegionAction();
MetaClipRegionAction(MetaClipRegionAction const &) = default;
MetaClipRegionAction(MetaClipRegionAction &&) = default;
MetaClipRegionAction & operator =(MetaClipRegionAction const &) = delete; // due to MetaAction
@@ -1069,7 +1038,6 @@ private:
tools::Rectangle maRect;
public:
- SAL_DLLPRIVATE MetaISectRectClipRegionAction();
MetaISectRectClipRegionAction(MetaISectRectClipRegionAction const &) = default;
MetaISectRectClipRegionAction(MetaISectRectClipRegionAction &&) = default;
MetaISectRectClipRegionAction & operator =(MetaISectRectClipRegionAction const &) = delete; // due to MetaAction
@@ -1095,7 +1063,6 @@ private:
vcl::Region maRegion;
public:
- SAL_DLLPRIVATE MetaISectRegionClipRegionAction();
MetaISectRegionClipRegionAction(MetaISectRegionClipRegionAction const &) = default;
MetaISectRegionClipRegionAction(MetaISectRegionClipRegionAction &&) = default;
MetaISectRegionClipRegionAction & operator =(MetaISectRegionClipRegionAction const &) = delete; // due to MetaAction
@@ -1122,7 +1089,6 @@ private:
tools::Long mnVertMove;
public:
- SAL_DLLPRIVATE MetaMoveClipRegionAction();
MetaMoveClipRegionAction(MetaMoveClipRegionAction const &) = default;
MetaMoveClipRegionAction(MetaMoveClipRegionAction &&) = default;
MetaMoveClipRegionAction & operator =(MetaMoveClipRegionAction const &) = delete; // due to MetaAction
@@ -1149,7 +1115,6 @@ private:
bool mbSet;
public:
- SAL_DLLPRIVATE MetaLineColorAction();
MetaLineColorAction(MetaLineColorAction const &) = default;
MetaLineColorAction(MetaLineColorAction &&) = default;
MetaLineColorAction & operator =(MetaLineColorAction const &) = delete; // due to MetaAction
@@ -1174,7 +1139,6 @@ private:
bool mbSet;
public:
- SAL_DLLPRIVATE MetaFillColorAction();
MetaFillColorAction(MetaFillColorAction const &) = default;
MetaFillColorAction(MetaFillColorAction &&) = default;
MetaFillColorAction & operator =(MetaFillColorAction const &) = delete; // due to MetaAction
@@ -1199,7 +1163,6 @@ private:
Color maColor;
public:
- SAL_DLLPRIVATE MetaTextColorAction();
MetaTextColorAction(MetaTextColorAction const &) = default;
MetaTextColorAction(MetaTextColorAction &&) = default;
MetaTextColorAction & operator =(MetaTextColorAction const &) = delete; // due to MetaAction
@@ -1223,7 +1186,6 @@ private:
bool mbSet;
public:
- SAL_DLLPRIVATE MetaTextFillColorAction();
MetaTextFillColorAction(MetaTextFillColorAction const &) = default;
MetaTextFillColorAction(MetaTextFillColorAction &&) = default;
MetaTextFillColorAction & operator =(MetaTextFillColorAction const &) = delete; // due to MetaAction
@@ -1249,7 +1211,6 @@ private:
bool mbSet;
public:
- SAL_DLLPRIVATE MetaTextLineColorAction();
MetaTextLineColorAction(MetaTextLineColorAction const &) = default;
MetaTextLineColorAction(MetaTextLineColorAction &&) = default;
MetaTextLineColorAction & operator =(MetaTextLineColorAction const &) = delete; // due to MetaAction
@@ -1274,7 +1235,6 @@ private:
bool mbSet;
public:
- SAL_DLLPRIVATE MetaOverlineColorAction();
MetaOverlineColorAction(MetaOverlineColorAction const &) = default;
MetaOverlineColorAction(MetaOverlineColorAction &&) = default;
MetaOverlineColorAction & operator =(MetaOverlineColorAction const &) = delete; // due to MetaAction
@@ -1298,7 +1258,6 @@ private:
TextAlign maAlign;
public:
- SAL_DLLPRIVATE MetaTextAlignAction();
MetaTextAlignAction(MetaTextAlignAction const &) = default;
MetaTextAlignAction(MetaTextAlignAction &&) = default;
MetaTextAlignAction & operator =(MetaTextAlignAction const &) = delete; // due to MetaAction
@@ -1354,7 +1313,6 @@ private:
void correctFontScale(tools::Long nNewFontScale) { maFont.SetAverageFontWidth(nNewFontScale); }
public:
- SAL_DLLPRIVATE MetaFontAction();
MetaFontAction(MetaFontAction const &) = default;
MetaFontAction(MetaFontAction &&) = default;
MetaFontAction & operator =(MetaFontAction const &) = delete; // due to MetaAction
@@ -1380,7 +1338,6 @@ private:
vcl::PushFlags mnFlags;
public:
- SAL_DLLPRIVATE MetaPushAction();
MetaPushAction(MetaPushAction const &) = default;
MetaPushAction(MetaPushAction &&) = default;
MetaPushAction & operator =(MetaPushAction const &) = delete; // due to MetaAction
@@ -1419,7 +1376,6 @@ private:
RasterOp meRasterOp;
public:
- SAL_DLLPRIVATE MetaRasterOpAction();
MetaRasterOpAction(MetaRasterOpAction const &) = default;
MetaRasterOpAction(MetaRasterOpAction &&) = default;
MetaRasterOpAction & operator =(MetaRasterOpAction const &) = delete; // due to MetaAction
@@ -1443,7 +1399,6 @@ private:
sal_uInt16 mnTransPercent;
public:
- MetaTransparentAction();
MetaTransparentAction(MetaTransparentAction const &) = default;
MetaTransparentAction(MetaTransparentAction &&) = default;
MetaTransparentAction & operator =(MetaTransparentAction const &) = delete; // due to MetaAction
@@ -1478,7 +1433,6 @@ private:
std::optional<basegfx::BColorStops> maSVGTransparencyColorStops;
public:
- MetaFloatTransparentAction();
MetaFloatTransparentAction(MetaFloatTransparentAction const &) = default;
MetaFloatTransparentAction(MetaFloatTransparentAction &&) = default;
MetaFloatTransparentAction & operator =(MetaFloatTransparentAction const &) = delete; // due to MetaAction
@@ -1517,7 +1471,6 @@ private:
Size maSize;
public:
- MetaEPSAction();
MetaEPSAction(MetaEPSAction const &) = default;
MetaEPSAction(MetaEPSAction &&) = default;
MetaEPSAction & operator =(MetaEPSAction const &) = delete; // due to MetaAction
@@ -1548,7 +1501,6 @@ private:
bool mbSet;
public:
- SAL_DLLPRIVATE MetaRefPointAction();
MetaRefPointAction(MetaRefPointAction const &) = default;
MetaRefPointAction(MetaRefPointAction &&) = default;
MetaRefPointAction & operator =(MetaRefPointAction const &) = delete; // due to MetaAction
@@ -1581,7 +1533,6 @@ private:
SAL_DLLPRIVATE virtual ~MetaCommentAction() override;
public:
- SAL_DLLPRIVATE explicit MetaCommentAction();
SAL_DLLPRIVATE explicit MetaCommentAction( const MetaCommentAction& rAct );
explicit MetaCommentAction( OString aComment, sal_Int32 nValue = 0, const sal_uInt8* pData = nullptr, sal_uInt32 nDataSize = 0 );
@@ -1604,7 +1555,6 @@ private:
vcl::text::ComplexTextLayoutFlags mnLayoutMode;
public:
- SAL_DLLPRIVATE MetaLayoutModeAction();
MetaLayoutModeAction(MetaLayoutModeAction const &) = default;
MetaLayoutModeAction(MetaLayoutModeAction &&) = default;
MetaLayoutModeAction & operator =(MetaLayoutModeAction const &) = delete; // due to MetaAction
@@ -1627,7 +1577,6 @@ private:
LanguageType meTextLanguage;
public:
- SAL_DLLPRIVATE MetaTextLanguageAction();
MetaTextLanguageAction(MetaTextLanguageAction const &) = default;
MetaTextLanguageAction(MetaTextLanguageAction &&) = default;
MetaTextLanguageAction & operator =(MetaTextLanguageAction const &) = delete; // due to MetaAction
diff --git a/include/vcl/settings.hxx b/include/vcl/settings.hxx
index b50bcc67293a..5c57fe8d9eba 100644
--- a/include/vcl/settings.hxx
+++ b/include/vcl/settings.hxx
@@ -123,8 +123,6 @@ public:
void SetButtonRepeat( sal_Int32 nRepeat );
sal_Int32 GetButtonRepeat() const;
- SAL_DLLPRIVATE static sal_Int32 GetActionDelay();
-
void SetMenuDelay( sal_Int32 nDelay );
sal_Int32 GetMenuDelay() const;
diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx
index 058402d4b5e1..ef908f61931b 100644
--- a/include/vcl/svapp.hxx
+++ b/include/vcl/svapp.hxx
@@ -1325,7 +1325,8 @@ public:
const OUString& rAction,
const std::vector<vcl::LOKPayloadItem>& rPayload = std::vector<vcl::LOKPayloadItem>()) const override;
virtual void libreOfficeKitViewCallback(int nType, const OString& pPayload) const override;
- virtual void notifyInvalidation(tools::Rectangle const *) const override;
+ virtual void notifyInvalidation(tools::Rectangle const* pRect) const override;
+ virtual void notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent) const override;
virtual OString dumpNotifyState() const override;
private:
diff --git a/include/vcl/toolkit/MenuButton.hxx b/include/vcl/toolkit/MenuButton.hxx
index 79f0edd9d71a..29b2ff53a556 100644
--- a/include/vcl/toolkit/MenuButton.hxx
+++ b/include/vcl/toolkit/MenuButton.hxx
@@ -47,8 +47,6 @@ private:
Link<MenuButton*,void> maActivateHdl;
Link<MenuButton*,void> maSelectHdl;
- DECL_DLLPRIVATE_LINK( ImplMenuTimeoutHdl, Timer*, void );
-
MenuButton( const MenuButton & ) = delete;
MenuButton& operator=( const MenuButton & ) = delete;
diff --git a/include/vcl/toolkit/button.hxx b/include/vcl/toolkit/button.hxx
index e1f10eb67242..4d8e6fdc8571 100644
--- a/include/vcl/toolkit/button.hxx
+++ b/include/vcl/toolkit/button.hxx
@@ -57,7 +57,6 @@ public:
SAL_DLLPRIVATE const tools::Rectangle& ImplGetFocusRect() const;
SAL_DLLPRIVATE void ImplSetSymbolAlign( SymbolAlign eAlign );
/// The x-coordinate of the vertical separator line, use in MenuButton subclass only.
- SAL_DLLPRIVATE tools::Long ImplGetSeparatorX() const;
SAL_DLLPRIVATE void ImplSetSeparatorX( tools::Long nX );
protected:
diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx
index 06b5a5478446..8369693dd05f 100644
--- a/include/vcl/window.hxx
+++ b/include/vcl/window.hxx
@@ -768,6 +768,8 @@ public:
void SetType( WindowType eType );
WindowType GetType() const;
std::string_view GetTypeName() const;
+ bool IsFormControl() const;
+ void SetFormControl(bool bFormControl);
bool IsSystemWindow() const;
SAL_DLLPRIVATE bool IsDockingWindow() const;
bool IsDialog() const;
@@ -1442,7 +1444,14 @@ public:
void SimulateKeyPress( sal_uInt16 nKeyCode ) const;
virtual OUString GetSurroundingText() const;
+
+ /**
+ * Return the non-normalized Selection, i.e. calling Selection::Min() on
+ * the returned Selection returns the selection anchor and Selection::Max()
+ * returns the cursor position.
+ */
virtual Selection GetSurroundingTextSelection() const;
+
virtual bool DeleteSurroundingText(const Selection& rSelection);
virtual FactoryFunction GetUITestFactory() const;
diff --git a/m4/ax_boost_system.m4 b/m4/ax_boost_system.m4
deleted file mode 100644
index 323e2a676a8e..000000000000
--- a/m4/ax_boost_system.m4
+++ /dev/null
@@ -1,121 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_boost_system.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_BOOST_SYSTEM
-#
-# DESCRIPTION
-#
-# Test for System library from the Boost C++ libraries. The macro requires
-# a preceding call to AX_BOOST_BASE. Further documentation is available at
-# <http://randspringer.de/boost/index.html>.
-#
-# This macro calls:
-#
-# AC_SUBST(BOOST_SYSTEM_LIB)
-#
-# And sets:
-#
-# HAVE_BOOST_SYSTEM
-#
-# LICENSE
-#
-# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
-# Copyright (c) 2008 Michael Tindal
-# Copyright (c) 2008 Daniel Casimiro <dan.casimiro@gmail.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 20
-
-AC_DEFUN([AX_BOOST_SYSTEM],
-[
- AC_ARG_WITH([boost-system],
- AS_HELP_STRING([--with-boost-system@<:@=special-lib@:>@],
- [use the System library from boost - it is possible to specify a certain library for the linker
- e.g. --with-boost-system=boost_system-gcc-mt ]),
- [
- if test "$withval" = "no"; then
- want_boost="no"
- elif test "$withval" = "yes"; then
- want_boost="yes"
- ax_boost_user_system_lib=""
- else
- want_boost="yes"
- ax_boost_user_system_lib="$withval"
- fi
- ],
- [want_boost="yes"]
- )
-
- if test "x$want_boost" = "xyes"; then
- AC_REQUIRE([AC_PROG_CC])
- AC_REQUIRE([AC_CANONICAL_BUILD])
- CPPFLAGS_SAVED="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
- export CPPFLAGS
-
- LDFLAGS_SAVED="$LDFLAGS"
- LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
- export LDFLAGS
-
- AC_CACHE_CHECK(whether the Boost::System library is available,
- ax_cv_boost_system,
- [AC_LANG_PUSH([C++])
- CXXFLAGS_SAVE=$CXXFLAGS
- CXXFLAGS=
-
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/system/error_code.hpp>]],
- [[boost::system::error_category *a = 0;]])],
- ax_cv_boost_system=yes, ax_cv_boost_system=no)
- CXXFLAGS=$CXXFLAGS_SAVE
- AC_LANG_POP([C++])
- ])
- if test "x$ax_cv_boost_system" = "xyes"; then
- AC_SUBST(BOOST_CPPFLAGS)
-
- AC_DEFINE(HAVE_BOOST_SYSTEM,,[define if the Boost::System library is available])
- BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
-
- LDFLAGS_SAVE=$LDFLAGS
- if test "x$ax_boost_user_system_lib" = "x"; then
- for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
- ax_lib=${libextension}
- AC_CHECK_LIB($ax_lib, exit,
- [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
- [link_system="no"])
- done
- if test "x$link_system" != "xyes"; then
- for libextension in `ls -r $BOOSTLIBDIR/boost_system* 2>/dev/null | sed 's,.*/,,' | sed -e 's,\..*,,'` ; do
- ax_lib=${libextension}
- AC_CHECK_LIB($ax_lib, exit,
- [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
- [link_system="no"])
- done
- fi
-
- else
- for ax_lib in $ax_boost_user_system_lib boost_system-$ax_boost_user_system_lib; do
- AC_CHECK_LIB($ax_lib, exit,
- [BOOST_SYSTEM_LIB="-l$ax_lib"; AC_SUBST(BOOST_SYSTEM_LIB) link_system="yes"; break],
- [link_system="no"])
- done
-
- fi
- if test "x$ax_lib" = "x"; then
- AC_MSG_ERROR(Could not find a version of the Boost::System library!)
- fi
- if test "x$link_system" = "xno"; then
- AC_MSG_ERROR(Could not link against $ax_lib !)
- fi
- fi
-
- CPPFLAGS="$CPPFLAGS_SAVED"
- LDFLAGS="$LDFLAGS_SAVED"
- fi
-])
diff --git a/odk/examples/DevelopersGuide/FirstSteps/FirstLoadComponent/csharp/Makefile b/odk/examples/DevelopersGuide/FirstSteps/FirstLoadComponent/csharp/Makefile
index 2cd58d246ac7..3387e8672cb0 100644
--- a/odk/examples/DevelopersGuide/FirstSteps/FirstLoadComponent/csharp/Makefile
+++ b/odk/examples/DevelopersGuide/FirstSteps/FirstLoadComponent/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/DevelopersGuide/FirstSteps/FirstUnoContact/csharp/Makefile b/odk/examples/DevelopersGuide/FirstSteps/FirstUnoContact/csharp/Makefile
index c3257605e853..c4797f4f5b3b 100644
--- a/odk/examples/DevelopersGuide/FirstSteps/FirstUnoContact/csharp/Makefile
+++ b/odk/examples/DevelopersGuide/FirstSteps/FirstUnoContact/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/DevelopersGuide/FirstSteps/HelloTextTableShape/csharp/Makefile b/odk/examples/DevelopersGuide/FirstSteps/HelloTextTableShape/csharp/Makefile
index b30bfb7afcbd..bdc0fd054178 100644
--- a/odk/examples/DevelopersGuide/FirstSteps/HelloTextTableShape/csharp/Makefile
+++ b/odk/examples/DevelopersGuide/FirstSteps/HelloTextTableShape/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/DevelopersGuide/OfficeDev/PathSettings/csharp/Makefile b/odk/examples/DevelopersGuide/OfficeDev/PathSettings/csharp/Makefile
index 5509df52153a..81d0d3d5e60b 100644
--- a/odk/examples/DevelopersGuide/OfficeDev/PathSettings/csharp/Makefile
+++ b/odk/examples/DevelopersGuide/OfficeDev/PathSettings/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/DevelopersGuide/OfficeDev/PathSubstitution/csharp/Makefile b/odk/examples/DevelopersGuide/OfficeDev/PathSubstitution/csharp/Makefile
index 363c4ca92587..1477f7da5de9 100644
--- a/odk/examples/DevelopersGuide/OfficeDev/PathSubstitution/csharp/Makefile
+++ b/odk/examples/DevelopersGuide/OfficeDev/PathSubstitution/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/DevelopersGuide/OfficeDev/TerminationTest/csharp/Makefile b/odk/examples/DevelopersGuide/OfficeDev/TerminationTest/csharp/Makefile
index 76d685fd3dcc..a4977c7709f7 100644
--- a/odk/examples/DevelopersGuide/OfficeDev/TerminationTest/csharp/Makefile
+++ b/odk/examples/DevelopersGuide/OfficeDev/TerminationTest/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/dotnet/WriterDemo/csharp/Makefile b/odk/examples/dotnet/WriterDemo/csharp/Makefile
index 28992ec130d4..7bc34acf597b 100644
--- a/odk/examples/dotnet/WriterDemo/csharp/Makefile
+++ b/odk/examples/dotnet/WriterDemo/csharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/dotnet/WriterDemo/fsharp/Makefile b/odk/examples/dotnet/WriterDemo/fsharp/Makefile
index d3aaad0c6499..83fc278d7f91 100644
--- a/odk/examples/dotnet/WriterDemo/fsharp/Makefile
+++ b/odk/examples/dotnet/WriterDemo/fsharp/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/odk/examples/dotnet/WriterDemo/vbasic/Makefile b/odk/examples/dotnet/WriterDemo/vbasic/Makefile
index 01014c71a820..0bd37f6f219c 100644
--- a/odk/examples/dotnet/WriterDemo/vbasic/Makefile
+++ b/odk/examples/dotnet/WriterDemo/vbasic/Makefile
@@ -24,6 +24,7 @@ DOTNET_FLAGS = -c Release
LO_NUPKG_ID = LibreOffice.Bindings
LO_NUPKG_VERSION = 0.1.0
LO_NUPKG_DIR = $(abspath $(PRJ)/dotnet)
+TARGET_FRAMEWORK = net$(shell dotnet --version | cut -d. -f1-2)
# Targets
.PHONY: ALL
@@ -36,7 +37,7 @@ $(APP_PROJ_FILE) :
$(ECHO) "<Project Sdk=\"Microsoft.NET.Sdk\">" > $@
$(ECHO) " <PropertyGroup>" >> $@
$(ECHO) " <AssemblyName>$(APP_NAME)</AssemblyName>" >> $@
- $(ECHO) " <TargetFramework>net8.0</TargetFramework>" >> $@
+ $(ECHO) " <TargetFramework>$(TARGET_FRAMEWORK)</TargetFramework>" >> $@
$(ECHO) " <OutputType>exe</OutputType>" >> $@
$(ECHO) " <PublishSingleFile>true</PublishSingleFile>" >> $@
$(ECHO) " <SelfContained>false</SelfContained>" >> $@
diff --git a/rust_uno/.gitignore b/rust_uno/.gitignore
new file mode 100644
index 000000000000..310213a05bc3
--- /dev/null
+++ b/rust_uno/.gitignore
@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+generated/
diff --git a/rust_uno/Cargo.toml b/rust_uno/Cargo.toml
new file mode 100644
index 000000000000..f54f9bc3c85e
--- /dev/null
+++ b/rust_uno/Cargo.toml
@@ -0,0 +1,20 @@
+# -*- Mode: toml; tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+[package]
+name = "rust_uno"
+version = "0.1.0"
+edition = "2024"
+description = "Rust FFI binding for LibreOffice UNO API"
+
+[lib]
+name = "rust_uno"
+crate-type = ["cdylib"]
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/CustomTarget_cargo.mk b/rust_uno/CustomTarget_cargo.mk
new file mode 100644
index 000000000000..d27ec0b0797a
--- /dev/null
+++ b/rust_uno/CustomTarget_cargo.mk
@@ -0,0 +1,18 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,rust_uno/cargo))
+
+.PHONY: $(call gb_CustomTarget_get_target,rust_uno/cargo)
+$(call gb_CustomTarget_get_target,rust_uno/cargo): \
+ $(call gb_Library_get_target,rust_uno-cpp) \
+ $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+ cd $(SRCDIR)/rust_uno && cargo build $(if $(verbose),--verbose,) --release
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/CustomTarget_rustmaker.mk b/rust_uno/CustomTarget_rustmaker.mk
new file mode 100644
index 000000000000..b519be3c627c
--- /dev/null
+++ b/rust_uno/CustomTarget_rustmaker.mk
@@ -0,0 +1,31 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,rust_uno/rustmaker))
+
+$(call gb_CustomTarget_get_target,rust_uno/rustmaker): \
+ $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+
+$(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp: \
+ $(call gb_Executable_get_target,rustmaker) \
+ $(call gb_Executable_get_runtime_dependencies,rustmaker) \
+ $(call gb_UnoApi_get_target,offapi) \
+ $(call gb_UnoApi_get_target,udkapi) \
+ $(gb_CustomTarget_workdir)/rust_uno/rustmaker/.dir
+ rm -fr $(SRCDIR)/rust_uno/src/generated
+ mkdir $(SRCDIR)/rust_uno/src/generated
+ rm -fr $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+ mkdir $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp
+ $(call gb_Helper_abbreviate_dirs, \
+ $(call gb_Helper_execute,rustmaker $(if $(verbose),--verbose,) -Ocpp $(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp \
+ $(if $(verbose),--verbose,) -Orust $(SRCDIR)/rust_uno/src/generated \
+ $(call gb_UnoApi_get_target,offapi) $(call gb_UnoApi_get_target,udkapi)))
+ touch $@
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Extension_rust_uno-example.mk b/rust_uno/Extension_rust_uno-example.mk
new file mode 100644
index 000000000000..fea1677e1966
--- /dev/null
+++ b/rust_uno/Extension_rust_uno-example.mk
@@ -0,0 +1,26 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Extension_Extension,rust_uno-example,rust_uno/example,nodeliver))
+
+$(eval $(call gb_Extension_add_file,rust_uno-example,platform.components,$(call gb_Rdb_get_target,rust_uno-example)))
+
+$(eval $(call gb_Extension_add_files,rust_uno-example,, \
+ $(SRCDIR)/rust_uno/example/Addons.xcu \
+ $(SRCDIR)/rust_uno/example/ProtocolHandler.xcu \
+ $(SRCDIR)/rust_uno/target/release/librust_uno.so \
+))
+
+$(eval $(call gb_Extension_add_libraries,rust_uno-example, \
+ rust_uno-example \
+))
+
+$(SRCDIR)/rust_uno/target/release/librust_uno.so: $(call gb_CustomTarget_get_target,rust_uno/cargo)
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Library_rust_uno-cpp.mk b/rust_uno/Library_rust_uno-cpp.mk
new file mode 100644
index 000000000000..4a1875015b7f
--- /dev/null
+++ b/rust_uno/Library_rust_uno-cpp.mk
@@ -0,0 +1,41 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,rust_uno-cpp))
+
+$(eval $(call gb_Library_use_libraries,rust_uno-cpp, \
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_use_sdk_api,rust_uno-cpp))
+
+# Add the uno_bootstrap.cxx file for bootstrap functionality
+$(eval $(call gb_Library_add_exception_objects,rust_uno-cpp, \
+ rust_uno/uno_bootstrap \
+))
+
+# Combined generated files instead of thousands of individual files
+rust_uno_generated_cxx = \
+ rust_uno_bindings
+
+define rust_uno_add_generated_cxx
+$(gb_CustomTarget_workdir)/rust_uno/rustmaker/cpp/$(1).cxx: \
+ $(call gb_CustomTarget_get_target,rust_uno/rustmaker)
+
+$(eval $(call gb_Library_add_generated_exception_objects,rust_uno-cpp, \
+ CustomTarget/rust_uno/rustmaker/cpp/$(1) \
+))
+
+endef
+
+$(foreach gencxx,$(rust_uno_generated_cxx),$(eval $(call rust_uno_add_generated_cxx,$(gencxx))))
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Library_rust_uno-example.mk b/rust_uno/Library_rust_uno-example.mk
new file mode 100644
index 000000000000..bee03c23c3b6
--- /dev/null
+++ b/rust_uno/Library_rust_uno-example.mk
@@ -0,0 +1,37 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Library_Library,rust_uno-example))
+
+$(eval $(call gb_Library_add_exception_objects,rust_uno-example, \
+ rust_uno/example/example \
+))
+
+$(eval $(call gb_Library_set_componentfile,rust_uno-example,rust_uno/example/example,rust_uno-example))
+
+$(eval $(call gb_Library_set_external_code,rust_uno-example))
+
+$(eval $(call gb_Library_use_externals,rust_uno-example, \
+ boost_headers \
+))
+
+$(eval $(call gb_Library_use_libraries,rust_uno-example, \
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_use_sdk_api,rust_uno-example))
+
+$(call gb_Library_get_target,rust_uno-example): $(call gb_CustomTarget_get_target,rust_uno/cargo)
+$(eval $(call gb_Library_add_libs,rust_uno-example,\
+ $(SRCDIR)/rust_uno/target/release/librust_uno.so \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Makefile b/rust_uno/Makefile
new file mode 100644
index 000000000000..d5aa252aa8c3
--- /dev/null
+++ b/rust_uno/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/Module_rust_uno.mk b/rust_uno/Module_rust_uno.mk
new file mode 100644
index 000000000000..ab6fa695a0cc
--- /dev/null
+++ b/rust_uno/Module_rust_uno.mk
@@ -0,0 +1,22 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Module_Module,rust_uno))
+
+ifeq ($(ENABLE_RUST_UNO),TRUE)
+$(eval $(call gb_Module_add_targets,rust_uno, \
+ CustomTarget_cargo \
+ CustomTarget_rustmaker \
+ Extension_rust_uno-example \
+ Library_rust_uno-cpp \
+ Library_rust_uno-example \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/rust_uno/build.rs b/rust_uno/build.rs
new file mode 100644
index 000000000000..5d25a125b4fc
--- /dev/null
+++ b/rust_uno/build.rs
@@ -0,0 +1,39 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Build script for rust_uno crate
+//!
+//! Links the generated C++ bridge library (librust_uno-cpp.so) to the Rust cdylib
+
+fn main() {
+ // Tell cargo to link against the rust_uno-cpp library
+ // This library contains the generated C++ bridge functions
+ println!("cargo:rustc-link-lib=rust_uno-cpplo");
+
+ // Add the LibreOffice instdir/program directory to the library search path
+ // This is where librust_uno-cpplo.so is located
+ if let Ok(instdir) = std::env::var("INSTDIR") {
+ println!("cargo:rustc-link-search=native={}/program", instdir);
+ }
+
+ // Also try the workdir path where the library might be during build
+ if let Ok(workdir) = std::env::var("WORKDIR") {
+ println!(
+ "cargo:rustc-link-search=native={}/LinkTarget/Library",
+ workdir
+ );
+ }
+
+ // Fallback: try relative paths from the rust_uno directory
+ println!("cargo:rustc-link-search=native=../instdir/program");
+ println!("cargo:rustc-link-search=native=../workdir/LinkTarget/Library");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/rust_uno/example/Addons.xcu b/rust_uno/example/Addons.xcu
new file mode 100644
index 000000000000..9d906a2a4e9f
--- /dev/null
+++ b/rust_uno/example/Addons.xcu
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<o:items xmlns:o="http://openoffice.org/2001/registry">
+ <item o:path="/org.openoffice.Office.Addons">
+ <node o:name="AddonUI">
+ <node o:name="OfficeMenuBar">
+ <node o:name="org.libreoffice.rust_uno.example"
+ o:op="replace">
+ <prop o:name="Title" xml:lang="en-US">
+ <value>Rust UNO</value>
+ </prop>
+ <node o:name="Submenu">
+ <node o:name="1" o:op="replace">
+ <prop o:name="URL">
+ <value>vnd.org.libreoffice.rust_uno.example:</value>
+ </prop>
+ <prop o:name="Title" xml:lang="en-US">
+ <value>Example</value>
+ </prop>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </item>
+</o:items>
diff --git a/rust_uno/example/META-INF/manifest.xml b/rust_uno/example/META-INF/manifest.xml
new file mode 100644
index 000000000000..51af7893f844
--- /dev/null
+++ b/rust_uno/example/META-INF/manifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<m:manifest xmlns:m="http://openoffice.org/2001/manifest">
+ <m:file-entry m:media-type="application/vnd.sun.star.configuration-data"
+ m:full-path="Addons.xcu"/>
+ <m:file-entry m:media-type="application/vnd.sun.star.configuration-data"
+ m:full-path="ProtocolHandler.xcu"/>
+ <m:file-entry
+ m:media-type="application/vnd.sun.star.uno-components;platform=@PLATFORM@"
+ m:full-path="platform.components"/>
+</m:manifest>
diff --git a/rust_uno/example/ProtocolHandler.xcu b/rust_uno/example/ProtocolHandler.xcu
new file mode 100644
index 000000000000..2d205f7f878f
--- /dev/null
+++ b/rust_uno/example/ProtocolHandler.xcu
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<o:component-data xmlns:o="http://openoffice.org/2001/registry"
+ o:package="org.openoffice.Office" o:name="ProtocolHandler">
+ <node o:name="HandlerSet">
+ <node o:name="org.libreoffice.rust_uno.example" o:op="replace">
+ <prop o:name="Protocols">
+ <value>vnd.org.libreoffice.rust_uno.example:*</value>
+ </prop>
+ </node>
+ </node>
+</o:component-data>
diff --git a/rust_uno/example/description.xml b/rust_uno/example/description.xml
new file mode 100644
index 000000000000..526680a84dbd
--- /dev/null
+++ b/rust_uno/example/description.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<d:description xmlns:d="http://openoffice.org/extensions/description/2006">
+ <d:identifier value="org.libreoffice/rust_uno/example"/>
+ <d:version value="1"/>
+ <d:dependencies>
+ <d:OpenOffice.org-minimal-version d:name="OpenOffice.org 3.4" value="3.4"/>
+ </d:dependencies>
+</d:description>
diff --git a/rust_uno/example/example.component b/rust_uno/example/example.component
new file mode 100644
index 000000000000..da779dac84c0
--- /dev/null
+++ b/rust_uno/example/example.component
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.libreoffice.comp.rust_uno.example">
+ <service name="org.libreoffice.rust_uno.example"/>
+ </implementation>
+ <implementation name="org.libreoffice.comp.rust_uno.example_singleton">
+ <singleton name="org.libreoffice.rust_uno.example_singleton"/>
+ </implementation>
+</component>
diff --git a/rust_uno/example/example.cxx b/rust_uno/example/example.cxx
new file mode 100644
index 000000000000..5fc0279281d5
--- /dev/null
+++ b/rust_uno/example/example.cxx
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/DispatchDescriptor.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/XStatusListener.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/DeploymentException.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/util/URL.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <uno/lbnames.h>
+
+#include "rust_uno_hook.hxx"
+
+namespace
+{
+class Provider
+ : public cppu::WeakImplHelper2<css::lang::XServiceInfo, css::frame::XDispatchProvider>
+{
+public:
+ Provider(const Provider&) = delete;
+ const Provider& operator=(const Provider&) = delete;
+
+ static css::uno::Reference<css::uno::XInterface>
+ SAL_CALL static_create(css::uno::Reference<css::uno::XComponentContext> const& xContext)
+ {
+ return static_cast<cppu::OWeakObject*>(new Provider(xContext));
+ }
+
+ static rtl::OUString SAL_CALL static_getImplementationName();
+
+ static css::uno::Sequence<rtl::OUString> SAL_CALL static_getSupportedServiceNames();
+
+private:
+ explicit Provider(css::uno::Reference<css::uno::XComponentContext> const& context)
+ : context_(context)
+ {
+ assert(context.is());
+ }
+
+ virtual ~Provider() {}
+
+ virtual rtl::OUString SAL_CALL getImplementationName() override
+ {
+ return static_getImplementationName();
+ }
+
+ virtual sal_Bool SAL_CALL supportsService(rtl::OUString const& ServiceName) override
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ virtual css::uno::Sequence<rtl::OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return static_getSupportedServiceNames();
+ }
+
+ virtual css::uno::Reference<css::frame::XDispatch>
+ SAL_CALL queryDispatch(css::util::URL const&, rtl::OUString const&, sal_Int32) override;
+
+ virtual css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>> SAL_CALL
+ queryDispatches(css::uno::Sequence<css::frame::DispatchDescriptor> const& Requests) override;
+
+ css::uno::Reference<css::uno::XComponentContext> context_;
+};
+
+rtl::OUString Provider::static_getImplementationName()
+{
+ return rtl::OUString("org.libreoffice.comp.rust_uno.example");
+}
+
+css::uno::Sequence<rtl::OUString> Provider::static_getSupportedServiceNames()
+{
+ rtl::OUString name("org.libreoffice.rust_uno.example");
+ return css::uno::Sequence<rtl::OUString>(&name, 1);
+}
+
+css::uno::Reference<css::frame::XDispatch> Provider::queryDispatch(css::util::URL const&,
+ rtl::OUString const&, sal_Int32)
+{
+ css::uno::Reference<css::frame::XDispatch> dispatch;
+ if (!(context_->getValueByName("/singletons/org.libreoffice.rust_uno.example_singleton")
+ >>= dispatch)
+ || !dispatch.is())
+ {
+ throw css::uno::DeploymentException("component context fails to supply singleton "
+ "org.libreoffice.rust_uno.example_singleton of type "
+ "com.sun.star.frame.XDispatch",
+ context_);
+ }
+ return dispatch;
+}
+
+css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>>
+Provider::queryDispatches(css::uno::Sequence<css::frame::DispatchDescriptor> const& Requests)
+{
+ css::uno::Sequence<css::uno::Reference<css::frame::XDispatch>> s(Requests.getLength());
+ for (sal_Int32 i = 0; i < s.getLength(); ++i)
+ {
+ s[i]
+ = queryDispatch(Requests[i].FeatureURL, Requests[i].FrameName, Requests[i].SearchFlags);
+ }
+ return s;
+}
+
+class Dispatch : public cppu::WeakImplHelper2<css::lang::XServiceInfo, css::frame::XDispatch>
+{
+public:
+ Dispatch(const Dispatch&) = delete;
+ const Dispatch& operator=(const Dispatch&) = delete;
+
+ static css::uno::Reference<css::uno::XInterface>
+ SAL_CALL static_create(css::uno::Reference<css::uno::XComponentContext> const& xContext)
+ {
+ return static_cast<cppu::OWeakObject*>(new Dispatch(xContext));
+ }
+
+ static rtl::OUString SAL_CALL static_getImplementationName();
+
+ static css::uno::Sequence<rtl::OUString> SAL_CALL static_getSupportedServiceNames()
+ {
+ return css::uno::Sequence<rtl::OUString>();
+ }
+
+private:
+ explicit Dispatch(css::uno::Reference<css::uno::XComponentContext> const& context)
+ : context_(context)
+ {
+ assert(context.is());
+ }
+
+ virtual ~Dispatch() {}
+
+ virtual rtl::OUString SAL_CALL getImplementationName() override
+ {
+ return static_getImplementationName();
+ }
+
+ virtual sal_Bool SAL_CALL supportsService(rtl::OUString const& ServiceName) override
+ {
+ return cppu::supportsService(this, ServiceName);
+ }
+
+ virtual css::uno::Sequence<rtl::OUString> SAL_CALL getSupportedServiceNames() override
+ {
+ return static_getSupportedServiceNames();
+ }
+
+ virtual void SAL_CALL dispatch(css::util::URL const&,
+ css::uno::Sequence<css::beans::PropertyValue> const&) override;
+
+ virtual void SAL_CALL addStatusListener(css::uno::Reference<css::frame::XStatusListener> const&,
+ css::util::URL const&) override
+ {
+ }
+
+ virtual void SAL_CALL removeStatusListener(
+ css::uno::Reference<css::frame::XStatusListener> const&, css::util::URL const&) override
+ {
+ }
+
+ css::uno::Reference<css::uno::XComponentContext> context_;
+};
+
+rtl::OUString Dispatch::static_getImplementationName()
+{
+ return rtl::OUString("org.libreoffice.comp.rust_uno.example_singleton");
+}
+
+void Dispatch::dispatch(css::util::URL const&, css::uno::Sequence<css::beans::PropertyValue> const&)
+{
+ // === RUST UNO BINDING TEST ===
+ // Call our Rust UNO binding to test it works within LibreOffice
+ SAL_INFO("desktop.app", "Testing Rust UNO binding...");
+ try
+ {
+ run_rust_uno_test();
+ SAL_INFO("desktop.app", "Rust UNO binding test completed successfully!");
+ }
+ catch (...)
+ {
+ SAL_WARN("desktop.app", "Rust UNO binding test failed!");
+ }
+}
+
+cppu::ImplementationEntry const services[] = {
+ { &Provider::static_create, &Provider::static_getImplementationName,
+ &Provider::static_getSupportedServiceNames, &cppu::createSingleComponentFactory, nullptr, 0 },
+ { &Dispatch::static_create, &Dispatch::static_getImplementationName,
+ &Dispatch::static_getSupportedServiceNames, &cppu::createSingleComponentFactory, nullptr, 0 },
+ { nullptr, nullptr, nullptr, nullptr, nullptr, 0 }
+};
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void*
+component_getFactory(char const* pImplName, void* pServiceManager, void* pRegistryKey)
+{
+ return cppu::component_getFactoryHelper(pImplName, pServiceManager, pRegistryKey, services);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void
+component_getImplementationEnvironment(char const** ppEnvTypeName, uno_Environment**)
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/include/vcl/bitmap/BitmapAlphaClampFilter.hxx b/rust_uno/example/rust_uno_hook.hxx
index 4a036263e0d9..8987ffeb8b4f 100644
--- a/include/vcl/bitmap/BitmapAlphaClampFilter.hxx
+++ b/rust_uno/example/rust_uno_hook.hxx
@@ -5,27 +5,13 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
*/
#pragma once
-#include <vcl/bitmap/BitmapFilter.hxx>
-
-/** If the alpha is beyond a certain threshold, make it fully transparent
- */
-class VCL_DLLPUBLIC BitmapAlphaClampFilter final : public BitmapFilter
-{
-public:
- BitmapAlphaClampFilter(sal_uInt8 cThreshold)
- : mcThreshold(cThreshold)
- {
- }
-
- virtual Bitmap execute(Bitmap const& rBitmap) const override;
-
-private:
- sal_uInt8 mcThreshold;
-};
+extern "C" {
+/// Function from the Rust UNO binding library that we'll call from LibreOffice
+void run_rust_uno_test();
+}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/any.rs b/rust_uno/src/core/any.rs
new file mode 100644
index 000000000000..7e307239720b
--- /dev/null
+++ b/rust_uno/src/core/any.rs
@@ -0,0 +1,257 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO Any Types and Functions
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's uno_Any.
+//! It includes automatic memory management and safe conversions to/from Rust values.
+//!
+//! ## Key Components
+//! - `Any` - Safe Rust wrapper around LibreOffice's uno_Any
+//! - Value conversion functions with automatic type handling
+//! - Memory management with automatic cleanup
+//!
+//! ## Features
+//! - Safe construction from various Rust types
+//! - Automatic memory management via RAII
+//! - Safe value extraction with type checking
+//! - Clone, equality, and display trait implementations
+//! - Direct FFI interop with raw pointer access methods
+
+use crate::ffi::uno_any::*;
+// Interface operations now use generated XInterface wrapper methods
+// TODO: Replace with generated XInterface::from_ptr(ptr).acquire() pattern
+
+// === Safe UNO Any Wrapper ===
+
+/// UNO Any wrapper - a safe Rust wrapper around LibreOffice's uno_Any
+///
+/// Any provides a safe, memory-managed interface to LibreOffice's native
+/// any type. It automatically handles reference counting and memory cleanup.
+pub struct Any {
+ inner: uno_Any,
+}
+
+impl Any {
+ /// Create a new empty UNO Any (void type)
+ ///
+ /// This creates an empty Any that contains no value (void type).
+ pub fn new() -> Self {
+ unsafe {
+ let mut any = Any {
+ inner: uno_Any {
+ pType: std::ptr::null_mut(),
+ pData: std::ptr::null_mut(),
+ pReserved: std::ptr::null_mut(),
+ },
+ };
+
+ // Initialize as void using uno_any_construct
+ uno_any_construct(
+ &mut any.inner,
+ std::ptr::null_mut(), // pSource (null for void)
+ std::ptr::null_mut(), // pTypeDescr (null for void)
+ None,
+ );
+ any
+ }
+ }
+
+ /// Create Any from a boolean value
+ ///
+ /// This creates an Any containing a boolean value.
+ pub fn from_bool(value: bool) -> Self {
+ unsafe {
+ let mut any = Any {
+ inner: uno_Any {
+ pType: std::ptr::null_mut(),
+ pData: std::ptr::null_mut(),
+ pReserved: std::ptr::null_mut(),
+ },
+ };
+
+ let bool_val = if value { 1u8 } else { 0u8 };
+
+ // Initialize with boolean data using uno_type_any_construct
+ uno_type_any_construct(
+ &mut any.inner,
+ &bool_val as *const u8 as *mut std::ffi::c_void,
+ get_boolean_type(),
+ None,
+ );
+ any
+ }
+ }
+
+ /// Create Any from a 32-bit integer
+ ///
+ /// This creates an Any containing a 32-bit signed integer.
+ pub fn from_i32(value: i32) -> Self {
+ unsafe {
+ let mut any = Any {
+ inner: uno_Any {
+ pType: std::ptr::null_mut(),
+ pData: std::ptr::null_mut(),
+ pReserved: std::ptr::null_mut(),
+ },
+ };
+
+ // Initialize with integer data using uno_type_any_construct
+ uno_type_any_construct(
+ &mut any.inner,
+ &value as *const i32 as *mut std::ffi::c_void,
+ get_long_type(),
+ None,
+ );
+
+ any
+ }
+ }
+
+ /// Create Any from raw uno_Any (takes ownership)
+ ///
+ /// # Safety
+ /// The caller must ensure that:
+ /// - The uno_Any is valid and properly initialized
+ /// - The uno_Any is not used elsewhere after this call
+ /// - Proper reference counting is maintained
+ pub unsafe fn from_raw(any: uno_Any) -> Self {
+ Any { inner: any }
+ }
+
+ /// Convert to raw uno_Any (releases ownership)
+ ///
+ /// The caller becomes responsible for calling uno_any_destruct
+ pub fn into_raw(self) -> uno_Any {
+ unsafe {
+ let inner = std::ptr::read(&self.inner);
+ std::mem::forget(self); // Don't run destructor
+ inner
+ }
+ }
+
+ /// Get the raw pointer for FFI calls (retains ownership)
+ pub fn as_ptr(&self) -> *const uno_Any {
+ &self.inner
+ }
+
+ /// Get the mutable raw pointer for FFI calls (retains ownership)
+ pub fn as_mut_ptr(&mut self) -> *mut uno_Any {
+ &mut self.inner
+ }
+
+ /// Check if the Any contains a value (not void)
+ pub fn has_value(&self) -> bool {
+ !self.inner.pType.is_null()
+ }
+
+ /// Clear the Any (set to void)
+ pub fn clear(&mut self) {
+ unsafe {
+ uno_any_clear(&mut self.inner, None);
+ }
+ }
+}
+
+impl Default for Any {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Clone implementation: Create a copy of another Any
+///
+/// This creates a new Any that contains the same value but is independently
+/// managed (proper deep copy with reference counting).
+impl Clone for Any {
+ fn clone(&self) -> Self {
+ let mut new_any = Any::new();
+
+ if self.has_value() {
+ unsafe {
+ // Clone by assigning from the existing any's data using type reference
+ uno_type_any_assign(
+ &mut new_any.inner,
+ self.inner.pData,
+ self.inner.pType,
+ None,
+ None,
+ );
+ }
+ }
+
+ new_any
+ }
+}
+
+/// Comparison with other Any
+impl PartialEq for Any {
+ fn eq(&self, other: &Self) -> bool {
+ // Handle cases where one or both are void
+ match (self.has_value(), other.has_value()) {
+ (false, false) => true, // Both void = equal
+ (false, true) | (true, false) => false, // One void, one not = not equal
+ (true, true) => {
+ // Both have values - basic pointer comparison for now
+ self.inner.pType == other.inner.pType && self.inner.pData == other.inner.pData
+ }
+ }
+ }
+}
+
+impl Eq for Any {}
+
+/// From trait implementation for bool
+impl From<bool> for Any {
+ fn from(value: bool) -> Self {
+ Self::from_bool(value)
+ }
+}
+
+/// From trait implementation for i32
+impl From<i32> for Any {
+ fn from(value: i32) -> Self {
+ Self::from_i32(value)
+ }
+}
+
+/// Display trait for printing
+impl std::fmt::Display for Any {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if !self.has_value() {
+ write!(f, "Any(void)")
+ } else {
+ write!(f, "Any(<value>)")
+ }
+ }
+}
+
+/// Debug trait for debugging
+impl std::fmt::Debug for Any {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Any")
+ .field("has_value", &self.has_value())
+ .field("pType", &self.inner.pType)
+ .field("pData", &self.inner.pData)
+ .finish()
+ }
+}
+
+/// Destructor: Automatic cleanup when Any goes out of scope
+impl Drop for Any {
+ fn drop(&mut self) {
+ if self.has_value() {
+ unsafe {
+ uno_any_destruct(&mut self.inner, None);
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/mod.rs b/rust_uno/src/core/mod.rs
new file mode 100644
index 000000000000..0546fdf51917
--- /dev/null
+++ b/rust_uno/src/core/mod.rs
@@ -0,0 +1,37 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Core Module
+//!
+//! This module contains the high-level safe Rust wrappers for LibreOffice UNO types.
+//! These provide memory-safe, idiomatic Rust interfaces to the underlying C APIs.
+
+pub mod any;
+pub mod oustring;
+pub mod sequence;
+pub mod r#type;
+pub mod uno_wrapper;
+
+// Re-export the main types for convenience
+pub use crate::ffi::type_ffi::typelib_TypeClass;
+pub use any::Any;
+pub use oustring::OUString;
+pub use sequence::Sequence;
+pub use r#type::Type;
+// UnoInterface replaced with generated XInterface from rustmaker
+pub use uno_wrapper::{UnoError, UnoResult, defaultBootstrap_InitialComponentContext};
+
+// Include unit tests
+#[cfg(test)]
+mod tests {
+ mod string_tests;
+ mod type_tests;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/oustring.rs b/rust_uno/src/core/oustring.rs
new file mode 100644
index 000000000000..8be5188168e1
--- /dev/null
+++ b/rust_uno/src/core/oustring.rs
@@ -0,0 +1,256 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO String Types and Functions
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's rtl_uString.
+//! It includes automatic memory management and safe conversions to/from Rust strings.
+//!
+//! ## Key Components
+//! - `OUString` - Safe Rust wrapper around LibreOffice's rtl_uString
+//! - String conversion functions with automatic encoding handling
+//! - Memory management with automatic reference counting
+//!
+//! ## Features
+//! - UTF-8, UTF-16, and ASCII string creation methods
+//! - Automatic memory management via RAII
+//! - Safe conversion to/from Rust strings
+//! - Clone, equality, and display trait implementations
+//! - Direct FFI interop with raw pointer access methods
+
+use std::ptr::NonNull;
+
+use crate::ffi::rtl_string::*;
+use crate::ffi::sal_types::*;
+
+// === Safe UNO String Wrapper ===
+
+/// UNO String wrapper - a safe Rust wrapper around LibreOffice's rtl_uString
+///
+/// OUString provides a safe, memory-managed interface to LibreOffice's native
+/// string type. It automatically handles reference counting and memory cleanup,
+/// and provides conversions to/from standard Rust string types.
+pub struct OUString {
+ inner: NonNull<rtl_uString>,
+}
+
+impl OUString {
+ /// Create a new empty UNO string
+ ///
+ /// This creates an empty OUString with zero length.
+ pub fn new() -> Self {
+ unsafe {
+ let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+ rtl_uString_new(&mut ptr);
+
+ // Convert to NonNull, panic if allocation failed
+ let inner =
+ NonNull::new(ptr).expect("RTL string allocation failed - system out of memory");
+
+ OUString { inner }
+ }
+ }
+
+ /// Create a UNO string from UTF-8 text
+ ///
+ /// This uses LibreOffice's direct UTF-8 to UString conversion function,
+ /// which is more efficient than converting through UTF-16. Handles all
+ /// valid UTF-8 including Unicode characters and emojis.
+ pub fn from_utf8(text: &str) -> Self {
+ unsafe {
+ let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+ rtl_string2UString(
+ &mut ptr,
+ text.as_ptr() as *const std::os::raw::c_char,
+ text.len() as sal_Int32,
+ RTL_TEXTENCODING_UTF8,
+ OSTRING_TO_OUSTRING_CVTFLAGS,
+ );
+
+ let inner = NonNull::new(ptr).expect("RTL UTF-8 string creation failed");
+
+ OUString { inner }
+ }
+ }
+
+ /// Create a UNO string from ASCII text
+ ///
+ /// This method uses LibreOffice's native ASCII conversion function for
+ /// actual ASCII text (7-bit characters only). More efficient than UTF-8
+ /// conversion when you know the text is pure ASCII.
+ pub fn from_ascii(text: &str) -> Self {
+ unsafe {
+ let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+ // Ensure the string is null-terminated for the C function
+ let c_string = std::ffi::CString::new(text).expect("CString creation failed");
+ rtl_uString_newFromAscii(&mut ptr, c_string.as_ptr());
+
+ let inner = NonNull::new(ptr).expect("RTL ASCII string creation failed");
+
+ OUString { inner }
+ }
+ }
+
+ /// Create OUString from UTF-16 data
+ ///
+ /// Creates a UNO string directly from UTF-16 data. This is the most efficient
+ /// method when you already have UTF-16 data, since LibreOffice uses UTF-16
+ /// internally (sal_Unicode is UTF-16 code units).
+ pub fn from_utf16(data: &[sal_Unicode]) -> Self {
+ unsafe {
+ let mut ptr: *mut rtl_uString = std::ptr::null_mut();
+ rtl_uString_newFromStr_WithLength(&mut ptr, data.as_ptr(), data.len() as sal_Int32);
+
+ let inner = NonNull::new(ptr).expect("RTL UTF-16 string creation failed");
+
+ OUString { inner }
+ }
+ }
+
+ /// Create OUString from raw rtl_uString pointer (takes ownership)
+ ///
+ /// # Safety
+ /// The caller must ensure that:
+ /// - The pointer is valid and points to a properly initialized rtl_uString
+ /// - The pointer is not used elsewhere after this call
+ /// - The rtl_uString has the correct reference count
+ pub unsafe fn from_raw(str: *mut rtl_uString) -> Self {
+ let inner = NonNull::new(str).expect("Cannot create OUString from null pointer");
+
+ unsafe {
+ rtl_uString_acquire(inner.as_ptr());
+ }
+ OUString { inner }
+ }
+
+ /// Convert to raw rtl_uString pointer (releases ownership)
+ ///
+ /// The caller becomes responsible for calling rtl_uString_release
+ pub fn into_raw(self) -> *mut rtl_uString {
+ let ptr = self.inner.as_ptr();
+ std::mem::forget(self); // Don't run destructor
+ ptr
+ }
+
+ /// Get the raw pointer for FFI calls (retains ownership)
+ pub fn as_ptr(&self) -> *const rtl_uString {
+ self.inner.as_ptr() as *const _
+ }
+
+ /// Get the mutable raw pointer for FFI calls (retains ownership)
+ pub fn as_mut_ptr(&mut self) -> *mut rtl_uString {
+ self.inner.as_ptr()
+ }
+
+ /// Get the length of the string
+ pub fn len(&self) -> usize {
+ unsafe { rtl_uString_getLength(self.inner.as_ptr()) as usize }
+ }
+
+ /// Check if the string is empty
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+}
+
+impl Default for OUString {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Clone implementation: Create a copy of another OUString
+///
+/// This creates a new OUString that shares the same content but is independently
+/// managed (proper deep copy with reference counting).
+impl Clone for OUString {
+ fn clone(&self) -> Self {
+ unsafe {
+ rtl_uString_acquire(self.inner.as_ptr());
+ OUString { inner: self.inner }
+ }
+ }
+}
+
+/// From trait implementation for &str (UTF-8)
+///
+/// Convenient conversion from string slices to OUString using UTF-8 encoding.
+impl<T: AsRef<str>> From<T> for OUString {
+ fn from(text: T) -> Self {
+ Self::from_utf8(text.as_ref())
+ }
+}
+
+/// Comparison with other OUString
+impl PartialEq for OUString {
+ fn eq(&self, other: &Self) -> bool {
+ unsafe {
+ // Compare lengths first (fast check)
+ let self_len = rtl_uString_getLength(self.inner.as_ptr());
+ let other_len = rtl_uString_getLength(other.inner.as_ptr());
+
+ if self_len != other_len {
+ return false;
+ }
+
+ // If lengths are equal, compare UTF-16 data directly
+ if self_len == 0 {
+ return true; // Both empty strings
+ }
+
+ let self_ptr = rtl_uString_getStr(self.inner.as_ptr());
+ let other_ptr = rtl_uString_getStr(other.inner.as_ptr());
+
+ // Compare UTF-16 data byte by byte
+ let self_slice = std::slice::from_raw_parts(self_ptr, self_len as usize);
+ let other_slice = std::slice::from_raw_parts(other_ptr, other_len as usize);
+
+ self_slice == other_slice
+ }
+ }
+}
+
+impl Eq for OUString {}
+
+/// Display trait for printing
+impl std::fmt::Display for OUString {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if self.is_empty() {
+ return Ok(());
+ }
+
+ unsafe {
+ let ptr = rtl_uString_getStr(self.inner.as_ptr());
+ let len = rtl_uString_getLength(self.inner.as_ptr()) as usize;
+
+ // Convert from UTF-16 to UTF-8
+ let utf16_slice = std::slice::from_raw_parts(ptr, len);
+ let string = String::from_utf16_lossy(utf16_slice);
+ write!(f, "{string}")
+ }
+ }
+}
+
+/// Debug trait for debugging - shows type and content for UNO string identification
+impl std::fmt::Debug for OUString {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_tuple("OUString").field(&self.to_string()).finish()
+ }
+}
+
+/// Destructor: Automatic cleanup when OUString goes out of scope
+impl Drop for OUString {
+ fn drop(&mut self) {
+ unsafe {
+ rtl_uString_release(self.inner.as_ptr());
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/sequence.rs b/rust_uno/src/core/sequence.rs
new file mode 100644
index 000000000000..f9d8a237b0a2
--- /dev/null
+++ b/rust_uno/src/core/sequence.rs
@@ -0,0 +1,245 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO Sequence Types and Functions
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's uno_Sequence.
+//! It includes automatic memory management and safe conversions to/from Rust values.
+//!
+//! ## Key Components
+//! - `Sequence` - Safe Rust wrapper around LibreOffice's uno_Sequence
+//! - Value conversion functions with automatic type handling
+//! - Memory management with automatic cleanup
+//!
+//! ## Features
+//! - Safe construction from various Rust types
+//! - Automatic memory management via RAII
+//! - Safe value extraction with type checking
+//! - Clone, equality, and display trait implementations
+//! - Direct FFI interop with raw pointer access methods
+
+use crate::core::r#type::*;
+use crate::ffi::type_ffi::*;
+// Interface operations now use generated XInterface wrapper methods
+// TODO: Replace with generated XInterface::from_ptr(ptr).acquire() pattern
+use crate::ffi::uno_sequence::*;
+use std::ptr::NonNull;
+
+// === Safe UNO Sequence Wrapper ===
+
+/// UNO Sequence wrapper - a safe Rust wrapper around LibreOffice's uno_Sequence
+///
+/// Sequence provides a safe, memory-managed interface to LibreOffice's native
+/// Sequence type. It automatically handles reference counting and memory cleanup.
+pub struct Sequence {
+ inner: NonNull<uno_Sequence>,
+}
+
+impl Sequence {
+ /// Create a new empty Sequence
+ ///
+ /// Creates an empty sequence of Any elements, similar to the C++ default constructor.
+ /// The sequence will be empty (0 elements) and uses the Any type as the element type.
+ pub fn new() -> Self {
+ Self::with_capacity(0)
+ }
+
+ pub fn with_capacity(capacity: i32) -> Self {
+ if capacity < 0 {
+ panic!("Sequence capacity cannot be negative: {}", capacity);
+ }
+ unsafe {
+ let mut ptr: *mut uno_Sequence = std::ptr::null_mut();
+
+ // Create an Any type for the sequence elements
+ let element_type = Type::new();
+
+ // Get the type description from the type reference
+ let mut type_desc = std::ptr::null_mut();
+ typelib_typedescriptionreference_getDescription(
+ &mut type_desc,
+ element_type.get_typelib_type(),
+ );
+
+ // Construct empty sequence
+ let success = uno_type_sequence_construct(
+ &mut ptr,
+ type_desc,
+ std::ptr::null(),
+ capacity,
+ None, // TODO: Replace with generated XInterface acquire wrapper
+ );
+
+ // Check for construction success
+ if success == 0 {
+ panic!("Failed to construct UNO sequence");
+ }
+
+ Sequence {
+ inner: NonNull::new(ptr)
+ .expect("uno_type_sequence_construct returned null pointer"),
+ }
+ }
+ }
+
+ /// Get the length of the sequence
+ ///
+ /// Returns the number of elements in this sequence.
+ /// Equivalent to C++ `getLength()` method.
+ pub fn get_length(&self) -> i32 {
+ unsafe { self.inner.as_ref().nElements }
+ }
+
+ /// Check if the sequence has elements
+ ///
+ /// Returns true if the sequence contains at least one element.
+ /// Equivalent to C++ `hasElements()` method.
+ pub fn has_elements(&self) -> bool {
+ self.get_length() > 0
+ }
+
+ /// Get the length as usize for Rust iterator compatibility
+ ///
+ /// Returns the length as usize, which is commonly used in Rust.
+ pub fn len(&self) -> usize {
+ self.get_length() as usize
+ }
+
+ /// Check if the sequence is empty
+ ///
+ /// Returns true if the sequence has no elements.
+ pub fn is_empty(&self) -> bool {
+ self.get_length() == 0
+ }
+
+ /// Get raw pointer to the underlying uno_Sequence
+ ///
+ /// This provides direct access to the underlying UNO sequence for FFI interop.
+ /// The returned pointer remains valid as long as this Sequence instance exists.
+ pub fn as_raw(&self) -> *mut uno_Sequence {
+ self.inner.as_ptr()
+ }
+
+ /// Get the raw pointer for FFI calls (retains ownership)
+ pub fn as_ptr(&self) -> *const uno_Sequence {
+ self.inner.as_ptr() as *const _
+ }
+
+ /// Get the mutable raw pointer for FFI calls (retains ownership)
+ pub fn as_mut_ptr(&mut self) -> *mut uno_Sequence {
+ self.inner.as_ptr()
+ }
+}
+
+impl Default for Sequence {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Clone implementation: Create an independent copy of another Sequence
+///
+/// This creates a new Sequence that references the same sequence data but is
+/// independently managed. The clone operation increments the reference count
+/// of the underlying sequence, ensuring proper memory management.
+impl Clone for Sequence {
+ fn clone(&self) -> Self {
+ unsafe {
+ let ptr = self.inner.as_ptr();
+ // Increment reference count
+ (*ptr).nRefCount += 1;
+
+ Sequence {
+ inner: NonNull::new(ptr).expect("Cloning sequence with invalid pointer"),
+ }
+ }
+ }
+}
+
+/// Equality comparison with other Sequence instances
+///
+/// Two Sequence instances are considered equal if they have the same length
+/// and contain the same elements in the same order. This uses pointer comparison
+/// for efficiency when both sequences reference the same underlying data.
+impl PartialEq for Sequence {
+ fn eq(&self, other: &Self) -> bool {
+ unsafe {
+ let self_ptr = self.inner.as_ptr();
+ let other_ptr = other.inner.as_ptr();
+
+ // Fast path: same pointer
+ if self_ptr == other_ptr {
+ return true;
+ }
+
+ let self_seq = self.inner.as_ref();
+ let other_seq = other.inner.as_ref();
+
+ // Different lengths means not equal
+ if self_seq.nElements != other_seq.nElements {
+ return false;
+ }
+
+ // For now, do basic comparison - in a full implementation,
+ // this would need to compare actual element values
+ self_seq.nElements == other_seq.nElements
+ }
+ }
+}
+
+impl Eq for Sequence {}
+
+/// Debug trait for debugging - shows sequence length and type for UNO sequence identification
+impl std::fmt::Debug for Sequence {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_tuple("Sequence")
+ .field(&format!("length={}", self.get_length()))
+ .finish()
+ }
+}
+
+/// Display trait for printing sequences
+///
+/// Provides a user-friendly string representation of the sequence.
+impl std::fmt::Display for Sequence {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if self.is_empty() {
+ write!(f, "Sequence[]")
+ } else {
+ write!(f, "Sequence[{}]", self.get_length())
+ }
+ }
+}
+
+/// Destructor: Automatic cleanup when Sequence goes out of scope
+impl Drop for Sequence {
+ fn drop(&mut self) {
+ unsafe {
+ let ptr = self.inner.as_ptr();
+ let seq = &mut *ptr;
+ seq.nRefCount -= 1;
+
+ // If reference count reaches zero, destroy the sequence
+ if seq.nRefCount == 0 {
+ // Get the element type for proper cleanup
+ let element_type = Type::new();
+ let mut type_desc = std::ptr::null_mut();
+ typelib_typedescriptionreference_getDescription(
+ &mut type_desc,
+ element_type.get_typelib_type(),
+ );
+
+ // Call UNO sequence destructor
+ uno_type_sequence_destroy(ptr, type_desc, None); // TODO: Replace with generated XInterface release wrapper
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/tests/string_tests.rs b/rust_uno/src/core/tests/string_tests.rs
new file mode 100644
index 000000000000..b931dfa6a2ba
--- /dev/null
+++ b/rust_uno/src/core/tests/string_tests.rs
@@ -0,0 +1,387 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Unit tests for OUString (Rust-side functionality)
+//!
+//! These tests verify OUString's Rust implementation including:
+//! - Creation methods (new, from_utf8, from_ascii, from_utf16)
+//! - Trait implementations (Clone, PartialEq, From, Display, Debug, Default)
+//! - Instance methods (len, is_empty, as_ptr, etc.)
+//! - Memory management and safety (RAII, reference counting)
+//! - FFI interop (from_raw, into_raw)
+//!
+//! These tests do NOT require LibreOffice UNO components and test
+//! only the Rust-side implementation and FFI safety.
+
+use crate::core::OUString;
+
+// === Creation Method Tests ===
+
+#[test]
+fn test_oustring_new() {
+ let s = OUString::new();
+ assert_eq!(s.len(), 0);
+ assert!(s.is_empty());
+ assert_eq!(s.to_string(), "");
+}
+
+#[test]
+fn test_oustring_default() {
+ let s = OUString::default();
+ assert_eq!(s.len(), 0);
+ assert!(s.is_empty());
+ assert_eq!(s.to_string(), "");
+}
+
+#[test]
+fn test_oustring_from_utf8() {
+ let s = OUString::from_utf8("Hello, 世界!");
+ assert!(!s.is_empty());
+ assert_eq!(s.to_string(), "Hello, 世界!");
+
+ // Test empty string
+ let empty = OUString::from_utf8("");
+ assert!(empty.is_empty());
+ assert_eq!(empty.len(), 0);
+
+ // Test with Unicode characters
+ let unicode = OUString::from_utf8("Ñiño 🦀 café");
+ assert_eq!(unicode.to_string(), "Ñiño 🦀 café");
+}
+
+#[test]
+fn test_oustring_from_ascii() {
+ let s = OUString::from_ascii("Hello, World!");
+ assert_eq!(s.to_string(), "Hello, World!");
+ assert!(!s.is_empty());
+
+ // Test empty ASCII string
+ let empty = OUString::from_ascii("");
+ assert!(empty.is_empty());
+ assert_eq!(empty.len(), 0);
+}
+
+// === Trait Implementation Tests ===
+
+#[test]
+fn test_oustring_clone() {
+ let original = OUString::from_utf8("Test string for cloning");
+ let cloned = original.clone();
+
+ // They should be equal
+ assert_eq!(original, cloned);
+ assert_eq!(original.to_string(), cloned.to_string());
+ assert_eq!(original.len(), cloned.len());
+
+ // Test cloning empty string
+ let empty = OUString::new();
+ let empty_clone = empty.clone();
+ assert_eq!(empty, empty_clone);
+ assert!(empty_clone.is_empty());
+}
+
+#[test]
+fn test_oustring_partial_eq() {
+ let s1 = OUString::from_utf8("Hello");
+ let s2 = OUString::from_utf8("Hello");
+ let s3 = OUString::from_utf8("World");
+ let empty1 = OUString::new();
+ let empty2 = OUString::new();
+
+ // Equal strings
+ assert_eq!(s1, s2);
+ assert_eq!(empty1, empty2);
+
+ // Different strings
+ assert_ne!(s1, s3);
+ assert_ne!(s1, empty1);
+ assert_ne!(empty1, s1);
+
+ // Test with Unicode
+ let unicode1 = OUString::from_utf8("café");
+ let unicode2 = OUString::from_utf8("café");
+ let unicode3 = OUString::from_utf8("cafe"); // without accent
+
+ assert_eq!(unicode1, unicode2);
+ assert_ne!(unicode1, unicode3);
+}
+
+#[test]
+fn test_oustring_from_str() {
+ let s = OUString::from("Hello from &str");
+ assert_eq!(s.to_string(), "Hello from &str");
+
+ // Test with Unicode
+ let unicode: OUString = "Héllo wørld 🌍".into();
+ assert_eq!(unicode.to_string(), "Héllo wørld 🌍");
+}
+
+#[test]
+fn test_oustring_from_string() {
+ let rust_string = String::from("Hello from String");
+ let s = OUString::from(rust_string);
+ assert_eq!(s.to_string(), "Hello from String");
+
+ // Test with owned Unicode String
+ let unicode_string = "Ñiño 🦀".to_string();
+ let unicode_oustring = OUString::from(unicode_string);
+ assert_eq!(unicode_oustring.to_string(), "Ñiño 🦀");
+}
+
+#[test]
+fn test_oustring_display() {
+ let s = OUString::from_utf8("Display test");
+ assert_eq!(format!("{s}"), "Display test");
+
+ // Test empty string display
+ let empty = OUString::new();
+ assert_eq!(format!("{empty}"), "");
+
+ // Test Unicode display
+ let unicode = OUString::from_utf8("Display 测试 🦀");
+ assert_eq!(format!("{unicode}"), "Display 测试 🦀");
+}
+
+#[test]
+fn test_oustring_debug() {
+ let s = OUString::from_utf8("Debug test");
+ let debug_output = format!("{s:?}");
+ assert!(debug_output.contains("OUString"));
+ assert!(debug_output.contains("Debug test"));
+
+ // Test empty string debug
+ let empty = OUString::new();
+ let empty_debug = format!("{empty:?}");
+ assert!(empty_debug.contains("OUString"));
+}
+
+// === Method Tests ===
+
+#[test]
+fn test_oustring_len() {
+ let empty = OUString::new();
+ assert_eq!(empty.len(), 0);
+
+ let ascii = OUString::from_utf8("Hello");
+ assert_eq!(ascii.len(), 5);
+
+ // Note: len() returns UTF-16 code units, not Unicode codepoints
+ let unicode = OUString::from_utf8("café"); // 'é' is one UTF-16 unit
+ assert_eq!(unicode.len(), 4);
+
+ // Emoji takes 2 UTF-16 code units (surrogate pair)
+ let emoji = OUString::from_utf8("🦀");
+ assert_eq!(emoji.len(), 2);
+}
+
+#[test]
+fn test_oustring_is_empty() {
+ let empty = OUString::new();
+ assert!(empty.is_empty());
+
+ let non_empty = OUString::from_utf8("Not empty");
+ assert!(!non_empty.is_empty());
+
+ let empty_from_str = OUString::from_utf8("");
+ assert!(empty_from_str.is_empty());
+}
+
+// === Special Cases and Edge Cases ===
+
+#[test]
+fn test_oustring_special_characters() {
+ // Test various special Unicode characters
+ let special_chars = vec![
+ "\0", // Null character
+ "\n", // Newline
+ "\r\n", // Windows line ending
+ "\t", // Tab
+ "\"", // Quote
+ "\\", // Backslash
+ "©", // Copyright symbol
+ "€", // Euro symbol
+ "™", // Trademark
+ "🦀", // Rust crab emoji
+ "👨‍💻", // Man technologist (complex emoji)
+ ];
+
+ for special in special_chars {
+ let s = OUString::from_utf8(special);
+ assert_eq!(s.to_string(), special);
+ }
+}
+
+#[test]
+fn test_oustring_long_strings() {
+ // Test with long strings to ensure proper memory management
+ let long_text = "A".repeat(10000);
+ let s = OUString::from_utf8(&long_text);
+ assert_eq!(s.len(), 10000);
+ assert_eq!(s.to_string(), long_text);
+
+ // Test cloning long strings
+ let cloned = s.clone();
+ assert_eq!(cloned, s);
+ assert_eq!(cloned.len(), 10000);
+}
+
+#[test]
+fn test_oustring_multilingual() {
+ // Test various languages and scripts
+ let multilingual = "English, 中文, العربية, Русский, ελληνικά, עברית";
+ let s = OUString::from_utf8(multilingual);
+ assert_eq!(s.to_string(), multilingual);
+ assert!(!s.is_empty());
+}
+
+#[test]
+fn test_oustring_consistency_across_constructors() {
+ let text = "Test consistency";
+
+ let from_utf8 = OUString::from_utf8(text);
+ let from_str: OUString = text.into();
+ let from_string = OUString::from(text.to_string());
+
+ // All should produce equivalent strings
+ assert_eq!(from_utf8, from_str);
+ assert_eq!(from_utf8, from_string);
+ assert_eq!(from_str, from_string);
+
+ // All should have same content
+ assert_eq!(from_utf8.to_string(), text);
+ assert_eq!(from_str.to_string(), text);
+ assert_eq!(from_string.to_string(), text);
+}
+
+#[test]
+fn test_oustring_memory_safety() {
+ // Test that dropping strings doesn't cause issues
+ {
+ let s1 = OUString::from_utf8("Temporary string 1");
+ let s2 = s1.clone();
+ let s3 = OUString::from_utf8("Temporary string 2");
+
+ assert_eq!(s1, s2);
+ assert_ne!(s1, s3);
+
+ // Strings will be dropped here - this should not cause issues
+ }
+
+ // Create new strings after the previous ones were dropped
+ let s4 = OUString::from_utf8("After drop test");
+ assert_eq!(s4.to_string(), "After drop test");
+}
+
+#[test]
+fn test_oustring_memory_release() {
+ // Simple memory release test - create and drop many strings
+ // If memory isn't released properly, this would cause memory leaks
+
+ // Create many strings in a loop and let them drop
+ for i in 0..1000 {
+ let s = OUString::from_utf8(&format!("Test string number {i}"));
+ assert_eq!(s.to_string(), format!("Test string number {i}"));
+ // String automatically drops here
+ }
+
+ // Create and explicitly drop strings
+ for _ in 0..1000 {
+ let s1 = OUString::from_utf8("Temporary string");
+ let s2 = s1.clone(); // This should increase ref count
+ let s3 = s2.clone(); // This should increase ref count more
+
+ // All should be equal
+ assert_eq!(s1, s2);
+ assert_eq!(s2, s3);
+
+ // All will be dropped here - ref counts should decrease properly
+ }
+
+ // If we reach here without crashes or memory issues, memory management is working
+}
+
+#[test]
+fn test_oustring_reference_counting_behavior() {
+ // Test that cloning works properly with reference counting
+ let original = OUString::from_utf8("Reference counted string");
+
+ // Create multiple references
+ let clone1 = original.clone();
+ let clone2 = original.clone();
+ let clone3 = clone1.clone();
+
+ // All should be equal
+ assert_eq!(original, clone1);
+ assert_eq!(original, clone2);
+ assert_eq!(original, clone3);
+ assert_eq!(clone1, clone2);
+ assert_eq!(clone1, clone3);
+ assert_eq!(clone2, clone3);
+
+ // All have same content
+ assert_eq!(original.to_string(), "Reference counted string");
+ assert_eq!(clone1.to_string(), "Reference counted string");
+ assert_eq!(clone2.to_string(), "Reference counted string");
+ assert_eq!(clone3.to_string(), "Reference counted string");
+
+ // When this function ends, all clones should be properly released
+}
+
+#[test]
+fn test_oustring_memory_from_raw_into_raw() {
+ // Test raw pointer ownership transfer (unique functionality)
+ for i in 0..100 {
+ let original = OUString::from_utf8(&format!("Raw pointer test {i}"));
+ let original_content = original.to_string();
+
+ // Transfer ownership to raw pointer
+ let raw_ptr = original.into_raw();
+
+ // Create new OUString from raw pointer (takes ownership back)
+ let restored = unsafe { OUString::from_raw(raw_ptr) };
+
+ assert_eq!(restored.to_string(), original_content);
+ }
+}
+
+#[test]
+fn test_oustring_memory_mixed_operations() {
+ // Test complex combinations of operations (not covered by existing tests)
+ for i in 0..50 {
+ // Create initial string
+ let s1 = OUString::from_utf8(&format!("Mixed test {i}"));
+
+ // Convert through different types
+ let s2 = OUString::from(s1.to_string());
+ let s3: OUString = s1.to_string().as_str().into();
+
+ // Clone operations
+ let c1 = s1.clone();
+ let c2 = s2.clone();
+ let c3 = s3.clone();
+
+ // Verify equality
+ assert_eq!(s1, s2);
+ assert_eq!(s2, s3);
+ assert_eq!(c1, c2);
+ assert_eq!(c2, c3);
+
+ // Raw pointer operations
+ let raw1 = c1.into_raw();
+ let raw2 = c2.into_raw();
+
+ let restored1 = unsafe { OUString::from_raw(raw1) };
+ let restored2 = unsafe { OUString::from_raw(raw2) };
+
+ assert_eq!(restored1, restored2);
+ assert_eq!(restored1.to_string(), format!("Mixed test {i}"));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/tests/type_tests.rs b/rust_uno/src/core/tests/type_tests.rs
new file mode 100644
index 000000000000..3248ac372175
--- /dev/null
+++ b/rust_uno/src/core/tests/type_tests.rs
@@ -0,0 +1,520 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Unit tests for Type (Rust-side functionality)
+//!
+//! These tests verify Type's Rust implementation including:
+//! - Creation methods (new, new_with_name, from_typelib_ref, from_typelib_ref_no_acquire)
+//! - Trait implementations (Clone, PartialEq, From, Default)
+//! - Instance methods (get_type_class, get_type_name, equals, is_assignable_from)
+//! - Memory management and safety (RAII, reference counting)
+//! - FFI interop (get_typelib_type)
+//! - Ergonomic API (generic string parameters)
+//!
+//! These tests do NOT require LibreOffice UNO components and test
+//! only the Rust-side implementation and FFI safety.
+
+use crate::core::{OUString, Type, typelib_TypeClass};
+
+// === Creation Method Tests ===
+
+#[test]
+fn test_type_new() {
+ let void_type = Type::new();
+ assert_eq!(
+ void_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_VOID
+ );
+ assert_eq!(void_type.get_type_name().to_string(), "void");
+}
+
+#[test]
+fn test_type_default() {
+ let default_type = Type::default();
+ assert_eq!(
+ default_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_VOID
+ );
+ assert_eq!(default_type.get_type_name().to_string(), "void");
+
+ // Test that default equals new()
+ let new_type = Type::new();
+ assert!(default_type.equals(&new_type));
+}
+
+#[test]
+fn test_type_new_with_name_str() {
+ let void_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_VOID, "void");
+ assert_eq!(
+ void_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_VOID
+ );
+ assert_eq!(void_type.get_type_name().to_string(), "void");
+
+ let int_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ assert_eq!(
+ int_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_LONG
+ );
+ assert_eq!(int_type.get_type_name().to_string(), "sal_Int32");
+
+ let interface_type = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ );
+ assert_eq!(
+ interface_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(
+ interface_type.get_type_name().to_string(),
+ "com.sun.star.lang.XComponent"
+ );
+}
+
+#[test]
+fn test_type_new_with_name_string() {
+ let type_name = "com.sun.star.text.XText".to_string();
+ let text_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_INTERFACE, type_name);
+ assert_eq!(
+ text_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(
+ text_type.get_type_name().to_string(),
+ "com.sun.star.text.XText"
+ );
+}
+
+#[test]
+fn test_type_new_with_name_oustring() {
+ let oustring_name = OUString::from("com.sun.star.beans.XPropertySet");
+ let prop_type = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ oustring_name,
+ );
+ assert_eq!(
+ prop_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(
+ prop_type.get_type_name().to_string(),
+ "com.sun.star.beans.XPropertySet"
+ );
+}
+
+// === From Trait Tests ===
+
+#[test]
+fn test_type_from_typelib_typeclass() {
+ let string_type = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ assert_eq!(
+ string_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_STRING
+ );
+
+ let boolean_type = Type::from(typelib_TypeClass::typelib_TypeClass_BOOLEAN);
+ assert_eq!(
+ boolean_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_BOOLEAN
+ );
+
+ let double_type = Type::from(typelib_TypeClass::typelib_TypeClass_DOUBLE);
+ assert_eq!(
+ double_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_DOUBLE
+ );
+}
+
+#[test]
+fn test_type_from_tuple_with_str() {
+ let primitive_types = vec![
+ ("void", typelib_TypeClass::typelib_TypeClass_VOID),
+ ("boolean", typelib_TypeClass::typelib_TypeClass_BOOLEAN),
+ ("byte", typelib_TypeClass::typelib_TypeClass_BYTE),
+ ("short", typelib_TypeClass::typelib_TypeClass_SHORT),
+ (
+ "unsigned short",
+ typelib_TypeClass::typelib_TypeClass_UNSIGNED_SHORT,
+ ),
+ ("long", typelib_TypeClass::typelib_TypeClass_LONG),
+ (
+ "unsigned long",
+ typelib_TypeClass::typelib_TypeClass_UNSIGNED_LONG,
+ ),
+ ("hyper", typelib_TypeClass::typelib_TypeClass_HYPER),
+ (
+ "unsigned hyper",
+ typelib_TypeClass::typelib_TypeClass_UNSIGNED_HYPER,
+ ),
+ ("float", typelib_TypeClass::typelib_TypeClass_FLOAT),
+ ("double", typelib_TypeClass::typelib_TypeClass_DOUBLE),
+ ("char", typelib_TypeClass::typelib_TypeClass_CHAR),
+ ("string", typelib_TypeClass::typelib_TypeClass_STRING),
+ ("type", typelib_TypeClass::typelib_TypeClass_TYPE),
+ ("any", typelib_TypeClass::typelib_TypeClass_ANY),
+ ];
+
+ for (type_name, expected_class) in primitive_types {
+ let type_obj = Type::from((expected_class, type_name));
+ assert_eq!(
+ type_obj.get_type_class(),
+ expected_class,
+ "Failed for type: {}",
+ type_name
+ );
+ assert_eq!(type_obj.get_type_name().to_string(), type_name);
+ }
+}
+
+#[test]
+fn test_type_from_tuple_with_string() {
+ let type_name = "com.sun.star.awt.XControl".to_string();
+ let control_type = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, type_name));
+ assert_eq!(
+ control_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(
+ control_type.get_type_name().to_string(),
+ "com.sun.star.awt.XControl"
+ );
+}
+
+#[test]
+fn test_type_from_tuple_with_oustring() {
+ let type_name = OUString::from("com.sun.star.beans.XPropertySet");
+ let prop_type = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, type_name));
+ assert_eq!(
+ prop_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(
+ prop_type.get_type_name().to_string(),
+ "com.sun.star.beans.XPropertySet"
+ );
+}
+
+// === Trait Implementation Tests ===
+
+#[test]
+fn test_type_clone() {
+ let original = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ );
+ let cloned = original.clone();
+
+ // They should be equal
+ assert!(original.equals(&cloned));
+ assert_eq!(original.get_type_class(), cloned.get_type_class());
+ assert_eq!(
+ original.get_type_name().to_string(),
+ cloned.get_type_name().to_string()
+ );
+
+ // Test cloning void type
+ let void_original = Type::new();
+ let void_clone = void_original.clone();
+ assert!(void_original.equals(&void_clone));
+}
+
+#[test]
+fn test_type_partial_eq() {
+ let type1 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ let type2 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ let type3 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_SHORT, "sal_Int16");
+ let void1 = Type::new();
+ let void2 = Type::new();
+
+ // Equal types
+ assert_eq!(type1, type2);
+ assert_eq!(void1, void2);
+
+ // Different types
+ assert_ne!(type1, type3);
+ assert_ne!(type1, void1);
+
+ // Test with interface types
+ let interface1 = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ ));
+ let interface2 = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ ));
+ let interface3 = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.uno.XInterface",
+ ));
+
+ assert_eq!(interface1, interface2);
+ assert_ne!(interface1, interface3);
+}
+
+// === Method Tests ===
+
+#[test]
+fn test_type_get_type_class() {
+ let void_type = Type::new();
+ assert_eq!(
+ void_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_VOID
+ );
+
+ let string_type = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ assert_eq!(
+ string_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_STRING
+ );
+
+ let interface_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ ));
+ assert_eq!(
+ interface_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+}
+
+#[test]
+fn test_type_get_type_name() {
+ let void_type = Type::new();
+ assert_eq!(void_type.get_type_name().to_string(), "void");
+
+ let int_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ assert_eq!(int_type.get_type_name().to_string(), "sal_Int32");
+
+ let interface_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.text.XTextDocument",
+ ));
+ assert_eq!(
+ interface_type.get_type_name().to_string(),
+ "com.sun.star.text.XTextDocument"
+ );
+}
+
+#[test]
+fn test_type_equals() {
+ let type1 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ let type2 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ let type3 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_SHORT, "sal_Int16");
+
+ // Test equality
+ assert!(type1.equals(&type2));
+ assert!(type2.equals(&type1)); // Symmetry
+
+ // Test inequality
+ assert!(!type1.equals(&type3));
+ assert!(!type3.equals(&type1)); // Symmetry
+
+ // Test self-equality
+ assert!(type1.equals(&type1));
+}
+
+#[test]
+fn test_type_is_assignable_from() {
+ // Create different types for testing assignment compatibility
+ let long_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ let short_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_SHORT, "sal_Int16");
+ let byte_type = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_BYTE, "sal_Int8");
+
+ // Test self-assignment (should always be true)
+ assert!(long_type.is_assignable_from(&long_type));
+ assert!(short_type.is_assignable_from(&short_type));
+ assert!(byte_type.is_assignable_from(&byte_type));
+
+ // These tests depend on UNO's specific assignment rules
+ // Note: The actual behavior depends on LibreOffice's typelib implementation
+ // We're just testing that the method calls work correctly
+ let _long_from_short = long_type.is_assignable_from(&short_type);
+ let _long_from_byte = long_type.is_assignable_from(&byte_type);
+ let _short_from_byte = short_type.is_assignable_from(&byte_type);
+}
+
+#[test]
+fn test_type_get_typelib_type() {
+ let type_obj = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_STRING, "string");
+ let raw_ptr = type_obj.get_typelib_type();
+
+ // Should return a non-null pointer
+ assert!(!raw_ptr.is_null());
+
+ // Test with void type
+ let void_type = Type::new();
+ let void_ptr = void_type.get_typelib_type();
+ assert!(!void_ptr.is_null());
+}
+
+// === Special Cases and Edge Cases ===
+
+#[test]
+fn test_type_primitive_type_classes() {
+ // Test creating types for primitive type classes that have static type references
+ let primitive_type_classes = vec![
+ typelib_TypeClass::typelib_TypeClass_VOID,
+ typelib_TypeClass::typelib_TypeClass_CHAR,
+ typelib_TypeClass::typelib_TypeClass_BOOLEAN,
+ typelib_TypeClass::typelib_TypeClass_BYTE,
+ typelib_TypeClass::typelib_TypeClass_SHORT,
+ typelib_TypeClass::typelib_TypeClass_UNSIGNED_SHORT,
+ typelib_TypeClass::typelib_TypeClass_LONG,
+ typelib_TypeClass::typelib_TypeClass_UNSIGNED_LONG,
+ typelib_TypeClass::typelib_TypeClass_HYPER,
+ typelib_TypeClass::typelib_TypeClass_UNSIGNED_HYPER,
+ typelib_TypeClass::typelib_TypeClass_FLOAT,
+ typelib_TypeClass::typelib_TypeClass_DOUBLE,
+ typelib_TypeClass::typelib_TypeClass_STRING,
+ typelib_TypeClass::typelib_TypeClass_TYPE,
+ typelib_TypeClass::typelib_TypeClass_ANY,
+ ];
+
+ for type_class in primitive_type_classes {
+ let type_obj = Type::from(type_class);
+ assert_eq!(type_obj.get_type_class(), type_class);
+ }
+}
+
+#[test]
+fn test_type_complex_interface_names() {
+ let complex_names = vec![
+ "com.sun.star.lang.XComponent",
+ "com.sun.star.uno.XInterface",
+ "com.sun.star.text.XTextDocument",
+ "com.sun.star.beans.XPropertySet",
+ "com.sun.star.awt.XControl",
+ "com.sun.star.frame.XController",
+ ];
+
+ for name in complex_names {
+ let type_obj = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, name));
+ assert_eq!(
+ type_obj.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(type_obj.get_type_name().to_string(), name);
+ }
+}
+
+#[test]
+fn test_type_consistency_across_creation_methods() {
+ // Test that different creation methods produce equivalent results for same type
+
+ // String type via different methods
+ let string_from_class = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ let string_from_tuple = Type::from((typelib_TypeClass::typelib_TypeClass_STRING, "string"));
+ let string_from_new_with_name =
+ Type::new_with_name(typelib_TypeClass::typelib_TypeClass_STRING, "string");
+
+ assert!(string_from_class.equals(&string_from_tuple));
+ assert!(string_from_tuple.equals(&string_from_new_with_name));
+ assert!(string_from_class.equals(&string_from_new_with_name));
+
+ // Interface type via different methods
+ let interface_name = "com.sun.star.lang.XComponent";
+ let interface_from_tuple = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ interface_name,
+ ));
+ let interface_from_new_with_name = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ interface_name,
+ );
+
+ assert!(interface_from_tuple.equals(&interface_from_new_with_name));
+}
+
+// === Memory Management Tests ===
+
+#[test]
+fn test_type_memory_safety() {
+ // Test that Types can be created and dropped without issues
+
+ {
+ let _type1 = Type::new();
+ let _type2 = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ let _type3 = Type::new_with_name(typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32");
+ } // Types should be properly cleaned up here
+
+ // Create more types after the previous ones were dropped
+ let type4 = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ ));
+ let type5 = type4.clone();
+
+ assert!(type4.equals(&type5));
+}
+
+#[test]
+fn test_type_multiple_references() {
+ // Test that multiple references to the same logical type work correctly
+ let name = "com.sun.star.text.XTextDocument";
+
+ let type1 = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, name));
+ let type2 = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, name));
+ let type3 = type1.clone();
+
+ // All should be equal
+ assert!(type1.equals(&type2));
+ assert!(type2.equals(&type3));
+ assert!(type1.equals(&type3));
+
+ // All should have same properties
+ assert_eq!(type1.get_type_class(), type2.get_type_class());
+ assert_eq!(type2.get_type_class(), type3.get_type_class());
+
+ assert_eq!(
+ type1.get_type_name().to_string(),
+ type2.get_type_name().to_string()
+ );
+ assert_eq!(
+ type2.get_type_name().to_string(),
+ type3.get_type_name().to_string()
+ );
+}
+
+#[test]
+fn test_type_mixed_operations() {
+ // Test mixing different operations
+ let original = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ );
+
+ // Clone and compare
+ let cloned = original.clone();
+ assert!(original.equals(&cloned));
+
+ // Create equivalent via From trait
+ let from_tuple = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ ));
+ assert!(original.equals(&from_tuple));
+
+ // Test assignment compatibility with itself
+ assert!(original.is_assignable_from(&original));
+ assert!(cloned.is_assignable_from(&from_tuple));
+
+ // Check type information
+ assert_eq!(
+ original.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_INTERFACE
+ );
+ assert_eq!(
+ original.get_type_name().to_string(),
+ "com.sun.star.lang.XComponent"
+ );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/type.rs b/rust_uno/src/core/type.rs
new file mode 100644
index 000000000000..21363952ddcf
--- /dev/null
+++ b/rust_uno/src/core/type.rs
@@ -0,0 +1,328 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO Type System and Type References
+//!
+//! This module provides the high-level safe Rust wrapper around LibreOffice's type system.
+//! It includes safe type creation, automatic memory management, and type compatibility testing.
+//!
+//! ## Key Components
+//! - `Type` - Safe Rust wrapper around LibreOffice's typelib_TypeDescriptionReference
+//!
+//! ## Features
+//! - Safe type creation with automatic memory management via RAII
+//! - Type equality and assignment compatibility testing
+//! - Type class and name retrieval
+//! - Clone, equality, and default trait implementations
+//! - Direct FFI interop with raw pointer access methods
+//! - Support for all UNO type classes (void, primitive types, interfaces, etc.)
+//! - Safe From trait implementations for creating types from type classes and explicit type/name tuples
+
+use crate::core::oustring::*;
+use crate::ffi::type_ffi::*;
+use std::ptr;
+
+// === Safe Type Wrapper ===
+
+/// Safe Rust wrapper for UNO Type
+///
+/// This struct provides a safe, ergonomic interface to UNO's type system.
+/// It handles memory management automatically and provides idiomatic Rust
+/// methods for type operations and comparisons.
+///
+/// # Examples
+///
+/// ```rust
+/// use rust_uno::{Type, typelib_TypeClass};
+///
+/// // Create a void type
+/// let void_type = Type::new();
+///
+/// // Create a primitive type
+/// let int_type = Type::from(typelib_TypeClass::typelib_TypeClass_LONG);
+///
+/// // Create an interface type
+/// let interface_type = Type::from((
+/// typelib_TypeClass::typelib_TypeClass_INTERFACE,
+/// "com.sun.star.lang.XComponent"
+/// ));
+/// ```
+#[allow(non_snake_case)] // _pType follows FFI naming conventions
+pub struct Type {
+ /// C typelib reference pointer
+ _pType: *mut typelib_TypeDescriptionReference,
+}
+
+impl Type {
+ /// Create a new Type set to void
+ ///
+ /// Creates the default UNO type (void). This is equivalent to the default
+ /// constructor in C++ com::sun::star::uno::Type.
+ pub fn new() -> Self {
+ unsafe {
+ let void_type_ref =
+ typelib_static_type_getByTypeClass(typelib_TypeClass::typelib_TypeClass_VOID);
+ typelib_typedescriptionreference_acquire(*void_type_ref);
+ Type {
+ _pType: *void_type_ref,
+ }
+ }
+ }
+
+ /// Create a Type from type class and name
+ ///
+ /// Creates a new Type from the specified type class and a string that will be
+ /// converted to OUString. Accepts any type that can be converted to OUString
+ /// (such as &str, String, etc.) through the Into trait. This is the most common
+ /// way to create custom types with specific names.
+ ///
+ /// # Arguments
+ /// * `type_class` - The UNO type class (VOID, STRING, INTERFACE, etc.)
+ /// * `type_name` - The fully qualified type name (convertible to OUString)
+ pub fn new_with_name<T: Into<OUString>>(type_class: typelib_TypeClass, type_name: T) -> Self {
+ let mut oustring_name = type_name.into();
+ let mut type_ref: *mut typelib_TypeDescriptionReference = ptr::null_mut();
+
+ unsafe {
+ typelib_typedescriptionreference_new(
+ &mut type_ref,
+ type_class,
+ oustring_name.as_mut_ptr(),
+ );
+ }
+
+ Type { _pType: type_ref }
+ }
+
+ /// Create Type from existing typelib reference (acquires reference)
+ ///
+ /// Takes ownership of an existing type reference by incrementing its reference count.
+ /// This is useful when interfacing with C code that provides type references.
+ ///
+ /// # Safety
+ /// The caller must ensure that `type_ref` points to a valid typelib_TypeDescriptionReference.
+ pub unsafe fn from_typelib_ref(type_ref: *mut typelib_TypeDescriptionReference) -> Self {
+ unsafe {
+ typelib_typedescriptionreference_acquire(type_ref);
+ }
+ Type { _pType: type_ref }
+ }
+
+ /// Create Type from existing typelib reference (no acquire)
+ ///
+ /// Takes ownership of an existing type reference without incrementing reference count.
+ /// Use this when transferring ownership from C code that already has a reference.
+ /// This avoids unnecessary reference count manipulation when you know the ownership
+ /// is being transferred.
+ ///
+ /// # Safety
+ /// The caller must ensure that:
+ /// - `type_ref` points to a valid typelib_TypeDescriptionReference
+ /// - The reference count is properly managed (caller transfers ownership)
+ pub unsafe fn from_typelib_ref_no_acquire(
+ type_ref: *mut typelib_TypeDescriptionReference,
+ ) -> Self {
+ Type { _pType: type_ref }
+ }
+
+ /// Get the type class of this type
+ ///
+ /// Returns the UNO type class (VOID, STRING, INTERFACE, etc.) that categorizes
+ /// this type within the UNO type system. This is used for type checking and
+ /// dispatch in UNO method calls.
+ pub fn get_type_class(&self) -> typelib_TypeClass {
+ unsafe { (*self._pType).eTypeClass }
+ }
+
+ /// Get the fully qualified name of this type
+ ///
+ /// Returns an OUString containing the type name (e.g., "com.sun.star.lang.XComponent").
+ /// For primitive types, returns the type name (e.g., "long", "string"). The returned
+ /// string is a copy, so it can be safely used without worrying about the lifetime
+ /// of the original Type instance.
+ pub fn get_type_name(&self) -> OUString {
+ unsafe {
+ let name_ptr = (*self._pType).pTypeName;
+ if name_ptr.is_null() {
+ return OUString::new();
+ }
+ // Use OUString::from_raw which handles the acquisition internally
+ OUString::from_raw(name_ptr)
+ }
+ }
+
+ /// Get the raw typelib reference pointer for FFI calls
+ ///
+ /// Returns the underlying pointer for FFI interoperability. The returned
+ /// pointer remains owned by this Type instance and should not be freed
+ /// by the caller. Useful when calling LibreOffice C APIs directly.
+ pub fn get_typelib_type(&self) -> *mut typelib_TypeDescriptionReference {
+ self._pType
+ }
+
+ /// Convert Type into raw pointer (releases Rust ownership)
+ ///
+ /// Transfers ownership of the underlying type reference to the caller.
+ /// The caller becomes responsible for calling typelib_typedescriptionreference_release
+ /// when done with the pointer. The Type instance is consumed and cannot be used
+ /// after this call.
+ pub fn into_raw(self) -> *mut typelib_TypeDescriptionReference {
+ let ptr = self._pType;
+ std::mem::forget(self); // Don't run destructor since we're transferring ownership
+ ptr
+ }
+
+ /// Test if values of this type can be assigned from values of the given type
+ ///
+ /// This includes widening conversions (e.g., long assignable from short)
+ /// as long as there is no data loss. The test follows UNO assignment rules
+ /// and is used in method dispatch to determine if argument types are compatible.
+ ///
+ /// # Arguments
+ /// * `other` - The source type to test assignment compatibility from
+ ///
+ /// # Returns
+ /// `true` if values of `other` type can be assigned to this type, `false` otherwise
+ pub fn is_assignable_from(&self, other: &Type) -> bool {
+ unsafe { typelib_typedescriptionreference_isAssignableFrom(self._pType, other._pType) != 0 }
+ }
+
+ /// Test if this type is equal to another type
+ ///
+ /// Two types are equal if they have the same type class and fully qualified name.
+ /// This is used for type matching in UNO method dispatch and interface queries.
+ /// The comparison is efficient and uses LibreOffice's native type comparison.
+ ///
+ /// # Arguments
+ /// * `other` - The type to compare with
+ ///
+ /// # Returns
+ /// `true` if the types are equal, `false` otherwise
+ pub fn equals(&self, other: &Type) -> bool {
+ unsafe { typelib_typedescriptionreference_equals(self._pType, other._pType) != 0 }
+ }
+}
+
+/// Default implementation: Creates a void type
+///
+/// When a Type is created without explicit initialization, it defaults to
+/// the void type, which is the UNO equivalent of "no type" or "empty type".
+impl Default for Type {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Clone implementation: Create an independent copy of another Type
+///
+/// This creates a new Type that references the same type description but is
+/// independently managed. The clone operation increments the reference count
+/// of the underlying type description, ensuring proper memory management.
+impl Clone for Type {
+ fn clone(&self) -> Self {
+ unsafe {
+ typelib_typedescriptionreference_acquire(self._pType);
+ }
+ Type {
+ _pType: self._pType,
+ }
+ }
+}
+
+/// Equality comparison with other Type instances
+///
+/// Two Type instances are considered equal if they refer to the same type
+/// (same type class and name). This uses LibreOffice's native type comparison
+/// which is efficient and handles all type categories correctly.
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ self.equals(other)
+ }
+}
+
+impl Eq for Type {}
+
+/// Debug trait for debugging - shows type class and name for UNO type identification
+///
+/// Displays the Type in a debug-friendly format showing both the type class
+/// and the type name, which is useful for debugging UNO type-related issues.
+impl std::fmt::Debug for Type {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let type_class = self.get_type_class();
+ let type_name = self.get_type_name().to_string();
+ f.debug_struct("Type")
+ .field("type_class", &type_class)
+ .field("type_name", &type_name)
+ .finish()
+ }
+}
+
+/// Destructor: Automatic cleanup when Type goes out of scope
+///
+/// Automatically releases the reference to the underlying type description
+/// when the Type instance is dropped. This ensures proper memory management
+/// without manual intervention.
+impl Drop for Type {
+ fn drop(&mut self) {
+ unsafe {
+ typelib_typedescriptionreference_release(self._pType);
+ }
+ }
+}
+
+/// From trait implementation for typelib_TypeClass (primitive types)
+///
+/// Creates a Type from a primitive type class. This uses LibreOffice's static
+/// type system to get pre-defined type references for standard UNO types like
+/// void, boolean, string, etc. This is the most efficient way to create
+/// primitive types since they're statically allocated.
+impl From<typelib_TypeClass> for Type {
+ fn from(type_class: typelib_TypeClass) -> Self {
+ unsafe {
+ let type_ref = typelib_static_type_getByTypeClass(type_class);
+ typelib_typedescriptionreference_acquire(*type_ref);
+ Type { _pType: *type_ref }
+ }
+ }
+}
+
+/// From trait implementation for (typelib_TypeClass, &str) tuples
+///
+/// Convenient conversion from type class and string slice to Type. The string
+/// is automatically converted to OUString using UTF-8 encoding. This is useful
+/// for creating complex types with explicit type names.
+impl From<(typelib_TypeClass, &str)> for Type {
+ fn from((type_class, type_name): (typelib_TypeClass, &str)) -> Self {
+ Self::new_with_name(type_class, type_name)
+ }
+}
+
+/// From trait implementation for (typelib_TypeClass, String) tuples
+///
+/// Convenient conversion from type class and owned String to Type. The string
+/// is automatically converted to OUString using UTF-8 encoding. This allows
+/// using dynamically generated type names.
+impl From<(typelib_TypeClass, String)> for Type {
+ fn from((type_class, type_name): (typelib_TypeClass, String)) -> Self {
+ Self::new_with_name(type_class, type_name)
+ }
+}
+
+/// From trait implementation for (typelib_TypeClass, OUString) tuples
+///
+/// Direct conversion from type class and OUString to Type. This is the most
+/// efficient conversion when you already have an OUString, as it avoids
+/// additional string conversions.
+impl From<(typelib_TypeClass, OUString)> for Type {
+ fn from((type_class, type_name): (typelib_TypeClass, OUString)) -> Self {
+ Self::new_with_name(type_class, type_name)
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/core/uno_wrapper.rs b/rust_uno/src/core/uno_wrapper.rs
new file mode 100644
index 000000000000..b9ad23bccd04
--- /dev/null
+++ b/rust_uno/src/core/uno_wrapper.rs
@@ -0,0 +1,59 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Safe Rust wrappers for UNO interfaces
+//!
+//! This module provides memory-safe, RAII-based wrappers around raw UNO interface pointers.
+//! For specific UNO interface method calls, use the auto-generated FFI functions
+//! in the `generated` module directly.
+
+use crate::ffi::uno_bridge;
+use crate::generated::com::sun::star::uno::XComponentContext::XComponentContext;
+use std::ffi::NulError;
+
+/// Error types for UNO operations
+#[derive(Debug)]
+pub enum UnoError {
+ /// Failed to create C string (contains null byte)
+ InvalidString(NulError),
+ /// UNO operation failed
+ OperationFailed,
+ /// Interface not supported
+ InterfaceNotSupported,
+ /// Null pointer encountered
+ NullPointer,
+ /// Bridge initialization failed
+ BridgeInitializationFailed,
+}
+
+impl From<NulError> for UnoError {
+ fn from(err: NulError) -> Self {
+ UnoError::InvalidString(err)
+ }
+}
+
+pub type UnoResult<T> = Result<T, UnoError>;
+
+/// Initialize the UNO bridge by directly calling LibreOffice bootstrap
+/// Returns the initial component context
+#[allow(non_snake_case)]
+pub fn defaultBootstrap_InitialComponentContext() -> UnoResult<XComponentContext> {
+ unsafe {
+ let context_ptr = uno_bridge::defaultBootstrap_InitialComponentContext();
+ if context_ptr.is_null() {
+ Err(UnoError::BridgeInitializationFailed)
+ } else {
+ // The bootstrap function returns Reference<XComponentContext>* directly
+ // Use from_ptr which now handles Reference<T>* correctly
+ XComponentContext::from_ptr(context_ptr).ok_or(UnoError::BridgeInitializationFailed)
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/examples/any_example.rs b/rust_uno/src/examples/any_example.rs
new file mode 100644
index 000000000000..4a6b717a0e5a
--- /dev/null
+++ b/rust_uno/src/examples/any_example.rs
@@ -0,0 +1,158 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Simple UNO Any Examples
+//!
+//! This example shows the basic usage of Any for UNO operations.
+//!
+//! ## Any Creation Methods:
+//! - `Any::new()` - Creates an empty Any (void type)
+//! - `Any::from_bool(value)` - Creates an Any containing a boolean
+//! - `Any::from_i32(value)` - Creates an Any containing a 32-bit integer
+//! - `Any::from(value)` - Uses From trait for supported types
+
+use crate::core::Any;
+
+/// Run the UNO Any example
+///
+/// This function demonstrates the usage of Any for UNO operations,
+/// including various creation methods, operations, and traits.
+pub fn run_example() {
+ println!("=== UNO Any Examples ===\n");
+
+ // Create Any values using different methods
+ let empty = Any::new();
+ let bool_any = Any::from_bool(true);
+ let int_any = Any::from_i32(42);
+ let false_any = Any::from_bool(false);
+ let zero_any = Any::from_i32(0);
+
+ println!("Empty Any: {} (has value: {})", empty, empty.has_value());
+ println!(
+ "Boolean Any (true): {} (has value: {})",
+ bool_any,
+ bool_any.has_value()
+ );
+ println!(
+ "Integer Any (42): {} (has value: {})",
+ int_any,
+ int_any.has_value()
+ );
+ println!(
+ "Boolean Any (false): {} (has value: {})",
+ false_any,
+ false_any.has_value()
+ );
+ println!(
+ "Integer Any (0): {} (has value: {})",
+ zero_any,
+ zero_any.has_value()
+ );
+
+ // Test From trait implementations
+ println!("\n--- From Trait Examples ---");
+ let from_bool: Any = true.into();
+ let from_int: Any = 123i32.into();
+
+ println!(
+ "From bool (true): {} (has value: {})",
+ from_bool,
+ from_bool.has_value()
+ );
+ println!(
+ "From i32 (123): {} (has value: {})",
+ from_int,
+ from_int.has_value()
+ );
+
+ // Any operations and traits
+ println!("\n--- Any Operations ---");
+ let cloned = bool_any.clone();
+ println!("Cloned == Original: {}", cloned == bool_any);
+
+ // Trait examples
+ println!("\n--- Trait Examples ---");
+
+ // Default trait
+ let default_any = Any::default();
+ println!(
+ "Default Any: '{}' (has value: {})",
+ default_any,
+ default_any.has_value()
+ );
+
+ // Debug trait
+ println!("Debug output: {bool_any:?}");
+
+ // PartialEq trait
+ let test1 = Any::from_bool(true);
+ let test2 = Any::from_bool(true);
+ let test3 = Any::from_bool(false);
+ let test4 = Any::new(); // void
+ let test5 = Any::new(); // void
+
+ println!("true == true: {}", test1 == test2);
+ println!("true != false: {}", test1 != test3);
+ println!("void == void: {}", test4 == test5);
+ println!("true != void: {}", test1 != test4);
+
+ // Test clear operation
+ println!("\n--- Clear Operation ---");
+ let mut mutable_any = Any::from_i32(999);
+ println!(
+ "Before clear: {} (has value: {})",
+ mutable_any,
+ mutable_any.has_value()
+ );
+ mutable_any.clear();
+ println!(
+ "After clear: {} (has value: {})",
+ mutable_any,
+ mutable_any.has_value()
+ );
+
+ // Raw conversion examples
+ println!("\n--- Raw Conversion Examples ---");
+ let original = Any::from_bool(true);
+ println!(
+ "Original: {} (has value: {})",
+ original,
+ original.has_value()
+ );
+
+ // Convert to raw and back (unsafe operations)
+ let raw_any = original.into_raw();
+ let restored = unsafe { Any::from_raw(raw_any) };
+ println!(
+ "Restored: {} (has value: {})",
+ restored,
+ restored.has_value()
+ );
+
+ // Test various integer values
+ println!("\n--- Integer Value Tests ---");
+ let numbers = vec![-1, 0, 1, 42, 2024, i32::MAX, i32::MIN];
+ for num in numbers {
+ let any = Any::from_i32(num);
+ println!("Any({num}): {} (has value: {})", any, any.has_value());
+ }
+
+ // Test memory safety with multiple clones
+ println!("\n--- Memory Safety Test ---");
+ let original = Any::from_i32(12345);
+ let clones: Vec<Any> = (0..5).map(|_| original.clone()).collect();
+ println!("Created {} clones of Any(12345)", clones.len());
+ for (i, clone) in clones.iter().enumerate() {
+ println!("Clone {}: {} (has value: {})", i, clone, clone.has_value());
+ }
+
+ println!("\n✓ Any examples completed!");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/examples/basic_example.rs b/rust_uno/src/examples/basic_example.rs
new file mode 100644
index 000000000000..4190cf043605
--- /dev/null
+++ b/rust_uno/src/examples/basic_example.rs
@@ -0,0 +1,120 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Basic usage example of the Rust UNO Language Binding
+//!
+//! This example demonstrates how to use the Rust UNO bindings to interact
+//! with LibreOffice UNO components, including the OUString wrapper for safe
+//! string handling and cross-platform SAL types.
+
+// Import from the current crate since examples are now part of the library
+use crate::core::OUString;
+
+/// Example function demonstrating OUString creation and operations
+pub fn oustring_basic_example() {
+ println!("=== LibreOffice UNO Rust Binding - OUString Demonstration ===");
+
+ // Basic string creation
+ let empty = OUString::new();
+ let hello = OUString::from("Hello UNO!");
+ let unicode = OUString::from_utf8("Unicode: café 中文 🚀");
+
+ println!("Empty string: '{}' (len: {})", empty, empty.len());
+ println!("Hello string: '{}' (len: {})", hello, hello.len());
+ println!("Unicode string: '{}' (len: {})", unicode, unicode.len());
+
+ // String operations
+ let cloned = hello.clone();
+ println!("Cloned == Original: {}", cloned == hello);
+
+ // Display string conversion
+ println!("Display conversion: '{unicode}'");
+
+ println!("✓ OUString operations completed successfully!");
+ println!("✓ Successfully demonstrated Rust UNO String Handling");
+}
+
+/// Example function demonstrating advanced OUString operations
+///
+/// Shows various ways to create and manipulate OUString instances,
+/// including UTF-8, ASCII, and Unicode handling.
+pub fn advanced_string_example() {
+ println!("=== Advanced UNO String Types (OUString) Examples ===");
+
+ // Basic string creation using different methods
+ let empty_string = OUString::new();
+ let hello_string = OUString::from("Hello, LibreOffice!");
+ let unicode_string = OUString::from_utf8("Unicode: αβγ, 中文, 🚀");
+
+ println!("Empty: '{empty_string}' (length: {})", empty_string.len());
+ println!("Hello: '{hello_string}' (length: {})", hello_string.len());
+ println!(
+ "Unicode: '{unicode_string}' (length: {})",
+ unicode_string.len()
+ );
+
+ // String operations
+ let cloned = hello_string.clone();
+ println!("Cloned == Original: {}", cloned == hello_string);
+ println!("Convert to String: '{unicode_string}'");
+
+ // More string examples
+ let ascii_only = OUString::from_ascii("ASCII Only!");
+ println!(
+ "ASCII string: '{ascii_only}' (length: {})",
+ ascii_only.len()
+ );
+
+ // Comparison operations
+ let same_hello = OUString::from("Hello, LibreOffice!");
+ println!("String equality: {}", hello_string == same_hello);
+
+ println!("✓ Advanced string operations completed successfully!");
+}
+
+/// Run the basic UNO example
+///
+/// This function demonstrates the complete basic usage of the Rust UNO bindings,
+/// focusing on OUString operations and core library functionality.
+pub fn run_example() {
+ println!("=== Rust UNO Language Binding - Basic Usage Example ===\n");
+
+ // Run the basic OUString demonstration
+ oustring_basic_example();
+
+ println!("\n=== Advanced String Examples ===");
+
+ // Run advanced string examples
+ advanced_string_example();
+
+ println!("\n=== Data Type Examples ===");
+
+ // Demonstrate various data type operations
+ println!("UNO Type System Examples:");
+
+ // Basic type demonstrations (without requiring UNO runtime)
+ println!(" Rust types compatible with UNO:");
+ println!(" i8 (sal_Int8/byte): {}", i8::MIN);
+ println!(" i16 (sal_Int16/short): {}", i16::MIN);
+ println!(" i32 (sal_Int32/long): {}", i32::MIN);
+ println!(" i64 (sal_Int64/hyper): {}", i64::MIN);
+ println!(" u16 (sal_uInt16/unsigned short): {}", u16::MAX);
+ println!(" u32 (sal_uInt32/unsigned long): {}", u32::MAX);
+ println!(" u64 (sal_uInt64/unsigned hyper): {}", u64::MAX);
+ println!(" f32 (float): {}", std::f32::consts::PI);
+ println!(" f64 (double): {}", std::f64::consts::E);
+ println!(" bool (sal_Bool): true");
+ println!(" u16 (sal_Unicode/char): {}", 'Ö' as u16);
+
+ println!("\n✓ All UNO basic operations completed successfully!");
+ println!("✓ Rust UNO Language Binding core functionality demonstrated!");
+ println!("✓ OUString operations are fully functional!");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/examples/load_writer.rs b/rust_uno/src/examples/load_writer.rs
new file mode 100644
index 000000000000..575f64237005
--- /dev/null
+++ b/rust_uno/src/examples/load_writer.rs
@@ -0,0 +1,124 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+use crate::core::uno_wrapper::{UnoError, defaultBootstrap_InitialComponentContext};
+use crate::core::OUString;
+use crate::generated::rustmaker::com::sun::star::frame::Desktop::Desktop;
+use crate::generated::rustmaker::com::sun::star::frame::XComponentLoader::XComponentLoader;
+use crate::generated::rustmaker::com::sun::star::text::XTextDocument::XTextDocument;
+use crate::generated::rustmaker::com::sun::star::text::XSimpleText::XSimpleText;
+use std::ffi::c_void;
+
+/// LibreOffice Writer automation demo using generated Rust UNO bindings.
+/// Creates a Writer document and inserts text using auto-generated interface wrappers.
+pub fn run() {
+ println!("=== Rust UNO Bridge Test ===");
+ println!("-> Running 'load_writer' example...");
+
+ match run_internal() {
+ Ok(()) => {
+ println!("=== Rust UNO Bridge Test Done ===");
+ println!("<- 'load_writer' example completed successfully.");
+ },
+ Err(e) => {
+ println!("=== Rust UNO Bridge Test Done ===");
+ eprintln!(" ERROR: 'load_writer' example failed: {e:?}");
+ },
+ }
+}
+
+fn run_internal() -> Result<(), UnoError> {
+ // Initialize UNO bridge
+ println!(" Initializing UNO bridge...");
+ let context = defaultBootstrap_InitialComponentContext()?;
+ println!(" ✓ UNO bridge initialized successfully!");
+
+ // Create Desktop service
+ println!(" Creating Desktop service using generated wrapper...");
+ let desktop = Desktop::create(context.as_ptr()).ok_or(UnoError::OperationFailed)?;
+ println!(" ✓ Desktop service created: {:p}", desktop.as_ptr());
+
+ // Get XComponentLoader interface
+ let component_loader = XComponentLoader::from_ptr(desktop.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
+ println!(" ✓ XComponentLoader interface acquired: {:p}", component_loader.as_ptr());
+
+ // Load Writer document
+ println!(" Loading Writer document via XComponentLoader::loadComponentFromURL...");
+ let url = OUString::from("private:factory/swriter");
+ let target = OUString::from("_blank");
+ let search_flags: i32 = 0;
+ let empty_args = std::ptr::null_mut();
+
+ let document_interface_ptr = component_loader.loadComponentFromURL(
+ url.as_ptr() as *mut c_void,
+ target.as_ptr() as *mut c_void,
+ &search_flags as *const i32 as *mut c_void,
+ empty_args,
+ ).ok_or(UnoError::OperationFailed)?;
+
+ if document_interface_ptr.as_ptr().is_null() {
+ return Err(UnoError::OperationFailed);
+ }
+
+ println!(" ✓ Writer document loaded successfully!");
+ println!(" Document interface pointer: {:p}", document_interface_ptr.as_ptr());
+
+ // Cast to XTextDocument
+ println!(" Casting document to XTextDocument...");
+ let text_document = XTextDocument::from_ptr(document_interface_ptr.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
+ println!(" ✓ XTextDocument interface acquired: {:p}", text_document.as_ptr());
+
+ // Get text object
+ println!(" Getting text object via XTextDocument::getText...");
+ let text = text_document.getText().ok_or(UnoError::OperationFailed)?;
+ println!(" ✓ Text object acquired: {:p}", text.as_ptr());
+
+ // Cast to XSimpleText
+ println!(" Casting XText to XSimpleText...");
+ let simple_text = XSimpleText::from_ptr(text.as_ptr()).ok_or(UnoError::InterfaceNotSupported)?;
+ println!(" ✓ XSimpleText interface acquired: {:p}", simple_text.as_ptr());
+
+ // Create text cursor
+ println!(" Creating text cursor via XSimpleText::createTextCursor...");
+ let cursor = simple_text.createTextCursor().ok_or(UnoError::OperationFailed)?;
+ println!(" ✓ Text cursor created: {:p}", cursor.as_ptr());
+
+ // Insert text
+ println!(" Inserting text via XSimpleText::insertString...");
+ let hello_text = OUString::from(
+ "Hello from Generated Rust UNO Bindings!\n\n\
+ This text was inserted using auto-generated service and interface wrappers:\n\n\
+ - Desktop::create() - Generated service wrapper\n\
+ - XComponentLoader::loadComponentFromURL() - Generated interface method\n\
+ - XTextDocument::getText() - Generated interface method\n\
+ - XSimpleText::createTextCursor() - Generated interface method\n\
+ - XSimpleText::insertString() - Generated interface method\n\n\
+ All types generated automatically from UNO IDL with type-safe opaque pointer architecture!\n\n\
+ FFI Validation Features Demonstrated:\n\
+ - Automatic null pointer checking in all generated methods\n\
+ - Reference validity validation (is() checking) \n\
+ - Memory cleanup on validation failure (delete + return nullptr)\n\
+ - Detailed debug logging for troubleshooting\n\
+ - Type-safe opaque pointer architecture prevents crashes\n\
+ - Follows uno_bootstrap.cxx validation pattern exactly"
+ );
+ let absorb: i32 = 0;
+
+ simple_text.insertString(
+ cursor.as_ptr() as *mut c_void,
+ hello_text.as_ptr() as *mut c_void,
+ &absorb as *const i32 as *mut c_void,
+ );
+
+ println!(" ✓ Text inserted successfully using generated interfaces!");
+
+ Ok(())
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file
diff --git a/rust_uno/src/examples/mod.rs b/rust_uno/src/examples/mod.rs
new file mode 100644
index 000000000000..f28de5d7bbbe
--- /dev/null
+++ b/rust_uno/src/examples/mod.rs
@@ -0,0 +1,41 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Example usage of the Rust UNO bridge
+
+pub mod any_example;
+pub mod basic_example;
+pub mod load_writer;
+pub mod string_example;
+pub mod type_example;
+// pub mod autogen_test; // Temporarily disabled
+
+/// Run all examples
+pub fn run_all() {
+ println!("=== Running all UNO examples ===");
+
+ println!("\n--- Load Writer example ---");
+ load_writer::run();
+
+ println!("\n--- Basic example ---");
+ basic_example::run_example();
+
+ println!("\n--- String example ---");
+ string_example::run_example();
+
+ println!("\n--- Any example ---");
+ any_example::run_example();
+
+ println!("\n--- Type example ---");
+ type_example::run_example();
+
+ println!("\n=== All examples completed ===");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/examples/string_example.rs b/rust_uno/src/examples/string_example.rs
new file mode 100644
index 000000000000..ff73ee433d3f
--- /dev/null
+++ b/rust_uno/src/examples/string_example.rs
@@ -0,0 +1,131 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Simple UNO String Examples
+//!
+//! This example shows the basic usage of OUString for UNO operations.
+//!
+//! ## String Creation Methods:
+//! - `OUString::from(str)` - Uses UTF-8 via From trait (most common)
+//! - `OUString::from_utf8(str)` - Explicit UTF-8 conversion (recommended)
+//! - `OUString::from_ascii(str)` - For pure ASCII text only
+//! - `OUString::from_utf16(data)` - When you already have UTF-16 data
+
+use crate::core::oustring::OUString;
+use crate::ffi::rtl_string::rtl_uString;
+use crate::ffi::sal_types::sal_Unicode;
+use std::ptr::NonNull;
+
+/// Test what happens with allocation failure
+/// NOTE: This is just for demonstration - real failure is hard to trigger
+pub fn test_allocation_failure_behavior() {
+ println!("=== Testing Allocation Failure Behavior ===");
+
+ // Simulate what happens when NonNull::new gets a null pointer
+ let null_ptr: *mut rtl_uString = std::ptr::null_mut();
+
+ println!("Simulating allocation failure...");
+
+ // This will demonstrate the behavior:
+ match NonNull::new(null_ptr) {
+ Some(_) => println!("Got valid pointer"),
+ None => {
+ println!("Got null pointer - this would cause panic in OUString::new()");
+ println!("In real code: .expect(\"RTL string allocation failed\") would panic here");
+ println!(
+ "Program would terminate with: 'RTL string allocation failed - system out of memory'"
+ );
+ return;
+ }
+ }
+
+ println!("If you see this message, allocation succeeded");
+}
+
+/// Run the UNO string example
+///
+/// This function demonstrates the usage of OUString for UNO operations,
+/// including various creation methods, operations, and traits.
+pub fn run_example() {
+ println!("=== UNO String Examples ===");
+
+ // Create strings using different methods
+ let empty = OUString::new();
+ let hello = OUString::from("Hello UNO!"); // Uses from_utf8 via From trait (most common)
+ let unicode = OUString::from_utf8("Unicode: café 中文 🚀"); // Explicit UTF-8 (recommended)
+ let ascii_only = OUString::from_ascii("ASCII Only!"); // For pure ASCII text only
+
+ // UTF-16 example (for when you already have UTF-16 data)
+ let utf16_data: Vec<sal_Unicode> = "UTF-16 example"
+ .encode_utf16()
+ .map(|c| c as sal_Unicode)
+ .collect();
+ let utf16_string = OUString::from_utf16(&utf16_data);
+
+ println!("Empty string: '{}' (len: {})", empty, empty.len());
+ println!("Hello string: '{}' (len: {})", hello, hello.len());
+ println!("UTF-8 string: '{}' (len: {})", unicode, unicode.len());
+ println!("ASCII string: '{}' (len: {})", ascii_only, ascii_only.len());
+ println!(
+ "UTF-16 string: '{}' (len: {})",
+ utf16_string,
+ utf16_string.len()
+ );
+
+ // String operations and traits
+ let cloned = hello.clone();
+ println!("Cloned == Original: {}", cloned == hello);
+
+ // Convert to Rust String (inherited from Display trait)
+ let rust_str = unicode.to_string();
+ println!("As Rust String: '{rust_str}'");
+
+ // Trait examples
+ println!("\n--- Trait Examples ---");
+
+ // Default trait
+ let default_str = OUString::default();
+ println!(
+ "Default string: '{}' (empty: {})",
+ default_str,
+ default_str.is_empty()
+ );
+
+ // Debug trait
+ println!("Debug output: {hello:?}");
+
+ // PartialEq trait
+ let test1 = OUString::from("test");
+ let test2 = OUString::from("test");
+ let test3 = OUString::from("different");
+ println!("'{}' == '{}': {}", test1, test2, test1 == test2);
+ println!("'{}' != '{}': {}", test1, test2, test1 != test2);
+ println!("'{}' == '{}': {}", test1, test3, test1 == test3);
+ println!("'{}' != '{}': {}", test1, test3, test1 != test3);
+
+ // Additional string examples
+ println!("\n--- Additional String Operations ---");
+
+ let special_chars = OUString::from_utf8("Special: αβγ, ñañá, العربية");
+ println!("Special characters: '{special_chars}'");
+
+ let mixed = OUString::from("Mixed content: 123 + αβγ = 🎉");
+ println!("Mixed content: '{mixed}' (len: {})", mixed.len());
+
+ // Test empty string operations
+ println!("Empty string is empty: {}", empty.is_empty());
+ println!("Hello string is empty: {}", hello.is_empty());
+
+ println!("\n--- Testing Allocation Failure Behavior ---");
+ test_allocation_failure_behavior();
+
+ println!("\n✓ OUString examples completed!");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/examples/type_example.rs b/rust_uno/src/examples/type_example.rs
new file mode 100644
index 000000000000..31889f8dd999
--- /dev/null
+++ b/rust_uno/src/examples/type_example.rs
@@ -0,0 +1,324 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO Type System Examples
+//!
+//! This example demonstrates the usage of the UNO Type system in Rust.
+//! The Type class represents IDL meta types, holding type names and type classes.
+//!
+//! ## Type Creation Methods:
+//! - `Type::new()` - Creates void type (default)
+//! - `Type::from(typelib_TypeClass)` - Creates type from type class only
+//! - `Type::from((typelib_TypeClass, name))` - Creates type with class and name
+//! - `Type::new_with_name(class, name)` - Explicit creation with name
+//!
+//! ## Type Operations:
+//! - `get_type_class()` - Get the UNO type class
+//! - `get_type_name()` - Get the fully qualified type name
+//! - `equals()` - Test type equality
+//! - `is_assignable_from()` - Test assignment compatibility
+
+use crate::core::{OUString, Type};
+use crate::ffi::type_ffi::typelib_TypeClass;
+
+/// Run the UNO type system example
+///
+/// This function demonstrates the usage of the UNO Type system in Rust,
+/// including type creation, operations, traits, and UNO interface integration.
+pub fn run_example() {
+ println!("=== UNO Type System Examples ===\n");
+
+ // === Basic Type Creation ===
+ println!("--- Basic Type Creation ---");
+
+ // Default void type
+ let void_type = Type::new();
+ let default_type = Type::default();
+ println!("Void type: {void_type:?}");
+ println!("Default type: {default_type:?}");
+ println!("Void == Default: {}", void_type.equals(&default_type));
+
+ // === Primitive Types from Type Classes ===
+ println!("\n--- Primitive Types from Type Classes ---");
+
+ let boolean_type = Type::from(typelib_TypeClass::typelib_TypeClass_BOOLEAN);
+ let byte_type = Type::from(typelib_TypeClass::typelib_TypeClass_BYTE);
+ let short_type = Type::from(typelib_TypeClass::typelib_TypeClass_SHORT);
+ let long_type = Type::from(typelib_TypeClass::typelib_TypeClass_LONG);
+ let float_type = Type::from(typelib_TypeClass::typelib_TypeClass_FLOAT);
+ let double_type = Type::from(typelib_TypeClass::typelib_TypeClass_DOUBLE);
+ let char_type = Type::from(typelib_TypeClass::typelib_TypeClass_CHAR);
+ let string_type = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ let type_type = Type::from(typelib_TypeClass::typelib_TypeClass_TYPE);
+ let any_type = Type::from(typelib_TypeClass::typelib_TypeClass_ANY);
+
+ println!(
+ "Boolean: {} (class: {:?})",
+ boolean_type.get_type_name(),
+ boolean_type.get_type_class()
+ );
+ println!(
+ "Byte: {} (class: {:?})",
+ byte_type.get_type_name(),
+ byte_type.get_type_class()
+ );
+ println!(
+ "Short: {} (class: {:?})",
+ short_type.get_type_name(),
+ short_type.get_type_class()
+ );
+ println!(
+ "Long: {} (class: {:?})",
+ long_type.get_type_name(),
+ long_type.get_type_class()
+ );
+ println!(
+ "Float: {} (class: {:?})",
+ float_type.get_type_name(),
+ float_type.get_type_class()
+ );
+ println!(
+ "Double: {} (class: {:?})",
+ double_type.get_type_name(),
+ double_type.get_type_class()
+ );
+ println!(
+ "Char: {} (class: {:?})",
+ char_type.get_type_name(),
+ char_type.get_type_class()
+ );
+ println!(
+ "String: {} (class: {:?})",
+ string_type.get_type_name(),
+ string_type.get_type_class()
+ );
+ println!(
+ "Type: {} (class: {:?})",
+ type_type.get_type_name(),
+ type_type.get_type_class()
+ );
+ println!(
+ "Any: {} (class: {:?})",
+ any_type.get_type_name(),
+ any_type.get_type_class()
+ );
+
+ // === Complex Types with Names ===
+ println!("\n--- Complex Types with Names ---");
+
+ // Interface types using tuple syntax
+ let component_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XComponent",
+ ));
+
+ let property_set_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.beans.XPropertySet",
+ ));
+
+ // Service types
+ let text_service = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_SERVICE,
+ "com.sun.star.text.Text",
+ );
+
+ // Using String and OUString for type names
+ let string_name = "com.sun.star.awt.XControl".to_string();
+ let control_type = Type::from((typelib_TypeClass::typelib_TypeClass_INTERFACE, string_name));
+
+ let oustring_name = OUString::from("com.sun.star.uno.XInterface");
+ let interface_type = Type::new_with_name(
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ oustring_name,
+ );
+
+ println!(
+ "Component: {} (class: {:?})",
+ component_type.get_type_name(),
+ component_type.get_type_class()
+ );
+ println!(
+ "PropertySet: {} (class: {:?})",
+ property_set_type.get_type_name(),
+ property_set_type.get_type_class()
+ );
+ println!(
+ "Text Service: {} (class: {:?})",
+ text_service.get_type_name(),
+ text_service.get_type_class()
+ );
+ println!(
+ "Control: {} (class: {:?})",
+ control_type.get_type_name(),
+ control_type.get_type_class()
+ );
+ println!(
+ "XInterface: {} (class: {:?})",
+ interface_type.get_type_name(),
+ interface_type.get_type_class()
+ );
+
+ // === Type Properties and Operations ===
+ println!("\n--- Type Properties and Operations ---");
+
+ println!("Type class of long: {:?}", long_type.get_type_class());
+ println!(
+ "Type name of component: '{}'",
+ component_type.get_type_name()
+ );
+
+ // Type equality testing
+ let long_type2 = Type::from(typelib_TypeClass::typelib_TypeClass_LONG);
+ let short_type2 = Type::from(typelib_TypeClass::typelib_TypeClass_SHORT);
+
+ println!("long == long: {}", long_type.equals(&long_type2));
+ println!("long == short: {}", long_type.equals(&short_type2));
+
+ // Assignment compatibility testing
+ println!(
+ "long assignable from short: {}",
+ long_type.is_assignable_from(&short_type)
+ );
+ println!(
+ "short assignable from long: {}",
+ short_type.is_assignable_from(&long_type)
+ );
+ println!(
+ "any assignable from long: {}",
+ any_type.is_assignable_from(&long_type)
+ );
+ println!(
+ "long assignable from any: {}",
+ long_type.is_assignable_from(&any_type)
+ );
+
+ // === Trait Examples ===
+ println!("\n--- Trait Examples ---");
+
+ // Clone trait
+ let original = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.lang.XServiceInfo",
+ ));
+ let cloned = original.clone();
+ println!("Original: {}", original.get_type_name());
+ println!("Cloned: {}", cloned.get_type_name());
+ println!("Clone equals original: {}", original.equals(&cloned));
+
+ // PartialEq trait (using == operator)
+ let type1 = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ let type2 = Type::from(typelib_TypeClass::typelib_TypeClass_STRING);
+ let type3 = Type::from(typelib_TypeClass::typelib_TypeClass_LONG);
+ println!("string == string: {}", type1 == type2);
+ println!("string != long: {}", type1 != type3);
+
+ // Debug trait
+ println!("Debug output: {long_type:?}");
+
+ // === Additional Type Examples ===
+ println!("\n--- Additional Type Examples ---");
+
+ // Create types for common UNO interfaces
+ let service_manager_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_SERVICE,
+ "com.sun.star.lang.XMultiServiceFactory",
+ ));
+
+ let document_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.document.XDocumentPropertiesSupplier",
+ ));
+
+ println!(
+ "Service Manager: {} (class: {:?})",
+ service_manager_type.get_type_name(),
+ service_manager_type.get_type_class()
+ );
+ println!(
+ "Document: {} (class: {:?})",
+ document_type.get_type_name(),
+ document_type.get_type_class()
+ );
+
+ // Create expected sal_Int32 type for comparison
+ let sal_int32_type = Type::from((typelib_TypeClass::typelib_TypeClass_LONG, "sal_Int32"));
+ println!(
+ "sal_Int32 type: {} (class: {:?})",
+ sal_int32_type.get_type_name(),
+ sal_int32_type.get_type_class()
+ );
+
+ // === Advanced Type Operations ===
+ println!("\n--- Advanced Type Operations ---");
+
+ // Demonstrate type compatibility chains
+ let unsigned_short_type = Type::from(typelib_TypeClass::typelib_TypeClass_UNSIGNED_SHORT);
+ let unsigned_long_type = Type::from(typelib_TypeClass::typelib_TypeClass_UNSIGNED_LONG);
+ let hyper_type = Type::from(typelib_TypeClass::typelib_TypeClass_HYPER);
+
+ println!("Type compatibility chain:");
+ println!(
+ " unsigned_long assignable from unsigned_short: {}",
+ unsigned_long_type.is_assignable_from(&unsigned_short_type)
+ );
+ println!(
+ " hyper assignable from unsigned_short: {}",
+ hyper_type.is_assignable_from(&unsigned_short_type)
+ );
+ println!(
+ " hyper assignable from long: {}",
+ hyper_type.is_assignable_from(&long_type)
+ );
+
+ // Interface hierarchy compatibility
+ let xinterface_type = Type::from((
+ typelib_TypeClass::typelib_TypeClass_INTERFACE,
+ "com.sun.star.uno.XInterface",
+ ));
+ println!(
+ "XInterface assignable from XComponent: {}",
+ xinterface_type.is_assignable_from(&component_type)
+ );
+ println!(
+ "XInterface type: {} (class: {:?})",
+ xinterface_type.get_type_name(),
+ xinterface_type.get_type_class()
+ );
+ println!(
+ "XComponent type: {} (class: {:?})",
+ component_type.get_type_name(),
+ component_type.get_type_class()
+ );
+
+ // === Memory Management Demo ===
+ println!("\n--- Memory Management Demo ---");
+
+ // Create multiple references to the same type
+ let type_a = Type::from(typelib_TypeClass::typelib_TypeClass_DOUBLE);
+ let type_b = type_a.clone();
+ let type_c = Type::from(typelib_TypeClass::typelib_TypeClass_DOUBLE);
+
+ println!("type_a: {}", type_a.get_type_name());
+ println!("type_b (cloned): {}", type_b.get_type_name());
+ println!("type_c (new): {}", type_c.get_type_name());
+ println!(
+ "All three equal: {}",
+ type_a.equals(&type_b) && type_b.equals(&type_c)
+ );
+
+ // Types are automatically cleaned up when they go out of scope
+ // due to RAII (Drop trait implementation)
+
+ println!("\n✓ UNO Type system examples completed!");
+ println!("✓ All Type creation methods, operations, and traits demonstrated!");
+ println!("✓ Type system functionality working correctly!");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/mod.rs b/rust_uno/src/ffi/mod.rs
new file mode 100644
index 000000000000..6f2518283076
--- /dev/null
+++ b/rust_uno/src/ffi/mod.rs
@@ -0,0 +1,27 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! FFI modules for interacting with C/C++ code.
+
+// This module will contain the raw bindings generated by bindgen.
+pub mod uno_any;
+pub mod uno_bridge;
+pub mod uno_sequence;
+
+pub mod rtl_string;
+pub mod sal_types;
+pub mod type_ffi;
+
+// Include unit tests
+#[cfg(test)]
+mod tests {
+ mod integration_tests;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/rtl_string.rs b/rust_uno/src/ffi/rtl_string.rs
new file mode 100644
index 000000000000..bb1f0a9f0dd5
--- /dev/null
+++ b/rust_uno/src/ffi/rtl_string.rs
@@ -0,0 +1,87 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! RTL String FFI Bindings
+//!
+//! This module contains the raw FFI bindings for LibreOffice's rtl_uString
+//! functions and types. These are low-level C API bindings that should
+//! typically be used through the high-level OUString wrapper.
+
+// Allow non-standard naming for FFI types that must match C API exactly
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use crate::ffi::sal_types::*;
+
+// === RTL String Types and FFI Declarations ===
+
+/// Interlocked count type for reference counting and atomic operations
+pub type oslInterlockedCount = sal_Int32;
+
+/// Text encoding constants
+pub type rtl_TextEncoding = sal_Int32;
+pub const RTL_TEXTENCODING_UTF8: rtl_TextEncoding = 76;
+
+/// Conversion flags for string conversion
+pub const OSTRING_TO_OUSTRING_CVTFLAGS: sal_uInt32 = 0x00000003;
+
+/// Internal structure for LibreOffice UNO strings
+#[repr(C)]
+pub struct rtl_uString {
+ /// reference count of string
+ pub refCount: oslInterlockedCount,
+ /// length of the string in UTF-16 code units
+ pub length: sal_Int32,
+ /// UTF-16 buffer array
+ pub buffer: [sal_Unicode; 1usize],
+}
+
+unsafe extern "C" {
+ /// Create a new empty string
+ pub fn rtl_uString_new(newStr: *mut *mut rtl_uString);
+
+ /// Create string from ASCII
+ pub fn rtl_uString_newFromAscii(
+ newStr: *mut *mut rtl_uString,
+ value: *const std::os::raw::c_char,
+ );
+
+ /// Create string from existing string
+ pub fn rtl_uString_newFromString(newStr: *mut *mut rtl_uString, value: *const rtl_uString);
+
+ /// Create string from UTF-16 data with length
+ pub fn rtl_uString_newFromStr_WithLength(
+ newStr: *mut *mut rtl_uString,
+ value: *const sal_Unicode,
+ len: sal_Int32,
+ );
+
+ /// Create UNO string from byte string with encoding
+ pub fn rtl_string2UString(
+ newStr: *mut *mut rtl_uString,
+ str: *const std::os::raw::c_char,
+ len: sal_Int32,
+ encoding: rtl_TextEncoding,
+ convertFlags: sal_uInt32,
+ );
+
+ /// Release string reference
+ pub fn rtl_uString_release(str: *mut rtl_uString);
+
+ /// Acquire string reference
+ pub fn rtl_uString_acquire(str: *mut rtl_uString);
+
+ /// Get string length
+ pub fn rtl_uString_getLength(str: *const rtl_uString) -> sal_Int32;
+
+ /// Get string data pointer
+ pub fn rtl_uString_getStr(str: *const rtl_uString) -> *const sal_Unicode;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/sal_types.rs b/rust_uno/src/ffi/sal_types.rs
new file mode 100644
index 000000000000..784db4c1c51c
--- /dev/null
+++ b/rust_uno/src/ffi/sal_types.rs
@@ -0,0 +1,50 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO Basic Types - Cross-Platform Implementation
+//!
+//! This module contains the fundamental SAL (System Abstraction Layer) types
+//! that form the foundation of UNO's type system. These types use Rust native
+//! types to ensure consistent behavior across all platforms.
+
+// Allow non-standard naming for FFI types that must match C API exactly
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+// === Fixed-size integer types ===
+// These types have guaranteed sizes across all platforms
+
+pub type sal_Bool = u8; // Always 8-bit boolean
+pub type sal_Int8 = i8; // Always 8-bit signed
+pub type sal_uInt8 = u8; // Always 8-bit unsigned
+pub type sal_Int16 = i16; // Always 16-bit signed
+pub type sal_uInt16 = u16; // Always 16-bit unsigned
+pub type sal_Int32 = i32; // Always 32-bit signed
+pub type sal_uInt32 = u32; // Always 32-bit unsigned
+pub type sal_Int64 = i64; // Always 64-bit signed
+pub type sal_uInt64 = u64; // Always 64-bit unsigned
+
+// === Platform-dependent types ===
+// These types adapt to the target platform's pointer width
+
+pub type sal_Size = usize; // Platform pointer width (32/64-bit)
+pub type sal_sSize = isize; // Signed platform pointer width
+pub type sal_PtrDiff = isize; // Pointer difference type
+pub type sal_IntPtr = isize; // Integer type that can hold a pointer
+pub type sal_uIntPtr = usize; // Unsigned integer type that can hold a pointer
+
+// === Special types ===
+
+pub type sal_Unicode = u16; // UTF-16 code unit (always 16-bit)
+pub type sal_Handle = *mut std::ffi::c_void; // Generic opaque handle
+
+pub const SAL_FALSE: sal_Bool = 0;
+pub const SAL_TRUE: sal_Bool = 1;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/tests/integration_tests.rs b/rust_uno/src/ffi/tests/integration_tests.rs
new file mode 100644
index 000000000000..4b89c229e052
--- /dev/null
+++ b/rust_uno/src/ffi/tests/integration_tests.rs
@@ -0,0 +1,828 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! Integration tests for Rust UNO Language Binding
+//!
+//! These tests verify that the UNO binding works correctly with the
+//! actual LibreOffice UNO components through FFI/C interop.
+//!
+//! **Note**: Rust-side unit tests (traits, constructors, etc.) are located
+//! in separate test files like `string_tests.rs`.
+//!
+//! # Test Coverage
+//!
+//! ## Core FFI Functionality Tests
+//! - `test_xtest_interface_creation()` - Basic interface instantiation
+//! - `test_boolean_operations()` - Boolean data type FFI handling (both true/false)
+//! - `test_integer_operations()` - Signed integer types FFI with wrong values
+//! - `test_unsigned_integer_operations()` - Unsigned integer types FFI with wrong values
+//! - `test_64bit_operations()` - 64-bit integer types FFI with wrong values
+//! - `test_floating_point_operations()` - Float and double types FFI with wrong values
+//! - `test_char_operations()` - Unicode character FFI handling with wrong values
+//! - `test_string_operations()` - OUString FFI handling with UNO components
+//! - `test_type_operations()` - UNO Type FFI interop with C++ components
+//! - `test_rust_type_creation()` - Rust Type wrapper construction and basic operations
+//! - `test_type_assignment_compatibility()` - Type assignment compatibility testing
+//! - `test_type_cloning_and_memory()` - Type cloning and memory management validation
+//!
+//! ## Comprehensive UNO Component Validation Tests
+//! - `test_wrong_values_comprehensive()` - Extensive wrong value testing for all data types
+//! - `test_edge_cases_and_boundary_values()` - Boundary conditions and special values
+//! - `test_consistency_across_multiple_calls()` - Stability and consistency verification
+//! - `test_all_operations_comprehensive()` - Cross-functional integration testing
+//!
+//! ## Test Strategy
+//! Each FFI function is tested with:
+//! - Correct expected values (should return true)
+//! - Multiple wrong values (should return false)
+//! - Boundary values and edge cases
+//! - Consistency across multiple calls
+//!
+//! This ensures robust validation of the UNO binding's FFI data type handling
+//! and error detection capabilities with actual UNO components.
+
+use crate::ffi::rtl_string::rtl_uString;
+use crate::ffi::sal_types::*;
+use crate::ffi::type_ffi::typelib_TypeDescriptionReference;
+use crate::core::{OUString, Type, typelib_TypeClass};
+
+// === FFI Declarations for Test Functions ===
+#[allow(unused)]
+unsafe extern "C" {
+ /// Print a greeting message from the UNO test component
+ pub fn xtest_hello();
+
+ /// Get a boolean value from UNO test component (always returns true)
+ pub fn xtest_getBoolean() -> sal_Bool;
+
+ /// Test if a boolean value matches the expected UNO boolean
+ pub fn xtest_isBoolean(value: sal_Bool) -> sal_Bool;
+
+ /// Get a byte value from UNO test component (always returns -12)
+ pub fn xtest_getByte() -> sal_Int8;
+
+ /// Test if a byte value matches the expected UNO byte (-12)
+ pub fn xtest_isByte(value: sal_Int8) -> sal_Bool;
+
+ /// Get a short value from UNO test component (always returns -1234)
+ pub fn xtest_getShort() -> sal_Int16;
+
+ /// Test if a short value matches the expected UNO short (-1234)
+ pub fn xtest_isShort(value: sal_Int16) -> sal_Bool;
+
+ /// Get a long value from UNO test component (always returns -123456)
+ pub fn xtest_getLong() -> sal_Int32;
+
+ /// Test if a long value matches the expected UNO long (-123456)
+ pub fn xtest_isLong(value: sal_Int32) -> sal_Bool;
+
+ /// Get an unsigned short value from UNO test component (always returns 54321)
+ pub fn xtest_getUnsignedShort() -> sal_uInt16;
+
+ /// Test if an unsigned short value matches the expected UNO unsigned short (54321)
+ pub fn xtest_isUnsignedShort(value: sal_uInt16) -> sal_Bool;
+
+ /// Get an unsigned long value from UNO test component (always returns 3456789012)
+ pub fn xtest_getUnsignedLong() -> sal_uInt32;
+
+ /// Test if an unsigned long value matches the expected UNO unsigned long (3456789012)
+ pub fn xtest_isUnsignedLong(value: sal_uInt32) -> sal_Bool;
+
+ /// Get a hyper (64-bit) value from UNO test component (always returns -123456789)
+ pub fn xtest_getHyper() -> sal_Int64;
+
+ /// Test if a hyper value matches the expected UNO hyper (-123456789)
+ pub fn xtest_isHyper(value: sal_Int64) -> sal_Bool;
+
+ /// Get an unsigned hyper (64-bit) value from UNO test component (always returns 9876543210)
+ pub fn xtest_getUnsignedHyper() -> sal_uInt64;
+
+ /// Test if an unsigned hyper value matches the expected UNO unsigned hyper (9876543210)
+ pub fn xtest_isUnsignedHyper(value: sal_uInt64) -> sal_Bool;
+
+ /// Get a float value from UNO test component (always returns -10.25)
+ pub fn xtest_getFloat() -> f32;
+
+ /// Test if a float value matches the expected UNO float (-10.25)
+ pub fn xtest_isFloat(value: f32) -> sal_Bool;
+
+ /// Get a double value from UNO test component (always returns 100.5)
+ pub fn xtest_getDouble() -> f64;
+
+ /// Test if a double value matches the expected UNO double (100.5)
+ pub fn xtest_isDouble(value: f64) -> sal_Bool;
+
+ /// Test if a character value matches the expected UNO character ('Ö')
+ pub fn xtest_isChar(value: sal_Unicode) -> sal_Bool;
+
+ /// Get a character value from UNO test component (always returns 'Ö')
+ pub fn xtest_getChar() -> sal_Unicode;
+
+ /// Get a string value from UNO test component - returns pointer to rtl_uString
+ pub fn xtest_getString() -> *mut rtl_uString;
+
+ /// Test if a string value matches the expected string ("hä") - takes pointer to rtl_uString
+ pub fn xtest_isString(value: *mut rtl_uString) -> sal_Bool;
+
+ /// Get a Type value from UNO test component - returns pointer to typelib_TypeDescriptionReference
+ pub fn xtest_getType() -> *mut typelib_TypeDescriptionReference;
+
+ /// Test if a Type value matches the expected Type (cppu::UnoType<sal_Int32>) - takes pointer to typelib_TypeDescriptionReference
+ pub fn xtest_isType(value: *mut typelib_TypeDescriptionReference) -> sal_Bool;
+}
+
+// === Test Interface Wrapper ===
+
+/// Rust wrapper for the XTest UNO interface (TEST ONLY)
+///
+/// This interface provides methods for testing basic UNO data types
+/// and serves as a demonstration of the Rust UNO binding functionality.
+///
+/// **Note**: This is a test interface, not part of the core UNO API.
+pub struct XTest;
+
+#[allow(unused)]
+impl XTest {
+ /// Create a new XTest interface instance
+ pub fn new() -> Self {
+ XTest
+ }
+
+ /// Print a greeting message from the UNO component
+ pub fn hello(&self) {
+ unsafe {
+ xtest_hello();
+ }
+ }
+
+ /// Get a boolean value from UNO
+ pub fn get_boolean(&self) -> bool {
+ unsafe {
+ let result = xtest_getBoolean();
+ result != 0
+ }
+ }
+
+ /// Test if a boolean value matches the expected UNO boolean
+ pub fn is_boolean(&self, value: bool) -> bool {
+ unsafe {
+ let sal_value = if value { 1 } else { 0 };
+ let result = xtest_isBoolean(sal_value);
+ result != 0
+ }
+ }
+
+ /// Get a byte value from UNO
+ pub fn get_byte(&self) -> i8 {
+ unsafe { xtest_getByte() }
+ }
+
+ /// Test if a byte value matches the expected UNO byte
+ pub fn is_byte(&self, value: i8) -> bool {
+ unsafe {
+ let result = xtest_isByte(value);
+ result != 0
+ }
+ }
+
+ /// Get a short value from UNO
+ pub fn get_short(&self) -> i16 {
+ unsafe { xtest_getShort() }
+ }
+
+ /// Test if a short value matches the expected UNO short
+ pub fn is_short(&self, value: i16) -> bool {
+ unsafe {
+ let result = xtest_isShort(value);
+ result != 0
+ }
+ }
+
+ /// Get a long value from UNO
+ pub fn get_long(&self) -> i32 {
+ unsafe { xtest_getLong() }
+ }
+
+ /// Test if a long value matches the expected UNO long
+ pub fn is_long(&self, value: i32) -> bool {
+ unsafe {
+ let result = xtest_isLong(value);
+ result != 0
+ }
+ }
+
+ /// Get an unsigned short value from UNO
+ pub fn get_unsigned_short(&self) -> u16 {
+ unsafe { xtest_getUnsignedShort() }
+ }
+
+ /// Test if an unsigned short value matches the expected UNO unsigned short
+ pub fn is_unsigned_short(&self, value: u16) -> bool {
+ unsafe {
+ let result = xtest_isUnsignedShort(value);
+ result != 0
+ }
+ }
+
+ /// Get an unsigned long value from UNO
+ pub fn get_unsigned_long(&self) -> u32 {
+ unsafe { xtest_getUnsignedLong() }
+ }
+
+ /// Test if an unsigned long value matches the expected UNO unsigned long
+ pub fn is_unsigned_long(&self, value: u32) -> bool {
+ unsafe {
+ let result = xtest_isUnsignedLong(value);
+ result != 0
+ }
+ }
+
+ /// Get a hyper (64-bit) value from UNO
+ pub fn get_hyper(&self) -> i64 {
+ unsafe { xtest_getHyper() }
+ }
+
+ /// Test if a hyper value matches the expected UNO hyper
+ pub fn is_hyper(&self, value: i64) -> bool {
+ unsafe {
+ let result = xtest_isHyper(value);
+ result != 0
+ }
+ }
+
+ /// Get an unsigned hyper (64-bit) value from UNO
+ pub fn get_unsigned_hyper(&self) -> u64 {
+ unsafe { xtest_getUnsignedHyper() }
+ }
+
+ /// Test if an unsigned hyper value matches the expected UNO unsigned hyper
+ pub fn is_unsigned_hyper(&self, value: u64) -> bool {
+ unsafe {
+ let result = xtest_isUnsignedHyper(value);
+ result != 0
+ }
+ }
+
+ /// Get a float value from UNO
+ pub fn get_float(&self) -> f32 {
+ unsafe { xtest_getFloat() }
+ }
+
+ /// Test if a float value matches the expected UNO float
+ pub fn is_float(&self, value: f32) -> bool {
+ unsafe {
+ let result = xtest_isFloat(value);
+ result != 0
+ }
+ }
+
+ /// Get a double value from UNO
+ pub fn get_double(&self) -> f64 {
+ unsafe { xtest_getDouble() }
+ }
+
+ /// Test if a double value matches the expected UNO double
+ pub fn is_double(&self, value: f64) -> bool {
+ unsafe {
+ let result = xtest_isDouble(value);
+ result != 0
+ }
+ }
+ /// Get a char value from UNO
+ pub fn get_char(&self) -> sal_Unicode {
+ unsafe { xtest_getChar() }
+ }
+
+ /// Test if a char value matches the expected UNO char
+ pub fn is_char(&self, value: sal_Unicode) -> bool {
+ unsafe {
+ let result = xtest_isChar(value);
+ result != 0
+ }
+ }
+
+ /// Get a string value from UNO
+ pub fn get_string(&self) -> OUString {
+ unsafe {
+ let result = xtest_getString();
+ OUString::from_raw(result)
+ }
+ }
+
+ /// Test if a string value matches the expected UNO string
+ pub fn is_string(&self, value: OUString) -> bool {
+ unsafe {
+ let result = xtest_isString(value.into_raw());
+ result != 0
+ }
+ }
+
+ /// Get a Type value from UNO (returns cppu::UnoType<sal_Int32>)
+ pub fn get_type(&self) -> Type {
+ unsafe { Type::from_typelib_ref_no_acquire(xtest_getType()) }
+ }
+
+ /// Test if a Type value matches the expected UNO Type
+ ///
+ /// Note: This test uses raw pointers for C++ Type interop.
+ /// For Rust Type instances, use direct comparison methods.
+ pub fn is_type(&self, cpp_type: Type) -> bool {
+ unsafe {
+ let result = xtest_isType(cpp_type.into_raw());
+ result != 0
+ }
+ }
+}
+
+impl Default for XTest {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+// === Integration Tests ===
+
+#[test]
+fn test_xtest_interface_creation() {
+ let xtest = XTest::new();
+ // Test that we can create the interface without panicking
+ xtest.hello(); // This should print a message
+}
+
+#[test]
+fn test_boolean_operations() {
+ let xtest = XTest::new();
+
+ // Test getBoolean
+ let result = xtest.get_boolean();
+ assert!(result, "getBoolean should return true");
+
+ // Test isBoolean with true
+ let is_true = xtest.is_boolean(true);
+ assert!(is_true, "isBoolean(true) should return true");
+
+ // Test isBoolean with false
+ let is_false = xtest.is_boolean(false);
+ assert!(!is_false, "isBoolean(false) should return false");
+}
+
+#[test]
+fn test_integer_operations() {
+ let xtest = XTest::new();
+
+ // Test byte operations
+ let byte_val = xtest.get_byte();
+ assert_eq!(byte_val, -12, "getByte should return -12");
+
+ let is_byte = xtest.is_byte(-12);
+ assert!(is_byte, "isByte(-12) should return true");
+
+ let is_wrong_byte = xtest.is_byte(0);
+ assert!(!is_wrong_byte, "isByte(0) should return false");
+
+ // Test short operations
+ let short_val = xtest.get_short();
+ assert_eq!(short_val, -1234, "getShort should return -1234");
+
+ let is_short = xtest.is_short(-1234);
+ assert!(is_short, "isShort(-1234) should return true");
+
+ let is_wrong_short = xtest.is_short(0);
+ assert!(!is_wrong_short, "isShort(0) should return false");
+
+ // Test long operations
+ let long_val = xtest.get_long();
+ assert_eq!(long_val, -123456, "getLong should return -123456");
+
+ let is_long = xtest.is_long(-123456);
+ assert!(is_long, "isLong(-123456) should return true");
+
+ let is_wrong_long = xtest.is_long(0);
+ assert!(!is_wrong_long, "isLong(0) should return false");
+}
+
+#[test]
+fn test_unsigned_integer_operations() {
+ let xtest = XTest::new();
+
+ // Test unsigned short operations
+ let ushort_val = xtest.get_unsigned_short();
+ assert_eq!(ushort_val, 54321, "getUnsignedShort should return 54321");
+
+ let is_ushort = xtest.is_unsigned_short(54321);
+ assert!(is_ushort, "isUnsignedShort(54321) should return true");
+
+ let is_wrong_ushort = xtest.is_unsigned_short(0);
+ assert!(!is_wrong_ushort, "isUnsignedShort(0) should return false");
+
+ // Test unsigned long operations
+ let ulong_val = xtest.get_unsigned_long();
+ assert_eq!(
+ ulong_val, 3456789012,
+ "getUnsignedLong should return 3456789012"
+ );
+
+ let is_ulong = xtest.is_unsigned_long(3456789012);
+ assert!(is_ulong, "isUnsignedLong(3456789012) should return true");
+
+ let is_wrong_ulong = xtest.is_unsigned_long(0);
+ assert!(!is_wrong_ulong, "isUnsignedLong(0) should return false");
+}
+
+#[test]
+fn test_64bit_operations() {
+ let xtest = XTest::new();
+
+ // Test hyper operations
+ let hyper_val = xtest.get_hyper();
+ assert_eq!(hyper_val, -123456789, "getHyper should return -123456789");
+
+ let is_hyper = xtest.is_hyper(-123456789);
+ assert!(is_hyper, "isHyper(-123456789) should return true");
+
+ let is_wrong_hyper = xtest.is_hyper(0);
+ assert!(!is_wrong_hyper, "isHyper(0) should return false");
+
+ // Test unsigned hyper operations
+ let uhyper_val = xtest.get_unsigned_hyper();
+ assert_eq!(
+ uhyper_val, 9876543210,
+ "getUnsignedHyper should return 9876543210"
+ );
+
+ let is_uhyper = xtest.is_unsigned_hyper(9876543210);
+ assert!(is_uhyper, "isUnsignedHyper(9876543210) should return true");
+
+ let is_wrong_uhyper = xtest.is_unsigned_hyper(0);
+ assert!(!is_wrong_uhyper, "isUnsignedHyper(0) should return false");
+}
+
+#[test]
+fn test_floating_point_operations() {
+ let xtest = XTest::new();
+
+ // Test float operations
+ let float_val = xtest.get_float();
+ assert_eq!(float_val, -10.25, "getFloat should return -10.25");
+
+ let is_float = xtest.is_float(-10.25);
+ assert!(is_float, "isFloat(-10.25) should return true");
+
+ let is_wrong_float = xtest.is_float(0.0);
+ assert!(!is_wrong_float, "isFloat(0.0) should return false");
+
+ // Test double operations
+ let double_val = xtest.get_double();
+ assert_eq!(double_val, 100.5, "getDouble should return 100.5");
+
+ let is_double = xtest.is_double(100.5);
+ assert!(is_double, "isDouble(100.5) should return true");
+
+ let is_wrong_double = xtest.is_double(0.0);
+ assert!(!is_wrong_double, "isDouble(0.0) should return false");
+}
+
+#[test]
+fn test_char_operations() {
+ let xtest = XTest::new();
+
+ // Test char operations - 'Ö' is Unicode codepoint U+00D6 (214)
+ let char_val = xtest.get_char();
+ assert_eq!(
+ char_val, 214u16,
+ "getChar should return 214 (Unicode for 'Ö')"
+ );
+
+ let is_char = xtest.is_char(214u16);
+ assert!(is_char, "isChar(214) should return true");
+
+ let is_wrong_char = xtest.is_char(65u16); // 'A'
+ assert!(!is_wrong_char, "isChar(65) should return false");
+}
+
+#[test]
+fn test_string_operations() {
+ let xtest = XTest::new();
+
+ // Test string operations - expected value is "hä"
+ let string_val = xtest.get_string();
+ assert_eq!(string_val.to_string(), "hä", "getString should return 'hä'");
+
+ // Test string validation with correct value
+ let test_string = OUString::from_utf8("hä");
+ let is_string = xtest.is_string(test_string);
+ assert!(is_string, "isString('hä') should return true");
+
+ // Test string validation with wrong value
+ let wrong_string = OUString::from_utf8("wrong");
+ let is_wrong_string = xtest.is_string(wrong_string);
+ assert!(!is_wrong_string, "isString('wrong') should return false");
+}
+
+#[test]
+fn test_type_operations() {
+ let xtest = XTest::new();
+
+ // Test getting a Type value from C++ component
+ let cpp_type = xtest.get_type();
+ // Test that we got a valid Type (non-void type in this case)
+ assert_ne!(
+ cpp_type.get_type_class(),
+ typelib_TypeClass::typelib_TypeClass_VOID,
+ "C++ Type should not be void type"
+ );
+ println!("Got C++ Type: {:?}", cpp_type);
+
+ // Test that the returned Type matches the expected Type (cppu::UnoType<sal_Int32>)
+ let is_correct = xtest.is_type(cpp_type);
+ assert!(is_correct, "C++ Type should match expected sal_Int32 type");
+}
+
+#[test]
+fn test_wrong_values_comprehensive() {
+ let xtest = XTest::new();
+
+ // Test multiple wrong values for each function to ensure robust validation
+
+ // Test multiple wrong byte values
+ let is_wrong_byte1 = xtest.is_byte(100);
+ assert!(!is_wrong_byte1, "isByte(100) should return false");
+
+ let is_wrong_byte2 = xtest.is_byte(-100);
+ assert!(!is_wrong_byte2, "isByte(-100) should return false");
+
+ // Test multiple wrong short values
+ let is_wrong_short1 = xtest.is_short(1000);
+ assert!(!is_wrong_short1, "isShort(1000) should return false");
+
+ let is_wrong_short2 = xtest.is_short(-5000);
+ assert!(!is_wrong_short2, "isShort(-5000) should return false");
+
+ // Test multiple wrong long values
+ let is_wrong_long1 = xtest.is_long(999999);
+ assert!(!is_wrong_long1, "isLong(999999) should return false");
+
+ let is_wrong_long2 = xtest.is_long(-999999);
+ assert!(!is_wrong_long2, "isLong(-999999) should return false");
+
+ // Test multiple wrong unsigned short values
+ let is_wrong_ushort1 = xtest.is_unsigned_short(12345);
+ assert!(
+ !is_wrong_ushort1,
+ "isUnsignedShort(12345) should return false"
+ );
+
+ let is_wrong_ushort2 = xtest.is_unsigned_short(65535);
+ assert!(
+ !is_wrong_ushort2,
+ "isUnsignedShort(65535) should return false"
+ );
+
+ // Test multiple wrong unsigned long values
+ let is_wrong_ulong1 = xtest.is_unsigned_long(1234567890);
+ assert!(
+ !is_wrong_ulong1,
+ "isUnsignedLong(1234567890) should return false"
+ );
+
+ let is_wrong_ulong2 = xtest.is_unsigned_long(4294967295);
+ assert!(
+ !is_wrong_ulong2,
+ "isUnsignedLong(4294967295) should return false"
+ );
+
+ // Test multiple wrong hyper values
+ let is_wrong_hyper1 = xtest.is_hyper(987654321);
+ assert!(!is_wrong_hyper1, "isHyper(987654321) should return false");
+
+ let is_wrong_hyper2 = xtest.is_hyper(-987654321);
+ assert!(!is_wrong_hyper2, "isHyper(-987654321) should return false");
+
+ // Test multiple wrong unsigned hyper values
+ let is_wrong_uhyper1 = xtest.is_unsigned_hyper(1234567890);
+ assert!(
+ !is_wrong_uhyper1,
+ "isUnsignedHyper(1234567890) should return false"
+ );
+
+ let is_wrong_uhyper2 = xtest.is_unsigned_hyper(18446744073709551615);
+ assert!(
+ !is_wrong_uhyper2,
+ "isUnsignedHyper(18446744073709551615) should return false"
+ );
+
+ // Test multiple wrong float values
+ let is_wrong_float1 = xtest.is_float(std::f32::consts::PI);
+ assert!(!is_wrong_float1, "isFloat(3.14159) should return false");
+
+ let is_wrong_float2 = xtest.is_float(-99.99);
+ assert!(!is_wrong_float2, "isFloat(-99.99) should return false");
+
+ // Test multiple wrong double values
+ let is_wrong_double1 = xtest.is_double(std::f64::consts::E);
+ assert!(!is_wrong_double1, "isDouble(2.71828) should return false");
+
+ let is_wrong_double2 = xtest.is_double(-200.75);
+ assert!(!is_wrong_double2, "isDouble(-200.75) should return false");
+
+ // Test multiple wrong char values
+ let is_wrong_char1 = xtest.is_char(72u16); // 'H'
+ assert!(!is_wrong_char1, "isChar(72) should return false");
+
+ let is_wrong_char2 = xtest.is_char(8364u16); // Euro symbol '€'
+ assert!(!is_wrong_char2, "isChar(8364) should return false");
+}
+
+#[test]
+fn test_all_operations_comprehensive() {
+ let xtest = XTest::new();
+
+ // This test verifies that all methods work together
+ // and the component maintains state correctly
+
+ // Test multiple calls to the same method
+ let bool1 = xtest.get_boolean();
+ let bool2 = xtest.get_boolean();
+ assert_eq!(
+ bool1, bool2,
+ "Multiple calls to getBoolean should return same value"
+ );
+
+ // Test that different data types work independently
+ let _byte_val = xtest.get_byte();
+ let _short_val = xtest.get_short();
+ let _long_val = xtest.get_long();
+ let _float_val = xtest.get_float();
+ let _double_val = xtest.get_double();
+
+ // Verify boolean still works after other operations
+ let bool3 = xtest.get_boolean();
+ assert_eq!(bool1, bool3, "Boolean operations should be consistent");
+}
+
+#[test]
+fn test_edge_cases_and_boundary_values() {
+ let xtest = XTest::new();
+
+ // Test edge cases for each data type to ensure robust handling
+
+ // Test maximum and minimum values for signed integers
+ let is_max_byte = xtest.is_byte(i8::MAX);
+ assert!(!is_max_byte, "isByte(i8::MAX) should return false");
+
+ let is_min_byte = xtest.is_byte(i8::MIN);
+ assert!(!is_min_byte, "isByte(i8::MIN) should return false");
+
+ let is_max_short = xtest.is_short(i16::MAX);
+ assert!(!is_max_short, "isShort(i16::MAX) should return false");
+
+ let is_min_short = xtest.is_short(i16::MIN);
+ assert!(!is_min_short, "isShort(i16::MIN) should return false");
+
+ let is_max_long = xtest.is_long(i32::MAX);
+ assert!(!is_max_long, "isLong(i32::MAX) should return false");
+
+ let is_min_long = xtest.is_long(i32::MIN);
+ assert!(!is_min_long, "isLong(i32::MIN) should return false");
+
+ // Test maximum values for unsigned integers
+ let is_max_ushort = xtest.is_unsigned_short(u16::MAX);
+ assert!(
+ !is_max_ushort,
+ "isUnsignedShort(u16::MAX) should return false"
+ );
+
+ let is_max_ulong = xtest.is_unsigned_long(u32::MAX);
+ assert!(
+ !is_max_ulong,
+ "isUnsignedLong(u32::MAX) should return false"
+ );
+
+ // Test edge cases for 64-bit integers
+ let is_max_hyper = xtest.is_hyper(i64::MAX);
+ assert!(!is_max_hyper, "isHyper(i64::MAX) should return false");
+
+ let is_min_hyper = xtest.is_hyper(i64::MIN);
+ assert!(!is_min_hyper, "isHyper(i64::MIN) should return false");
+
+ let is_max_uhyper = xtest.is_unsigned_hyper(u64::MAX);
+ assert!(
+ !is_max_uhyper,
+ "isUnsignedHyper(u64::MAX) should return false"
+ );
+
+ // Test floating point edge cases
+ let is_infinity = xtest.is_float(f32::INFINITY);
+ assert!(!is_infinity, "isFloat(INFINITY) should return false");
+
+ let is_neg_infinity = xtest.is_float(f32::NEG_INFINITY);
+ assert!(
+ !is_neg_infinity,
+ "isFloat(NEG_INFINITY) should return false"
+ );
+
+ let is_double_infinity = xtest.is_double(f64::INFINITY);
+ assert!(
+ !is_double_infinity,
+ "isDouble(INFINITY) should return false"
+ );
+
+ let is_double_neg_infinity = xtest.is_double(f64::NEG_INFINITY);
+ assert!(
+ !is_double_neg_infinity,
+ "isDouble(NEG_INFINITY) should return false"
+ );
+
+ // Test special Unicode characters
+ let is_null_char = xtest.is_char(0u16); // Null character
+ assert!(!is_null_char, "isChar(0) should return false");
+
+ let is_high_unicode = xtest.is_char(0xFFFF); // Maximum Unicode BMP
+ assert!(!is_high_unicode, "isChar(0xFFFF) should return false");
+
+ // Test empty and special strings
+ let empty_string = OUString::from_utf8("");
+ let is_empty_string = xtest.is_string(empty_string);
+ assert!(!is_empty_string, "isString(\"\") should return false");
+
+ let unicode_string = OUString::from_utf8("🦀"); // Rust crab emoji
+ let is_unicode_string = xtest.is_string(unicode_string);
+ assert!(!is_unicode_string, "isString(\"🦀\") should return false");
+}
+
+#[test]
+fn test_consistency_across_multiple_calls() {
+ let xtest = XTest::new();
+
+ // Test that all getter functions return consistent values across multiple calls
+
+ // Test consistency for all data types
+ for _ in 0..5 {
+ // Boolean consistency
+ let bool_val = xtest.get_boolean();
+ assert!(bool_val, "getBoolean should always return true");
+
+ // Integer consistency
+ let byte_val = xtest.get_byte();
+ assert_eq!(byte_val, -12, "getByte should always return -12");
+
+ let short_val = xtest.get_short();
+ assert_eq!(short_val, -1234, "getShort should always return -1234");
+
+ let long_val = xtest.get_long();
+ assert_eq!(long_val, -123456, "getLong should always return -123456");
+
+ // Unsigned integer consistency
+ let ushort_val = xtest.get_unsigned_short();
+ assert_eq!(
+ ushort_val, 54321,
+ "getUnsignedShort should always return 54321"
+ );
+
+ let ulong_val = xtest.get_unsigned_long();
+ assert_eq!(
+ ulong_val, 3456789012,
+ "getUnsignedLong should always return 3456789012"
+ );
+
+ // 64-bit consistency
+ let hyper_val = xtest.get_hyper();
+ assert_eq!(
+ hyper_val, -123456789,
+ "getHyper should always return -123456789"
+ );
+
+ let uhyper_val = xtest.get_unsigned_hyper();
+ assert_eq!(
+ uhyper_val, 9876543210,
+ "getUnsignedHyper should always return 9876543210"
+ );
+
+ // Floating point consistency
+ let float_val = xtest.get_float();
+ assert_eq!(float_val, -10.25, "getFloat should always return -10.25");
+
+ let double_val = xtest.get_double();
+ assert_eq!(double_val, 100.5, "getDouble should always return 100.5");
+
+ // Character consistency
+ let char_val = xtest.get_char();
+ assert_eq!(char_val, 214u16, "getChar should always return 214");
+
+ // String consistency
+ let string_val = xtest.get_string();
+ assert_eq!(
+ string_val.to_string(),
+ "hä",
+ "getString should always return 'hä'"
+ );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/type_ffi.rs b/rust_uno/src/ffi/type_ffi.rs
new file mode 100644
index 000000000000..ad7aa75530f3
--- /dev/null
+++ b/rust_uno/src/ffi/type_ffi.rs
@@ -0,0 +1,173 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! UNO Type System FFI
+//!
+//! This module contains FFI bindings for the UNO type system, including the
+//! typelib_TypeClass enum and related structures for type introspection.
+
+// Allow non-standard naming for FFI types that must match C API exactly
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use crate::ffi::rtl_string::rtl_uString;
+use crate::ffi::sal_types::*;
+
+// === UNO Type System FFI Declarations ===
+
+/// UNO type class enumeration - binary compatible with the IDL enum com.sun.star.uno.TypeClass
+///
+/// This enumeration defines all possible type categories in the UNO type system.
+/// Each type has a specific class that determines how it's handled in marshalling,
+/// method dispatch, and memory management. The values must match exactly with
+/// the corresponding C/C++ enum to ensure binary compatibility.
+#[repr(C)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum typelib_TypeClass {
+ typelib_TypeClass_VOID = 0,
+ typelib_TypeClass_CHAR = 1,
+ typelib_TypeClass_BOOLEAN = 2,
+ typelib_TypeClass_BYTE = 3,
+ typelib_TypeClass_SHORT = 4,
+ typelib_TypeClass_UNSIGNED_SHORT = 5,
+ typelib_TypeClass_LONG = 6,
+ typelib_TypeClass_UNSIGNED_LONG = 7,
+ typelib_TypeClass_HYPER = 8,
+ typelib_TypeClass_UNSIGNED_HYPER = 9,
+ typelib_TypeClass_FLOAT = 10,
+ typelib_TypeClass_DOUBLE = 11,
+ typelib_TypeClass_STRING = 12,
+ typelib_TypeClass_TYPE = 13,
+ typelib_TypeClass_ANY = 14,
+ typelib_TypeClass_ENUM = 15,
+ typelib_TypeClass_TYPEDEF = 16,
+ typelib_TypeClass_STRUCT = 17,
+
+ #[deprecated = "UNOIDL does not have a union concept"]
+ typelib_TypeClass_UNION = 18,
+ typelib_TypeClass_EXCEPTION = 19,
+ typelib_TypeClass_SEQUENCE = 20,
+
+ #[deprecated = "UNOIDL does not have an array concept"]
+ typelib_TypeClass_ARRAY = 21,
+ typelib_TypeClass_INTERFACE = 22,
+ typelib_TypeClass_SERVICE = 23,
+ typelib_TypeClass_MODULE = 24,
+ typelib_TypeClass_INTERFACE_METHOD = 25,
+ typelib_TypeClass_INTERFACE_ATTRIBUTE = 26,
+ typelib_TypeClass_UNKNOWN = 27,
+ typelib_TypeClass_PROPERTY = 28,
+ typelib_TypeClass_CONSTANT = 29,
+ typelib_TypeClass_CONSTANTS = 30,
+ typelib_TypeClass_SINGLETON = 31,
+ typelib_TypeClass_MAKE_FIXED_SIZE = 0x7fffffff,
+}
+
+/// Weak reference to a type description - the core UNO type reference structure
+///
+/// This structure holds a weak reference to a type description in the UNO type system.
+/// It provides efficient type identification without requiring the full type description
+/// to be loaded. Memory layout is designed for binary compatibility with LibreOffice's
+/// C implementation.
+#[repr(C)]
+pub struct typelib_TypeDescriptionReference {
+ /// Reference count of type - managed automatically by acquire/release functions
+ pub nRefCount: sal_Int32,
+ /// Static reference count for types that persist until program termination
+ pub nStaticRefCount: sal_Int32,
+ /// Type class category (VOID, STRING, INTERFACE, etc.)
+ pub eTypeClass: typelib_TypeClass,
+ /// Fully qualified name of the type (e.g., "com.sun.star.lang.XComponent")
+ pub pTypeName: *mut rtl_uString,
+ /// Pointer to full type description (may be null if not loaded)
+ pub pType: *mut typelib_TypeDescription,
+ /// Internal unique identifier for runtime optimization
+ pub pUniqueIdentifier: *mut std::os::raw::c_void,
+ /// Reserved for future use
+ pub pReserved: *mut std::os::raw::c_void,
+}
+
+/// Full type description with complete metadata
+///
+/// Contains comprehensive information about a UNO type including size, alignment,
+/// and member details. This is loaded on demand when detailed type information
+/// is needed for marshalling, method dispatch, or introspection.
+#[repr(C)]
+pub struct typelib_TypeDescription {
+ /// Reference count - managed automatically by acquire/release functions
+ pub nRefCount: sal_Int32,
+ /// Static reference count for types that persist until program termination
+ pub nStaticRefCount: sal_Int32,
+ /// Type class category (VOID, STRING, INTERFACE, etc.)
+ pub eTypeClass: typelib_TypeClass,
+ /// Fully qualified name of the type
+ pub pTypeName: *mut rtl_uString,
+ /// Self-reference pointer for type identification
+ pub pSelf: *mut typelib_TypeDescription,
+ /// Internal unique identifier for runtime optimization
+ pub pUniqueIdentifier: *mut std::os::raw::c_void,
+ /// Reserved for future use
+ pub pReserved: *mut std::os::raw::c_void,
+ /// Flag indicating whether the description is complete and ready to use
+ pub bComplete: sal_Bool,
+ /// Size of the type in bytes
+ pub nSize: sal_Int32,
+ /// Memory alignment requirements for the type
+ pub nAlignment: sal_Int32,
+ /// Back-reference to the weak type reference
+ pub pWeakRef: *mut typelib_TypeDescriptionReference,
+ /// Flag indicating if type can be unloaded and reloaded on demand
+ pub bOnDemand: sal_Bool,
+}
+
+unsafe extern "C" {
+ /// Increment reference count of type description reference
+ pub fn typelib_typedescriptionreference_acquire(pRef: *mut typelib_TypeDescriptionReference);
+
+ /// Decrement reference count of type description reference
+ pub fn typelib_typedescriptionreference_release(pRef: *mut typelib_TypeDescriptionReference);
+
+ /// Create new type description reference from type class and name
+ pub fn typelib_typedescriptionreference_new(
+ ppTDR: *mut *mut typelib_TypeDescriptionReference,
+ eTypeClass: typelib_TypeClass,
+ pTypeName: *mut rtl_uString,
+ );
+
+ /// Test equality of two type description references
+ pub fn typelib_typedescriptionreference_equals(
+ p1: *const typelib_TypeDescriptionReference,
+ p2: *const typelib_TypeDescriptionReference,
+ ) -> sal_Bool;
+
+ /// Test type assignment compatibility
+ pub fn typelib_typedescriptionreference_isAssignableFrom(
+ pAssignable: *mut typelib_TypeDescriptionReference,
+ pFrom: *mut typelib_TypeDescriptionReference,
+ ) -> sal_Bool;
+
+ /// Get full type description from type reference
+ pub fn typelib_typedescriptionreference_getDescription(
+ ppRet: *mut *mut typelib_TypeDescription,
+ pRef: *mut typelib_TypeDescriptionReference,
+ );
+
+ /// Get static type reference for primitive type classes
+ pub fn typelib_static_type_getByTypeClass(
+ eTypeClass: typelib_TypeClass,
+ ) -> *mut *mut typelib_TypeDescriptionReference;
+
+ /// Assign type reference (with proper reference counting)
+ pub fn typelib_typedescriptionreference_assign(
+ ppDest: *mut *mut typelib_TypeDescriptionReference,
+ pSource: *mut typelib_TypeDescriptionReference,
+ );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/uno_any.rs b/rust_uno/src/ffi/uno_any.rs
new file mode 100644
index 000000000000..b1e42df9b681
--- /dev/null
+++ b/rust_uno/src/ffi/uno_any.rs
@@ -0,0 +1,108 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! FFI bindings for UNO Any type operations.
+//!
+//! This module contains direct bindings to LibreOffice's uno_Any
+//! C functions for creating, manipulating, and destroying Any values.
+//!
+//! These are low-level FFI bindings. For safe Rust wrapper, use
+//! the `Any` type from the `core` module instead.
+
+// Allow non-standard naming for FFI types that must match C API exactly
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+// Note: sal_types are included via typelib types
+use crate::ffi::type_ffi::{
+ typelib_TypeClass, typelib_TypeDescription, typelib_TypeDescriptionReference,
+};
+
+/// UNO Any type - represents a value of any UNO type
+/// This matches the C structure _uno_Any from include/uno/any2.h
+#[repr(C)]
+pub struct uno_Any {
+ /// type of value
+ pub pType: *mut typelib_TypeDescriptionReference,
+ /// pointer to value; this may point to pReserved
+ pub pData: *mut std::ffi::c_void,
+ /// reserved space for storing value
+ pub pReserved: *mut std::ffi::c_void,
+}
+
+/// Function types for acquire/release callbacks
+pub type uno_AcquireFunc = unsafe extern "C" fn(*mut std::ffi::c_void);
+pub type uno_ReleaseFunc = unsafe extern "C" fn(*mut std::ffi::c_void);
+
+unsafe extern "C" {
+ /// Assign an any with a given value
+ pub fn uno_any_assign(
+ pDest: *mut uno_Any,
+ pSource: *mut std::ffi::c_void,
+ pTypeDescr: *mut typelib_TypeDescription,
+ acquire: Option<uno_AcquireFunc>,
+ release: Option<uno_ReleaseFunc>,
+ );
+
+ /// Assign an any with a given value (using type reference)
+ pub fn uno_type_any_assign(
+ pDest: *mut uno_Any,
+ pSource: *mut std::ffi::c_void,
+ pType: *mut typelib_TypeDescriptionReference,
+ acquire: Option<uno_AcquireFunc>,
+ release: Option<uno_ReleaseFunc>,
+ );
+
+ /// Constructs an any with a given value
+ pub fn uno_any_construct(
+ pDest: *mut uno_Any,
+ pSource: *mut std::ffi::c_void,
+ pTypeDescr: *mut typelib_TypeDescription,
+ acquire: Option<uno_AcquireFunc>,
+ );
+
+ /// Constructs an any with a given value (using type reference)
+ pub fn uno_type_any_construct(
+ pDest: *mut uno_Any,
+ pSource: *mut std::ffi::c_void,
+ pType: *mut typelib_TypeDescriptionReference,
+ acquire: Option<uno_AcquireFunc>,
+ );
+
+ /// Destructs an any
+ pub fn uno_any_destruct(pValue: *mut uno_Any, release: Option<uno_ReleaseFunc>);
+
+ /// Sets value to void (clears the any)
+ pub fn uno_any_clear(pValue: *mut uno_Any, release: Option<uno_ReleaseFunc>);
+
+ // Get static type descriptors by type class (returns pointer to pointer)
+ pub fn typelib_static_type_getByTypeClass(
+ eTypeClass: typelib_TypeClass,
+ ) -> *mut *mut typelib_TypeDescriptionReference;
+
+}
+
+/// Get type descriptor for boolean values
+pub fn get_boolean_type() -> *mut typelib_TypeDescriptionReference {
+ unsafe {
+ let ptr_ptr =
+ typelib_static_type_getByTypeClass(typelib_TypeClass::typelib_TypeClass_BOOLEAN);
+ *ptr_ptr
+ }
+}
+
+/// Get type descriptor for 32-bit integer values
+pub fn get_long_type() -> *mut typelib_TypeDescriptionReference {
+ unsafe {
+ let ptr_ptr = typelib_static_type_getByTypeClass(typelib_TypeClass::typelib_TypeClass_LONG);
+ *ptr_ptr
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/rust_uno/src/ffi/uno_bridge.rs b/rust_uno/src/ffi/uno_bridge.rs
new file mode 100644
index 000000000000..e85a67d6e301
--- /dev/null
+++ b/rust_uno/src/ffi/uno_bridge.rs
@@ -0,0 +1,37 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! FFI bindings for UNO bridge functionality.
+//!
+//! This module contains direct bindings to C++ functions
+//! in the UNO bridge for core functionality like initialization
+//! and interface management.
+//!
+//! For specific UNO interface method calls, use the auto-generated
+//! FFI functions in the `generated` module instead.
+
+// c_char import removed - no longer needed
+
+// Basic UNO types
+pub use crate::ffi::sal_types::*;
+
+/// Opaque pointer to a UNO XInterface
+pub type XInterface = std::ffi::c_void;
+
+/// Function types for acquire/release callbacks
+#[allow(non_camel_case_types)]
+pub type uno_AcquireFunc = unsafe extern "C" fn(*mut std::ffi::c_void);
+#[allow(non_camel_case_types)]
+pub type uno_ReleaseFunc = unsafe extern "C" fn(*mut std::ffi::c_void);
+
+unsafe extern "C" {
+ /// Direct LibreOffice bootstrap function from cppuhelper
+ /// Returns Reference<XComponentContext> as opaque pointer
+ pub fn defaultBootstrap_InitialComponentContext() -> *mut XInterface;
+}
diff --git a/rust_uno/src/ffi/uno_sequence.rs b/rust_uno/src/ffi/uno_sequence.rs
new file mode 100644
index 000000000000..912557bff6a4
--- /dev/null
+++ b/rust_uno/src/ffi/uno_sequence.rs
@@ -0,0 +1,54 @@
+/* -*- Mode: rust; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//! FFI bindings for UNO Any type operations.
+//!
+//! This module contains direct bindings to LibreOffice's uno_Sequence
+//! C functions for creating, manipulating, and destroying Sequence values.
+//!
+//! These are low-level FFI bindings. For safe Rust wrapper, use
+//! the `Sequence` type from the `core` module instead.
+
+// Allow non-standard naming for FFI types that must match C API exactly
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use std::os::raw::c_void;
+
+use crate::ffi::sal_types::sal_Bool;
+use crate::ffi::type_ffi::*;
+use crate::ffi::uno_bridge::{uno_AcquireFunc, uno_ReleaseFunc};
+
+/// UNO Sequence type - a dynamically sized array type.
+/// This matches the C structure _uno_Sequence from include/uno/sequence.h
+#[repr(C)]
+pub struct uno_Sequence {
+ /// Reference count of sequence
+ pub nRefCount: i32,
+ /// element count
+ pub nElements: i32,
+ /// elements array
+ pub elements: [u8; 0],
+}
+
+unsafe extern "C" {
+ pub fn uno_type_sequence_construct(
+ ppSequence: *mut *mut uno_Sequence,
+ pType: *const typelib_TypeDescription,
+ pElements: *const c_void,
+ nElements: i32,
+ acquire: Option<uno_AcquireFunc>,
+ ) -> sal_Bool;
+
+ pub fn uno_type_sequence_destroy(
+ pSequence: *mut uno_Sequence,
+ pType: *const typelib_TypeDescription,
+ release: Option<uno_ReleaseFunc>,
+ );
+}
diff --git a/rust_uno/src/lib.rs b/rust_uno/src/lib.rs
new file mode 100644
index 000000000000..d716168d53c5
--- /dev/null
+++ b/rust_uno/src/lib.rs
@@ -0,0 +1,24 @@
+//! Generated Rust bindings for LibreOffice UNO types
+//!
+//! This crate contains automatically generated Rust bindings
+//! for LibreOffice UNO (Universal Network Objects) types.
+
+// Core UNO functionality
+pub mod core;
+pub mod examples;
+pub mod ffi;
+
+// Auto-generated FFI bindings
+pub mod generated;
+
+/// Entry point function called by LibreOffice to test Rust UNO bindings
+/// This function is called from desktop/source/app/app.cxx during LibreOffice startup
+#[unsafe(no_mangle)]
+pub extern "C" fn run_rust_uno_test() {
+ println!("=== Rust UNO Bridge Test with Auto-Generated FFI ===");
+
+ // Run the load_writer example to demonstrate service-style FFI functions
+ examples::load_writer::run();
+
+ println!("=== Rust UNO Bridge Test Done ===");
+}
diff --git a/rust_uno/uno_bootstrap.cxx b/rust_uno/uno_bootstrap.cxx
new file mode 100644
index 000000000000..ef75e81e85d7
--- /dev/null
+++ b/rust_uno/uno_bootstrap.cxx
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppuhelper/bootstrap.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/frame/XDesktop.hpp>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::frame;
+
+extern "C" {
+
+/**
+ * C wrapper for cppu::defaultBootstrap_InitialComponentContext()
+ *
+ * This function provides a C interface to the LibreOffice UNO bootstrap
+ * functionality, allowing Rust code to initialize the UNO component context.
+ *
+ * @return XInterface* - Opaque pointer to XComponentContext (as XInterface)
+ * Returns nullptr on failure.
+ */
+SAL_DLLPUBLIC_EXPORT void* defaultBootstrap_InitialComponentContext()
+{
+ SAL_INFO("rust_uno", "Initializing UNO component context for Rust binding");
+
+ try
+ {
+ // Call the actual LibreOffice bootstrap function
+ SAL_INFO("rust_uno", "Calling cppu::defaultBootstrap_InitialComponentContext");
+ Reference<XComponentContext> xContext = cppu::defaultBootstrap_InitialComponentContext();
+
+ if (!xContext.is())
+ {
+ SAL_WARN("rust_uno", "LibreOffice bootstrap failed - component context is invalid");
+ return nullptr;
+ }
+
+ SAL_INFO("rust_uno", "Component context created successfully");
+
+ auto res = new Reference<XComponentContext>(xContext);
+
+ if (!res->is())
+ {
+ SAL_WARN("rust_uno", "Reference wrapper creation failed - context became invalid");
+ delete res;
+ return nullptr;
+ }
+
+ SAL_INFO("rust_uno", "Reference wrapper created successfully - returning context to Rust");
+ // Return as opaque XComponentContext pointer for Rust
+ // Note: This creates a new Reference that transfers ownership to caller
+ return res;
+ }
+ catch (const Exception& e)
+ {
+ SAL_WARN("rust_uno",
+ "UNO exception during component context initialization: " << e.Message);
+ return nullptr;
+ }
+ catch (const std::exception& e)
+ {
+ SAL_WARN("rust_uno",
+ "Standard exception during component context initialization: " << e.what());
+ return nullptr;
+ }
+ catch (...)
+ {
+ SAL_WARN("rust_uno", "Unknown exception during component context initialization");
+ return nullptr;
+ }
+}
+} // extern "C"
diff --git a/sc/inc/SheetView.hxx b/sc/inc/SheetView.hxx
index abb0a3278ca7..cc29eb196423 100644
--- a/sc/inc/SheetView.hxx
+++ b/sc/inc/SheetView.hxx
@@ -10,6 +10,7 @@
#pragma once
#include <vector>
#include "SheetViewTypes.hxx"
+#include "types.hxx"
class ScTable;
@@ -30,6 +31,7 @@ public:
SheetView(ScTable* pTable);
ScTable* getTablePointer() const;
+ SCTAB getTableNumber() const;
/** A sheet view is valid if the pointer to the table is set */
bool isValid() const;
@@ -49,6 +51,7 @@ public:
/** Returns a sheet view for the ID. */
SheetView get(SheetViewID nID);
+ std::vector<SheetView> const& getSheetViews() { return maViews; }
};
}
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 7a4a7a55861e..c7900b8b348d 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -114,7 +114,7 @@ class ExternalDataMapper;
class Sparkline;
class SparklineGroup;
class SparklineList;
-
+class SheetViewManager;
}
class Fraction;
@@ -2401,6 +2401,7 @@ public:
/** Return the sheet view table for the ID */
SCTAB GetSheetViewNumber(SCTAB nTab, sc::SheetViewID nID);
+ std::shared_ptr<sc::SheetViewManager> GetSheetViewManager(SCTAB nTable);
bool IsSheetView(SCTAB nTab) const;
void SetSheetView(SCTAB nTab, bool bSheetView);
diff --git a/sc/qa/unit/tiledrendering/SheetViewTest.cxx b/sc/qa/unit/tiledrendering/SheetViewTest.cxx
index 351ca3d2123c..639dd967007d 100644
--- a/sc/qa/unit/tiledrendering/SheetViewTest.cxx
+++ b/sc/qa/unit/tiledrendering/SheetViewTest.cxx
@@ -86,6 +86,93 @@ CPPUNIT_TEST_FIXTURE(SheetViewTest, testSheetViewAutoFilter)
CPPUNIT_ASSERT_EQUAL(u"7"_ustr, pTabView1->GetCurrentString(0, 4));
}
+CPPUNIT_TEST_FIXTURE(SheetViewTest, testSyncValuesBetweenMainSheetAndSheetView)
+{
+ // Create two views, and leave the second one current.
+ ScModelObj* pModelObj = createDoc("empty.ods");
+ pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ ScDocument* pDocument = pModelObj->GetDocument();
+
+ // Setup 2 views
+ ScTestViewCallback aView1;
+ ScTabViewShell* pTabView1 = aView1.getTabViewShell();
+ SfxLokHelper::createView();
+ Scheduler::ProcessEventsToIdle();
+ ScTestViewCallback aView2;
+ ScTabViewShell* pTabView2 = aView2.getTabViewShell();
+ CPPUNIT_ASSERT(pTabView1 != pTabView2);
+ CPPUNIT_ASSERT(aView1.getViewID() != aView2.getViewID());
+
+ // Setup data
+ // String in A1, and a formula in A2
+ ScAddress aA1(0, 0, 0);
+ ScAddress aA1SheetView(0, 0, 1);
+
+ ScAddress aA2(0, 1, 0);
+ ScAddress aA2SheetView(0, 1, 1);
+
+ typeCharsInCell(std::string("ABCD"), aA1.Col(), aA1.Row(), pTabView1, pModelObj);
+ typeCharsInCell(std::string("=UPPER(\"A\"&\"b\"&\"C\"&\"d\")"), aA2.Col(), aA2.Row(), pTabView1,
+ pModelObj);
+
+ CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pDocument->GetString(aA1));
+ CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pDocument->GetString(aA2));
+
+ // Check what the View1 and View2 sees
+ CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView1->GetCurrentString(aA1.Col(), aA1.Row()));
+ CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView2->GetCurrentString(aA1.Col(), aA1.Row()));
+
+ CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView1->GetCurrentString(aA2.Col(), aA2.Row()));
+ CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pTabView2->GetCurrentString(aA2.Col(), aA2.Row()));
+
+ // Create a sheet view in View2
+ SfxLokHelper::setView(aView2.getViewID());
+ Scheduler::ProcessEventsToIdle();
+ dispatchCommand(mxComponent, u".uno:NewSheetView"_ustr, {});
+
+ // Change content in View1 with default view -> default view ro sheet view sync
+ SfxLokHelper::setView(aView1.getViewID());
+ typeCharsInCell(std::string("XYZ"), aA1.Col(), aA1.Row(), pTabView1, pModelObj);
+ typeCharsInCell(std::string("=UPPER(\"x\"&\"Y\"&\"z\""), aA2.Col(), aA2.Row(), pTabView1,
+ pModelObj);
+
+ // Check the content is synced
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView1->GetCurrentString(aA1.Col(), aA1.Row()));
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView2->GetCurrentString(aA1.Col(), aA1.Row()));
+
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView1->GetCurrentString(aA2.Col(), aA2.Row()));
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pTabView2->GetCurrentString(aA2.Col(), aA2.Row()));
+
+ // Check the content directly in sheets
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA1));
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA1SheetView));
+
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA2));
+ CPPUNIT_ASSERT_EQUAL(u"XYZ"_ustr, pDocument->GetString(aA2SheetView));
+
+ // Change content in the View2 with the sheet view -> sheet view to default view sync
+ SfxLokHelper::setView(aView2.getViewID());
+ Scheduler::ProcessEventsToIdle();
+
+ typeCharsInCell(std::string("ABC123"), aA1.Col(), aA1.Row(), pTabView2, pModelObj);
+ typeCharsInCell(std::string("=UPPER(\"aBc\"&\"123\""), aA2.Col(), aA2.Row(), pTabView2,
+ pModelObj);
+
+ // Check the content is synced
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView1->GetCurrentString(aA1.Col(), aA1.Row()));
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView2->GetCurrentString(aA1.Col(), aA1.Row()));
+
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView1->GetCurrentString(aA2.Col(), aA2.Row()));
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pTabView2->GetCurrentString(aA2.Col(), aA2.Row()));
+
+ // Check the content directly in sheets
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA1));
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA1SheetView));
+
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA2));
+ CPPUNIT_ASSERT_EQUAL(u"ABC123"_ustr, pDocument->GetString(aA2SheetView));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/tiledrendering/data/autofilter.ods b/sc/qa/unit/tiledrendering/data/autofilter.ods
new file mode 100644
index 000000000000..a4ad405fdcc2
--- /dev/null
+++ b/sc/qa/unit/tiledrendering/data/autofilter.ods
Binary files differ
diff --git a/sc/qa/unit/tiledrendering/data/pivotTableFilter.ods b/sc/qa/unit/tiledrendering/data/pivotTableFilter.ods
new file mode 100644
index 000000000000..401b957338e2
--- /dev/null
+++ b/sc/qa/unit/tiledrendering/data/pivotTableFilter.ods
Binary files differ
diff --git a/sc/qa/unit/tiledrendering/data/shape-textbox.ods b/sc/qa/unit/tiledrendering/data/shape-textbox.ods
new file mode 100644
index 000000000000..0904f44f8455
--- /dev/null
+++ b/sc/qa/unit/tiledrendering/data/shape-textbox.ods
Binary files differ
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 90a68ae7d49a..df3035b55b77 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -360,6 +360,34 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testMoveShapeHandle)
}
}
+CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testMoveShapeHandleTextBox)
+{
+ ScModelObj* pModelObj = createDoc("shape-textbox.ods");
+ ScTestViewCallback aView1;
+ pModelObj->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, /*x=*/ 1,/*y=*/ 1,/*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
+ pModelObj->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, /*x=*/ 1, /*y=*/ 1, /*count=*/ 1, /*buttons=*/ 1, /*modifier=*/0);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT(!aView1.m_ShapeSelection.isEmpty());
+ {
+ sal_uInt32 id, x, y;
+ lcl_extractHandleParameters(aView1.m_ShapeSelection, id, x ,y);
+ sal_uInt32 oldX = x;
+ sal_uInt32 oldY = y;
+ uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
+ {
+ {"HandleNum", uno::Any(id)},
+ {"NewPosX", uno::Any(x+1)},
+ {"NewPosY", uno::Any(y+1)}
+ }));
+ dispatchCommand(mxComponent, u".uno:MoveShapeHandle"_ustr, aPropertyValues);
+ CPPUNIT_ASSERT(!aView1.m_ShapeSelection.isEmpty());
+ lcl_extractHandleParameters(aView1.m_ShapeSelection, id, x ,y);
+ CPPUNIT_ASSERT_EQUAL(x-1, oldX);
+ CPPUNIT_ASSERT_EQUAL(y-1, oldY);
+ }
+}
+
CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testColRowResize)
{
ScModelObj* pModelObj = createDoc("sort-range.ods");
@@ -3587,6 +3615,46 @@ CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testCursorVisibilityAfterPaste)
CPPUNIT_ASSERT_EQUAL(true, aView.m_textCursorVisible);
}
+CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testAutoFilterPosition)
+{
+ ScModelObj* pModelObj = createDoc("autofilter.ods");
+ ScTestViewCallback aView;
+ pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ ScTabViewShell* pView = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+
+ pView->SetCursor(0, 0); // Go to A1.
+ Scheduler::ProcessEventsToIdle();
+
+ // Use autofilter button shortcut (ALT + DOWNARROW) to avoid coordinate based click.
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::DOWN | KEY_MOD2);
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::DOWN | KEY_MOD2);
+ Scheduler::ProcessEventsToIdle();
+
+ // We should have the autofilter position callback.
+ auto it = aView.m_aStateChanges.find("AutoFilterInfo");
+ CPPUNIT_ASSERT(it != aView.m_aStateChanges.end());
+}
+
+CPPUNIT_TEST_FIXTURE(ScTiledRenderingTest, testPivotFilterPosition)
+{
+ ScModelObj* pModelObj = createDoc("pivotTableFilter.ods");
+ ScTestViewCallback aView;
+ pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ ScTabViewShell* pView = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+
+ pView->SetCursor(1, 0); // Go to B1.
+ Scheduler::ProcessEventsToIdle();
+
+ // Use filter button shortcut (ALT + DOWNARROW) to avoid coordinate based click.
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::DOWN | KEY_MOD2);
+ pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::DOWN | KEY_MOD2);
+ Scheduler::ProcessEventsToIdle();
+
+ // We should have the autofilter position callback.
+ auto it = aView.m_aStateChanges.find("PivotTableFilterInfo");
+ CPPUNIT_ASSERT(it != aView.m_aStateChanges.end());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/qa/unit/ucalc_sort.cxx b/sc/qa/unit/ucalc_sort.cxx
index 0c24b4b8063b..86e44d9f9699 100644
--- a/sc/qa/unit/ucalc_sort.cxx
+++ b/sc/qa/unit/ucalc_sort.cxx
@@ -30,6 +30,7 @@
#include <svx/svdocirc.hxx>
#include <svx/svdpage.hxx>
#include <rtl/math.hxx>
+#include <unotools/syslocaleoptions.hxx>
class TestSort : public ScUcalcTestBase
{
@@ -2222,6 +2223,66 @@ CPPUNIT_TEST_FIXTURE(TestSort, testQueryBinarySearch)
m_pDoc->DeleteTab(0);
}
+CPPUNIT_TEST_FIXTURE(TestSort, testLanguageDependentNaturalSort)
+{
+ // Set the system locale to "en-US" for to have different decimal separator than "de-EN".
+ SvtSysLocaleOptions aOptions;
+ OUString sLocaleConfigString = aOptions.GetLanguageTag().getBcp47();
+ aOptions.SetLocaleConfigString(u"en-US"_ustr);
+ aOptions.Commit();
+ comphelper::ScopeGuard g([&aOptions, &sLocaleConfigString] {
+ aOptions.SetLocaleConfigString(sLocaleConfigString);
+ aOptions.Commit();
+ });
+
+ // Generate test data
+ m_pDoc->InsertTab(0, u"NaturalSortTest"_ustr);
+ m_pDoc->SetString(ScAddress(0,0,0),u"Item"_ustr); // ScAddress(col, row, tab)
+ m_pDoc->SetString(ScAddress(0,1,0),u"K2,5"_ustr);
+ m_pDoc->SetString(ScAddress(0,2,0),u"K2,501"_ustr);
+ m_pDoc->SetString(ScAddress(0,3,0),u"K10"_ustr);
+ m_pDoc->SetString(ScAddress(0,4,0),u"K1,104"_ustr);
+ m_pDoc->SetString(ScAddress(0,5,0),u"K1,2"_ustr);
+ m_pDoc->SetString(ScAddress(0,6,0),u"K2,40"_ustr);
+ m_pDoc->SetAnonymousDBData(
+ 0, std::unique_ptr<ScDBData>(new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 6)));
+
+ // Create sort parameters
+ ScSortParam aSortParam;
+ aSortParam.nCol1 = 0;
+ aSortParam.nCol2 = 0;
+ aSortParam.nRow1 = 0;
+ aSortParam.nRow2 = 6;
+ aSortParam.bHasHeader = true;
+ aSortParam.bNaturalSort = true; // needs to be adapted when mode 'integer' is implemented
+ aSortParam.bInplace = false;
+ aSortParam.nDestTab = 0;
+ aSortParam.nDestCol = 2;
+ aSortParam.nDestRow = 0;
+ aSortParam.aCollatorLocale = css::lang::Locale(u"de"_ustr, u"DE"_ustr, u""_ustr);
+ aSortParam.maKeyState[0].bDoSort = true;
+ aSortParam.maKeyState[0].nField = 0;
+ aSortParam.maKeyState[0].bAscending = true;
+ aSortParam.maKeyState[0].aColorSortMode = ScColorSortMode::None;
+
+ // Actually sort
+ ScDBDocFunc aFunc(*m_xDocShell);
+ bool bSorted = aFunc.Sort(0, aSortParam, true, true, true);
+ CPPUNIT_ASSERT(bSorted);
+
+ // Verify sort result. Without fix the comma was treated as ordinary character and thus the order
+ // had been Item | K1,2 | K1,104 | K2,5 | K2,40 | K2,501 | K10
+ const std::array<OUString, 7> aExpected
+ = { u"Item"_ustr, u"K1,104"_ustr, u"K1,2"_ustr, u"K2,40"_ustr,
+ u"K2,5"_ustr, u"K2,501"_ustr, u"K10"_ustr };
+ for (SCROW nRow = 0; nRow <= 6; nRow++)
+ {
+ CPPUNIT_ASSERT_EQUAL(aExpected[nRow], m_pDoc->GetString(ScAddress(2, nRow, 0)));
+ }
+
+ m_pDoc->DeleteTab(0);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/SheetView.cxx b/sc/source/core/data/SheetView.cxx
index 05ae7a72cc70..d96719eb13ad 100644
--- a/sc/source/core/data/SheetView.cxx
+++ b/sc/source/core/data/SheetView.cxx
@@ -8,6 +8,7 @@
*/
#include <SheetView.hxx>
+#include <table.hxx>
namespace sc
{
@@ -18,6 +19,11 @@ SheetView::SheetView(ScTable* pTable)
ScTable* SheetView::getTablePointer() const { return mpTable; }
bool SheetView::isValid() const { return mpTable; }
+SCTAB SheetView::getTableNumber() const
+{
+ assert(mpTable);
+ return mpTable->GetTab();
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 761c44612042..fc38a04ae378 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -1148,6 +1148,16 @@ sc::SheetViewID ScDocument::CreateNewSheetView(SCTAB nMainTable, SCTAB nSheetVie
return -1;
}
+std::shared_ptr<sc::SheetViewManager> ScDocument::GetSheetViewManager(SCTAB nTable)
+{
+ if (ScTable* pTable = FetchTable(nTable))
+ {
+ if (!pTable->IsSheetView())
+ return pTable->GetSheetViewManager();
+ }
+ return {};
+}
+
SCTAB ScDocument::GetSheetViewNumber(SCTAB nTab, sc::SheetViewID nID)
{
if (ScTable* pMainSheet = FetchTable(nTab))
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 055617dfec14..a8eb314f935b 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -23,11 +23,13 @@
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <unotools/collatorwrapper.hxx>
+#include <unotools/charclass.hxx>
#include <stdlib.h>
#include <com/sun/star/i18n/KParseTokens.hpp>
#include <com/sun/star/i18n/KParseType.hpp>
#include <sal/log.hxx>
#include <osl/diagnose.h>
+#include <i18nlangtag/languagetag.hxx>
#include <refdata.hxx>
#include <table.hxx>
@@ -83,6 +85,9 @@ using namespace ::com::sun::star::i18n;
@param sWhole
Original string to be split into pieces
+ @param rLanguageTag
+ Contains the language related infos from the sort parameters
+
@param sPrefix
Prefix string that consists of the part before the first number token.
If no number was found, sPrefix is unchanged.
@@ -98,14 +103,15 @@ using namespace ::com::sun::star::i18n;
@return Returns TRUE if a numeral element is found in a given string, or
FALSE if no numeral element is found.
*/
-static bool SplitString( const OUString &sWhole,
- OUString &sPrefix, OUString &sSuffix, double &fNum )
+static bool SplitString(const OUString &sWhole, const LanguageTag& rLanguageTag, OUString &sPrefix,
+ OUString &sSuffix, double &fNum)
{
// Get prefix element, search for any digit and stop.
sal_Int32 nPos = 0;
+ const CharClass aCharClass(rLanguageTag);
while (nPos < sWhole.getLength())
{
- const sal_uInt16 nType = ScGlobal::getCharClass().getCharacterType( sWhole, nPos);
+ const sal_uInt16 nType = aCharClass.getCharacterType( sWhole, nPos);
if (nType & KCharacterType::DIGIT)
break;
sWhole.iterateCodePoints( &nPos );
@@ -116,10 +122,10 @@ static bool SplitString( const OUString &sWhole,
return false;
// Get numeral element
- const OUString& sUser = ScGlobal::getLocaleData().getNumDecimalSep();
- ParseResult aPRNum = ScGlobal::getCharClass().parsePredefinedToken(
- KParseType::ANY_NUMBER, sWhole, nPos,
- KParseTokens::ANY_NUMBER, u""_ustr, KParseTokens::ANY_NUMBER, sUser );
+ const OUString& sUser = LocaleDataWrapper::get(rLanguageTag)->getNumDecimalSep();
+ ParseResult aPRNum = aCharClass.parsePredefinedToken(KParseType::ANY_NUMBER, sWhole, nPos,
+ KParseTokens::ANY_NUMBER, u""_ustr,
+ KParseTokens::ANY_NUMBER, sUser);
if ( aPRNum.EndPos == nPos )
{
@@ -146,6 +152,10 @@ static bool SplitString( const OUString &sWhole,
@param sInput2
Input string 2
+ @param rLanguageTag
+ Contains the language related infos from the sort parameters. They are needed
+ in method SplitString.
+
@param bCaseSens
Boolean value for case sensitivity
@@ -158,16 +168,17 @@ static bool SplitString( const OUString &sWhole,
@return Returns 1 if sInput1 is greater, 0 if sInput1 == sInput2, and -1 if
sInput2 is greater.
*/
-static short Compare( const OUString &sInput1, const OUString &sInput2,
- const bool bCaseSens, const ScUserListData* pData, const CollatorWrapper *pCW )
+static short Compare(const OUString &sInput1, const OUString &sInput2,
+ const LanguageTag& rLanguageTag, const bool bCaseSens,
+ const ScUserListData* pData, const CollatorWrapper *pCW)
{
OUString sStr1( sInput1 ), sStr2( sInput2 ), sPre1, sSuf1, sPre2, sSuf2;
do
{
double nNum1, nNum2;
- bool bNumFound1 = SplitString( sStr1, sPre1, sSuf1, nNum1 );
- bool bNumFound2 = SplitString( sStr2, sPre2, sSuf2, nNum2 );
+ bool bNumFound1 = SplitString( sStr1, rLanguageTag, sPre1, sSuf1, nNum1 );
+ bool bNumFound2 = SplitString( sStr2, rLanguageTag, sPre2, sSuf2, nNum2 );
short nPreRes; // Prefix comparison result
if ( pData )
@@ -1493,6 +1504,7 @@ short ScTable::CompareCell(
bool bUserDef = aSortParam.bUserDef; // custom sort order
bool bNaturalSort = aSortParam.bNaturalSort; // natural sort
bool bCaseSens = aSortParam.bCaseSens; // case sensitivity
+ LanguageTag aSortLanguageTag(aSortParam.aCollatorLocale);
ScUserList& rList = ScGlobal::GetUserList();
if (bUserDef && rList.size() > aSortParam.nUserIndex)
@@ -1500,7 +1512,8 @@ short ScTable::CompareCell(
const ScUserListData& rData = rList[aSortParam.nUserIndex];
if ( bNaturalSort )
- nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, &rData, pSortCollator );
+ nRes = naturalsort::Compare(aStr1, aStr2, aSortLanguageTag, bCaseSens,
+ &rData, pSortCollator);
else
{
if ( bCaseSens )
@@ -1513,7 +1526,8 @@ short ScTable::CompareCell(
if (!bUserDef)
{
if ( bNaturalSort )
- nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, nullptr, pSortCollator );
+ nRes = naturalsort::Compare(aStr1, aStr2, aSortLanguageTag, bCaseSens,
+ nullptr, pSortCollator );
else
nRes = static_cast<short>( pSortCollator->compareString( aStr1, aStr2 ) );
}
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index 1744d3473951..8edd187df9e8 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -136,8 +136,13 @@ void ScInterpreter::ScGetMonth()
void ScInterpreter::ScGetDay()
{
Date aDate = mrContext.NFGetNullDate();
- aDate.AddDays( GetFloor32());
- PushDouble(static_cast<double>(aDate.GetDay()));
+ if (aDate.CheckedAddDays(GetFloor32()))
+ PushDouble(static_cast<double>(aDate.GetDay()));
+ else
+ {
+ SetError(FormulaError::IllegalArgument);
+ PushDouble(HUGE_VAL);
+ }
}
void ScInterpreter::ScGetMin()
diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx
index f4fdbe4fdfe8..868135c74809 100644
--- a/sc/source/ui/app/inputwin.cxx
+++ b/sc/source/ui/app/inputwin.cxx
@@ -1823,8 +1823,6 @@ bool ScTextWnd::Command( const CommandEvent& rCEvt )
return true;
ScModule* mod = ScModule::get();
- // if we focus input after "Accept Formula" command, we need to notify to get it working
- mod->InputChanged(m_xEditView.get());
// information about paragraph is in additional data
// information about position in a paragraph in a Mouse Pos
diff --git a/sc/source/ui/drawfunc/fuins1.cxx b/sc/source/ui/drawfunc/fuins1.cxx
index 38e6684c0dec..d9a1d83568c3 100644
--- a/sc/source/ui/drawfunc/fuins1.cxx
+++ b/sc/source/ui/drawfunc/fuins1.cxx
@@ -37,8 +37,6 @@
#include <avmedia/mediawindow.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
-#include <vcl/GraphicNativeTransform.hxx>
-#include <vcl/GraphicNativeMetadata.hxx>
#include <fuinsert.hxx>
#include <tabvwsh.hxx>
#include <drwlayer.hxx>
@@ -114,16 +112,6 @@ static void lcl_InsertGraphic( const Graphic& rGraphic,
ScAnchorType aAnchorType = SCA_CELL )
{
Graphic& rGraphic1 = const_cast<Graphic &>(rGraphic);
- GraphicNativeMetadata aMetadata;
- if ( aMetadata.read(rGraphic1) )
- {
- const Degree10 aRotation = aMetadata.getRotation();
- if (aRotation)
- {
- GraphicNativeTransform aTransform( rGraphic1 );
- aTransform.rotate( aRotation );
- }
- }
ScDrawView* pDrawView = rViewSh.GetScDrawView();
// #i123922# check if an existing object is selected; if yes, evtl. replace
diff --git a/sc/source/ui/inc/colrowba.hxx b/sc/source/ui/inc/colrowba.hxx
index 536a78dd1d71..57c6204e88dc 100644
--- a/sc/source/ui/inc/colrowba.hxx
+++ b/sc/source/ui/inc/colrowba.hxx
@@ -71,7 +71,6 @@ public:
virtual sal_uInt16 GetEntrySize( SCCOLROW nEntryNo ) const override;
virtual OUString GetEntryText( SCCOLROW nEntryNo ) const override;
- virtual bool IsMirrored() const override;
virtual SCCOLROW GetHiddenCount( SCCOLROW nEntryNo ) const override;
virtual void SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewSize ) override;
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index f12865d3f773..228d5088f527 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -234,6 +234,7 @@ class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::DocWindow, public DropTarget
bool DoPageFieldSelection( SCCOL nCol, SCROW nRow );
bool DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt );
+ void SendAutofilterPopupPosition(SCCOL nCol, SCROW nRow);
void DoPushPivotButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt, bool bButton, bool bPopup, bool bMultiField );
void DoPushPivotToggle( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt );
diff --git a/sc/source/ui/inc/hdrcont.hxx b/sc/source/ui/inc/hdrcont.hxx
index 149db145e2be..86682f78f2e2 100644
--- a/sc/source/ui/inc/hdrcont.hxx
+++ b/sc/source/ui/inc/hdrcont.hxx
@@ -97,7 +97,6 @@ protected:
virtual SCCOLROW GetHiddenCount( SCCOLROW nEntryNo ) const;
virtual bool IsLayoutRTL() const;
- virtual bool IsMirrored() const;
virtual void SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewWidth ) = 0;
virtual void HideEntries( SCCOLROW nStart, SCCOLROW nEnd ) = 0;
diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx
index f05e1981957a..55fe418435ed 100644
--- a/sc/source/ui/inc/viewfunc.hxx
+++ b/sc/source/ui/inc/viewfunc.hxx
@@ -78,7 +78,7 @@ public:
ScViewFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell );
~ScViewFunc();
- SC_DLLPUBLIC const ScPatternAttr* GetSelectionPattern ();
+ SC_DLLPUBLIC const ScPatternAttr* GetSelectionPattern();
SC_DLLPUBLIC OUString GetCurrentString(SCCOL nCol, SCROW nRow);
void GetSelectionFrame(
diff --git a/sc/source/ui/view/colrowba.cxx b/sc/source/ui/view/colrowba.cxx
index 9da02f3f4756..b6653cdb86e5 100644
--- a/sc/source/ui/view/colrowba.cxx
+++ b/sc/source/ui/view/colrowba.cxx
@@ -372,10 +372,4 @@ SCCOLROW ScRowBar::GetHiddenCount( SCCOLROW nEntryNo ) const // override only fo
return rDoc.GetHiddenRowCount( nEntryNo, nTab );
}
-bool ScRowBar::IsMirrored() const // override only for rows
-{
- const ScViewData& rViewData = pTabView->GetViewData();
- return rViewData.GetDocument().IsLayoutRTL( rViewData.CurrentTabForData() );
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index 85cd9b719062..b99dfbbe1cad 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -146,6 +146,7 @@
#include <sfx2/lokhelper.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <tools/json_writer.hxx>
#include <vector>
#include <boost/property_tree/json_parser.hpp>
@@ -938,6 +939,22 @@ void collectUIInformation(const OUString& aRow, const OUString& aCol , const OUS
}
+void ScGridWindow::SendAutofilterPopupPosition(SCCOL nCol, SCROW nRow) {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ if (pViewShell)
+ {
+ tools::JsonWriter writer;
+ writer.put("commandName", "AutoFilterInfo");
+ {
+ const auto aState = writer.startNode("state");
+ writer.put("column", nCol);
+ writer.put("row", nRow);
+ }
+ OString info = writer.finishAndGetAsOString();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, info);
+ }
+}
+
void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
{
SCTAB nTab = mrViewData.CurrentTabForData();
@@ -1009,6 +1026,7 @@ void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
aPos.setY(aPos.getY() / fZoomY);
nSizeX = nSizeX / fZoomX;
nSizeY = nSizeY / fZoomY;
+ SendAutofilterPopupPosition(nCol, nRow); // Send the position of the autofilter popup.
}
tools::Rectangle aCellRect(bLOKActive ? aPos : OutputToScreenPixel(aPos), Size(nSizeX, nSizeY));
@@ -1514,6 +1532,7 @@ void ScGridWindow::LaunchDataSelectMenu(const SCCOL nCol, const SCROW nRow)
// client (effective double scaling) causing wrong positioning/size.
double fZoomX(mrViewData.GetZoomX());
double fZoomY(mrViewData.GetZoomY());
+ assert(fZoomX != 0.0 && fZoomY != 0.0 && "cannot be zero");
aPos.setX(aPos.getX() / fZoomX);
aPos.setY(aPos.getY() / fZoomY);
nSizeX = nSizeX / fZoomX;
diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx
index 519f55f57c28..5c07253e1de8 100644
--- a/sc/source/ui/view/gridwin2.cxx
+++ b/sc/source/ui/view/gridwin2.cxx
@@ -48,6 +48,9 @@
#include <memory>
#include <vector>
+#include <tools/json_writer.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
using namespace css;
using namespace css::sheet;
@@ -549,6 +552,24 @@ void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScreenPosition, const Si
DataPilotFieldOrientation nOrient;
tools::Long nDimIndex = pDPObject->GetHeaderDim(rAddress, nOrient);
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // We send the cell position of the filter button to Online side. So the position of the popup can be adjusted near to the cell.
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ if (pViewShell)
+ {
+ tools::JsonWriter writer;
+ writer.put("commandName", "PivotTableFilterInfo");
+ {
+ const auto aState = writer.startNode("state");
+ writer.put("column", rAddress.Col());
+ writer.put("row", rAddress.Row());
+ }
+ OString info = writer.finishAndGetAsOString();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, info);
+ }
+ }
+
DPLaunchFieldPopupMenu(rScreenPosition, rScreenSize, nDimIndex, pDPObject);
}
diff --git a/sc/source/ui/view/hdrcont.cxx b/sc/source/ui/view/hdrcont.cxx
index 31585c2a8ccd..3aecfb9cc814 100644
--- a/sc/source/ui/view/hdrcont.cxx
+++ b/sc/source/ui/view/hdrcont.cxx
@@ -1073,11 +1073,6 @@ bool ScHeaderControl::IsLayoutRTL() const
return false;
}
-bool ScHeaderControl::IsMirrored() const
-{
- return false;
-}
-
bool ScHeaderControl::IsDisabled() const
{
return false;
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
index 312b9d537aa7..d0002823ef7f 100644
--- a/sc/source/ui/view/viewfun3.cxx
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -2067,10 +2067,15 @@ void ScViewFunc::MakeNewSheetView()
SCTAB nSheetViewTab = nTab + 1;
if (rDoc.CopyTab(nTab, nSheetViewTab))
{
- SetTabNo(nSheetViewTab);
+ // Add and register the created sheet view
rDoc.SetSheetView(nSheetViewTab, true);
sc::SheetViewID nSheetViewID = rDoc.CreateNewSheetView(nTab, nSheetViewTab);
GetViewData().SetSheetViewID(nSheetViewID);
+
+ // Update
+ GetViewData().SetTabNo(nSheetViewTab); // force add the sheet view tab
+ GetViewData().SetTabNo(nTab); // then change back to the current tab
+ PaintExtras(); // update Tab Control
}
}
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index b7df1d6092ef..6c8c43fc1cfd 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -77,6 +77,7 @@
#include <columnspanset.hxx>
#include <stringutil.hxx>
#include <SparklineList.hxx>
+#include <SheetView.hxx>
#include <memory>
@@ -664,36 +665,12 @@ void ScViewFunc::EnterDataToCurrentCell(const OUString& rString, const EditTextO
EnterData(nCol, nRow, nTab, rString, pData, bMatrixExpand);
}
-// input - undo OK
-void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
- const OUString& rString,
- const EditTextObject* pData,
- bool bMatrixExpand )
+namespace
+{
+bool checkFormula(ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString)
{
- ScDocument& rDoc = GetViewData().GetDocument();
- ScMarkData aMark(GetViewData().GetMarkData());
- bool bRecord = rDoc.IsUndoEnabled();
- SCTAB i;
-
- ScDocShell& rDocSh = GetViewData().GetDocShell();
- ScDocFunc &rFunc = GetViewData().GetDocFunc();
- std::shared_ptr<ScDocShellModificator> xModificator = std::make_shared<ScDocShellModificator>(rDocSh);
-
- ScEditableTester aTester( rDoc, nCol,nRow, nCol,nRow, aMark );
- if (!aTester.IsEditable())
- {
- ErrorMessage(aTester.GetMessageId());
- PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
- return;
- }
-
- if ( bRecord )
- rFunc.EnterListAction( STR_UNDO_ENTERDATA );
-
- bool bFormula = false;
-
// do not check formula if it is a text cell
- sal_uInt32 format = rDoc.GetNumberFormat( nCol, nRow, nTab );
+ sal_uInt32 format = rDoc.GetNumberFormat(nCol, nRow, nTab );
SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
// a single '=' character is handled as string (needed for special filters)
if ( pFormatter->GetType(format) != SvNumFormatType::TEXT && rString.getLength() > 1 )
@@ -701,7 +678,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
if ( rString[0] == '=' )
{
// handle as formula
- bFormula = true;
+ return true;
}
else if ( rString[0] == '+' || rString[0] == '-' )
{
@@ -721,65 +698,150 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
double fNumber = 0;
if ( !pFormatter->IsNumberFormat( aString, format, fNumber ) )
{
- bFormula = true;
+ return true;
}
}
}
}
+ return false;
+}
- bool bNumFmtChanged = false;
- if ( bFormula )
- { // formula, compile with autoCorrection
- i = aMark.GetFirstSelected();
- auto xPosPtr = std::make_shared<ScAddress>(nCol, nRow, i);
- auto xCompPtr = std::make_shared<ScCompiler>(rDoc, *xPosPtr, rDoc.GetGrammar(), true, false);
- std::unique_ptr<EditTextObject> xTextObject(pData ? pData->Clone() : nullptr);
+void applyFormulaToCell(ScViewFunc& rViewFunc, SCCOL nCol, SCROW nRow, SCTAB nTab, OUString const& rString,
+ const EditTextObject* pData, std::shared_ptr<ScDocShellModificator> xModificator,
+ ScMarkData const& rMark, bool bMatrixExpand, bool bRecord, bool& rbNumFmtChanged)
+{
+ ScDocument& rDoc = rViewFunc.GetViewData().GetDocument();
- //2do: enable/disable autoCorrection via calcoptions
- xCompPtr->SetAutoCorrection( true );
- if ( rString[0] == '+' || rString[0] == '-' )
- {
- xCompPtr->SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
- }
+ // formula, compile with autoCorrection
+ auto xPosPtr = std::make_shared<ScAddress>(nCol, nRow, nTab);
+ auto xCompPtr = std::make_shared<ScCompiler>(rDoc, *xPosPtr, rDoc.GetGrammar(), true, false);
+ std::unique_ptr<EditTextObject> xTextObject(pData ? pData->Clone() : nullptr);
+
+ //2do: enable/disable autoCorrection via calcoptions
+ xCompPtr->SetAutoCorrection( true );
+ if (rString[0] == '+' || rString[0] == '-')
+ {
+ xCompPtr->SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
+ }
- OUString aFormula( rString );
+ OUString aFormula(rString);
- FormulaProcessingContext context_instance{
- std::move(xPosPtr), std::move(xCompPtr), std::move(xModificator), nullptr,
- nullptr, std::move(xTextObject), std::move(aMark), *this,
- OUString(), aFormula, rString, nCol,
- nRow, nTab, bMatrixExpand, bNumFmtChanged,
- bRecord
- };
+ FormulaProcessingContext context_instance{
+ std::move(xPosPtr), std::move(xCompPtr), xModificator, nullptr,
+ nullptr, std::move(xTextObject), rMark, rViewFunc,
+ OUString(), aFormula, rString, nCol,
+ nRow, nTab, bMatrixExpand, rbNumFmtChanged,
+ bRecord
+ };
- parseAndCorrectFormula(std::make_shared<FormulaProcessingContext>(context_instance));
+ parseAndCorrectFormula(std::make_shared<FormulaProcessingContext>(context_instance));
+}
+
+void applyText(ScViewFunc& rViewFunc, SCCOL nCol, SCROW nRow, SCTAB nTab, OUString const& rString, bool& rbNumFmtChanged)
+{
+ ScViewData& rViewData = rViewFunc.GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDocShell& rDocSh = rViewData.GetDocShell();
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ ScDocFunc& rFunc = rViewData.GetDocFunc();
+
+ bool bNumFmtSet = false;
+ const ScAddress aAddress(nCol, nRow, nTab);
+
+ // tdf#104902 - handle embedded newline
+ if (ScStringUtil::isMultiline(rString))
+ {
+ rEngine.SetTextCurrentDefaults(rString);
+ rDoc.SetEditText(aAddress, rEngine.CreateTextObject());
+ rDocSh.AdjustRowHeight(nRow, nRow, nTab);
}
else
{
- ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
- for (const auto& rTab : aMark)
+ rFunc.SetNormalString(bNumFmtSet, aAddress, rString, false);
+ }
+
+ if (bNumFmtSet)
+ {
+ /* FIXME: if set on any sheet results in changed only on
+ * sheet nTab for TestFormatArea() and DoAutoAttributes() */
+ rbNumFmtChanged = true;
+ }
+}
+
+} // end anonymous namespace
+
+// input - undo OK
+void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const OUString& rString,
+ const EditTextObject* pData,
+ bool bMatrixExpand )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData aMark(GetViewData().GetMarkData());
+ bool bRecord = rDoc.IsUndoEnabled();
+
+ ScDocFunc &rFunc = GetViewData().GetDocFunc();
+ std::shared_ptr<ScDocShellModificator> xModificator = std::make_shared<ScDocShellModificator>(GetViewData().GetDocShell());
+
+ ScEditableTester aTester( rDoc, nCol,nRow, nCol,nRow, aMark );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
+ return;
+ }
+
+ if ( bRecord )
+ rFunc.EnterListAction( STR_UNDO_ENTERDATA );
+
+ bool bFormula = checkFormula(rDoc, nCol, nRow, nTab, rString);
+ bool bNumFmtChanged = false;
+
+ if (bFormula)
+ {
+ SCTAB nSelectedTab = aMark.GetFirstSelected();
+
+ applyFormulaToCell(*this, nCol, nRow, nTab, rString, pData, xModificator, aMark, bMatrixExpand, bRecord, bNumFmtChanged);
+
+ if (!rDoc.IsSheetView(nSelectedTab))
{
- bool bNumFmtSet = false;
- const ScAddress aScAddress(nCol, nRow, rTab);
+ auto pManager = rDoc.GetSheetViewManager(nSelectedTab);
- // tdf#104902 - handle embedded newline
- if (ScStringUtil::isMultiline(rString))
+ for (auto const& rSheetView : pManager->getSheetViews())
{
- rEngine.SetTextCurrentDefaults(rString);
- rDoc.SetEditText(aScAddress, rEngine.CreateTextObject());
- rDocSh.AdjustRowHeight(nRow, nRow, rTab);
+ if (!rSheetView.isValid())
+ continue;
+
+ SCTAB nSheetViewTab = rSheetView.getTableNumber();
+
+ ScMarkData aSheetViewMark(rDoc.GetSheetLimits());
+ aSheetViewMark.SelectTable(nSheetViewTab, false);
+ ScRange aSheetViewRange(aMark.GetMarkArea());
+ aSheetViewRange.aStart.SetTab(nSheetViewTab);
+ aSheetViewRange.aEnd.SetTab(nSheetViewTab);
+ aSheetViewMark.SetMarkArea(aSheetViewRange);
+
+ applyFormulaToCell(*this, nCol, nRow, nSheetViewTab, rString, pData, xModificator, aSheetViewMark, bMatrixExpand, bRecord, bNumFmtChanged);
}
- else
+ }
+ }
+ else
+ {
+ for (const auto& rTab : aMark)
+ {
+ if (!rDoc.IsSheetView(rTab))
{
- rFunc.SetNormalString(bNumFmtSet, aScAddress, rString, false);
- }
+ auto pManager = rDoc.GetSheetViewManager(rTab);
+ for (auto const& rSheetView : pManager->getSheetViews())
+ {
+ if (!rSheetView.isValid())
+ continue;
- if (bNumFmtSet)
- {
- /* FIXME: if set on any sheet results in changed only on
- * sheet nTab for TestFormatArea() and DoAutoAttributes() */
- bNumFmtChanged = true;
+ SCTAB nSheetViewTab = rSheetView.getTableNumber();
+ applyText(*this, nCol, nRow, nSheetViewTab, rString, bNumFmtChanged);
+ }
}
+ applyText(*this, nCol, nRow, rTab, rString, bNumFmtChanged);
}
performAutoFormatAndUpdate(rString, aMark, nCol, nRow, nTab, bNumFmtChanged, bRecord, xModificator, *this);
}
diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
index 05bc58c52dc7..0721512cbf7b 100644
--- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
@@ -4188,10 +4188,42 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
<rng:define name="text-changed-region" combine="choice">
<rng:element name="text:changed-region">
<rng:ref name="text-changed-region-attr"/>
- <rng:ref name="text-changed-region-content"/>
- <rng:optional>
- <rng:ref name="text-changed-region-content"/>
- </rng:optional>
+ <rng:choice>
+ <rng:ref name="text-changed-region-content-insertion"/>
+ <rng:group>
+ <rng:ref name="text-changed-region-content-deletion"/>
+ <rng:optional>
+ <rng:ref name="text-changed-region-content-insertion"/>
+ </rng:optional>
+ </rng:group>
+ <rng:group>
+ <rng:ref name="text-changed-region-content-format-change"/>
+ <rng:optional>
+ <rng:choice>
+ <rng:ref name="text-changed-region-content-insertion"/>
+ <rng:ref name="text-changed-region-content-deletion"/>
+ </rng:choice>
+ </rng:optional>
+ </rng:group>
+ </rng:choice>
+ </rng:element>
+ </rng:define>
+ <rng:define name="text-changed-region-content-insertion">
+ <rng:element name="text:insertion">
+ <rng:ref name="office-change-info"/>
+ </rng:element>
+ </rng:define>
+ <rng:define name="text-changed-region-content-deletion">
+ <rng:element name="text:deletion">
+ <rng:ref name="office-change-info"/>
+ <rng:zeroOrMore>
+ <rng:ref name="text-content"/>
+ </rng:zeroOrMore>
+ </rng:element>
+ </rng:define>
+ <rng:define name="text-changed-region-content-format-change">
+ <rng:element name="text:format-change">
+ <rng:ref name="office-change-info"/>
</rng:element>
</rng:define>
diff --git a/sd/qa/uitest/impress_tests2/tdf146019.py b/sd/qa/uitest/impress_tests2/tdf146019.py
index 86b8ed48180f..dc568b5151c2 100644
--- a/sd/qa/uitest/impress_tests2/tdf146019.py
+++ b/sd/qa/uitest/impress_tests2/tdf146019.py
@@ -29,7 +29,7 @@ class tdf146019(UITestCase):
# Check the shape is rotated, height > width
shape = document.getDrawPages()[0][2]
- self.assertEqual(8996, shape.getSize().Width)
- self.assertEqual(11745, shape.getSize().Height)
+ self.assertEqual(8995, shape.getSize().Width)
+ self.assertEqual(11746, shape.getSize().Height)
# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sd/source/ui/func/fuinsert.cxx b/sd/source/ui/func/fuinsert.cxx
index 041a4465172a..1b88fc4ff891 100644
--- a/sd/source/ui/func/fuinsert.cxx
+++ b/sd/source/ui/func/fuinsert.cxx
@@ -80,9 +80,6 @@
#include <vcl/errinf.hxx>
#include <vcl/graphicfilter.hxx>
-#include <vcl/GraphicNativeTransform.hxx>
-#include <vcl/GraphicNativeMetadata.hxx>
-
#include <comphelper/lok.hxx>
using namespace com::sun::star;
@@ -156,16 +153,6 @@ void FuInsertGraphic::DoExecute( SfxRequest& rReq )
if( nError == ERRCODE_NONE )
{
- GraphicNativeMetadata aMetadata;
- if ( aMetadata.read(aGraphic) )
- {
- const Degree10 aRotation = aMetadata.getRotation();
- if (aRotation)
- {
- GraphicNativeTransform aTransform( aGraphic );
- aTransform.rotate( aRotation );
- }
- }
if( dynamic_cast< DrawViewShell *>( &mrViewShell ) )
{
sal_Int8 nAction = DND_ACTION_COPY;
diff --git a/sd/source/ui/view/sdview3.cxx b/sd/source/ui/view/sdview3.cxx
index d692c80b2397..6d89abe6b32b 100644
--- a/sd/source/ui/view/sdview3.cxx
+++ b/sd/source/ui/view/sdview3.cxx
@@ -722,12 +722,13 @@ bool View::InsertData( const TransferableDataHelper& rDataHelper,
if (ShouldTry(SotClipboardFormatId::EMBED_SOURCE))
{
- sd::slidesorter::SlideSorter& xSlideSorter
- = ::sd::slidesorter::SlideSorterViewShell::GetSlideSorter(
- mrDoc.GetDocSh()->GetViewShell()->GetViewShellBase())
- ->GetSlideSorter();
- if (xSlideSorter.GetController().GetClipboard().PasteSlidesFromSystemClipboard())
- return true;
+ if (::sd::slidesorter::SlideSorterViewShell* pSlideSorterViewShell =
+ ::sd::slidesorter::SlideSorterViewShell::GetSlideSorter(
+ mrDoc.GetDocSh()->GetViewShell()->GetViewShellBase()))
+ {
+ if (pSlideSorterViewShell->GetSlideSorter().GetController().GetClipboard().PasteSlidesFromSystemClipboard())
+ return true;
+ }
}
if (ShouldTry(SotClipboardFormatId::DRAWING))
diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx
index 1d7241f42756..8f242373bb70 100644
--- a/sfx2/source/doc/guisaveas.cxx
+++ b/sfx2/source/doc/guisaveas.cxx
@@ -2095,7 +2095,8 @@ bool SfxStoringHelper::WarnUnacceptableFormat( const uno::Reference< frame::XMod
}
VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
- auto pDlg = pFact->CreateQueryDialog(pWin, SfxResId(STR_QUERY_ALIENFORMAT_TTITLE), sInfoText, sQuestion, true);
+ bool bShowAgain = !officecfg::Office::Common::Save::Document::WarnAlienFormat::isReadOnly();
+ auto pDlg = pFact->CreateQueryDialog(pWin, SfxResId(STR_QUERY_ALIENFORMAT_TTITLE), sInfoText, sQuestion, bShowAgain);
pDlg->SetYesLabel(SfxResId(STR_QUERY_ALIENFORMAT_YES).replaceAll("%FORMATNAME", aOldUIName)); // "Use %FORMATNAME Format"
pDlg->SetNoLabel(SfxResId(STR_QUERY_ALIENFORMAT_NO).replaceAll("%DEFAULTEXTENSION", sExtension)); // "Use %DEFAULTEXTENSION _Format"
diff --git a/sfx2/source/view/classificationhelper.cxx b/sfx2/source/view/classificationhelper.cxx
index b74f2486d2a9..d35df6733a05 100644
--- a/sfx2/source/view/classificationhelper.cxx
+++ b/sfx2/source/view/classificationhelper.cxx
@@ -13,6 +13,10 @@
#include <algorithm>
#include <iterator>
+#include <frozen/bits/defines.h>
+#include <frozen/bits/elsa_std.h>
+#include <frozen/unordered_map.h>
+
#include <com/sun/star/beans/XPropertyContainer.hpp>
#include <com/sun/star/beans/Property.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
@@ -761,12 +765,12 @@ sal_Int32 SfxClassificationHelper::GetImpactLevel()
}
else if (aScale == "FIPS-199")
{
- static std::map<OUString, sal_Int32> const aValues
+ static auto constexpr aValues = frozen::make_unordered_map<std::u16string_view, sal_Int32>(
{
- { "Low", 0 },
- { "Moderate", 1 },
- { "High", 2 }
- };
+ { u"Low", 0 },
+ { u"Moderate", 1 },
+ { u"High", 2 }
+ });
auto itValues = aValues.find(aLevel);
if (itValues == aValues.end())
return nRet;
diff --git a/sfx2/source/view/lokhelper.cxx b/sfx2/source/view/lokhelper.cxx
index d27e0cbca0d9..495eefd13029 100644
--- a/sfx2/source/view/lokhelper.cxx
+++ b/sfx2/source/view/lokhelper.cxx
@@ -679,6 +679,16 @@ void SfxLokHelper::notifyWindow(const SfxViewShell* pThisView,
pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_WINDOW, s);
}
+void SfxLokHelper::notifyCursorInvalidation(SfxViewShell const* pThisView, tools::Rectangle const* pRect, bool bControlEvent)
+{
+ int nViewId = SfxLokHelper::getView(*pThisView);
+ OString sPayload = OString::Concat("{ \"viewId\": \"") + OString::number(nViewId) + "\", \"rectangle\": \"" + pRect->toString();
+ if (bControlEvent)
+ sPayload += "\", \"controlEvent\": true";
+ sPayload += " }";
+ pThisView->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, sPayload);
+}
+
void SfxLokHelper::notifyInvalidation(SfxViewShell const* pThisView, tools::Rectangle const* pRect)
{
// -1 means all parts
diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx
index 98d3ee3a237d..a8e1e6237579 100644
--- a/sfx2/source/view/viewsh.cxx
+++ b/sfx2/source/view/viewsh.cxx
@@ -3565,6 +3565,11 @@ void SfxViewShell::notifyInvalidation(tools::Rectangle const* pRect) const
SfxLokHelper::notifyInvalidation(this, pRect);
}
+void SfxViewShell::notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent) const
+{
+ SfxLokHelper::notifyCursorInvalidation(this, pRect, bControlEvent);
+}
+
void SfxViewShell::NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload)
{
SfxLokHelper::notifyOtherViews(this, nType, rKey, rPayload);
diff --git a/solenv/gbuild/DotnetTest.mk b/solenv/gbuild/DotnetTest.mk
index c51487cecf5c..635797cf782f 100644
--- a/solenv/gbuild/DotnetTest.mk
+++ b/solenv/gbuild/DotnetTest.mk
@@ -72,7 +72,7 @@ define gb_DotnetTest_DotnetTest
gb_DotnetTest_$(1)_language := $(2)
gb_DotnetTest_$(1)_project := $(gb_DotnetTest_workdir)/$(1)/$(1).$(2)proj
-$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS := <TargetFramework>net8.0</TargetFramework>
+$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS := <TargetFramework>net$$(shell "$$(DOTNET)" --version | cut -d. -f1-2)</TargetFramework>
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += <IsPackable>false</IsPackable>
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += <IsTestProject>true</IsTestProject>
$$(gb_DotnetTest_$(1)_project) : DOTNET_PROPERTY_ELEMENTS += <AssemblyName>$(1)</AssemblyName>
diff --git a/solenv/gbuild/platform/com_GCC_defs.mk b/solenv/gbuild/platform/com_GCC_defs.mk
index 4e41aa48233f..31900e8b9551 100644
--- a/solenv/gbuild/platform/com_GCC_defs.mk
+++ b/solenv/gbuild/platform/com_GCC_defs.mk
@@ -46,7 +46,6 @@ gb_COMPILEROPTFLAGS += $(if $(ENABLE_HARDENING_FLAGS),$(HARDENING_OPT_CFLAGS))
gb_AFLAGS := $(AFLAGS)
gb_COMPILERDEFS := \
- -DBOOST_SYSTEM_NO_DEPRECATED \
-DCPPU_ENV=$(CPPU_ENV) \
$(if $(filter EMSCRIPTEN,$(OS)),-U_FORTIFY_SOURCE) \
diff --git a/solenv/gbuild/platform/com_MSC_defs.mk b/solenv/gbuild/platform/com_MSC_defs.mk
index e915036b54c8..12bac932532d 100644
--- a/solenv/gbuild/platform/com_MSC_defs.mk
+++ b/solenv/gbuild/platform/com_MSC_defs.mk
@@ -47,7 +47,6 @@ endif
gb_COMPILERDEFS := \
-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE \
- -DBOOST_SYSTEM_NO_DEPRECATED \
-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING \
-D_SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING \
-D_SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING \
diff --git a/svtools/source/brwbox/brwbox3.cxx b/svtools/source/brwbox/brwbox3.cxx
index b7f209ac8180..f72903e089c8 100644
--- a/svtools/source/brwbox/brwbox3.cxx
+++ b/svtools/source/brwbox/brwbox3.cxx
@@ -69,11 +69,9 @@ rtl::Reference<comphelper::OAccessible> BrowseBox::CreateAccessible()
{
if (!m_xAccessible)
{
- Reference<XAccessible> xAccParent = GetAccessibleParent();
- if( xAccParent.is() )
- {
- m_xAccessible = new AccessibleBrowseBox(xAccParent, *this);
- }
+ rtl::Reference<comphelper::OAccessible> pAccParent = GetAccessibleParent();
+ if (pAccParent.is())
+ m_xAccessible = new AccessibleBrowseBox(pAccParent, *this);
}
return m_xAccessible;
diff --git a/sw/CppunitTest_sw_filter_md.mk b/sw/CppunitTest_sw_filter_md.mk
index 533e6b9d6529..c16777849709 100644
--- a/sw/CppunitTest_sw_filter_md.mk
+++ b/sw/CppunitTest_sw_filter_md.mk
@@ -18,6 +18,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sw_filter_md, \
$(eval $(call gb_CppunitTest_use_libraries,sw_filter_md, \
cppu \
cppuhelper \
+ editeng \
sal \
subsequenttest \
sw \
diff --git a/sw/inc/init.hxx b/sw/inc/init.hxx
index 5c6e358c0a01..11c9936b14b6 100644
--- a/sw/inc/init.hxx
+++ b/sw/inc/init.hxx
@@ -32,7 +32,7 @@ class ItemInfoPackage;
void InitCore(); // bastyp/init.cxx
void FinitCore();
-ItemInfoPackage& getItemInfoPackageSwAttributes();
+std::unique_ptr<ItemInfoPackage> createItemInfoPackageSwAttributes();
namespace sw {
diff --git a/sw/inc/pagedesc.hxx b/sw/inc/pagedesc.hxx
index c213b03bf34c..0113371b7de8 100644
--- a/sw/inc/pagedesc.hxx
+++ b/sw/inc/pagedesc.hxx
@@ -244,6 +244,9 @@ public:
const SwFrameFormat &GetFirstMaster() const { return m_FirstMaster; }
const SwFrameFormat &GetFirstLeft() const { return m_FirstLeft; }
+ /// Set format properties on all non-shared odd/even/first headers (or footers)
+ bool SetFormatAttrOnAll(const SfxItemSet& rSet, const bool bHeader);
+
/** Reset all attrs of the format but keep the ones a pagedesc
cannot live without. */
inline void ResetAllMasterAttr();
diff --git a/sw/inc/swatrset.hxx b/sw/inc/swatrset.hxx
index ead0d7dcb11c..8e3df5fcb145 100644
--- a/sw/inc/swatrset.hxx
+++ b/sw/inc/swatrset.hxx
@@ -27,6 +27,7 @@
class SwDoc;
class OutputDevice;
class IDocumentSettingAccess;
+class ItemInfoPackage;
class SvxPostureItem;
class SvxWeightItem;
class SvxShadowedItem;
@@ -149,7 +150,7 @@ private:
SwDoc& m_rDoc;
public:
- SwAttrPool( SwDoc& rDoc );
+ SwAttrPool(ItemInfoPackage& rInfoPackage, SwDoc& rDoc);
private:
virtual ~SwAttrPool() override;
public:
diff --git a/sw/inc/swmodule.hxx b/sw/inc/swmodule.hxx
index fbd29640a160..d860b75f62af 100644
--- a/sw/inc/swmodule.hxx
+++ b/sw/inc/swmodule.hxx
@@ -36,6 +36,7 @@
#include "fldupde.hxx"
class Color;
+class ItemInfoPackage;
class SfxItemSet;
class SfxRequest;
class SfxErrorHandler;
@@ -94,6 +95,7 @@ class SAL_DLLPUBLIC_RTTI SwModule final : public SfxModule, public SfxListener,
std::unique_ptr<SwTableAutoFormatTable> m_xTableAutoFormatTable;
+ std::unique_ptr<ItemInfoPackage> m_xItemInfoPackageSwAttributes;
// Current view is held here in order to avoid one's being forced
// to work via GetActiveView.
@@ -233,6 +235,11 @@ public:
virtual std::unique_ptr<SfxTabPage> CreateTabPage( sal_uInt16 nId, weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet ) override;
SW_DLLPUBLIC virtual SfxStyleFamilies CreateStyleFamilies() override;
+ void InitItemInfoPackageSwAttributes();
+ void RemoveItemInfoPackageSwAttributes();
+
+ ItemInfoPackage& getItemInfoPackageSwAttributes();
+
// Invalidates online spell-wrong-lists if necessary.
static void CheckSpellChanges( bool bOnlineSpelling,
bool bIsSpellWrongAgain, bool bIsSpellAllAgain, bool bSmartTags );
diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx
index 7380d225139c..843536a5026d 100644
--- a/sw/inc/view.hxx
+++ b/sw/inc/view.hxx
@@ -272,7 +272,7 @@ class SW_DLLPUBLIC SwView: public SfxViewShell
int m_nMaxOutlineLevelShown = 10;
- bool m_bIsHighlightCharDF = false;
+ bool m_bIsSpotlightCharDF = false;
bool m_bIsSpotlightParaStyles = false;
bool m_bIsSpotlightCharStyles = false;
@@ -734,7 +734,7 @@ public:
virtual void flushPendingLOKInvalidateTiles() override;
virtual std::optional<OString> getLOKPayload(int nType, int nViewId) const override;
- bool IsHighlightCharDF() const { return m_bIsHighlightCharDF; }
+ bool IsSpotlightCharDF() const { return m_bIsSpotlightCharDF; }
bool IsSpotlightParaStyles() const { return m_bIsSpotlightParaStyles; }
bool IsSpotlightCharStyles() const { return m_bIsSpotlightCharStyles; }
diff --git a/sw/qa/extras/mailmerge/data/mm-single-date.fodt b/sw/qa/extras/mailmerge/data/mm-single-date.fodt
new file mode 100644
index 000000000000..d8fcf2e27c1a
--- /dev/null
+++ b/sw/qa/extras/mailmerge/data/mm-single-date.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:settings>
+ <config:config-item-set config:name="ooo:configuration-settings">
+ <config:config-item config:name="CurrentDatabaseDataSource" config:type="string">single-date</config:config-item>
+ <config:config-item config:name="CurrentDatabaseCommand" config:type="string">Sheet1</config:config-item>
+ <config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
+ </config:config-item-set>
+ </office:settings>
+ <office:automatic-styles>
+ <number:date-style style:name="ISO" number:language="en" number:country="US">
+ <number:year number:style="long"/>
+ <number:text>-</number:text>
+ <number:month number:style="long"/>
+ <number:text>-</number:text>
+ <number:day number:style="long"/>
+ </number:date-style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p><text:database-display text:table-name="Sheet1" text:table-type="table" text:column-name="date" style:data-style-name="ISO" text:database-name="single-date">&lt;date&gt;</text:database-display></text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/mailmerge/data/single-date.ods b/sw/qa/extras/mailmerge/data/single-date.ods
new file mode 100644
index 000000000000..6f3d36ddefa2
--- /dev/null
+++ b/sw/qa/extras/mailmerge/data/single-date.ods
Binary files differ
diff --git a/sw/qa/extras/mailmerge/mailmerge2.cxx b/sw/qa/extras/mailmerge/mailmerge2.cxx
index de3c8fb770c6..e1f21e2089ad 100644
--- a/sw/qa/extras/mailmerge/mailmerge2.cxx
+++ b/sw/qa/extras/mailmerge/mailmerge2.cxx
@@ -432,6 +432,20 @@ CPPUNIT_TEST_FIXTURE(MMTest2, testTdf156061)
getXPath(pXmlDoc, "//txt[2]/infos/bounds", "height").toInt32());
}
+// The document has a MM field referencing a date in the data source having a single record.
+// The check ensures that the date arrives correctly to the merged document.
+DECLARE_SHELL_MAILMERGE_TEST(testTdf168252, "mm-single-date.fodt", "single-date.ods", "Sheet1")
+{
+ executeMailMerge();
+ CPPUNIT_ASSERT(mxSwTextDocument);
+
+ // Without the fix, this would fail with
+ // - Expected: 2025-08-31
+ // - Actual : 2025-09-02
+ // because the DB filed code assumed obsolete null date.
+ CPPUNIT_ASSERT_EQUAL(u"2025-08-31"_ustr, mxSwTextDocument->getText()->getString());
+}
+
} // end of anonymous namespace
namespace com::sun::star::table {
diff --git a/sw/qa/filter/md/md.cxx b/sw/qa/filter/md/md.cxx
index 2f62fa80703b..824b80d3874d 100644
--- a/sw/qa/filter/md/md.cxx
+++ b/sw/qa/filter/md/md.cxx
@@ -355,7 +355,7 @@ CPPUNIT_TEST_FIXTURE(Test, testExportingTable)
SAL_NEWLINE_STRING
"| A1 | B1 | C1 |" SAL_NEWLINE_STRING
// Delimiter row consists of cells whose only content are hyphens (-).
- "|-|-|-|" SAL_NEWLINE_STRING
+ "| - | - | - |" SAL_NEWLINE_STRING
"| A2 | B2 | C2 |" SAL_NEWLINE_STRING
"| A3 | B3 | C3 |" SAL_NEWLINE_STRING
SAL_NEWLINE_STRING
@@ -463,6 +463,48 @@ CPPUNIT_TEST_FIXTURE(Test, testCodeBlockMdExport)
CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
}
+CPPUNIT_TEST_FIXTURE(Test, testTableColumnAdjustMdExport)
+{
+ // Given a document that has a table with custom adjustments:
+ createSwDoc();
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ pWrtShell->Insert(u"before"_ustr);
+ SwInsertTableOptions aInsertTableOptions(SwInsertTableFlags::DefaultBorder,
+ /*nRowsToRepeat=*/0);
+ pWrtShell->InsertTable(aInsertTableOptions, /*nRows=*/1, /*nCols=*/3);
+ pWrtShell->Insert(u"after"_ustr);
+ pWrtShell->SttPara();
+ pWrtShell->MoveTable(GotoPrevTable, fnTableStart);
+ pWrtShell->Insert(u"A1"_ustr);
+ pWrtShell->GoNextCell();
+ pWrtShell->Insert(u"B1"_ustr);
+ pWrtShell->SetAttrItem(SvxAdjustItem(SvxAdjust::Center, RES_PARATR_ADJUST));
+ pWrtShell->GoNextCell();
+ pWrtShell->Insert(u"C1"_ustr);
+ pWrtShell->SetAttrItem(SvxAdjustItem(SvxAdjust::Right, RES_PARATR_ADJUST));
+
+ // When saving that to markdown:
+ save(mpFilter);
+
+ // Then make sure the table content is not lost:
+ std::string aActual = TempFileToString();
+ std::string aExpected(
+ // clang-format off
+ "before" SAL_NEWLINE_STRING
+ SAL_NEWLINE_STRING
+ "| A1 | B1 | C1 |" SAL_NEWLINE_STRING
+ "| - | :-: | -: |" SAL_NEWLINE_STRING
+ SAL_NEWLINE_STRING
+ "after" SAL_NEWLINE_STRING
+ // clang-format on
+ );
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Actual : | - | - | - |
+ // i.e. the delimiter row's cell adjustments were lost.
+ CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/source/core/attr/hints.cxx b/sw/source/core/attr/hints.cxx
index 8aaabaf26816..a585aa81453a 100644
--- a/sw/source/core/attr/hints.cxx
+++ b/sw/source/core/attr/hints.cxx
@@ -21,6 +21,7 @@
#include <hintids.hxx>
#include <hints.hxx>
#include <ndtxt.hxx>
+#include <swmodule.hxx>
#include <swtypes.hxx>
#include <init.hxx>
#include <svl/languageoptions.hxx>
@@ -136,11 +137,11 @@ const SfxPoolItem* GetDfltAttr(sal_uInt16 nWhich)
{
#ifdef DBG_UTIL
OSL_ASSERT(nWhich < POOLATTR_END && nWhich >= POOLATTR_BEGIN);
- const SfxPoolItem* pRetval(getItemInfoPackageSwAttributes().getExistingItemInfo(nWhich - POOLATTR_BEGIN).getItem());
+ const SfxPoolItem* pRetval(SwModule::get()->getItemInfoPackageSwAttributes().getExistingItemInfo(nWhich - POOLATTR_BEGIN).getItem());
OSL_ENSURE(pRetval, "GetDfltFormatAttr(): Dflt == 0");
return pRetval;
#else
- return getItemInfoPackageSwAttributes().getExistingItemInfo(nWhich - POOLATTR_BEGIN).getItem();
+ return SwModule::get()->getItemInfoPackageSwAttributes().getExistingItemInfo(nWhich - POOLATTR_BEGIN).getItem();
#endif
}
diff --git a/sw/source/core/attr/swatrset.cxx b/sw/source/core/attr/swatrset.cxx
index 76865e745aac..f7f49dcef96e 100644
--- a/sw/source/core/attr/swatrset.cxx
+++ b/sw/source/core/attr/swatrset.cxx
@@ -45,11 +45,11 @@
-SwAttrPool::SwAttrPool(SwDoc& rDoc)
+SwAttrPool::SwAttrPool(ItemInfoPackage& rInfoPackage, SwDoc& rDoc)
: SfxItemPool(u"SWG"_ustr)
, m_rDoc(rDoc)
{
- registerItemInfoPackage(getItemInfoPackageSwAttributes());
+ registerItemInfoPackage(rInfoPackage);
// create SfxItemPool and EditEngine pool and add these in a chain. These
// belong us and will be removed/destroyed in removeAndDeleteSecondaryPools() used from
diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index ab482bfda115..21a5cc10c32f 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -271,7 +271,7 @@ SwTOXMark* createSwTOXMarkForItemInfoPackage()
return new SwTOXMark();
}
-ItemInfoPackage& getItemInfoPackageSwAttributes()
+std::unique_ptr<ItemInfoPackage> createItemInfoPackageSwAttributes()
{
class ItemInfoPackageSwAttributes : public ItemInfoPackage
{
@@ -496,11 +496,7 @@ ItemInfoPackage& getItemInfoPackageSwAttributes()
}
};
-
- static std::unique_ptr<ItemInfoPackageSwAttributes> g_aItemInfoPackageSwAttributes;
- if (!g_aItemInfoPackageSwAttributes)
- g_aItemInfoPackageSwAttributes.reset(new ItemInfoPackageSwAttributes);
- return *g_aItemInfoPackageSwAttributes;
+ return std::make_unique<ItemInfoPackageSwAttributes>();
}
std::vector<SvGlobalName> *pGlobalOLEExcludeList = nullptr;
diff --git a/sw/source/core/doc/docdesc.cxx b/sw/source/core/doc/docdesc.cxx
index 0aaa2d2a246d..5846812e924c 100644
--- a/sw/source/core/doc/docdesc.cxx
+++ b/sw/source/core/doc/docdesc.cxx
@@ -591,7 +591,7 @@ void SwDoc::ChgPageDesc( size_t i, const SwPageDesc &rChged )
CopyMasterFooter(rChged, pStashedFirstMasterFoot ? pStashedFirstMasterFoot->GetFooter() : rMasterFoot, rDesc, false, true); // Copy first master
CopyMasterFooter(rChged, pStashedFirstLeftFoot ? pStashedFirstLeftFoot->GetFooter() : rMasterFoot, rDesc, true, true); // Copy first left
- if (pStashedLeftFormat)
+ if (pStashedLeftFoot)
rDesc.RemoveStashedFormat(false, true, false);
if (pStashedFirstMasterFoot)
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 0032bbff3f06..5b8120ca973d 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -99,6 +99,7 @@
#include <DocumentStylePoolManager.hxx>
#include <DocumentExternalDataManager.hxx>
#include <wrtsh.hxx>
+#include <swmodule.hxx>
#include <unocrsr.hxx>
#include <fmthdft.hxx>
#include <frameformats.hxx>
@@ -206,7 +207,7 @@ static void lcl_DelFormatIndices( SwFormat const * pFormat )
*/
SwDoc::SwDoc()
: m_pNodes(new SwNodes(*this)),
- mpAttrPool(new SwAttrPool(*this)),
+ mpAttrPool(new SwAttrPool(SwModule::get()->getItemInfoPackageSwAttributes(), *this)),
maOLEModifiedIdle( "sw::SwDoc maOLEModifiedIdle" ),
mpMarkManager(new ::sw::mark::MarkManager(*this)),
m_pMetaFieldManager(new ::sw::MetaFieldManager()),
diff --git a/sw/source/core/fields/dbfld.cxx b/sw/source/core/fields/dbfld.cxx
index 700864f16818..573269e1ae01 100644
--- a/sw/source/core/fields/dbfld.cxx
+++ b/sw/source/core/fields/dbfld.cxx
@@ -264,7 +264,7 @@ bool SwDBField::FormatValue( SvNumberFormatter const * pDocFormatter, OUString c
if( DataType::DATE == nColumnType || DataType::TIME == nColumnType ||
DataType::TIMESTAMP == nColumnType )
{
- Date aStandard( 1, 1, 1900 );
+ Date aStandard(30, 12, 1899);
if( pDocFormatter->GetNullDate() != aStandard )
aNumber += (aStandard - pDocFormatter->GetNullDate());
}
diff --git a/sw/source/core/layout/pagedesc.cxx b/sw/source/core/layout/pagedesc.cxx
index a65f3332a792..780123d62452 100644
--- a/sw/source/core/layout/pagedesc.cxx
+++ b/sw/source/core/layout/pagedesc.cxx
@@ -28,6 +28,7 @@
#include <sal/log.hxx>
#include <fmtclds.hxx>
#include <fmtfsize.hxx>
+#include <fmthdft.hxx>
#include <pagefrm.hxx>
#include <pagedesc.hxx>
#include <swtable.hxx>
@@ -423,6 +424,59 @@ void SwPageDesc::ChgFirstShare( bool bNew )
m_eUse &= UseOnPage::NoFirstShare;
}
+bool SwPageDesc::SetFormatAttrOnAll(const SfxItemSet& rSet, const bool bHeader)
+{
+ if( !rSet.Count() )
+ return false;
+
+ // Warning: no attempt is made here to limit rSet to properties that are "safe"
+ // to duplicate to all of the different headers/footers.
+ assert(!rSet.HasItem(RES_CNTNT) && "unexpected use of SwPageDesc::SetFormatAttrOnAll");
+
+ bool bRet = false;
+ if (bHeader)
+ {
+ auto pHF = const_cast<SwFrameFormat*>(GetMaster().GetHeader().GetHeaderFormat());
+ bRet = pHF && pHF->SetFormatAttr(rSet);
+ if (bRet && !IsFirstShared())
+ {
+ pHF = const_cast<SwFrameFormat*>(GetFirstMaster().GetHeader().GetHeaderFormat());
+ pHF && pHF->SetFormatAttr(rSet);
+ }
+ if (bRet && !IsHeaderShared())
+ {
+ pHF = const_cast<SwFrameFormat*>(GetLeft().GetHeader().GetHeaderFormat());
+ pHF && pHF->SetFormatAttr(rSet);
+ if (!IsFirstShared())
+ {
+ pHF = const_cast<SwFrameFormat*>(GetFirstLeft().GetHeader().GetHeaderFormat());
+ pHF && pHF->SetFormatAttr(rSet);
+ }
+ }
+ }
+ else // footer
+ {
+ auto pHF = const_cast<SwFrameFormat*>(GetMaster().GetFooter().GetFooterFormat());
+ bRet = pHF && pHF->SetFormatAttr(rSet);
+ if (bRet && !IsFirstShared())
+ {
+ pHF = const_cast<SwFrameFormat*>(GetFirstMaster().GetFooter().GetFooterFormat());
+ pHF && pHF->SetFormatAttr(rSet);
+ }
+ if (bRet && !IsFooterShared())
+ {
+ pHF = const_cast<SwFrameFormat*>(GetLeft().GetFooter().GetFooterFormat());
+ pHF && pHF->SetFormatAttr(rSet);
+ if (bRet && !IsFirstShared())
+ {
+ pHF= const_cast<SwFrameFormat*>(GetFirstLeft().GetFooter().GetFooterFormat());
+ pHF && pHF->SetFormatAttr(rSet);
+ }
+ }
+ }
+ return bRet;
+}
+
void SwPageDesc::StashFrameFormat(const SwFrameFormat& rFormat, bool bHeader, bool bLeft, bool bFirst)
{
assert(rFormat.GetRegisteredIn());
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index 193b33afa2ae..6591bec892cd 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -1449,10 +1449,13 @@ void SwTaggedPDFHelper::BeginBlockStructureElements()
// open all parent sections, so that the SEs of sections
// are nested in the same way as their SwSectionNodes
std::vector<SwSection const*> parents;
- for (SwSection const* pParent = pSection->GetParent();
- pParent != nullptr; pParent = pParent->GetParent())
+ // iterate only *direct* parents - do not leave table cell!
+ for (SwSectionNode const* pSectionNode{pSection->GetFormat()
+ ->GetSectionNode()->StartOfSectionNode()->GetSectionNode()};
+ pSectionNode != nullptr;
+ pSectionNode = pSectionNode->StartOfSectionNode()->GetSectionNode())
{
- parents.push_back(pParent);
+ parents.push_back(&pSectionNode->GetSection());
}
for (auto it = parents.rbegin(); it != parents.rend(); ++it)
{
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index a9333e66b9b4..4f6eca343c12 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -1375,7 +1375,7 @@ void SwTextPaintInfo::DrawCSDFHighlighting(const SwLinePortion &rPor) const
if (!pView)
return;
- if (!pView->IsSpotlightCharStyles() && !pView->IsHighlightCharDF())
+ if (!pView->IsSpotlightCharStyles() && !pView->IsSpotlightCharDF())
return;
SwRect aRect;
@@ -1430,7 +1430,7 @@ void SwTextPaintInfo::DrawCSDFHighlighting(const SwLinePortion &rPor) const
}
}
// not character style formatted
- else if (pView->IsHighlightCharDF())
+ else if (pView->IsSpotlightCharDF())
{
const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID,
UNO_NAME_PARA_IS_NUMBERING_RESTART,
diff --git a/sw/source/filter/md/wrtmd.cxx b/sw/source/filter/md/wrtmd.cxx
index 75400719e687..7430aa389447 100644
--- a/sw/source/filter/md/wrtmd.cxx
+++ b/sw/source/filter/md/wrtmd.cxx
@@ -678,7 +678,20 @@ void OutMarkdown_SwTextNode(SwMDWriter& rWrt, const SwTextNode& rNode, bool bFir
rWrt.Strm().WriteUnicodeOrByteText(u"" SAL_NEWLINE_STRING);
for (size_t nBox = 0; nBox < oCellInfo->nFirstRowBoxCount; ++nBox)
{
- rWrt.Strm().WriteUnicodeOrByteText(u"|-");
+ std::u16string aDelimiter(u"| - ");
+ // Decorate with leading or trailing colon if the adjustment is not the default.
+ switch (oCellInfo->aFirstRowBoxAdjustments[nBox])
+ {
+ case SvxAdjust::Center:
+ aDelimiter = u"| :-: ";
+ break;
+ case SvxAdjust::Right:
+ aDelimiter = u"| -: ";
+ break;
+ default:
+ break;
+ }
+ rWrt.Strm().WriteUnicodeOrByteText(aDelimiter);
}
rWrt.Strm().WriteUnicodeOrByteText(u"|");
}
@@ -699,13 +712,30 @@ void OutMarkdown_SwTableNode(SwMDWriter& rWrt, const SwTableNode& rTableNode)
for (size_t nLine = 0; nLine < rTable.GetTabLines().size(); ++nLine)
{
const SwTableLine* pLine = rTable.GetTabLines()[nLine];
+ std::vector<SvxAdjust> aBoxAdjustments;
for (size_t nBox = 0; nBox < pLine->GetTabBoxes().size(); ++nBox)
{
const SwTableBox* pBox = pLine->GetTabBoxes()[nBox];
const SwStartNode* pStart = pBox->GetSttNd();
- SwMDCellInfo& rStartInfo = aTableInfo.aCellInfos[pStart->GetIndex() + 1];
+ SwNodeOffset nCellStartIndex = pStart->GetIndex() + 1;
+ SwMDCellInfo& rStartInfo = aTableInfo.aCellInfos[nCellStartIndex];
const SwEndNode* pEnd = pStart->EndOfSectionNode();
rStartInfo.bCellStart = true;
+
+ if (nLine == 0)
+ {
+ // First row, save the alignment of the first text node, if the cell has one.
+ SwTextNode* pCellStartNode
+ = rWrt.m_pDoc->GetNodes()[nCellStartIndex]->GetTextNode();
+ SvxAdjust eAdjust{};
+ if (pCellStartNode)
+ {
+ const SwAttrSet& rCellStartSet = pCellStartNode->GetSwAttrSet();
+ eAdjust = rCellStartSet.Get(RES_PARATR_ADJUST).GetAdjust();
+ }
+ aBoxAdjustments.push_back(eAdjust);
+ }
+
if (nBox == 0)
{
rStartInfo.bRowStart = true;
@@ -718,6 +748,7 @@ void OutMarkdown_SwTableNode(SwMDWriter& rWrt, const SwTableNode& rTableNode)
{
rEndInfo.bFirstRowEnd = true;
rEndInfo.nFirstRowBoxCount = pLine->GetTabBoxes().size();
+ rEndInfo.aFirstRowBoxAdjustments = aBoxAdjustments;
}
}
}
diff --git a/sw/source/filter/md/wrtmd.hxx b/sw/source/filter/md/wrtmd.hxx
index 10960de60461..d3f6d15db58f 100644
--- a/sw/source/filter/md/wrtmd.hxx
+++ b/sw/source/filter/md/wrtmd.hxx
@@ -36,7 +36,10 @@ struct SwMDCellInfo
bool bRowStart = false;
bool bRowEnd = false;
bool bFirstRowEnd = false;
+
+ // These are only set in the bFirstRowEnd == true case.
size_t nFirstRowBoxCount = 0;
+ std::vector<SvxAdjust> aFirstRowBoxAdjustments;
};
/// Tracks information about one SwTableNode, the instance is alive while the write of the table is
diff --git a/sw/source/ui/chrdlg/numpara.cxx b/sw/source/ui/chrdlg/numpara.cxx
index 07044fcfbfb4..f11e3fb6edf0 100644
--- a/sw/source/ui/chrdlg/numpara.cxx
+++ b/sw/source/ui/chrdlg/numpara.cxx
@@ -29,7 +29,6 @@
#include <fmtline.hxx>
#include <numpara.hxx>
-#include <officecfg/Office/Common.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/frame.hxx>
#include <sfx2/viewsh.hxx>
@@ -89,11 +88,6 @@ SwParagraphNumTabPage::SwParagraphNumTabPage(weld::Container* pPage, weld::Dialo
m_xRestartParaCountCB->connect_toggled(LINK(this, SwParagraphNumTabPage, LineCountHdl_Impl));
m_xNumberStyleLB->connect_changed(LINK(this, SwParagraphNumTabPage, EditNumStyleSelectHdl_Impl));
m_xEditNumStyleBtn->connect_clicked(LINK(this, SwParagraphNumTabPage, EditNumStyleHdl_Impl));
-
- if (officecfg::Office::Common::Misc::ExperimentalMode::get())
- m_xListLvBX->show();
- else
- m_xListLvBX->hide();
}
SwParagraphNumTabPage::~SwParagraphNumTabPage()
diff --git a/sw/source/ui/dbui/dbinsdlg.cxx b/sw/source/ui/dbui/dbinsdlg.cxx
index d12c56c8d287..ca29ed54341d 100644
--- a/sw/source/ui/dbui/dbinsdlg.cxx
+++ b/sw/source/ui/dbui/dbinsdlg.cxx
@@ -1085,7 +1085,7 @@ void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
{
if(rNumFormatr.GetType(aNumFormat.GetValue()) & SvNumFormatType::DATE)
{
- ::Date aStandard(1,1,1900);
+ ::Date aStandard(30, 12, 1899);
if (rNumFormatr.GetNullDate() != aStandard)
fVal += (aStandard - rNumFormatr.GetNullDate());
}
@@ -1280,10 +1280,8 @@ void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
DataType::TIMESTAMP == eDataType)
{
- ::Date aStandard(1,1,1900);
- ::Date aCompare(aDBFormatData.aNullDate.Day ,
- aDBFormatData.aNullDate.Month,
- aDBFormatData.aNullDate.Year);
+ ::Date aStandard(30, 12, 1899);
+ ::Date aCompare(aDBFormatData.aNullDate);
if(aStandard != aCompare)
nValue += (aStandard - aCompare);
}
@@ -1310,7 +1308,7 @@ void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
const Color* pCol;
if(rNumFormatr.GetType(pDBCol->nFormat) & SvNumFormatType::DATE)
{
- ::Date aStandard(1,1,1900);
+ ::Date aStandard(30, 12, 1899);
if (rNumFormatr.GetNullDate() != aStandard)
nValue += (aStandard - rNumFormatr.GetNullDate());
}
diff --git a/sw/source/uibase/app/docst.cxx b/sw/source/uibase/app/docst.cxx
index 989eeaa871ec..24ebdbbd5d03 100644
--- a/sw/source/uibase/app/docst.cxx
+++ b/sw/source/uibase/app/docst.cxx
@@ -657,7 +657,8 @@ IMPL_LINK_NOARG(ApplyStyle, ApplyHdl, LinkParamNone*, void)
::ConvertAttrGenToChar(aTmpSet, m_xTmp->GetItemSet());
}
- m_xTmp->SetItemSet( aTmpSet, false );
+ bool bParam1 = SfxStyleFamily::Page == m_nFamily; // bApplyToAllFormatFrames
+ m_xTmp->SetItemSet(aTmpSet, /*bBroadcast=*/ false, bParam1);
if( SfxStyleFamily::Page == m_nFamily && SvtCTLOptions::IsCTLFontEnabled() )
{
diff --git a/sw/source/uibase/app/docstyle.cxx b/sw/source/uibase/app/docstyle.cxx
index d03083ac6dd3..73818d9ac2d5 100644
--- a/sw/source/uibase/app/docstyle.cxx
+++ b/sw/source/uibase/app/docstyle.cxx
@@ -1622,8 +1622,7 @@ void SwDocStyleSheet::MergeIndentAttrsOfListStyle( SfxItemSet& rSet )
}
// handling of parameter <bResetIndentAttrsAtParagraphStyle>
-void SwDocStyleSheet::SetItemSet( const SfxItemSet& rSet, const bool bBroadcast,
- const bool bResetIndentAttrsAtParagraphStyle )
+void SwDocStyleSheet::SetItemSet(const SfxItemSet& rSet, const bool bBroadcast, const bool bParam1)
{
// if applicable determine format first
if(!m_bPhysical)
@@ -1715,6 +1714,7 @@ void SwDocStyleSheet::SetItemSet( const SfxItemSet& rSet, const bool bBroadcast,
m_rDoc.DelTextFormatColl( m_pColl );
m_pColl = pCColl;
}
+ const bool bResetIndentAttrsAtParagraphStyle = bParam1;
if ( bResetIndentAttrsAtParagraphStyle &&
rSet.GetItemState( RES_PARATR_NUMRULE, false ) == SfxItemState::SET &&
rSet.GetItemState(RES_MARGIN_FIRSTLINE, false) != SfxItemState::SET &&
@@ -1892,7 +1892,8 @@ void SwDocStyleSheet::SetItemSet( const SfxItemSet& rSet, const bool bBroadcast,
if( pNewDsc )
{
- ::ItemSetToPageDesc( aSet, *pNewDsc );
+ const bool bApplyToAllFormatFrames = bParam1;
+ ::ItemSetToPageDesc(aSet, *pNewDsc, bApplyToAllFormatFrames);
m_rDoc.ChgPageDesc( nPgDscPos, *pNewDsc );
m_pDesc = &m_rDoc.GetPageDesc( nPgDscPos );
m_rDoc.PreDelPageDesc(pNewDsc.get()); // #i7983#
diff --git a/sw/source/uibase/app/swdll.cxx b/sw/source/uibase/app/swdll.cxx
index 765330c9c257..c85355300898 100644
--- a/sw/source/uibase/app/swdll.cxx
+++ b/sw/source/uibase/app/swdll.cxx
@@ -95,6 +95,7 @@ SwDLL::SwDLL()
SfxObjectFactory* pWDocFact = &SwWebDocShell::Factory();
auto pUniqueModule = std::make_unique<SwModule>(pWDocFact, pDocFact, pGlobDocFact);
+ SwModule* pModule = pUniqueModule.get();
SfxApplication::SetModule(SfxToolsModule::Writer, std::move(pUniqueModule));
pWDocFact->SetDocumentServiceName(u"com.sun.star.text.WebDocument"_ustr);
@@ -119,6 +120,8 @@ SwDLL::SwDLL()
m_pFilters.reset(new sw::Filters);
::InitUI();
+ pModule->InitItemInfoPackageSwAttributes();
+
// register your view-factories here
RegisterFactories();
@@ -146,8 +149,11 @@ SwDLL::~SwDLL() COVERITY_NOEXCEPT_FALSE
m_pAutoCorrCfg->SetAutoCorrect(nullptr); // delete SwAutoCorrect before exit handlers
}
- ::FinitUI();
m_pFilters.reset();
+
+ SwModule::get()->RemoveItemInfoPackageSwAttributes();
+
+ ::FinitUI();
::FinitCore();
// sign out object-Factory
SdrObjFactory::RemoveMakeObjectHdl(LINK(&aSwObjectFactory, SwObjectFactory, MakeObject ));
diff --git a/sw/source/uibase/app/swmodule.cxx b/sw/source/uibase/app/swmodule.cxx
index 76986353f844..7d3cf07e2f47 100644
--- a/sw/source/uibase/app/swmodule.cxx
+++ b/sw/source/uibase/app/swmodule.cxx
@@ -72,6 +72,7 @@
#include <wlistsh.hxx>
#include <wtabsh.hxx>
#include <navipi.hxx>
+#include <init.hxx>
#include <inputwin.hxx>
#include <usrpref.hxx>
#include <uinums.hxx>
@@ -337,6 +338,23 @@ void SwDLL::RegisterControls()
SwJumpToSpecificPageControl::RegisterControl(SID_JUMP_TO_SPECIFIC_PAGE, pMod);
}
+void SwModule::InitItemInfoPackageSwAttributes()
+{
+ OSL_ENSURE(!m_xItemInfoPackageSwAttributes, "ItemInfoPackageSwAttributes already exists!");
+ m_xItemInfoPackageSwAttributes = createItemInfoPackageSwAttributes();
+}
+
+ItemInfoPackage& SwModule::getItemInfoPackageSwAttributes()
+{
+ assert(m_xItemInfoPackageSwAttributes && "InitItemInfoPackageSwAttributes should have been called before this");
+ return *m_xItemInfoPackageSwAttributes;
+}
+
+void SwModule::RemoveItemInfoPackageSwAttributes()
+{
+ m_xItemInfoPackageSwAttributes.reset();
+}
+
SfxStyleFamilies SwModule::CreateStyleFamilies()
{
SfxStyleFamilies aStyleFamilies;
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index bbd0fe4ac382..610bc9d3b7f5 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -136,8 +136,6 @@
#include <vcl/uitest/eventdescription.hxx>
#include <svx/GenericDropDownFieldDialog.hxx>
-#include <vcl/GraphicNativeTransform.hxx>
-#include <vcl/GraphicNativeMetadata.hxx>
#include <vcl/TypeSerializer.hxx>
#include <comphelper/lok.hxx>
#include <sfx2/classificationhelper.hxx>
@@ -427,20 +425,6 @@ namespace
rDest.GetMetaFieldManager().copyDocumentProperties(rSrc);
}
-
- void lclCheckAndPerformRotation(Graphic& aGraphic)
- {
- GraphicNativeMetadata aMetadata;
- if ( !aMetadata.read(aGraphic) )
- return;
-
- Degree10 aRotation = aMetadata.getRotation();
- if (aRotation)
- {
- GraphicNativeTransform aTransform( aGraphic );
- aTransform.rotate( aRotation );
- }
- }
}
sal_Bool SAL_CALL SwTransferable::isComplex()
@@ -2631,9 +2615,6 @@ bool SwTransferable::PasteTargetURL( const TransferableDataHelper& rData,
if( bRet )
{
- //Check and Perform rotation if needed
- lclCheckAndPerformRotation(aGraphic);
-
switch( nAction )
{
case SwPasteSdr::Insert:
@@ -3040,9 +3021,6 @@ bool SwTransferable::PasteGrf( const TransferableDataHelper& rData, SwWrtShell&
if( bRet )
{
- //Check and Perform rotation if needed
- lclCheckAndPerformRotation(aGraphic);
-
OUString sURL;
if( dynamic_cast< const SwWebDocShell *>( rSh.GetView().GetDocShell() ) != nullptr
// #i123922# if link action is noted, also take URL
diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx b/sw/source/uibase/docvw/HeaderFooterWin.cxx
index ebad3ae4c3a5..719e609d715c 100644
--- a/sw/source/uibase/docvw/HeaderFooterWin.cxx
+++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx
@@ -488,8 +488,8 @@ void SwHeaderFooterWin::ExecuteCommand(std::u16string_view rIdent)
}
else if (rIdent == u"borderback")
{
- const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
- const SwFrameFormat& rMaster = pDesc->GetMaster();
+ SwPageDesc& rPageDesc = const_cast<SwPageDesc&>(*pPageFrame->GetPageDesc());
+ SwFrameFormat& rMaster = rPageDesc.GetMaster();
SwFrameFormat* pHFFormat = const_cast< SwFrameFormat* >( rMaster.GetFooter().GetFooterFormat() );
if ( m_bIsHeader )
pHFFormat = const_cast< SwFrameFormat* >( rMaster.GetHeader().GetHeaderFormat() );
@@ -517,7 +517,9 @@ void SwHeaderFooterWin::ExecuteCommand(std::u16string_view rIdent)
if (svx::ShowBorderBackgroundDlg( GetFrameWeld(), &aSet ) )
{
- pHFFormat->SetFormatAttr( aSet );
+ // Apply the modified format to all (first, even, odd) of the page style's FrameFormats
+ aSet.DisableItem(RES_CNTNT); // don't duplicate the content though...
+ rPageDesc.SetFormatAttrOnAll(aSet, m_bIsHeader);
rView.GetDocShell()->SetModified();
}
}
diff --git a/sw/source/uibase/docvw/PageBreakWin.cxx b/sw/source/uibase/docvw/PageBreakWin.cxx
index 4ef4d86a60c1..8fc7615444d1 100644
--- a/sw/source/uibase/docvw/PageBreakWin.cxx
+++ b/sw/source/uibase/docvw/PageBreakWin.cxx
@@ -305,20 +305,17 @@ void SwBreakDashedLine::execute(std::u16string_view rIdent)
? *static_cast<SwTextFrame*>(pCnt)->GetTextNodeFirst()
: *static_cast<SwNoTextFrame*>(pCnt)->GetNode();
+ rSh.Push();
+ rSh.ClearMark();
+ rSh.SetSelection(SwPaM(rNd));
+
if ( pCnt->IsInTab() )
{
- rSh.Push( );
- rSh.ClearMark();
-
- rSh.SetSelection( SwPaM(rNd) );
-
SfxStringItem aItem(m_pEditWin->GetView().GetPool().GetWhichIDFromSlotID(FN_FORMAT_TABLE_DLG), u"textflow"_ustr);
m_pEditWin->GetView().GetViewFrame().GetDispatcher()->ExecuteList(
FN_FORMAT_TABLE_DLG,
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aItem });
-
- rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
}
else
{
@@ -330,6 +327,9 @@ void SwBreakDashedLine::execute(std::u16string_view rIdent)
SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
{ &aItem, &aPaMItem });
}
+
+ rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
+
rSh.LockView( bOldLock );
m_pEditWin->GrabFocus( );
}
diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx
index a1e688ae3f13..33ac354df7da 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -6939,14 +6939,18 @@ Selection SwEditWin::GetSurroundingTextSelection() const
if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingTextSelection();
- Selection aSel(0, 0);
if( rSh.HasSelection() )
{
OUString sReturn;
rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
- aSel = Selection( 0, sReturn.getLength() );
+ const SwCursor* pCursor = rSh.GetCursor();
+ if (pCursor && *pCursor->GetPoint() < *pCursor->GetMark())
+ return Selection(sReturn.getLength(), 0);
+ else
+ return Selection(0, sReturn.getLength());
}
- else if (rSh.GetCursor()->GetPoint()->GetNode().GetTextNode())
+
+ if (rSh.GetCursor()->GetPoint()->GetNode().GetTextNode())
{
bool bUnLockView = !rSh.IsViewLocked();
rSh.LockView(true);
@@ -6974,10 +6978,10 @@ Selection SwEditWin::GetSurroundingTextSelection() const
if (bUnLockView)
rSh.LockView(false);
- aSel = Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - nStartPos));
+ return Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - nStartPos));
}
- return aSel;
+ return Selection(0, 0);
}
bool SwEditWin::DeleteSurroundingText(const Selection& rSelection)
diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx
index d087cc2c666c..7da57f94f37c 100644
--- a/sw/source/uibase/docvw/edtwin2.cxx
+++ b/sw/source/uibase/docvw/edtwin2.cxx
@@ -105,7 +105,7 @@ bool PSCSDFPropsQuickHelp(const HelpEvent &rEvt, SwWrtShell& rSh)
UIName sText;
SwView& rView = rSh.GetView();
- if (rView.IsHighlightCharDF() || rView.IsSpotlightParaStyles()
+ if (rView.IsSpotlightCharDF() || rView.IsSpotlightParaStyles()
|| rView.IsSpotlightCharStyles())
{
SwPosition aPos(rSh.GetDoc()->GetNodes());
@@ -150,7 +150,7 @@ bool PSCSDFPropsQuickHelp(const HelpEvent &rEvt, SwWrtShell& rSh)
sText = SwStyleNameMapper::GetUIName(ProgName(sCharStyle), SwGetPoolIdFromName::ChrFmt);
}
- if (sText.isEmpty() && rView.IsHighlightCharDF())
+ if (sText.isEmpty() && rView.IsSpotlightCharDF())
{
// check if in direct formatting highlighted area
const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID,
diff --git a/sw/source/uibase/inc/uitool.hxx b/sw/source/uibase/inc/uitool.hxx
index d2c7c3b051c0..4b616b95e1cd 100644
--- a/sw/source/uibase/inc/uitool.hxx
+++ b/sw/source/uibase/inc/uitool.hxx
@@ -69,7 +69,8 @@ SW_DLLPUBLIC void ConvertAttrGenToChar(SfxItemSet& rSet, const SfxItemSet& rOrig
void ApplyCharBackground(Color const& rBackgroundColor, model::ComplexColor const& rComplexColor, SwWrtShell& rShell);
// SfxItemSets <-> PageDesc
-void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc );
+void ItemSetToPageDesc(const SfxItemSet& rSet, SwPageDesc& rPageDesc,
+ bool bApplyToAllFormatFrames = false);
void PageDescToItemSet( const SwPageDesc& rPageDesc, SfxItemSet& rSet);
// fill tabs with default tabs
diff --git a/sw/source/uibase/uiview/view0.cxx b/sw/source/uibase/uiview/view0.cxx
index 0147e3679cba..e88730ce0ba7 100644
--- a/sw/source/uibase/uiview/view0.cxx
+++ b/sw/source/uibase/uiview/view0.cxx
@@ -360,7 +360,7 @@ void SwView::StateViewOptions(SfxItemSet &rSet)
aBool.SetValue( pOpt->IsShowChangesInMargin() );
break;
case SID_SPOTLIGHT_CHAR_DF:
- aBool.SetValue(m_bIsHighlightCharDF);
+ aBool.SetValue(m_bIsSpotlightCharDF);
break;
case SID_SPOTLIGHT_PARASTYLES:
aBool.SetValue(m_bIsSpotlightParaStyles);
@@ -596,8 +596,8 @@ void SwView::ExecViewOptions(SfxRequest &rReq)
case SID_SPOTLIGHT_CHAR_DF:
if (STATE_TOGGLE == eState)
- bFlag = !m_bIsHighlightCharDF;
- m_bIsHighlightCharDF = bFlag;
+ bFlag = !m_bIsSpotlightCharDF;
+ m_bIsSpotlightCharDF = bFlag;
break;
case SID_SPOTLIGHT_PARASTYLES:
diff --git a/sw/source/uibase/utlui/uitool.cxx b/sw/source/uibase/utlui/uitool.cxx
index e7a79c92f929..5f98464af353 100644
--- a/sw/source/uibase/utlui/uitool.cxx
+++ b/sw/source/uibase/utlui/uitool.cxx
@@ -225,8 +225,20 @@ void ApplyCharBackground(Color const& rBackgroundColor, model::ComplexColor cons
// Fill header footer
-static void FillHdFt(SwFrameFormat* pFormat, const SfxItemSet& rSet)
+static void FillHdFt(SfxPoolItem& rFormat, const SfxItemSet& rSet, SwPageDesc& rPageDesc,
+ bool bApplyToAllFormatFrames)
{
+ auto pHeader = dynamic_cast<SwFormatHeader*>(&rFormat);
+ auto pFooter = dynamic_cast<SwFormatFooter*>(&rFormat);
+ assert(pHeader || pFooter);
+
+ SwFrameFormat* pFormat;
+ if (pHeader)
+ pFormat = pHeader->GetHeaderFormat();
+ else
+ pFormat = pFooter->GetFooterFormat();
+ OSL_ENSURE(pFormat != nullptr, "no header or footer format");
+
SwAttrSet aSet(pFormat->GetAttrSet());
aSet.Put(rSet);
@@ -238,7 +250,14 @@ static void FillHdFt(SwFrameFormat* pFormat, const SfxItemSet& rSet)
rSize.GetSize().Width(),
rSize.GetSize().Height());
aSet.Put(aFrameSize);
- pFormat->SetFormatAttr(aSet);
+ if (bApplyToAllFormatFrames)
+ {
+ // Apply the modified format to all (first, even, odd) of the page style's FrameFormats
+ aSet.DisableItem(RES_CNTNT); // don't duplicate the content though...
+ rPageDesc.SetFormatAttrOnAll(aSet, bool(pHeader));
+ }
+ else
+ pFormat->SetFormatAttr(aSet);
}
/// Convert from UseOnPage to SvxPageUsage.
@@ -273,7 +292,7 @@ static UseOnPage lcl_convertUseFromSvx(SvxPageUsage nUse)
// PageDesc <-> convert into sets and back
-void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc )
+void ItemSetToPageDesc(const SfxItemSet& rSet, SwPageDesc& rPageDesc, bool bApplyToAllFormatFrames)
{
SwFrameFormat& rMaster = rPageDesc.GetMaster();
bool bFirstShare = false;
@@ -364,10 +383,7 @@ void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc )
// Pick out everything and adapt the header format
SwFormatHeader aHeaderFormat(rMaster.GetHeader());
- SwFrameFormat *pHeaderFormat = aHeaderFormat.GetHeaderFormat();
- OSL_ENSURE(pHeaderFormat != nullptr, "no header format");
-
- ::FillHdFt(pHeaderFormat, rHeaderSet);
+ ::FillHdFt(aHeaderFormat, rHeaderSet, rPageDesc, bApplyToAllFormatFrames);
rPageDesc.ChgHeaderShare(rHeaderSet.Get(SID_ATTR_PAGE_SHARED).GetValue());
rPageDesc.ChgFirstShare(static_cast<const SfxBoolItem&>(
@@ -400,10 +416,7 @@ void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc )
// Pick out everything and adapt the footer format
SwFormatFooter aFooterFormat(rMaster.GetFooter());
- SwFrameFormat *pFooterFormat = aFooterFormat.GetFooterFormat();
- OSL_ENSURE(pFooterFormat != nullptr, "no footer format");
-
- ::FillHdFt(pFooterFormat, rFooterSet);
+ ::FillHdFt(aFooterFormat, rFooterSet, rPageDesc, bApplyToAllFormatFrames);
rPageDesc.ChgFooterShare(rFooterSet.Get(SID_ATTR_PAGE_SHARED).GetValue());
if (!bFirstShare)
diff --git a/toolkit/source/controls/table/cellvalueconversion.cxx b/toolkit/source/controls/table/cellvalueconversion.cxx
index 735fb57f7e5d..da9a83346565 100644
--- a/toolkit/source/controls/table/cellvalueconversion.cxx
+++ b/toolkit/source/controls/table/cellvalueconversion.cxx
@@ -75,6 +75,27 @@ double lcl_convertTimeToDays(tools::Long const i_hours, tools::Long const i_minu
//= StandardFormatNormalizer
+class StandardFormatNormalizer
+{
+public:
+ virtual ~StandardFormatNormalizer() = default;
+
+ /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter
+ */
+ virtual double convertToDouble(css::uno::Any const& i_value) const = 0;
+
+ /** returns the format key to be used for formatting values
+ */
+ sal_Int32 getFormatKey() const { return m_nFormatKey; }
+
+protected:
+ StandardFormatNormalizer(css::uno::Reference<css::util::XNumberFormatter> const& i_formatter,
+ ::sal_Int32 const i_numberFormatType);
+
+private:
+ ::sal_Int32 m_nFormatKey;
+};
+
StandardFormatNormalizer::StandardFormatNormalizer(Reference<XNumberFormatter> const& i_formatter,
::sal_Int32 const i_numberFormatType)
: m_nFormatKey(0)
@@ -278,55 +299,49 @@ bool CellValueConversion::ensureNumberFormatter()
return xNumberFormatter.is();
}
-bool CellValueConversion::getValueNormalizer(Type const& i_valueType,
- std::shared_ptr<StandardFormatNormalizer>& o_formatter)
+const StandardFormatNormalizer* CellValueConversion::getValueNormalizer(Type const& i_valueType)
{
- auto pos = aNormalizers.find(i_valueType.getTypeName());
- if (pos == aNormalizers.end())
+ auto [pos, inserted] = aNormalizers.try_emplace(i_valueType.getTypeName());
+ if (inserted)
{
// never encountered this type before
- o_formatter.reset();
-
OUString const sTypeName(i_valueType.getTypeName());
TypeClass const eTypeClass = i_valueType.getTypeClass();
if (sTypeName == ::cppu::UnoType<DateTime>::get().getTypeName())
{
- o_formatter = std::make_shared<DateTimeNormalization>(xNumberFormatter);
+ pos->second = std::make_unique<DateTimeNormalization>(xNumberFormatter);
}
else if (sTypeName == ::cppu::UnoType<css::util::Date>::get().getTypeName())
{
- o_formatter = std::make_shared<DateNormalization>(xNumberFormatter);
+ pos->second = std::make_unique<DateNormalization>(xNumberFormatter);
}
else if (sTypeName == ::cppu::UnoType<css::util::Time>::get().getTypeName())
{
- o_formatter = std::make_shared<TimeNormalization>(xNumberFormatter);
+ pos->second = std::make_unique<TimeNormalization>(xNumberFormatter);
}
else if (sTypeName == ::cppu::UnoType<sal_Bool>::get().getTypeName())
{
- o_formatter = std::make_shared<BooleanNormalization>(xNumberFormatter);
+ pos->second = std::make_unique<BooleanNormalization>(xNumberFormatter);
}
else if (sTypeName == ::cppu::UnoType<double>::get().getTypeName()
|| sTypeName == ::cppu::UnoType<float>::get().getTypeName())
{
- o_formatter = std::make_shared<DoubleNormalization>(xNumberFormatter);
+ pos->second = std::make_unique<DoubleNormalization>(xNumberFormatter);
}
else if ((eTypeClass == TypeClass_BYTE) || (eTypeClass == TypeClass_SHORT)
|| (eTypeClass == TypeClass_UNSIGNED_SHORT) || (eTypeClass == TypeClass_LONG)
|| (eTypeClass == TypeClass_UNSIGNED_LONG) || (eTypeClass == TypeClass_HYPER))
{
- o_formatter = std::make_shared<IntegerNormalization>(xNumberFormatter);
+ pos->second = std::make_unique<IntegerNormalization>(xNumberFormatter);
}
else
{
SAL_WARN("svtools.table", "unsupported type '" << sTypeName << "'!");
}
- aNormalizers[sTypeName] = o_formatter;
}
- else
- o_formatter = pos->second;
- return bool(o_formatter);
+ return pos->second.get();
}
//= CellValueConversion
@@ -350,8 +365,7 @@ OUString CellValueConversion::convertToString(const Any& i_value)
{
if (ensureNumberFormatter())
{
- std::shared_ptr<StandardFormatNormalizer> pNormalizer;
- if (getValueNormalizer(i_value.getValueType(), pNormalizer))
+ if (auto* pNormalizer = getValueNormalizer(i_value.getValueType()))
{
try
{
diff --git a/toolkit/source/controls/table/cellvalueconversion.hxx b/toolkit/source/controls/table/cellvalueconversion.hxx
index 2e05707e5bab..b50c1ebf098f 100644
--- a/toolkit/source/controls/table/cellvalueconversion.hxx
+++ b/toolkit/source/controls/table/cellvalueconversion.hxx
@@ -26,26 +26,7 @@
namespace svt
{
-class StandardFormatNormalizer
-{
-public:
- /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter
- */
- virtual double convertToDouble(css::uno::Any const& i_value) const = 0;
-
- /** returns the format key to be used for formatting values
- */
- sal_Int32 getFormatKey() const { return m_nFormatKey; }
-
-protected:
- StandardFormatNormalizer(css::uno::Reference<css::util::XNumberFormatter> const& i_formatter,
- ::sal_Int32 const i_numberFormatType);
-
- virtual ~StandardFormatNormalizer() {}
-
-private:
- ::sal_Int32 m_nFormatKey;
-};
+class StandardFormatNormalizer;
class CellValueConversion
{
@@ -57,14 +38,11 @@ public:
private:
bool ensureNumberFormatter();
- bool getValueNormalizer(css::uno::Type const& i_valueType,
- std::shared_ptr<StandardFormatNormalizer>& o_formatter);
-
- typedef std::unordered_map<OUString, std::shared_ptr<StandardFormatNormalizer>> NormalizerCache;
+ const StandardFormatNormalizer* getValueNormalizer(css::uno::Type const& i_valueType);
css::uno::Reference<css::util::XNumberFormatter> xNumberFormatter;
bool bAttemptedFormatterCreation;
- NormalizerCache aNormalizers;
+ std::unordered_map<OUString, std::unique_ptr<StandardFormatNormalizer>> aNormalizers;
};
} // namespace svt
diff --git a/tools/source/datetime/tdate.cxx b/tools/source/datetime/tdate.cxx
index 92da1cd3d42a..0b2b25ffc882 100644
--- a/tools/source/datetime/tdate.cxx
+++ b/tools/source/datetime/tdate.cxx
@@ -72,11 +72,9 @@ sal_Int32 Date::GetAsNormalizedDays() const
// This is a very common datum we often calculate from.
if (mnDate == 18991230) // 1899-12-30
{
-#ifndef NDEBUG
- static sal_Int32 nDays = DateToDays( GetDay(), GetMonth(), GetYear());
- assert(nDays == 693594);
-#endif
- return 693594;
+ assert(GetDay() == 30 && GetMonth() == 12 && GetYear() == 1899);
+ constexpr sal_Int32 nullDays = comphelper::date::convertDateToDays(30, 12, 1899);
+ return nullDays;
}
// Not calling comphelper::date::convertDateToDaysNormalizing() here just
// avoids a second check on null-date handling like above.
@@ -378,6 +376,17 @@ void Date::AddDays( sal_Int32 nDays )
*this = lcl_DaysToDate( GetAsNormalizedDays() + nDays );
}
+bool Date::CheckedAddDays( sal_Int32 nDays )
+{
+ if (nDays == 0)
+ return true;
+ sal_Int32 nTotalDays;
+ if (o3tl::checked_add(GetAsNormalizedDays(), nDays, nTotalDays))
+ return false;
+ *this = lcl_DaysToDate(nTotalDays);
+ return true;
+}
+
Date& Date::operator ++()
{
*this = lcl_DaysToDate( GetAsNormalizedDays() + 1 );
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index c70e84699562..d0ba4f73c12d 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -342,7 +342,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/gdi/mapmod \
vcl/source/gdi/metaact \
vcl/source/gdi/oldprintadaptor \
- vcl/source/gdi/pdfbuildin_fonts \
vcl/source/gdi/pdfextoutdevdata \
vcl/source/gdi/pdfwriter \
vcl/source/gdi/pdfwriter_impl2 \
@@ -392,7 +391,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/bitmap/bitmappaint \
vcl/source/bitmap/BitmapArithmeticBlendFilter \
vcl/source/bitmap/BitmapShadowFilter \
- vcl/source/bitmap/BitmapAlphaClampFilter \
vcl/source/bitmap/BitmapBasicMorphologyFilter \
vcl/source/bitmap/BitmapDarkenBlendFilter \
vcl/source/bitmap/BitmapLightenBlendFilter \
@@ -568,6 +566,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/pdf/ResourceDict \
vcl/source/pdf/Matrix3 \
vcl/source/pdf/XmpMetadata \
+ vcl/source/pdf/pdfbuildin_fonts \
vcl/source/uitest/logger \
vcl/source/uitest/toolboxitemuiobject \
vcl/source/uitest/toolboxuiobject \
diff --git a/vcl/commonfuzzer.mk b/vcl/commonfuzzer.mk
index 2d41dc27be24..a1df43ab435d 100644
--- a/vcl/commonfuzzer.mk
+++ b/vcl/commonfuzzer.mk
@@ -14,7 +14,6 @@ fuzzer_externals = \
orcus-parser \
boost_locale \
boost_filesystem \
- boost_system \
boost_iostreams \
curl \
dtoa \
diff --git a/vcl/inc/accessibility/accessibletablistbox.hxx b/vcl/inc/accessibility/accessibletablistbox.hxx
index 59050a82540c..f1678f0c6ab6 100644
--- a/vcl/inc/accessibility/accessibletablistbox.hxx
+++ b/vcl/inc/accessibility/accessibletablistbox.hxx
@@ -30,10 +30,10 @@ private:
public:
/** ctor()
- @param rxParent XAccessible interface of the parent object.
+ @param rpParent Accessible parent object.
@param rBox The HeaderTabListBox control. */
AccessibleTabListBox(
- const css::uno::Reference< css::accessibility::XAccessible >& rxParent,
+ const rtl::Reference<comphelper::OAccessible>& rpParent,
SvHeaderTabListBox& rBox );
// XAccessibleContext -----------------------------------------------------
@@ -45,8 +45,7 @@ public:
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
getAccessibleChild( sal_Int64 nChildIndex ) override;
- css::uno::Reference< css::accessibility::XAccessible >
- getHeaderBar()
+ rtl::Reference<comphelper::OAccessible> getHeaderBar()
{
return AccessibleBrowseBox::getHeaderBar( AccessibleBrowseBoxObjType::ColumnHeaderBar );
}
diff --git a/vcl/inc/graphic/GraphicFormatDetector.hxx b/vcl/inc/graphic/GraphicFormatDetector.hxx
index 5940f3e8ea78..19c4e2f7e9b1 100644
--- a/vcl/inc/graphic/GraphicFormatDetector.hxx
+++ b/vcl/inc/graphic/GraphicFormatDetector.hxx
@@ -169,7 +169,7 @@ public:
SAL_DLLPRIVATE bool checkPCD();
bool checkPSD();
bool checkEPS();
- SAL_DLLPRIVATE bool checkDXF();
+ bool checkDXF();
SAL_DLLPRIVATE bool checkPCT();
SAL_DLLPRIVATE bool checkPBM();
SAL_DLLPRIVATE bool checkPGM();
diff --git a/vcl/inc/menutogglebutton.hxx b/vcl/inc/menutogglebutton.hxx
index d15fbd474fec..ce8e14e9f7ee 100644
--- a/vcl/inc/menutogglebutton.hxx
+++ b/vcl/inc/menutogglebutton.hxx
@@ -26,9 +26,6 @@ class MenuToggleButton final : public MenuButton
public:
explicit MenuToggleButton(vcl::Window* pParent, WinBits nStyle);
virtual ~MenuToggleButton() override;
-
- void SetActive(bool bSel);
- bool GetActive() const;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/qt5/QtInstancePopover.hxx b/vcl/inc/qt5/QtInstancePopover.hxx
index db928aa4a600..8bcf1dfc865b 100644
--- a/vcl/inc/qt5/QtInstancePopover.hxx
+++ b/vcl/inc/qt5/QtInstancePopover.hxx
@@ -23,6 +23,8 @@ public:
virtual void popdown() override;
virtual void resize_to_request() override;
+
+ virtual bool eventFilter(QObject* pObject, QEvent* pEvent) override;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/vcl/inc/qt5/QtWidget.hxx b/vcl/inc/qt5/QtWidget.hxx
index 5e5fa2dcf6a0..f2af232a1a8d 100644
--- a/vcl/inc/qt5/QtWidget.hxx
+++ b/vcl/inc/qt5/QtWidget.hxx
@@ -23,6 +23,7 @@
#include <QtWidgets/QGestureEvent>
#include <QtWidgets/QWidget>
#include <rtl/ustring.hxx>
+#include <tools/solar.h>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
@@ -45,6 +46,8 @@ class QtWidget : public QWidget
void commitText(const QString& aText) const;
void deleteReplacementText(int nReplacementStart, int nReplacementLength) const;
+ void retrieveSurrounding(sal_uLong& rPosition, sal_uLong& rAnchor, QString* pText,
+ QString* pSelection) const;
bool handleEvent(QEvent* pEvent);
// mouse events are always accepted
void handleMouseButtonEvent(const QMouseEvent*) const;
diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx
index 8a61dd73562c..27240fca0baf 100644
--- a/vcl/inc/salwtype.hxx
+++ b/vcl/inc/salwtype.hxx
@@ -210,6 +210,7 @@ struct SalSurroundingTextRequestEvent
OUString maText; // Text
sal_uLong mnStart; // The beginning index of selected range
sal_uLong mnEnd; // The end index of selected range
+ sal_uLong mnCursorPos; // The cursor index (either mnStart or mnEnd)
};
struct SalSurroundingTextSelectionChangeEvent
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index ee14d6e86121..8f94d6580c97 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -183,14 +183,11 @@ public:
void dump(const char* file) const;
// Default blend mode for SkPaint is SkBlendMode::kSrcOver
- void drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap,
- SkBlendMode blendMode = SkBlendMode::kSrcOver);
+ void drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap);
- void drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage, int srcScaling = 1,
- SkBlendMode eBlendMode = SkBlendMode::kSrcOver);
+ void drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage, int srcScaling = 1);
- void drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader,
- SkBlendMode blendMode = SkBlendMode::kSrcOver);
+ void drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader);
void drawGenericLayout(const GenericSalLayout& layout, Color textColor, const SkFont& font,
const SkFont& verticalFont);
diff --git a/vcl/inc/window.h b/vcl/inc/window.h
index 1c92cbc58c0e..1fd18186ac71 100644
--- a/vcl/inc/window.h
+++ b/vcl/inc/window.h
@@ -393,6 +393,7 @@ public:
mbSecondary:1,
mbNonHomogeneous:1,
mbDoubleBufferingRequested:1;
+ bool mbIsFormControl : 1 = false;
rtl::Reference< DNDListenerContainer > mxDNDListenerContainer;
@@ -437,7 +438,4 @@ bool ImplLOKHandleMouseEvent( const VclPtr<vcl::Window>& xWindow, NotifyEventTyp
void ImplHandleResize( vcl::Window* pWindow, tools::Long nNewWidth, tools::Long nNewHeight );
-VCL_DLLPUBLIC css::uno::Reference<css::accessibility::XAccessibleEditableText>
-FindFocusedEditableText(css::uno::Reference<css::accessibility::XAccessibleContext> const&);
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qa/cppunit/BitmapFilterTest.cxx b/vcl/qa/cppunit/BitmapFilterTest.cxx
index 4c48d25fd69f..fb27ab59bd99 100644
--- a/vcl/qa/cppunit/BitmapFilterTest.cxx
+++ b/vcl/qa/cppunit/BitmapFilterTest.cxx
@@ -12,7 +12,6 @@
#include <tools/stream.hxx>
#include <vcl/BitmapWriteAccess.hxx>
-#include <vcl/bitmap/BitmapAlphaClampFilter.hxx>
#include <vcl/bitmap/BitmapArithmeticBlendFilter.hxx>
#include <vcl/bitmap/BitmapDarkenBlendFilter.hxx>
#include <vcl/bitmap/BitmapLightenBlendFilter.hxx>
@@ -41,7 +40,6 @@ public:
{
}
- void testClampAlpha();
void testBlurCorrectness();
void testBasicMorphology();
void testPerformance();
@@ -54,7 +52,6 @@ public:
void testArithmeticBlendFilter();
CPPUNIT_TEST_SUITE(BitmapFilterTest);
- CPPUNIT_TEST(testClampAlpha);
CPPUNIT_TEST(testBlurCorrectness);
CPPUNIT_TEST(testBasicMorphology);
CPPUNIT_TEST(testPerformance);
@@ -92,21 +89,6 @@ private:
}
};
-void BitmapFilterTest::testClampAlpha()
-{
- // Setup test bitmap
- Size aSize(1, 1);
- Bitmap aBitmap24Bit(aSize, vcl::PixelFormat::N24_BPP);
-
- {
- BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit);
- aWriteAccess->Erase(COL_RED);
- }
-
- BitmapFilter::Filter(aBitmap24Bit, BitmapAlphaClampFilter(0x7F));
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(0xFF), aBitmap24Bit.GetPixelColor(0, 0).GetAlpha());
-}
-
void BitmapFilterTest::testBlurCorrectness()
{
// Setup test bitmap
diff --git a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx
index aeed3e8bdfed..ad4bc9eed33f 100644
--- a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx
+++ b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx
@@ -54,6 +54,8 @@ class GraphicFormatDetectorTest : public test::BootstrapFixtureBase
void testDetectWEBP();
void testDetectEMF();
void testDetectEMZ();
+ void testDetectDXF();
+ void testDetectDXF2();
void testMatchArray();
void testCheckArrayForMatchingStrings();
@@ -80,6 +82,8 @@ class GraphicFormatDetectorTest : public test::BootstrapFixtureBase
CPPUNIT_TEST(testDetectWEBP);
CPPUNIT_TEST(testDetectEMF);
CPPUNIT_TEST(testDetectEMZ);
+ CPPUNIT_TEST(testDetectDXF);
+ CPPUNIT_TEST(testDetectDXF2);
CPPUNIT_TEST(testMatchArray);
CPPUNIT_TEST(testCheckArrayForMatchingStrings);
CPPUNIT_TEST_SUITE_END();
@@ -416,6 +420,36 @@ void GraphicFormatDetectorTest::testDetectEMZ()
CPPUNIT_ASSERT_EQUAL(u"EMZ"_ustr, rFormatExtension);
}
+void GraphicFormatDetectorTest::testDetectDXF()
+{
+ SvFileStream aFileStream(getFullUrl(u"TypeDetectionExample.dxf"), StreamMode::READ);
+ vcl::GraphicFormatDetector aDetector(aFileStream, u"<DXF"_ustr);
+
+ CPPUNIT_ASSERT(aDetector.detect());
+ CPPUNIT_ASSERT(aDetector.checkDXF());
+
+ aFileStream.Seek(aDetector.mnStreamPosition);
+
+ OUString rFormatExtension;
+ CPPUNIT_ASSERT(vcl::peekGraphicFormat(aFileStream, rFormatExtension, false));
+ CPPUNIT_ASSERT_EQUAL(u"DXF"_ustr, rFormatExtension);
+}
+
+void GraphicFormatDetectorTest::testDetectDXF2()
+{
+ SvFileStream aFileStream(getFullUrl(u"TypeDetectionExample2.dxf"), StreamMode::READ);
+ vcl::GraphicFormatDetector aDetector(aFileStream, u"<DXF"_ustr);
+
+ CPPUNIT_ASSERT(aDetector.detect());
+ CPPUNIT_ASSERT(aDetector.checkDXF());
+
+ aFileStream.Seek(aDetector.mnStreamPosition);
+
+ OUString rFormatExtension;
+ CPPUNIT_ASSERT(vcl::peekGraphicFormat(aFileStream, rFormatExtension, false));
+ CPPUNIT_ASSERT_EQUAL(u"DXF"_ustr, rFormatExtension);
+}
+
void GraphicFormatDetectorTest::testMatchArray()
{
std::string aString("<?xml version=\"1.0\" standalone=\"no\"?>\n"
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.dxf b/vcl/qa/cppunit/data/TypeDetectionExample.dxf
new file mode 100644
index 000000000000..29eff8c4564a
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample.dxf
@@ -0,0 +1,4184 @@
+ 0
+SECTION
+ 2
+ENTITIES
+ 0
+LINE
+ 8
+0
+ 10
+0.004042
+ 20
+-0.091303
+ 30
+0.014439
+ 11
+0.007453
+ 21
+-0.088746
+ 31
+0.014536
+ 0
+LINE
+ 8
+0
+ 10
+-0.002689
+ 20
+-0.096351
+ 30
+0.014476
+ 11
+0.004042
+ 21
+-0.091303
+ 31
+0.014439
+ 0
+LINE
+ 8
+0
+ 10
+-0.011156
+ 20
+-0.102699
+ 30
+0.014513
+ 11
+-0.002689
+ 21
+-0.096351
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.021838
+ 20
+-0.110707
+ 30
+0.014551
+ 11
+-0.011156
+ 21
+-0.102699
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.014513
+ 11
+-0.021838
+ 21
+-0.110707
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.042899
+ 20
+-0.1265
+ 30
+0.014551
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.05391
+ 20
+-0.134756
+ 30
+0.014513
+ 11
+-0.042899
+ 21
+-0.1265
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.064888
+ 20
+-0.142988
+ 30
+0.014476
+ 11
+-0.05391
+ 21
+-0.134756
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.014476
+ 11
+-0.064888
+ 21
+-0.142988
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.085502
+ 20
+-0.158444
+ 30
+0.014551
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.093041
+ 20
+-0.164098
+ 30
+0.014476
+ 11
+-0.085502
+ 21
+-0.158444
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.096871
+ 20
+-0.166969
+ 30
+0.014573
+ 11
+-0.093041
+ 21
+-0.164098
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.088164
+ 21
+-0.159741
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.088164
+ 21
+-0.159741
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.079942
+ 21
+-0.16996
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.090789
+ 21
+-0.162467
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.091168
+ 20
+-0.160927
+ 30
+-0.002693
+ 11
+-0.090123
+ 21
+-0.161099
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.090866
+ 20
+-0.159382
+ 30
+-0.002693
+ 11
+-0.091168
+ 21
+-0.160927
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.090866
+ 21
+-0.159382
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080451
+ 20
+-0.171349
+ 30
+0.009188
+ 11
+-0.079942
+ 21
+-0.16996
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.088164
+ 20
+-0.159741
+ 30
+0.009188
+ 11
+-0.080451
+ 21
+-0.171349
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.089492
+ 20
+-0.158529
+ 30
+-0.002693
+ 11
+-0.088164
+ 21
+-0.159741
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.089492
+ 21
+-0.158529
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082569
+ 20
+-0.172686
+ 30
+0.009188
+ 11
+-0.084111
+ 21
+-0.17261
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082854
+ 20
+-0.17362
+ 30
+-0.002693
+ 11
+-0.082569
+ 21
+-0.172686
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.081266
+ 20
+-0.173604
+ 30
+-0.002693
+ 11
+-0.082854
+ 21
+-0.17362
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082569
+ 20
+-0.172686
+ 30
+0.009188
+ 11
+-0.081266
+ 21
+-0.173604
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080451
+ 20
+-0.171349
+ 30
+0.009188
+ 11
+-0.082569
+ 21
+-0.172686
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.080184
+ 20
+-0.173003
+ 30
+-0.002693
+ 11
+-0.080451
+ 21
+-0.171349
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.079721
+ 20
+-0.171706
+ 30
+-0.002693
+ 11
+-0.080184
+ 21
+-0.173003
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080451
+ 20
+-0.171349
+ 30
+0.009188
+ 11
+-0.079721
+ 21
+-0.171706
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082569
+ 20
+-0.172686
+ 30
+0.009188
+ 11
+-0.080451
+ 21
+-0.171349
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.082569
+ 21
+-0.172686
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.079721
+ 20
+-0.171706
+ 30
+-0.002693
+ 11
+-0.079942
+ 21
+-0.16996
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080184
+ 20
+-0.173003
+ 30
+-0.002693
+ 11
+-0.079721
+ 21
+-0.171706
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.081266
+ 20
+-0.173604
+ 30
+-0.002693
+ 11
+-0.080184
+ 21
+-0.173003
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082854
+ 20
+-0.17362
+ 30
+-0.002693
+ 11
+-0.081266
+ 21
+-0.173604
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.084111
+ 20
+-0.17261
+ 30
+-0.002693
+ 11
+-0.082854
+ 21
+-0.17362
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090789
+ 20
+-0.162467
+ 30
+-0.002693
+ 11
+-0.084111
+ 21
+-0.17261
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.091168
+ 20
+-0.160927
+ 30
+-0.002693
+ 11
+-0.090789
+ 21
+-0.162467
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090866
+ 20
+-0.159382
+ 30
+-0.002693
+ 11
+-0.091168
+ 21
+-0.160927
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.089492
+ 20
+-0.158529
+ 30
+-0.002693
+ 11
+-0.090866
+ 21
+-0.159382
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.089492
+ 21
+-0.158529
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+0.000899
+ 21
+-0.092487
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+0.000899
+ 21
+-0.092487
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+0.00912
+ 21
+-0.102707
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+-0.001727
+ 21
+-0.095211
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.002105
+ 20
+-0.093672
+ 30
+-0.001109
+ 11
+-0.00106
+ 21
+-0.093844
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.001803
+ 20
+-0.092126
+ 30
+-0.001109
+ 11
+-0.002105
+ 21
+-0.093672
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+-0.001803
+ 21
+-0.092126
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008612
+ 20
+-0.104095
+ 30
+0.009188
+ 11
+0.00912
+ 21
+-0.102707
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.000899
+ 20
+-0.092487
+ 30
+0.009188
+ 11
+0.008612
+ 21
+-0.104095
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.000428
+ 20
+-0.091274
+ 30
+-0.001109
+ 11
+0.000899
+ 21
+-0.092487
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+-0.000428
+ 21
+-0.091274
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006495
+ 20
+-0.105431
+ 30
+0.009188
+ 11
+0.004952
+ 21
+-0.105356
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006208
+ 20
+-0.106364
+ 30
+-0.001109
+ 11
+0.006495
+ 21
+-0.105431
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.007796
+ 20
+-0.106349
+ 30
+-0.001109
+ 11
+0.006208
+ 21
+-0.106364
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006495
+ 20
+-0.105431
+ 30
+0.009188
+ 11
+0.007796
+ 21
+-0.106349
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008612
+ 20
+-0.104095
+ 30
+0.009188
+ 11
+0.006495
+ 21
+-0.105431
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.008879
+ 20
+-0.105748
+ 30
+-0.001109
+ 11
+0.008612
+ 21
+-0.104095
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.009342
+ 20
+-0.10445
+ 30
+-0.001109
+ 11
+0.008879
+ 21
+-0.105748
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008612
+ 20
+-0.104095
+ 30
+0.009188
+ 11
+0.009342
+ 21
+-0.10445
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006495
+ 20
+-0.105431
+ 30
+0.009188
+ 11
+0.008612
+ 21
+-0.104095
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+0.006495
+ 21
+-0.105431
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.009342
+ 20
+-0.10445
+ 30
+-0.001109
+ 11
+0.00912
+ 21
+-0.102707
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008879
+ 20
+-0.105748
+ 30
+-0.001109
+ 11
+0.009342
+ 21
+-0.10445
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.007796
+ 20
+-0.106349
+ 30
+-0.001109
+ 11
+0.008879
+ 21
+-0.105748
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006208
+ 20
+-0.106364
+ 30
+-0.001109
+ 11
+0.007796
+ 21
+-0.106349
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.004952
+ 20
+-0.105356
+ 30
+-0.001109
+ 11
+0.006208
+ 21
+-0.106364
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.001727
+ 20
+-0.095211
+ 30
+-0.001109
+ 11
+0.004952
+ 21
+-0.105356
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.002105
+ 20
+-0.093672
+ 30
+-0.001109
+ 11
+-0.001727
+ 21
+-0.095211
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.001803
+ 20
+-0.092126
+ 30
+-0.001109
+ 11
+-0.002105
+ 21
+-0.093672
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.000428
+ 20
+-0.091274
+ 30
+-0.001109
+ 11
+-0.001803
+ 21
+-0.092126
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+-0.000428
+ 21
+-0.091274
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.011409
+ 20
+-0.102736
+ 30
+0.014391
+ 11
+0.01482
+ 21
+-0.100179
+ 31
+0.014489
+ 0
+LINE
+ 8
+0
+ 10
+0.004678
+ 20
+-0.107783
+ 30
+0.01443
+ 11
+0.011409
+ 21
+-0.102736
+ 31
+0.014391
+ 0
+LINE
+ 8
+0
+ 10
+-0.003789
+ 20
+-0.114132
+ 30
+0.014466
+ 11
+0.004678
+ 21
+-0.107783
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.014469
+ 20
+-0.12214
+ 30
+0.014503
+ 11
+-0.003789
+ 21
+-0.114132
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.014466
+ 11
+-0.014469
+ 21
+-0.12214
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.035532
+ 20
+-0.137933
+ 30
+0.014503
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.046541
+ 20
+-0.146189
+ 30
+0.014466
+ 11
+-0.035532
+ 21
+-0.137933
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.057521
+ 20
+-0.154422
+ 30
+0.01443
+ 11
+-0.046541
+ 21
+-0.146189
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.01443
+ 11
+-0.057521
+ 21
+-0.154422
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.078135
+ 20
+-0.169877
+ 30
+0.014503
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.085674
+ 20
+-0.175531
+ 30
+0.01443
+ 11
+-0.078135
+ 21
+-0.169877
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.089503
+ 20
+-0.178402
+ 30
+0.014527
+ 11
+-0.085674
+ 21
+-0.175531
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+0.001416
+ 20
+-0.110228
+ 30
+0.025254
+ 11
+0.000781
+ 21
+-0.093749
+ 31
+0.020553
+ 0
+LINE
+ 8
+0
+ 10
+-0.016452
+ 20
+-0.106669
+ 30
+0.031317
+ 11
+0.001416
+ 21
+-0.110228
+ 31
+0.025254
+ 0
+LINE
+ 8
+0
+ 10
+-0.019645
+ 20
+-0.126021
+ 30
+0.03542
+ 11
+-0.016452
+ 21
+-0.106669
+ 31
+0.031317
+ 0
+LINE
+ 8
+0
+ 10
+-0.037035
+ 20
+-0.122103
+ 30
+0.037298
+ 11
+-0.019645
+ 21
+-0.126021
+ 31
+0.03542
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.037214
+ 11
+-0.037035
+ 21
+-0.122103
+ 31
+0.037298
+ 0
+LINE
+ 8
+0
+ 10
+-0.059055
+ 20
+-0.138615
+ 30
+0.035504
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.037214
+ 0
+LINE
+ 8
+0
+ 10
+-0.063205
+ 20
+-0.158683
+ 30
+0.031234
+ 11
+-0.059055
+ 21
+-0.138615
+ 31
+0.035504
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.025337
+ 11
+-0.063205
+ 21
+-0.158683
+ 31
+0.031234
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.02047
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.025337
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.020516
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.02047
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.025291
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.020516
+ 0
+LINE
+ 8
+0
+ 10
+-0.070574
+ 20
+-0.14725
+ 30
+0.03128
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.025291
+ 0
+LINE
+ 8
+0
+ 10
+-0.051688
+ 20
+-0.150048
+ 30
+0.035457
+ 11
+-0.070574
+ 21
+-0.14725
+ 31
+0.03128
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.03726
+ 11
+-0.051688
+ 21
+-0.150048
+ 31
+0.035457
+ 0
+LINE
+ 8
+0
+ 10
+-0.029668
+ 20
+-0.133536
+ 30
+0.037251
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.03726
+ 0
+LINE
+ 8
+0
+ 10
+-0.027012
+ 20
+-0.114588
+ 30
+0.035466
+ 11
+-0.029668
+ 21
+-0.133536
+ 31
+0.037251
+ 0
+LINE
+ 8
+0
+ 10
+-0.009085
+ 20
+-0.118102
+ 30
+0.031271
+ 11
+-0.027012
+ 21
+-0.114588
+ 31
+0.035466
+ 0
+LINE
+ 8
+0
+ 10
+-0.005951
+ 20
+-0.098795
+ 30
+0.0253
+ 11
+-0.009085
+ 21
+-0.118102
+ 31
+0.031271
+ 0
+LINE
+ 8
+0
+ 10
+0.008149
+ 20
+-0.105182
+ 30
+0.020507
+ 11
+-0.005951
+ 21
+-0.098795
+ 31
+0.0253
+ 0
+LINE
+ 8
+0
+ 10
+0.000781
+ 20
+-0.093749
+ 30
+0.020553
+ 11
+0.008149
+ 21
+-0.105182
+ 31
+0.020507
+ 0
+LINE
+ 8
+0
+ 10
+0.004042
+ 20
+-0.091303
+ 30
+0.014439
+ 11
+0.003952
+ 21
+-0.09137
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.002689
+ 20
+-0.096351
+ 30
+0.014476
+ 11
+-0.00266
+ 21
+-0.096328
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.011156
+ 20
+-0.102699
+ 30
+0.014513
+ 11
+-0.011186
+ 21
+-0.102721
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.021838
+ 20
+-0.110707
+ 30
+0.014551
+ 11
+-0.021867
+ 21
+-0.11073
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.014513
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.042899
+ 20
+-0.1265
+ 30
+0.014551
+ 11
+-0.042929
+ 21
+-0.126523
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.05391
+ 20
+-0.134756
+ 30
+0.014513
+ 11
+-0.053969
+ 21
+-0.134801
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.064888
+ 20
+-0.142988
+ 30
+0.014476
+ 11
+-0.064919
+ 21
+-0.14301
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.014476
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.085502
+ 20
+-0.158444
+ 30
+0.014551
+ 11
+-0.085533
+ 21
+-0.158467
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.093041
+ 20
+-0.164098
+ 30
+0.014476
+ 11
+-0.093012
+ 21
+-0.164076
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.020516
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.025337
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.070574
+ 20
+-0.14725
+ 30
+0.03128
+ 11
+-0.070603
+ 21
+-0.147273
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.059055
+ 20
+-0.138615
+ 30
+0.035504
+ 11
+-0.059115
+ 21
+-0.138659
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.03726
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.037035
+ 20
+-0.122103
+ 30
+0.037298
+ 11
+-0.037095
+ 21
+-0.122148
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.027012
+ 20
+-0.114588
+ 30
+0.035466
+ 11
+-0.027043
+ 21
+-0.114611
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.016452
+ 20
+-0.106669
+ 30
+0.031317
+ 11
+-0.016482
+ 21
+-0.106692
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.005951
+ 20
+-0.098795
+ 30
+0.0253
+ 11
+-0.00592
+ 21
+-0.098773
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.000781
+ 20
+-0.093749
+ 30
+0.020553
+ 11
+0.000721
+ 21
+-0.093794
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.093041
+ 20
+-0.164098
+ 30
+0.014476
+ 11
+-0.096931
+ 21
+-0.167014
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.00943
+ 11
+-0.093041
+ 21
+-0.164098
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.085502
+ 20
+-0.158444
+ 30
+0.014551
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.009392
+ 11
+-0.085502
+ 21
+-0.158444
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.014476
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.070603
+ 20
+-0.147273
+ 30
+0.00943
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.064888
+ 20
+-0.142988
+ 30
+0.014476
+ 11
+-0.070603
+ 21
+-0.147273
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.059115
+ 20
+-0.138659
+ 30
+0.009392
+ 11
+-0.064888
+ 21
+-0.142988
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.05391
+ 20
+-0.134756
+ 30
+0.014513
+ 11
+-0.059115
+ 21
+-0.138659
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.00943
+ 11
+-0.05391
+ 21
+-0.134756
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.042899
+ 20
+-0.1265
+ 30
+0.014551
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.037095
+ 20
+-0.122148
+ 30
+0.009392
+ 11
+-0.042899
+ 21
+-0.1265
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.014513
+ 11
+-0.037095
+ 21
+-0.122148
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.027043
+ 20
+-0.114611
+ 30
+0.00943
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.021838
+ 20
+-0.110707
+ 30
+0.014551
+ 11
+-0.027043
+ 21
+-0.114611
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.016482
+ 20
+-0.106692
+ 30
+0.009392
+ 11
+-0.021838
+ 21
+-0.110707
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.011156
+ 20
+-0.102699
+ 30
+0.014513
+ 11
+-0.016482
+ 21
+-0.106692
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.00592
+ 20
+-0.098773
+ 30
+0.00943
+ 11
+-0.011156
+ 21
+-0.102699
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.002689
+ 20
+-0.096351
+ 30
+0.014476
+ 11
+-0.00592
+ 21
+-0.098773
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.000721
+ 20
+-0.093794
+ 30
+0.009392
+ 11
+-0.002689
+ 21
+-0.096351
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+0.004042
+ 20
+-0.091303
+ 30
+0.014439
+ 11
+0.000721
+ 21
+-0.093794
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+0.007512
+ 20
+-0.088701
+ 30
+0.00943
+ 11
+0.004042
+ 21
+-0.091303
+ 31
+0.014439
+ 0
+LINE
+ 8
+0
+ 10
+0.007453
+ 20
+-0.088746
+ 30
+0.014536
+ 11
+0.007512
+ 21
+-0.088701
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.003952
+ 20
+-0.09137
+ 30
+0.009355
+ 11
+0.007512
+ 21
+-0.088701
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.000721
+ 20
+-0.093794
+ 30
+0.009392
+ 11
+0.003952
+ 21
+-0.09137
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.00266
+ 20
+-0.096328
+ 30
+0.009541
+ 11
+0.000721
+ 21
+-0.093794
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.00592
+ 20
+-0.098773
+ 30
+0.00943
+ 11
+-0.00266
+ 21
+-0.096328
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.011186
+ 20
+-0.102721
+ 30
+0.009355
+ 11
+-0.00592
+ 21
+-0.098773
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.016482
+ 20
+-0.106692
+ 30
+0.009392
+ 11
+-0.011186
+ 21
+-0.102721
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.021867
+ 20
+-0.11073
+ 30
+0.009392
+ 11
+-0.016482
+ 21
+-0.106692
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.027043
+ 20
+-0.114611
+ 30
+0.00943
+ 11
+-0.021867
+ 21
+-0.11073
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.009392
+ 11
+-0.027043
+ 21
+-0.114611
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.037095
+ 20
+-0.122148
+ 30
+0.009392
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.042929
+ 20
+-0.126523
+ 30
+0.009392
+ 11
+-0.037095
+ 21
+-0.122148
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.00943
+ 11
+-0.042929
+ 21
+-0.126523
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.053969
+ 20
+-0.134801
+ 30
+0.009392
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.059115
+ 20
+-0.138659
+ 30
+0.009392
+ 11
+-0.053969
+ 21
+-0.134801
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.064919
+ 20
+-0.14301
+ 30
+0.009355
+ 11
+-0.059115
+ 21
+-0.138659
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.070603
+ 20
+-0.147273
+ 30
+0.00943
+ 11
+-0.064919
+ 21
+-0.14301
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.00943
+ 11
+-0.070603
+ 21
+-0.147273
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.009392
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.085533
+ 20
+-0.158467
+ 30
+0.009392
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.00943
+ 11
+-0.085533
+ 21
+-0.158467
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.093012
+ 20
+-0.164076
+ 30
+0.009541
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.096931
+ 20
+-0.167014
+ 30
+0.009392
+ 11
+-0.093012
+ 21
+-0.164076
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.096871
+ 20
+-0.166969
+ 30
+0.014573
+ 11
+-0.096931
+ 21
+-0.167014
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.020516
+ 11
+-0.096871
+ 21
+-0.166969
+ 31
+0.014573
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.025337
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.020516
+ 0
+LINE
+ 8
+0
+ 10
+-0.070574
+ 20
+-0.14725
+ 30
+0.03128
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.025337
+ 0
+LINE
+ 8
+0
+ 10
+-0.059055
+ 20
+-0.138615
+ 30
+0.035504
+ 11
+-0.070574
+ 21
+-0.14725
+ 31
+0.03128
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.03726
+ 11
+-0.059055
+ 21
+-0.138615
+ 31
+0.035504
+ 0
+LINE
+ 8
+0
+ 10
+-0.037035
+ 20
+-0.122103
+ 30
+0.037298
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.03726
+ 0
+LINE
+ 8
+0
+ 10
+-0.027012
+ 20
+-0.114588
+ 30
+0.035466
+ 11
+-0.037035
+ 21
+-0.122103
+ 31
+0.037298
+ 0
+LINE
+ 8
+0
+ 10
+-0.016452
+ 20
+-0.106669
+ 30
+0.031317
+ 11
+-0.027012
+ 21
+-0.114588
+ 31
+0.035466
+ 0
+LINE
+ 8
+0
+ 10
+-0.005951
+ 20
+-0.098795
+ 30
+0.0253
+ 11
+-0.016452
+ 21
+-0.106669
+ 31
+0.031317
+ 0
+LINE
+ 8
+0
+ 10
+0.000781
+ 20
+-0.093749
+ 30
+0.020553
+ 11
+-0.005951
+ 21
+-0.098795
+ 31
+0.0253
+ 0
+LINE
+ 8
+0
+ 10
+0.007453
+ 20
+-0.088746
+ 30
+0.014536
+ 11
+0.000781
+ 21
+-0.093749
+ 31
+0.020553
+ 0
+LINE
+ 8
+0
+ 10
+0.011409
+ 20
+-0.102736
+ 30
+0.014391
+ 11
+0.011319
+ 21
+-0.102803
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+0.004678
+ 20
+-0.107783
+ 30
+0.01443
+ 11
+0.004709
+ 21
+-0.107761
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.003789
+ 20
+-0.114132
+ 30
+0.014466
+ 11
+-0.003819
+ 21
+-0.114154
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.014469
+ 20
+-0.12214
+ 30
+0.014503
+ 11
+-0.014499
+ 21
+-0.122163
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.014466
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.035532
+ 20
+-0.137933
+ 30
+0.014503
+ 11
+-0.035561
+ 21
+-0.137956
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.046541
+ 20
+-0.146189
+ 30
+0.014466
+ 11
+-0.046602
+ 21
+-0.146234
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.057521
+ 20
+-0.154422
+ 30
+0.01443
+ 11
+-0.057552
+ 21
+-0.154445
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.01443
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.078135
+ 20
+-0.169877
+ 30
+0.014503
+ 11
+-0.078164
+ 21
+-0.1699
+ 31
+0.014573
+ 0
+LINE
+ 8
+0
+ 10
+-0.085674
+ 20
+-0.175531
+ 30
+0.01443
+ 11
+-0.085644
+ 21
+-0.175509
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.02047
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.025291
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.063205
+ 20
+-0.158683
+ 30
+0.031234
+ 11
+-0.063236
+ 21
+-0.158706
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.051688
+ 20
+-0.150048
+ 30
+0.035457
+ 11
+-0.051747
+ 21
+-0.150092
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.037214
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.029668
+ 20
+-0.133536
+ 30
+0.037251
+ 11
+-0.029728
+ 21
+-0.133581
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.019645
+ 20
+-0.126021
+ 30
+0.03542
+ 11
+-0.019675
+ 21
+-0.126044
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.009085
+ 20
+-0.118102
+ 30
+0.031271
+ 11
+-0.009114
+ 21
+-0.118125
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.001416
+ 20
+-0.110228
+ 30
+0.025254
+ 11
+0.001447
+ 21
+-0.110206
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.008149
+ 20
+-0.105182
+ 30
+0.020507
+ 11
+0.008089
+ 21
+-0.105227
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.085674
+ 20
+-0.175531
+ 30
+0.01443
+ 11
+-0.089563
+ 21
+-0.178447
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.009383
+ 11
+-0.085674
+ 21
+-0.175531
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.078135
+ 20
+-0.169877
+ 30
+0.014503
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.009346
+ 11
+-0.078135
+ 21
+-0.169877
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.01443
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.063236
+ 20
+-0.158706
+ 30
+0.009383
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.057521
+ 20
+-0.154422
+ 30
+0.01443
+ 11
+-0.063236
+ 21
+-0.158706
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.051747
+ 20
+-0.150092
+ 30
+0.009346
+ 11
+-0.057521
+ 21
+-0.154422
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.046541
+ 20
+-0.146189
+ 30
+0.014466
+ 11
+-0.051747
+ 21
+-0.150092
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.009383
+ 11
+-0.046541
+ 21
+-0.146189
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.035532
+ 20
+-0.137933
+ 30
+0.014503
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.029728
+ 20
+-0.133581
+ 30
+0.009346
+ 11
+-0.035532
+ 21
+-0.137933
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.014466
+ 11
+-0.029728
+ 21
+-0.133581
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.019675
+ 20
+-0.126044
+ 30
+0.009383
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.014469
+ 20
+-0.12214
+ 30
+0.014503
+ 11
+-0.019675
+ 21
+-0.126044
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.009114
+ 20
+-0.118125
+ 30
+0.009346
+ 11
+-0.014469
+ 21
+-0.12214
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.003789
+ 20
+-0.114132
+ 30
+0.014466
+ 11
+-0.009114
+ 21
+-0.118125
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.001447
+ 20
+-0.110206
+ 30
+0.009383
+ 11
+-0.003789
+ 21
+-0.114132
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+0.004678
+ 20
+-0.107783
+ 30
+0.01443
+ 11
+0.001447
+ 21
+-0.110206
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.008089
+ 20
+-0.105227
+ 30
+0.009346
+ 11
+0.004678
+ 21
+-0.107783
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+0.011409
+ 20
+-0.102736
+ 30
+0.014391
+ 11
+0.008089
+ 21
+-0.105227
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.01488
+ 20
+-0.100134
+ 30
+0.009383
+ 11
+0.011409
+ 21
+-0.102736
+ 31
+0.014391
+ 0
+LINE
+ 8
+0
+ 10
+0.01482
+ 20
+-0.100179
+ 30
+0.014489
+ 11
+0.01488
+ 21
+-0.100134
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.011319
+ 20
+-0.102803
+ 30
+0.009309
+ 11
+0.01488
+ 21
+-0.100134
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.008089
+ 20
+-0.105227
+ 30
+0.009346
+ 11
+0.011319
+ 21
+-0.102803
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+0.004709
+ 20
+-0.107761
+ 30
+0.009495
+ 11
+0.008089
+ 21
+-0.105227
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.001447
+ 20
+-0.110206
+ 30
+0.009383
+ 11
+0.004709
+ 21
+-0.107761
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.003819
+ 20
+-0.114154
+ 30
+0.009309
+ 11
+0.001447
+ 21
+-0.110206
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.009114
+ 20
+-0.118125
+ 30
+0.009346
+ 11
+-0.003819
+ 21
+-0.114154
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.014499
+ 20
+-0.122163
+ 30
+0.009346
+ 11
+-0.009114
+ 21
+-0.118125
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.019675
+ 20
+-0.126044
+ 30
+0.009383
+ 11
+-0.014499
+ 21
+-0.122163
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.009346
+ 11
+-0.019675
+ 21
+-0.126044
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.029728
+ 20
+-0.133581
+ 30
+0.009346
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.035561
+ 20
+-0.137956
+ 30
+0.009346
+ 11
+-0.029728
+ 21
+-0.133581
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.009383
+ 11
+-0.035561
+ 21
+-0.137956
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.046602
+ 20
+-0.146234
+ 30
+0.009346
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.051747
+ 20
+-0.150092
+ 30
+0.009346
+ 11
+-0.046602
+ 21
+-0.146234
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.057552
+ 20
+-0.154445
+ 30
+0.009309
+ 11
+-0.051747
+ 21
+-0.150092
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.063236
+ 20
+-0.158706
+ 30
+0.009383
+ 11
+-0.057552
+ 21
+-0.154445
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.009383
+ 11
+-0.063236
+ 21
+-0.158706
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.009346
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.009383
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.085644
+ 20
+-0.175509
+ 30
+0.009495
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.089563
+ 20
+-0.178447
+ 30
+0.009346
+ 11
+-0.085644
+ 21
+-0.175509
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.089503
+ 20
+-0.178402
+ 30
+0.014527
+ 11
+-0.089563
+ 21
+-0.178447
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.02047
+ 11
+-0.089503
+ 21
+-0.178402
+ 31
+0.014527
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.025291
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.02047
+ 0
+LINE
+ 8
+0
+ 10
+-0.063205
+ 20
+-0.158683
+ 30
+0.031234
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.025291
+ 0
+LINE
+ 8
+0
+ 10
+-0.051688
+ 20
+-0.150048
+ 30
+0.035457
+ 11
+-0.063205
+ 21
+-0.158683
+ 31
+0.031234
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.037214
+ 11
+-0.051688
+ 21
+-0.150048
+ 31
+0.035457
+ 0
+LINE
+ 8
+0
+ 10
+-0.029668
+ 20
+-0.133536
+ 30
+0.037251
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.037214
+ 0
+LINE
+ 8
+0
+ 10
+-0.019645
+ 20
+-0.126021
+ 30
+0.03542
+ 11
+-0.029668
+ 21
+-0.133536
+ 31
+0.037251
+ 0
+LINE
+ 8
+0
+ 10
+-0.009085
+ 20
+-0.118102
+ 30
+0.031271
+ 11
+-0.019645
+ 21
+-0.126021
+ 31
+0.03542
+ 0
+LINE
+ 8
+0
+ 10
+0.001416
+ 20
+-0.110228
+ 30
+0.025254
+ 11
+-0.009085
+ 21
+-0.118102
+ 31
+0.031271
+ 0
+LINE
+ 8
+0
+ 10
+0.008149
+ 20
+-0.105182
+ 30
+0.020507
+ 11
+0.001416
+ 21
+-0.110228
+ 31
+0.025254
+ 0
+LINE
+ 8
+0
+ 10
+0.01482
+ 20
+-0.100179
+ 30
+0.014489
+ 11
+0.008149
+ 21
+-0.105182
+ 31
+0.020507
+ 0
+ENDSEC
+ 0
+EOF
diff --git a/vcl/qa/cppunit/data/TypeDetectionExample2.dxf b/vcl/qa/cppunit/data/TypeDetectionExample2.dxf
new file mode 100644
index 000000000000..dd278f6de009
--- /dev/null
+++ b/vcl/qa/cppunit/data/TypeDetectionExample2.dxf
@@ -0,0 +1,4186 @@
+999
+DXF data, created by potrace 1.16, written by Peter Selinger 2001-2019
+ 0
+SECTION
+ 2
+ENTITIES
+ 0
+LINE
+ 8
+0
+ 10
+0.004042
+ 20
+-0.091303
+ 30
+0.014439
+ 11
+0.007453
+ 21
+-0.088746
+ 31
+0.014536
+ 0
+LINE
+ 8
+0
+ 10
+-0.002689
+ 20
+-0.096351
+ 30
+0.014476
+ 11
+0.004042
+ 21
+-0.091303
+ 31
+0.014439
+ 0
+LINE
+ 8
+0
+ 10
+-0.011156
+ 20
+-0.102699
+ 30
+0.014513
+ 11
+-0.002689
+ 21
+-0.096351
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.021838
+ 20
+-0.110707
+ 30
+0.014551
+ 11
+-0.011156
+ 21
+-0.102699
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.014513
+ 11
+-0.021838
+ 21
+-0.110707
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.042899
+ 20
+-0.1265
+ 30
+0.014551
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.05391
+ 20
+-0.134756
+ 30
+0.014513
+ 11
+-0.042899
+ 21
+-0.1265
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.064888
+ 20
+-0.142988
+ 30
+0.014476
+ 11
+-0.05391
+ 21
+-0.134756
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.014476
+ 11
+-0.064888
+ 21
+-0.142988
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.085502
+ 20
+-0.158444
+ 30
+0.014551
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.093041
+ 20
+-0.164098
+ 30
+0.014476
+ 11
+-0.085502
+ 21
+-0.158444
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.096871
+ 20
+-0.166969
+ 30
+0.014573
+ 11
+-0.093041
+ 21
+-0.164098
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.088164
+ 21
+-0.159741
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.088164
+ 21
+-0.159741
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.079942
+ 21
+-0.16996
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.090789
+ 21
+-0.162467
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.091168
+ 20
+-0.160927
+ 30
+-0.002693
+ 11
+-0.090123
+ 21
+-0.161099
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.090866
+ 20
+-0.159382
+ 30
+-0.002693
+ 11
+-0.091168
+ 21
+-0.160927
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.090866
+ 21
+-0.159382
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080451
+ 20
+-0.171349
+ 30
+0.009188
+ 11
+-0.079942
+ 21
+-0.16996
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.088164
+ 20
+-0.159741
+ 30
+0.009188
+ 11
+-0.080451
+ 21
+-0.171349
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.089492
+ 20
+-0.158529
+ 30
+-0.002693
+ 11
+-0.088164
+ 21
+-0.159741
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.089492
+ 21
+-0.158529
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082569
+ 20
+-0.172686
+ 30
+0.009188
+ 11
+-0.084111
+ 21
+-0.17261
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082854
+ 20
+-0.17362
+ 30
+-0.002693
+ 11
+-0.082569
+ 21
+-0.172686
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.081266
+ 20
+-0.173604
+ 30
+-0.002693
+ 11
+-0.082854
+ 21
+-0.17362
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082569
+ 20
+-0.172686
+ 30
+0.009188
+ 11
+-0.081266
+ 21
+-0.173604
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080451
+ 20
+-0.171349
+ 30
+0.009188
+ 11
+-0.082569
+ 21
+-0.172686
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.080184
+ 20
+-0.173003
+ 30
+-0.002693
+ 11
+-0.080451
+ 21
+-0.171349
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.079721
+ 20
+-0.171706
+ 30
+-0.002693
+ 11
+-0.080184
+ 21
+-0.173003
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080451
+ 20
+-0.171349
+ 30
+0.009188
+ 11
+-0.079721
+ 21
+-0.171706
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082569
+ 20
+-0.172686
+ 30
+0.009188
+ 11
+-0.080451
+ 21
+-0.171349
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.090123
+ 20
+-0.161099
+ 30
+0.009188
+ 11
+-0.082569
+ 21
+-0.172686
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.079721
+ 20
+-0.171706
+ 30
+-0.002693
+ 11
+-0.079942
+ 21
+-0.16996
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.080184
+ 20
+-0.173003
+ 30
+-0.002693
+ 11
+-0.079721
+ 21
+-0.171706
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.081266
+ 20
+-0.173604
+ 30
+-0.002693
+ 11
+-0.080184
+ 21
+-0.173003
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.082854
+ 20
+-0.17362
+ 30
+-0.002693
+ 11
+-0.081266
+ 21
+-0.173604
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.084111
+ 20
+-0.17261
+ 30
+-0.002693
+ 11
+-0.082854
+ 21
+-0.17362
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090789
+ 20
+-0.162467
+ 30
+-0.002693
+ 11
+-0.084111
+ 21
+-0.17261
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.091168
+ 20
+-0.160927
+ 30
+-0.002693
+ 11
+-0.090789
+ 21
+-0.162467
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.090866
+ 20
+-0.159382
+ 30
+-0.002693
+ 11
+-0.091168
+ 21
+-0.160927
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.089492
+ 20
+-0.158529
+ 30
+-0.002693
+ 11
+-0.090866
+ 21
+-0.159382
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+-0.0877
+ 20
+-0.158443
+ 30
+-0.002693
+ 11
+-0.089492
+ 21
+-0.158529
+ 31
+-0.002693
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+0.000899
+ 21
+-0.092487
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+0.000899
+ 21
+-0.092487
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+0.00912
+ 21
+-0.102707
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+-0.001727
+ 21
+-0.095211
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.002105
+ 20
+-0.093672
+ 30
+-0.001109
+ 11
+-0.00106
+ 21
+-0.093844
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.001803
+ 20
+-0.092126
+ 30
+-0.001109
+ 11
+-0.002105
+ 21
+-0.093672
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+-0.001803
+ 21
+-0.092126
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008612
+ 20
+-0.104095
+ 30
+0.009188
+ 11
+0.00912
+ 21
+-0.102707
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.000899
+ 20
+-0.092487
+ 30
+0.009188
+ 11
+0.008612
+ 21
+-0.104095
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.000428
+ 20
+-0.091274
+ 30
+-0.001109
+ 11
+0.000899
+ 21
+-0.092487
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+-0.000428
+ 21
+-0.091274
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006495
+ 20
+-0.105431
+ 30
+0.009188
+ 11
+0.004952
+ 21
+-0.105356
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006208
+ 20
+-0.106364
+ 30
+-0.001109
+ 11
+0.006495
+ 21
+-0.105431
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.007796
+ 20
+-0.106349
+ 30
+-0.001109
+ 11
+0.006208
+ 21
+-0.106364
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006495
+ 20
+-0.105431
+ 30
+0.009188
+ 11
+0.007796
+ 21
+-0.106349
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008612
+ 20
+-0.104095
+ 30
+0.009188
+ 11
+0.006495
+ 21
+-0.105431
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.008879
+ 20
+-0.105748
+ 30
+-0.001109
+ 11
+0.008612
+ 21
+-0.104095
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.009342
+ 20
+-0.10445
+ 30
+-0.001109
+ 11
+0.008879
+ 21
+-0.105748
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008612
+ 20
+-0.104095
+ 30
+0.009188
+ 11
+0.009342
+ 21
+-0.10445
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006495
+ 20
+-0.105431
+ 30
+0.009188
+ 11
+0.008612
+ 21
+-0.104095
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+-0.00106
+ 20
+-0.093844
+ 30
+0.009188
+ 11
+0.006495
+ 21
+-0.105431
+ 31
+0.009188
+ 0
+LINE
+ 8
+0
+ 10
+0.009342
+ 20
+-0.10445
+ 30
+-0.001109
+ 11
+0.00912
+ 21
+-0.102707
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.008879
+ 20
+-0.105748
+ 30
+-0.001109
+ 11
+0.009342
+ 21
+-0.10445
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.007796
+ 20
+-0.106349
+ 30
+-0.001109
+ 11
+0.008879
+ 21
+-0.105748
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.006208
+ 20
+-0.106364
+ 30
+-0.001109
+ 11
+0.007796
+ 21
+-0.106349
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.004952
+ 20
+-0.105356
+ 30
+-0.001109
+ 11
+0.006208
+ 21
+-0.106364
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.001727
+ 20
+-0.095211
+ 30
+-0.001109
+ 11
+0.004952
+ 21
+-0.105356
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.002105
+ 20
+-0.093672
+ 30
+-0.001109
+ 11
+-0.001727
+ 21
+-0.095211
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.001803
+ 20
+-0.092126
+ 30
+-0.001109
+ 11
+-0.002105
+ 21
+-0.093672
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+-0.000428
+ 20
+-0.091274
+ 30
+-0.001109
+ 11
+-0.001803
+ 21
+-0.092126
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.001362
+ 20
+-0.091189
+ 30
+-0.001109
+ 11
+-0.000428
+ 21
+-0.091274
+ 31
+-0.001109
+ 0
+LINE
+ 8
+0
+ 10
+0.011409
+ 20
+-0.102736
+ 30
+0.014391
+ 11
+0.01482
+ 21
+-0.100179
+ 31
+0.014489
+ 0
+LINE
+ 8
+0
+ 10
+0.004678
+ 20
+-0.107783
+ 30
+0.01443
+ 11
+0.011409
+ 21
+-0.102736
+ 31
+0.014391
+ 0
+LINE
+ 8
+0
+ 10
+-0.003789
+ 20
+-0.114132
+ 30
+0.014466
+ 11
+0.004678
+ 21
+-0.107783
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.014469
+ 20
+-0.12214
+ 30
+0.014503
+ 11
+-0.003789
+ 21
+-0.114132
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.014466
+ 11
+-0.014469
+ 21
+-0.12214
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.035532
+ 20
+-0.137933
+ 30
+0.014503
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.046541
+ 20
+-0.146189
+ 30
+0.014466
+ 11
+-0.035532
+ 21
+-0.137933
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.057521
+ 20
+-0.154422
+ 30
+0.01443
+ 11
+-0.046541
+ 21
+-0.146189
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.01443
+ 11
+-0.057521
+ 21
+-0.154422
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.078135
+ 20
+-0.169877
+ 30
+0.014503
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.085674
+ 20
+-0.175531
+ 30
+0.01443
+ 11
+-0.078135
+ 21
+-0.169877
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.089503
+ 20
+-0.178402
+ 30
+0.014527
+ 11
+-0.085674
+ 21
+-0.175531
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+0.001416
+ 20
+-0.110228
+ 30
+0.025254
+ 11
+0.000781
+ 21
+-0.093749
+ 31
+0.020553
+ 0
+LINE
+ 8
+0
+ 10
+-0.016452
+ 20
+-0.106669
+ 30
+0.031317
+ 11
+0.001416
+ 21
+-0.110228
+ 31
+0.025254
+ 0
+LINE
+ 8
+0
+ 10
+-0.019645
+ 20
+-0.126021
+ 30
+0.03542
+ 11
+-0.016452
+ 21
+-0.106669
+ 31
+0.031317
+ 0
+LINE
+ 8
+0
+ 10
+-0.037035
+ 20
+-0.122103
+ 30
+0.037298
+ 11
+-0.019645
+ 21
+-0.126021
+ 31
+0.03542
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.037214
+ 11
+-0.037035
+ 21
+-0.122103
+ 31
+0.037298
+ 0
+LINE
+ 8
+0
+ 10
+-0.059055
+ 20
+-0.138615
+ 30
+0.035504
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.037214
+ 0
+LINE
+ 8
+0
+ 10
+-0.063205
+ 20
+-0.158683
+ 30
+0.031234
+ 11
+-0.059055
+ 21
+-0.138615
+ 31
+0.035504
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.025337
+ 11
+-0.063205
+ 21
+-0.158683
+ 31
+0.031234
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.02047
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.025337
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.020516
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.02047
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.025291
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.020516
+ 0
+LINE
+ 8
+0
+ 10
+-0.070574
+ 20
+-0.14725
+ 30
+0.03128
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.025291
+ 0
+LINE
+ 8
+0
+ 10
+-0.051688
+ 20
+-0.150048
+ 30
+0.035457
+ 11
+-0.070574
+ 21
+-0.14725
+ 31
+0.03128
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.03726
+ 11
+-0.051688
+ 21
+-0.150048
+ 31
+0.035457
+ 0
+LINE
+ 8
+0
+ 10
+-0.029668
+ 20
+-0.133536
+ 30
+0.037251
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.03726
+ 0
+LINE
+ 8
+0
+ 10
+-0.027012
+ 20
+-0.114588
+ 30
+0.035466
+ 11
+-0.029668
+ 21
+-0.133536
+ 31
+0.037251
+ 0
+LINE
+ 8
+0
+ 10
+-0.009085
+ 20
+-0.118102
+ 30
+0.031271
+ 11
+-0.027012
+ 21
+-0.114588
+ 31
+0.035466
+ 0
+LINE
+ 8
+0
+ 10
+-0.005951
+ 20
+-0.098795
+ 30
+0.0253
+ 11
+-0.009085
+ 21
+-0.118102
+ 31
+0.031271
+ 0
+LINE
+ 8
+0
+ 10
+0.008149
+ 20
+-0.105182
+ 30
+0.020507
+ 11
+-0.005951
+ 21
+-0.098795
+ 31
+0.0253
+ 0
+LINE
+ 8
+0
+ 10
+0.000781
+ 20
+-0.093749
+ 30
+0.020553
+ 11
+0.008149
+ 21
+-0.105182
+ 31
+0.020507
+ 0
+LINE
+ 8
+0
+ 10
+0.004042
+ 20
+-0.091303
+ 30
+0.014439
+ 11
+0.003952
+ 21
+-0.09137
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.002689
+ 20
+-0.096351
+ 30
+0.014476
+ 11
+-0.00266
+ 21
+-0.096328
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.011156
+ 20
+-0.102699
+ 30
+0.014513
+ 11
+-0.011186
+ 21
+-0.102721
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.021838
+ 20
+-0.110707
+ 30
+0.014551
+ 11
+-0.021867
+ 21
+-0.11073
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.014513
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.042899
+ 20
+-0.1265
+ 30
+0.014551
+ 11
+-0.042929
+ 21
+-0.126523
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.05391
+ 20
+-0.134756
+ 30
+0.014513
+ 11
+-0.053969
+ 21
+-0.134801
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.064888
+ 20
+-0.142988
+ 30
+0.014476
+ 11
+-0.064919
+ 21
+-0.14301
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.014476
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.085502
+ 20
+-0.158444
+ 30
+0.014551
+ 11
+-0.085533
+ 21
+-0.158467
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.093041
+ 20
+-0.164098
+ 30
+0.014476
+ 11
+-0.093012
+ 21
+-0.164076
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.020516
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.025337
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.070574
+ 20
+-0.14725
+ 30
+0.03128
+ 11
+-0.070603
+ 21
+-0.147273
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.059055
+ 20
+-0.138615
+ 30
+0.035504
+ 11
+-0.059115
+ 21
+-0.138659
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.03726
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.037035
+ 20
+-0.122103
+ 30
+0.037298
+ 11
+-0.037095
+ 21
+-0.122148
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.027012
+ 20
+-0.114588
+ 30
+0.035466
+ 11
+-0.027043
+ 21
+-0.114611
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.016452
+ 20
+-0.106669
+ 30
+0.031317
+ 11
+-0.016482
+ 21
+-0.106692
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.005951
+ 20
+-0.098795
+ 30
+0.0253
+ 11
+-0.00592
+ 21
+-0.098773
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.000781
+ 20
+-0.093749
+ 30
+0.020553
+ 11
+0.000721
+ 21
+-0.093794
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.093041
+ 20
+-0.164098
+ 30
+0.014476
+ 11
+-0.096931
+ 21
+-0.167014
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.00943
+ 11
+-0.093041
+ 21
+-0.164098
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.085502
+ 20
+-0.158444
+ 30
+0.014551
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.009392
+ 11
+-0.085502
+ 21
+-0.158444
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.014476
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.070603
+ 20
+-0.147273
+ 30
+0.00943
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.064888
+ 20
+-0.142988
+ 30
+0.014476
+ 11
+-0.070603
+ 21
+-0.147273
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.059115
+ 20
+-0.138659
+ 30
+0.009392
+ 11
+-0.064888
+ 21
+-0.142988
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+-0.05391
+ 20
+-0.134756
+ 30
+0.014513
+ 11
+-0.059115
+ 21
+-0.138659
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.00943
+ 11
+-0.05391
+ 21
+-0.134756
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.042899
+ 20
+-0.1265
+ 30
+0.014551
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.037095
+ 20
+-0.122148
+ 30
+0.009392
+ 11
+-0.042899
+ 21
+-0.1265
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.014513
+ 11
+-0.037095
+ 21
+-0.122148
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.027043
+ 20
+-0.114611
+ 30
+0.00943
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.021838
+ 20
+-0.110707
+ 30
+0.014551
+ 11
+-0.027043
+ 21
+-0.114611
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.016482
+ 20
+-0.106692
+ 30
+0.009392
+ 11
+-0.021838
+ 21
+-0.110707
+ 31
+0.014551
+ 0
+LINE
+ 8
+0
+ 10
+-0.011156
+ 20
+-0.102699
+ 30
+0.014513
+ 11
+-0.016482
+ 21
+-0.106692
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.00592
+ 20
+-0.098773
+ 30
+0.00943
+ 11
+-0.011156
+ 21
+-0.102699
+ 31
+0.014513
+ 0
+LINE
+ 8
+0
+ 10
+-0.002689
+ 20
+-0.096351
+ 30
+0.014476
+ 11
+-0.00592
+ 21
+-0.098773
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.000721
+ 20
+-0.093794
+ 30
+0.009392
+ 11
+-0.002689
+ 21
+-0.096351
+ 31
+0.014476
+ 0
+LINE
+ 8
+0
+ 10
+0.004042
+ 20
+-0.091303
+ 30
+0.014439
+ 11
+0.000721
+ 21
+-0.093794
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+0.007512
+ 20
+-0.088701
+ 30
+0.00943
+ 11
+0.004042
+ 21
+-0.091303
+ 31
+0.014439
+ 0
+LINE
+ 8
+0
+ 10
+0.007453
+ 20
+-0.088746
+ 30
+0.014536
+ 11
+0.007512
+ 21
+-0.088701
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.003952
+ 20
+-0.09137
+ 30
+0.009355
+ 11
+0.007512
+ 21
+-0.088701
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+0.000721
+ 20
+-0.093794
+ 30
+0.009392
+ 11
+0.003952
+ 21
+-0.09137
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.00266
+ 20
+-0.096328
+ 30
+0.009541
+ 11
+0.000721
+ 21
+-0.093794
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.00592
+ 20
+-0.098773
+ 30
+0.00943
+ 11
+-0.00266
+ 21
+-0.096328
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.011186
+ 20
+-0.102721
+ 30
+0.009355
+ 11
+-0.00592
+ 21
+-0.098773
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.016482
+ 20
+-0.106692
+ 30
+0.009392
+ 11
+-0.011186
+ 21
+-0.102721
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.021867
+ 20
+-0.11073
+ 30
+0.009392
+ 11
+-0.016482
+ 21
+-0.106692
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.027043
+ 20
+-0.114611
+ 30
+0.00943
+ 11
+-0.021867
+ 21
+-0.11073
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.032129
+ 20
+-0.118424
+ 30
+0.009392
+ 11
+-0.027043
+ 21
+-0.114611
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.037095
+ 20
+-0.122148
+ 30
+0.009392
+ 11
+-0.032129
+ 21
+-0.118424
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.042929
+ 20
+-0.126523
+ 30
+0.009392
+ 11
+-0.037095
+ 21
+-0.122148
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.00943
+ 11
+-0.042929
+ 21
+-0.126523
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.053969
+ 20
+-0.134801
+ 30
+0.009392
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.059115
+ 20
+-0.138659
+ 30
+0.009392
+ 11
+-0.053969
+ 21
+-0.134801
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.064919
+ 20
+-0.14301
+ 30
+0.009355
+ 11
+-0.059115
+ 21
+-0.138659
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.070603
+ 20
+-0.147273
+ 30
+0.00943
+ 11
+-0.064919
+ 21
+-0.14301
+ 31
+0.009355
+ 0
+LINE
+ 8
+0
+ 10
+-0.076438
+ 20
+-0.151647
+ 30
+0.00943
+ 11
+-0.070603
+ 21
+-0.147273
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.009392
+ 11
+-0.076438
+ 21
+-0.151647
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.085533
+ 20
+-0.158467
+ 30
+0.009392
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.00943
+ 11
+-0.085533
+ 21
+-0.158467
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.093012
+ 20
+-0.164076
+ 30
+0.009541
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.00943
+ 0
+LINE
+ 8
+0
+ 10
+-0.096931
+ 20
+-0.167014
+ 30
+0.009392
+ 11
+-0.093012
+ 21
+-0.164076
+ 31
+0.009541
+ 0
+LINE
+ 8
+0
+ 10
+-0.096871
+ 20
+-0.166969
+ 30
+0.014573
+ 11
+-0.096931
+ 21
+-0.167014
+ 31
+0.009392
+ 0
+LINE
+ 8
+0
+ 10
+-0.089242
+ 20
+-0.161249
+ 30
+0.020516
+ 11
+-0.096871
+ 21
+-0.166969
+ 31
+0.014573
+ 0
+LINE
+ 8
+0
+ 10
+-0.081553
+ 20
+-0.155484
+ 30
+0.025337
+ 11
+-0.089242
+ 21
+-0.161249
+ 31
+0.020516
+ 0
+LINE
+ 8
+0
+ 10
+-0.070574
+ 20
+-0.14725
+ 30
+0.03128
+ 11
+-0.081553
+ 21
+-0.155484
+ 31
+0.025337
+ 0
+LINE
+ 8
+0
+ 10
+-0.059055
+ 20
+-0.138615
+ 30
+0.035504
+ 11
+-0.070574
+ 21
+-0.14725
+ 31
+0.03128
+ 0
+LINE
+ 8
+0
+ 10
+-0.048554
+ 20
+-0.13074
+ 30
+0.03726
+ 11
+-0.059055
+ 21
+-0.138615
+ 31
+0.035504
+ 0
+LINE
+ 8
+0
+ 10
+-0.037035
+ 20
+-0.122103
+ 30
+0.037298
+ 11
+-0.048554
+ 21
+-0.13074
+ 31
+0.03726
+ 0
+LINE
+ 8
+0
+ 10
+-0.027012
+ 20
+-0.114588
+ 30
+0.035466
+ 11
+-0.037035
+ 21
+-0.122103
+ 31
+0.037298
+ 0
+LINE
+ 8
+0
+ 10
+-0.016452
+ 20
+-0.106669
+ 30
+0.031317
+ 11
+-0.027012
+ 21
+-0.114588
+ 31
+0.035466
+ 0
+LINE
+ 8
+0
+ 10
+-0.005951
+ 20
+-0.098795
+ 30
+0.0253
+ 11
+-0.016452
+ 21
+-0.106669
+ 31
+0.031317
+ 0
+LINE
+ 8
+0
+ 10
+0.000781
+ 20
+-0.093749
+ 30
+0.020553
+ 11
+-0.005951
+ 21
+-0.098795
+ 31
+0.0253
+ 0
+LINE
+ 8
+0
+ 10
+0.007453
+ 20
+-0.088746
+ 30
+0.014536
+ 11
+0.000781
+ 21
+-0.093749
+ 31
+0.020553
+ 0
+LINE
+ 8
+0
+ 10
+0.011409
+ 20
+-0.102736
+ 30
+0.014391
+ 11
+0.011319
+ 21
+-0.102803
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+0.004678
+ 20
+-0.107783
+ 30
+0.01443
+ 11
+0.004709
+ 21
+-0.107761
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.003789
+ 20
+-0.114132
+ 30
+0.014466
+ 11
+-0.003819
+ 21
+-0.114154
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.014469
+ 20
+-0.12214
+ 30
+0.014503
+ 11
+-0.014499
+ 21
+-0.122163
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.014466
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.035532
+ 20
+-0.137933
+ 30
+0.014503
+ 11
+-0.035561
+ 21
+-0.137956
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.046541
+ 20
+-0.146189
+ 30
+0.014466
+ 11
+-0.046602
+ 21
+-0.146234
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.057521
+ 20
+-0.154422
+ 30
+0.01443
+ 11
+-0.057552
+ 21
+-0.154445
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.01443
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.078135
+ 20
+-0.169877
+ 30
+0.014503
+ 11
+-0.078164
+ 21
+-0.1699
+ 31
+0.014573
+ 0
+LINE
+ 8
+0
+ 10
+-0.085674
+ 20
+-0.175531
+ 30
+0.01443
+ 11
+-0.085644
+ 21
+-0.175509
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.02047
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.025291
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.063205
+ 20
+-0.158683
+ 30
+0.031234
+ 11
+-0.063236
+ 21
+-0.158706
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.051688
+ 20
+-0.150048
+ 30
+0.035457
+ 11
+-0.051747
+ 21
+-0.150092
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.037214
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.029668
+ 20
+-0.133536
+ 30
+0.037251
+ 11
+-0.029728
+ 21
+-0.133581
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.019645
+ 20
+-0.126021
+ 30
+0.03542
+ 11
+-0.019675
+ 21
+-0.126044
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.009085
+ 20
+-0.118102
+ 30
+0.031271
+ 11
+-0.009114
+ 21
+-0.118125
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.001416
+ 20
+-0.110228
+ 30
+0.025254
+ 11
+0.001447
+ 21
+-0.110206
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.008149
+ 20
+-0.105182
+ 30
+0.020507
+ 11
+0.008089
+ 21
+-0.105227
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.085674
+ 20
+-0.175531
+ 30
+0.01443
+ 11
+-0.089563
+ 21
+-0.178447
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.009383
+ 11
+-0.085674
+ 21
+-0.175531
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.078135
+ 20
+-0.169877
+ 30
+0.014503
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.009346
+ 11
+-0.078135
+ 21
+-0.169877
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.01443
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.063236
+ 20
+-0.158706
+ 30
+0.009383
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.057521
+ 20
+-0.154422
+ 30
+0.01443
+ 11
+-0.063236
+ 21
+-0.158706
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.051747
+ 20
+-0.150092
+ 30
+0.009346
+ 11
+-0.057521
+ 21
+-0.154422
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+-0.046541
+ 20
+-0.146189
+ 30
+0.014466
+ 11
+-0.051747
+ 21
+-0.150092
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.009383
+ 11
+-0.046541
+ 21
+-0.146189
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.035532
+ 20
+-0.137933
+ 30
+0.014503
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.029728
+ 20
+-0.133581
+ 30
+0.009346
+ 11
+-0.035532
+ 21
+-0.137933
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.014466
+ 11
+-0.029728
+ 21
+-0.133581
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.019675
+ 20
+-0.126044
+ 30
+0.009383
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+-0.014469
+ 20
+-0.12214
+ 30
+0.014503
+ 11
+-0.019675
+ 21
+-0.126044
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.009114
+ 20
+-0.118125
+ 30
+0.009346
+ 11
+-0.014469
+ 21
+-0.12214
+ 31
+0.014503
+ 0
+LINE
+ 8
+0
+ 10
+-0.003789
+ 20
+-0.114132
+ 30
+0.014466
+ 11
+-0.009114
+ 21
+-0.118125
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.001447
+ 20
+-0.110206
+ 30
+0.009383
+ 11
+-0.003789
+ 21
+-0.114132
+ 31
+0.014466
+ 0
+LINE
+ 8
+0
+ 10
+0.004678
+ 20
+-0.107783
+ 30
+0.01443
+ 11
+0.001447
+ 21
+-0.110206
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.008089
+ 20
+-0.105227
+ 30
+0.009346
+ 11
+0.004678
+ 21
+-0.107783
+ 31
+0.01443
+ 0
+LINE
+ 8
+0
+ 10
+0.011409
+ 20
+-0.102736
+ 30
+0.014391
+ 11
+0.008089
+ 21
+-0.105227
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.01488
+ 20
+-0.100134
+ 30
+0.009383
+ 11
+0.011409
+ 21
+-0.102736
+ 31
+0.014391
+ 0
+LINE
+ 8
+0
+ 10
+0.01482
+ 20
+-0.100179
+ 30
+0.014489
+ 11
+0.01488
+ 21
+-0.100134
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.011319
+ 20
+-0.102803
+ 30
+0.009309
+ 11
+0.01488
+ 21
+-0.100134
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+0.008089
+ 20
+-0.105227
+ 30
+0.009346
+ 11
+0.011319
+ 21
+-0.102803
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+0.004709
+ 20
+-0.107761
+ 30
+0.009495
+ 11
+0.008089
+ 21
+-0.105227
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+0.001447
+ 20
+-0.110206
+ 30
+0.009383
+ 11
+0.004709
+ 21
+-0.107761
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.003819
+ 20
+-0.114154
+ 30
+0.009309
+ 11
+0.001447
+ 21
+-0.110206
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.009114
+ 20
+-0.118125
+ 30
+0.009346
+ 11
+-0.003819
+ 21
+-0.114154
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.014499
+ 20
+-0.122163
+ 30
+0.009346
+ 11
+-0.009114
+ 21
+-0.118125
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.019675
+ 20
+-0.126044
+ 30
+0.009383
+ 11
+-0.014499
+ 21
+-0.122163
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.024762
+ 20
+-0.129857
+ 30
+0.009346
+ 11
+-0.019675
+ 21
+-0.126044
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.029728
+ 20
+-0.133581
+ 30
+0.009346
+ 11
+-0.024762
+ 21
+-0.129857
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.035561
+ 20
+-0.137956
+ 30
+0.009346
+ 11
+-0.029728
+ 21
+-0.133581
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.009383
+ 11
+-0.035561
+ 21
+-0.137956
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.046602
+ 20
+-0.146234
+ 30
+0.009346
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.051747
+ 20
+-0.150092
+ 30
+0.009346
+ 11
+-0.046602
+ 21
+-0.146234
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.057552
+ 20
+-0.154445
+ 30
+0.009309
+ 11
+-0.051747
+ 21
+-0.150092
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.063236
+ 20
+-0.158706
+ 30
+0.009383
+ 11
+-0.057552
+ 21
+-0.154445
+ 31
+0.009309
+ 0
+LINE
+ 8
+0
+ 10
+-0.069069
+ 20
+-0.16308
+ 30
+0.009383
+ 11
+-0.063236
+ 21
+-0.158706
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.009346
+ 11
+-0.069069
+ 21
+-0.16308
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.009383
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.085644
+ 20
+-0.175509
+ 30
+0.009495
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.009383
+ 0
+LINE
+ 8
+0
+ 10
+-0.089563
+ 20
+-0.178447
+ 30
+0.009346
+ 11
+-0.085644
+ 21
+-0.175509
+ 31
+0.009495
+ 0
+LINE
+ 8
+0
+ 10
+-0.089503
+ 20
+-0.178402
+ 30
+0.014527
+ 11
+-0.089563
+ 21
+-0.178447
+ 31
+0.009346
+ 0
+LINE
+ 8
+0
+ 10
+-0.081875
+ 20
+-0.172682
+ 30
+0.02047
+ 11
+-0.089503
+ 21
+-0.178402
+ 31
+0.014527
+ 0
+LINE
+ 8
+0
+ 10
+-0.074186
+ 20
+-0.166916
+ 30
+0.025291
+ 11
+-0.081875
+ 21
+-0.172682
+ 31
+0.02047
+ 0
+LINE
+ 8
+0
+ 10
+-0.063205
+ 20
+-0.158683
+ 30
+0.031234
+ 11
+-0.074186
+ 21
+-0.166916
+ 31
+0.025291
+ 0
+LINE
+ 8
+0
+ 10
+-0.051688
+ 20
+-0.150048
+ 30
+0.035457
+ 11
+-0.063205
+ 21
+-0.158683
+ 31
+0.031234
+ 0
+LINE
+ 8
+0
+ 10
+-0.041186
+ 20
+-0.142173
+ 30
+0.037214
+ 11
+-0.051688
+ 21
+-0.150048
+ 31
+0.035457
+ 0
+LINE
+ 8
+0
+ 10
+-0.029668
+ 20
+-0.133536
+ 30
+0.037251
+ 11
+-0.041186
+ 21
+-0.142173
+ 31
+0.037214
+ 0
+LINE
+ 8
+0
+ 10
+-0.019645
+ 20
+-0.126021
+ 30
+0.03542
+ 11
+-0.029668
+ 21
+-0.133536
+ 31
+0.037251
+ 0
+LINE
+ 8
+0
+ 10
+-0.009085
+ 20
+-0.118102
+ 30
+0.031271
+ 11
+-0.019645
+ 21
+-0.126021
+ 31
+0.03542
+ 0
+LINE
+ 8
+0
+ 10
+0.001416
+ 20
+-0.110228
+ 30
+0.025254
+ 11
+-0.009085
+ 21
+-0.118102
+ 31
+0.031271
+ 0
+LINE
+ 8
+0
+ 10
+0.008149
+ 20
+-0.105182
+ 30
+0.020507
+ 11
+0.001416
+ 21
+-0.110228
+ 31
+0.025254
+ 0
+LINE
+ 8
+0
+ 10
+0.01482
+ 20
+-0.100179
+ 30
+0.014489
+ 11
+0.008149
+ 21
+-0.105182
+ 31
+0.020507
+ 0
+ENDSEC
+ 0
+EOF
diff --git a/vcl/qt5/QtInstancePopover.cxx b/vcl/qt5/QtInstancePopover.cxx
index df88afcf1741..68638bdf8237 100644
--- a/vcl/qt5/QtInstancePopover.cxx
+++ b/vcl/qt5/QtInstancePopover.cxx
@@ -44,4 +44,22 @@ void QtInstancePopover::popdown()
void QtInstancePopover::resize_to_request() { assert(false && "Not implemented yet"); }
+bool QtInstancePopover::eventFilter(QObject* pObject, QEvent* pEvent)
+{
+ if (pObject == getQWidget() && pEvent->type() == QEvent::Close)
+ {
+ // signal that the popup was closed when control returns to the
+ // main loop (at which point the event to close the popup has
+ // actually been processed)
+ QMetaObject::invokeMethod(this,
+ [this] {
+ SolarMutexGuard g;
+ signal_closed();
+ },
+ Qt::QueuedConnection);
+ }
+
+ return QtInstanceWidget::eventFilter(pObject, pEvent);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx
index 3e3ec91d98d1..3bf463ef7a06 100644
--- a/vcl/qt5/QtWidget.cxx
+++ b/vcl/qt5/QtWidget.cxx
@@ -343,7 +343,7 @@ bool QtWidget::handleKeyEvent(QKeyEvent* pEvent) const
return true;
}
- QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle);
+ QGuiApplication::inputMethod()->update(Qt::ImQueryInput);
if (nCode == 0 && pEvent->text().isEmpty())
{
@@ -661,52 +661,25 @@ void QtWidget::inputMethodEvent(QInputMethodEvent* pEvent)
pEvent->accept();
}
-static bool lcl_retrieveSurrounding(sal_Int32& rPosition, sal_Int32& rAnchor, QString* pText,
- QString* pSelection)
+void QtWidget::retrieveSurrounding(sal_uLong& rPosition, sal_uLong& rAnchor, QString* pText,
+ QString* pSelection) const
{
SolarMutexGuard aGuard;
- vcl::Window* pFocusWin = Application::GetFocusWindow();
- if (!pFocusWin)
- return false;
- uno::Reference<accessibility::XAccessibleEditableText> xText;
- try
- {
- xText = FindFocusedEditableText(pFocusWin->GetAccessible());
- }
- catch (const uno::Exception&)
- {
- TOOLS_WARN_EXCEPTION("vcl.qt", "Exception in getting input method surrounding text");
- }
+ SalSurroundingTextRequestEvent aEvt;
+ aEvt.mnStart = aEvt.mnEnd = aEvt.mnCursorPos = 0;
+ m_rFrame.CallCallback(SalEvent::SurroundingTextRequest, &aEvt);
- if (xText.is())
- {
- rPosition = xText->getCaretPosition();
- if (rPosition != -1)
- {
- if (pText)
- *pText = toQString(xText->getText());
-
- sal_Int32 nSelStart = xText->getSelectionStart();
- sal_Int32 nSelEnd = xText->getSelectionEnd();
- if (nSelStart == nSelEnd)
- {
- rAnchor = rPosition;
- }
- else
- {
- if (rPosition == nSelStart)
- rAnchor = nSelEnd;
- else
- rAnchor = nSelStart;
- if (pSelection)
- *pSelection = toQString(xText->getSelectedText());
- }
- return true;
- }
- }
+ rPosition = aEvt.mnCursorPos;
+ if (pText)
+ *pText = toQString(aEvt.maText);
- return false;
+ if (rPosition == aEvt.mnStart)
+ rAnchor = aEvt.mnEnd;
+ else
+ rAnchor = aEvt.mnStart;
+ if (pSelection)
+ *pSelection = toQString(aEvt.maText).mid(aEvt.mnStart, aEvt.mnEnd - aEvt.mnStart);
}
QVariant QtWidget::inputMethodQuery(Qt::InputMethodQuery property) const
@@ -716,17 +689,15 @@ QVariant QtWidget::inputMethodQuery(Qt::InputMethodQuery property) const
case Qt::ImSurroundingText:
{
QString aText;
- sal_Int32 nCursorPos, nAnchor;
- if (lcl_retrieveSurrounding(nCursorPos, nAnchor, &aText, nullptr))
- return QVariant(aText);
- return QVariant();
+ sal_uLong nCursorPos, nAnchor;
+ retrieveSurrounding(nCursorPos, nAnchor, &aText, nullptr);
+ return QVariant(aText);
}
case Qt::ImCursorPosition:
{
- sal_Int32 nCursorPos, nAnchor;
- if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr))
- return QVariant(static_cast<int>(nCursorPos));
- return QVariant();
+ sal_uLong nCursorPos, nAnchor;
+ retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr);
+ return QVariant(static_cast<int>(nCursorPos));
}
case Qt::ImCursorRectangle:
{
@@ -745,18 +716,16 @@ QVariant QtWidget::inputMethodQuery(Qt::InputMethodQuery property) const
}
case Qt::ImAnchorPosition:
{
- sal_Int32 nCursorPos, nAnchor;
- if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr))
- return QVariant(static_cast<int>(nAnchor));
- return QVariant();
+ sal_uLong nCursorPos, nAnchor;
+ retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr);
+ return QVariant(static_cast<int>(nAnchor));
}
case Qt::ImCurrentSelection:
{
QString aSelection;
- sal_Int32 nCursorPos, nAnchor;
- if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, &aSelection))
- return QVariant(aSelection);
- return QVariant();
+ sal_uLong nCursorPos, nAnchor;
+ retrieveSurrounding(nCursorPos, nAnchor, nullptr, &aSelection);
+ return QVariant(aSelection);
}
default:
return QWidget::inputMethodQuery(property);
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 629ab7552588..0872b0ac1c5c 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1701,8 +1701,7 @@ void SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi
drawShader(rPosAry, rSkiaSourceBitmap.GetSkShader(makeSamplingOptions(rPosAry, mScaling)));
}
-void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap,
- SkBlendMode blendMode)
+void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap)
{
// Use mergeCacheBitmaps(), which may decide to cache the result, avoiding repeated
// scaling.
@@ -1720,15 +1719,15 @@ void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBit
}
sk_sp<SkImage> image = mergeCacheBitmaps(bitmap, imageSize * mScaling);
if (image)
- drawImage(imagePosAry, image, mScaling, blendMode);
+ drawImage(imagePosAry, image, mScaling);
else if (bitmap.PreferSkShader())
- drawShader(rPosAry, bitmap.GetSkShader(makeSamplingOptions(rPosAry, mScaling)), blendMode);
+ drawShader(rPosAry, bitmap.GetSkShader(makeSamplingOptions(rPosAry, mScaling)));
else
- drawImage(rPosAry, bitmap.GetSkImage(), 1, blendMode);
+ drawImage(rPosAry, bitmap.GetSkImage(), 1);
}
void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage,
- int srcScaling, SkBlendMode eBlendMode)
+ int srcScaling)
{
SkRect aSourceRect
= SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
@@ -1738,11 +1737,11 @@ void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const sk_sp<SkIma
rPosAry.mnDestWidth, rPosAry.mnDestHeight);
SkPaint aPaint = makeBitmapPaint();
- aPaint.setBlendMode(eBlendMode);
+ aPaint.setBlendMode(SkBlendMode::kSrcOver);
preDraw();
- SAL_INFO("vcl.skia.trace",
- "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode));
+ SAL_INFO("vcl.skia.trace", "drawimage(" << this << "): " << rPosAry << ":"
+ << SkBlendMode_Name(SkBlendMode::kSrcOver));
addUpdateRegion(aDestinationRect);
getDrawCanvas()->drawImageRect(aImage, aSourceRect, aDestinationRect,
makeSamplingOptions(rPosAry, mScaling, srcScaling), &aPaint,
@@ -1753,8 +1752,7 @@ void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const sk_sp<SkIma
// SkShader can be used to merge multiple bitmaps with appropriate blend modes (e.g. when
// merging a bitmap with its alpha mask).
-void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader,
- SkBlendMode blendMode)
+void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader)
{
preDraw();
SAL_INFO("vcl.skia.trace", "drawshader(" << this << "): " << rPosAry);
@@ -1762,7 +1760,7 @@ void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp<SkSh
rPosAry.mnDestHeight);
addUpdateRegion(destinationRect);
SkPaint paint = makeBitmapPaint();
- paint.setBlendMode(blendMode);
+ paint.setBlendMode(SkBlendMode::kSrcOver);
paint.setShader(shader);
SkCanvas* canvas = getDrawCanvas();
// Scaling needs to be done explicitly using a matrix.
diff --git a/vcl/source/accessibility/AccessibleBrowseBox.cxx b/vcl/source/accessibility/AccessibleBrowseBox.cxx
index 8cc43e2678bc..934f82a6e804 100644
--- a/vcl/source/accessibility/AccessibleBrowseBox.cxx
+++ b/vcl/source/accessibility/AccessibleBrowseBox.cxx
@@ -35,9 +35,9 @@ using namespace ::com::sun::star::accessibility;
// Ctor/Dtor/disposing
AccessibleBrowseBox::AccessibleBrowseBox(
- const css::uno::Reference<css::accessibility::XAccessible>& _rxParent,
+ const rtl::Reference<comphelper::OAccessible>& rpParent,
::vcl::IAccessibleTableProvider& _rBrowseBox)
- : AccessibleBrowseBoxBase(_rxParent, _rBrowseBox, nullptr,
+ : AccessibleBrowseBoxBase(rpParent, _rBrowseBox, nullptr,
AccessibleBrowseBoxObjType::BrowseBox)
{
m_xFocusWindow.set(mpBrowseBox->GetWindowInstance()->GetComponentInterface(), css::uno::UNO_QUERY);
@@ -158,8 +158,7 @@ tools::Rectangle AccessibleBrowseBox::implGetBoundingBox()
return mpBrowseBox->GetWindowExtentsRelative( *pParent );
}
-// internal helper methods
-css::uno::Reference< css::accessibility::XAccessible > AccessibleBrowseBox::implGetTable()
+rtl::Reference<comphelper::OAccessible> AccessibleBrowseBox::getTable()
{
if( !mxTable.is() )
{
@@ -169,8 +168,8 @@ css::uno::Reference< css::accessibility::XAccessible > AccessibleBrowseBox::impl
return mxTable;
}
-css::uno::Reference< css::accessibility::XAccessible >
-AccessibleBrowseBox::implGetHeaderBar(AccessibleBrowseBoxObjType eObjType)
+rtl::Reference<comphelper::OAccessible>
+AccessibleBrowseBox::getHeaderBar(AccessibleBrowseBoxObjType eObjType)
{
if( eObjType == AccessibleBrowseBoxObjType::RowHeaderBar )
{
@@ -185,26 +184,23 @@ AccessibleBrowseBox::implGetHeaderBar(AccessibleBrowseBoxObjType eObjType)
return mxColumnHeaderBar;
}
- return css::uno::Reference<css::accessibility::XAccessible>();
+ return {};
}
-css::uno::Reference< css::accessibility::XAccessible >
-AccessibleBrowseBox::implGetFixedChild( sal_Int64 nChildIndex )
+rtl::Reference<comphelper::OAccessible>
+AccessibleBrowseBox::implGetFixedChild(sal_Int64 nChildIndex)
{
- css::uno::Reference< css::accessibility::XAccessible > xRet;
switch( nChildIndex )
{
case vcl::BBINDEX_COLUMNHEADERBAR:
- xRet = implGetHeaderBar( AccessibleBrowseBoxObjType::ColumnHeaderBar );
- break;
+ return getHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar);
case vcl::BBINDEX_ROWHEADERBAR:
- xRet = implGetHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar );
- break;
+ return getHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar);
case vcl::BBINDEX_TABLE:
- xRet = implGetTable();
- break;
+ return getTable();
}
- return xRet;
+
+ return {};
}
rtl::Reference<AccessibleBrowseBoxTable> AccessibleBrowseBox::createAccessibleTable()
diff --git a/vcl/source/accessibility/accessibletablistbox.cxx b/vcl/source/accessibility/accessibletablistbox.cxx
index 281ec34a2145..9479bf5494a6 100644
--- a/vcl/source/accessibility/accessibletablistbox.cxx
+++ b/vcl/source/accessibility/accessibletablistbox.cxx
@@ -32,9 +32,9 @@ using namespace ::com::sun::star;
// Ctor() and Dtor()
-AccessibleTabListBox::AccessibleTabListBox(const Reference<XAccessible>& rxParent,
+AccessibleTabListBox::AccessibleTabListBox(const rtl::Reference<comphelper::OAccessible>& rpParent,
SvHeaderTabListBox& rBox)
- : AccessibleBrowseBox(rxParent, rBox)
+ : AccessibleBrowseBox(rpParent, rBox)
, m_pTabListBox(&rBox)
{
}
@@ -72,7 +72,7 @@ AccessibleTabListBox::getAccessibleChild( sal_Int64 nChildIndex )
if (nChildIndex != 0)
throw IndexOutOfBoundsException();
- return implGetTable();
+ return getTable();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index 64495994e6e5..73a9f1388044 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -135,7 +135,9 @@ void Scheduler::ImplDeInitScheduler()
assert( nullptr == rSchedCtx.mpSchedulerStack || (!rSchedCtx.mpSchedulerStack->mpTask && !rSchedCtx.mpSchedulerStack->mpNext) );
- if (rSchedCtx.mpSalTimer) rSchedCtx.mpSalTimer->Stop();
+ if (rSchedCtx.mpSalTimer)
+ rSchedCtx.mpSalTimer->Stop();
+
delete rSchedCtx.mpSalTimer;
rSchedCtx.mpSalTimer = nullptr;
diff --git a/vcl/source/app/settings.cxx b/vcl/source/app/settings.cxx
index b809187d3f3a..bb3f25fa8851 100644
--- a/vcl/source/app/settings.cxx
+++ b/vcl/source/app/settings.cxx
@@ -404,12 +404,6 @@ MouseSettings::GetButtonRepeat() const
return mxData->mnButtonRepeat;
}
-sal_Int32
-MouseSettings::GetActionDelay()
-{
- return 250;
-}
-
void
MouseSettings::SetMenuDelay( sal_Int32 nDelay )
{
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index 124dc4289f29..d60d5fa59aea 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -341,6 +341,10 @@ void Application::notifyInvalidation(tools::Rectangle const* /*pRect*/) const
{
}
+void Application::notifyCursorInvalidation(tools::Rectangle const* /*pRect*/, bool /*bControlEvent*/) const
+{
+}
+
void Application::Execute()
{
ImplSVData* pSVData = ImplGetSVData();
diff --git a/vcl/source/bitmap/BitmapAlphaClampFilter.cxx b/vcl/source/bitmap/BitmapAlphaClampFilter.cxx
deleted file mode 100644
index 68061d4e37d6..000000000000
--- a/vcl/source/bitmap/BitmapAlphaClampFilter.cxx
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- */
-
-#include <vcl/bitmap/BitmapAlphaClampFilter.hxx>
-#include <vcl/BitmapWriteAccess.hxx>
-
-Bitmap BitmapAlphaClampFilter::execute(Bitmap const& rBitmap) const
-{
- if (!rBitmap.HasAlpha())
- return rBitmap;
-
- Bitmap aNewBitmap(rBitmap);
- {
- BitmapScopedWriteAccess pWriteAcc(aNewBitmap);
- const Size aSize(aNewBitmap.GetSizePixel());
-
- for (sal_Int32 nY = 0; nY < sal_Int32(aSize.Height()); ++nY)
- {
- Scanline pScan = pWriteAcc->GetScanline(nY);
-
- for (sal_Int32 nX = 0; nX < sal_Int32(aSize.Width()); ++nX)
- {
- BitmapColor aBitmapValue(pWriteAcc->GetPixelFromData(pScan, nX));
- if ((255 - aBitmapValue.GetAlpha()) > mcThreshold)
- {
- aBitmapValue.SetAlpha(0);
- pWriteAcc->SetPixelOnData(pScan, nX, aBitmapValue);
- }
- }
- }
- }
-
- return aNewBitmap;
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/control/MenuButton.cxx b/vcl/source/control/MenuButton.cxx
index d7b80ded0702..c1fdfd6b57b5 100644
--- a/vcl/source/control/MenuButton.cxx
+++ b/vcl/source/control/MenuButton.cxx
@@ -171,17 +171,6 @@ void MenuButton::dispose()
PushButton::dispose();
}
-IMPL_LINK_NOARG(MenuButton, ImplMenuTimeoutHdl, Timer *, void)
-{
- // See if Button Tracking is still active, as it could've been cancelled earlier
- if ( IsTracking() )
- {
- if ( !(GetStyle() & WB_NOPOINTERFOCUS) )
- GrabFocus();
- ExecuteMenu();
- }
-}
-
void MenuButton::MouseButtonDown( const MouseEvent& rMEvt )
{
if ( PushButton::ImplHitTestPushButton( this, rMEvt.GetPosPixel() ) )
@@ -278,14 +267,4 @@ MenuToggleButton::~MenuToggleButton()
disposeOnce();
}
-void MenuToggleButton::SetActive( bool bSel )
-{
- mbIsActive = bSel;
-}
-
-bool MenuToggleButton::GetActive() const
-{
- return mbIsActive;
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx
index c7e1ddf708fa..14f65c850142 100644
--- a/vcl/source/control/button.cxx
+++ b/vcl/source/control/button.cxx
@@ -81,7 +81,6 @@ public:
ImplCommonButtonData();
tools::Rectangle maFocusRect;
- tools::Long mnSeparatorX;
DrawButtonFlags mnButtonState;
bool mbSmallSymbol;
bool mbGeneratedTooltip;
@@ -96,7 +95,7 @@ public:
rtl::Reference<VclStatusListener<Button>> mpStatusListener;
};
-ImplCommonButtonData::ImplCommonButtonData() : mnSeparatorX(0), mnButtonState(DrawButtonFlags::NONE),
+ImplCommonButtonData::ImplCommonButtonData() : mnButtonState(DrawButtonFlags::NONE),
mbSmallSymbol(false), mbGeneratedTooltip(false), meImageAlign(ImageAlign::Top), meSymbolAlign(SymbolAlign::LEFT)
{
}
@@ -181,16 +180,6 @@ Image const & Button::GetCustomButtonImage() const
return mpButtonData->maCustomContentImage;
}
-tools::Long Button::ImplGetSeparatorX() const
-{
- return mpButtonData->mnSeparatorX;
-}
-
-void Button::ImplSetSeparatorX( tools::Long nX )
-{
- mpButtonData->mnSeparatorX = nX;
-}
-
DrawTextFlags Button::ImplGetTextStyle( WinBits nWinStyle, SystemTextColorFlags nSystemTextColorFlags ) const
{
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
@@ -963,7 +952,6 @@ void PushButton::ImplDrawPushButtonContent(OutputDevice *pDev, SystemTextColorFl
Point aEndPt( nSeparatorX, aSymbolRect.Bottom()-nDistance );
aDecoView.DrawSeparator( aStartPt, aEndPt );
}
- ImplSetSeparatorX( nSeparatorX );
aDecoView.DrawSymbol( aSymbolRect, SymbolType::SPIN_DOWN, aColor, nStyle );
diff --git a/vcl/source/edit/vclmedit.cxx b/vcl/source/edit/vclmedit.cxx
index 56232b32b58e..7475b7770d70 100644
--- a/vcl/source/edit/vclmedit.cxx
+++ b/vcl/source/edit/vclmedit.cxx
@@ -44,6 +44,8 @@
#include <strings.hrc>
#include <svdata.hxx>
+#include <comphelper/lok.hxx>
+
class ImpVclMEdit : public SfxListener
{
private:
@@ -743,6 +745,9 @@ void TextWindow::KeyInput( const KeyEvent& rKEvent )
if ( !bDone )
Window::KeyInput( rKEvent );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ LogicInvalidate(nullptr);
}
void TextWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
@@ -852,6 +857,10 @@ void TextWindow::Command( const CommandEvent& rCEvt )
{
mpExtTextView->Command( rCEvt );
}
+
+ if (comphelper::LibreOfficeKit::isActive())
+ LogicInvalidate(nullptr);
+
Window::Command( rCEvt );
}
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index d9a2802c25b7..49b385628de6 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -88,6 +88,8 @@
#include <o3tl/string_view.hxx>
#include <o3tl/test_info.hxx>
#include <vcl/TypeSerializer.hxx>
+#include <vcl/GraphicNativeMetadata.hxx>
+#include <vcl/GraphicNativeTransform.hxx>
#include "FilterConfigCache.hxx"
@@ -977,6 +979,18 @@ ErrCode GraphicFilter::readJPEG(SvStream & rStream, Graphic & rGraphic, GfxLinkT
}
}
+ // Get Orientation from EXIF data
+ GraphicNativeMetadata aMetadata;
+ if (aMetadata.read(rStream))
+ {
+ Degree10 aRotation = aMetadata.getRotation();
+ if (aRotation)
+ {
+ GraphicNativeTransform aTransform(rGraphic);
+ aTransform.rotate(aRotation);
+ }
+ }
+
return aReturnCode;
}
diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx
index 82d1827543bd..b0312c72610a 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -457,7 +457,7 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput,
case PNG_COLOR_TYPE_RGB:
aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP);
break;
- case PNG_COLOR_TYPE_RGBA:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N32_BPP);
break;
case PNG_COLOR_TYPE_GRAY:
@@ -515,44 +515,26 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput,
{
size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
- if (nNumberOfPasses == 1)
+ // Reuse the bitmap data as a buffer for reading the png data. The
+ // order is possibly incorrect from what it should finally be and
+ // in any case the result is not premultiplied.
+ for (int pass = 0; pass < nNumberOfPasses; pass++)
{
- // optimise the common case, where we can use a buffer of only a single row
- std::vector<png_byte> aRow(aRowSizeBytes, 0);
for (png_uint_32 y = 0; y < height; y++)
{
Scanline pScanline = pWriteAccess->GetScanline(y);
- png_bytep pRow = aRow.data();
- png_read_row(pPng, pRow, nullptr);
- for (size_t i = 0; i < aRowSizeBytes; i += 4)
- {
- Color aCol(ColorAlpha, pRow[i + 3], pRow[i + 0], pRow[i + 1], pRow[i + 2]);
- pWriteAccess->SetPixelOnData(pScanline, i / 4, aCol);
- }
+ png_read_row(pPng, pScanline, nullptr);
}
}
- else
+ // Fix order and do premultiplication
+ for (png_uint_32 y = 0; y < height; y++)
{
- std::vector<std::vector<png_byte>> aRows(height);
- for (auto& rRow : aRows)
- rRow.resize(aRowSizeBytes, 0);
- for (int pass = 0; pass < nNumberOfPasses; pass++)
- {
- for (png_uint_32 y = 0; y < height; y++)
- {
- png_bytep pRow = aRows[y].data();
- png_read_row(pPng, pRow, nullptr);
- }
- }
- for (png_uint_32 y = 0; y < height; y++)
+ Scanline pScanline = pWriteAccess->GetScanline(y);
+ for (size_t i = 0; i < aRowSizeBytes; i += 4)
{
- Scanline pScanline = pWriteAccess->GetScanline(y);
- png_bytep pRow = aRows[y].data();
- for (size_t i = 0; i < aRowSizeBytes; i += 4)
- {
- Color aCol(ColorAlpha, pRow[i + 3], pRow[i + 0], pRow[i + 1], pRow[i + 2]);
- pWriteAccess->SetPixelOnData(pScanline, i / 4, aCol);
- }
+ Color aCol(ColorAlpha, pScanline[i + 3], pScanline[i + 0], pScanline[i + 1],
+ pScanline[i + 2]);
+ pWriteAccess->SetPixelOnData(pScanline, i / 4, aCol);
}
}
}
diff --git a/vcl/source/filter/png/PngImageWriter.cxx b/vcl/source/filter/png/PngImageWriter.cxx
index da0dde32f93a..b0eb6ec0fb0e 100644
--- a/vcl/source/filter/png/PngImageWriter.cxx
+++ b/vcl/source/filter/png/PngImageWriter.cxx
@@ -208,7 +208,7 @@ static bool pngWrite(SvStream& rStream, const Graphic& rGraphic, int nCompressio
case ScanlineFormat::N32BitTcBgra:
{
assert(aBitmap.HasAlpha());
- colorType = PNG_COLOR_TYPE_RGBA;
+ colorType = PNG_COLOR_TYPE_RGB_ALPHA;
bitDepth = 8;
bCombineChannels = true;
break;
@@ -224,7 +224,7 @@ static bool pngWrite(SvStream& rStream, const Graphic& rGraphic, int nCompressio
case ScanlineFormat::N32BitTcRgba:
{
assert(aBitmap.HasAlpha());
- colorType = PNG_COLOR_TYPE_RGBA;
+ colorType = PNG_COLOR_TYPE_RGB_ALPHA;
bitDepth = 8;
bCombineChannels = true;
break;
diff --git a/vcl/source/gdi/metaact.cxx b/vcl/source/gdi/metaact.cxx
index 20406866e658..570083705f4b 100644
--- a/vcl/source/gdi/metaact.cxx
+++ b/vcl/source/gdi/metaact.cxx
@@ -113,10 +113,6 @@ void MetaAction::Scale( double, double )
{
}
-MetaPixelAction::MetaPixelAction() :
- MetaAction(MetaActionType::PIXEL)
-{}
-
MetaPixelAction::~MetaPixelAction()
{}
@@ -146,10 +142,6 @@ void MetaPixelAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
}
-MetaPointAction::MetaPointAction() :
- MetaAction(MetaActionType::POINT)
-{}
-
MetaPointAction::~MetaPointAction()
{}
@@ -178,10 +170,6 @@ void MetaPointAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
}
-MetaLineAction::MetaLineAction() :
- MetaAction(MetaActionType::LINE)
-{}
-
MetaLineAction::~MetaLineAction()
{}
@@ -225,10 +213,6 @@ void MetaLineAction::Scale( double fScaleX, double fScaleY )
ImplScaleLineInfo( maLineInfo, fScaleX, fScaleY );
}
-MetaRectAction::MetaRectAction() :
- MetaAction(MetaActionType::RECT)
-{}
-
MetaRectAction::~MetaRectAction()
{}
@@ -284,12 +268,6 @@ void MetaRectAction::Scale( double fScaleX, double fScaleY )
ImplScaleRect( maRect, fScaleX, fScaleY );
}
-MetaRoundRectAction::MetaRoundRectAction() :
- MetaAction ( MetaActionType::ROUNDRECT ),
- mnHorzRound ( 0 ),
- mnVertRound ( 0 )
-{}
-
MetaRoundRectAction::~MetaRoundRectAction()
{}
@@ -323,10 +301,6 @@ void MetaRoundRectAction::Scale( double fScaleX, double fScaleY )
mnVertRound = basegfx::fround<sal_uInt32>(mnVertRound * fabs(fScaleY));
}
-MetaEllipseAction::MetaEllipseAction() :
- MetaAction(MetaActionType::ELLIPSE)
-{}
-
MetaEllipseAction::~MetaEllipseAction()
{}
@@ -355,10 +329,6 @@ void MetaEllipseAction::Scale( double fScaleX, double fScaleY )
ImplScaleRect( maRect, fScaleX, fScaleY );
}
-MetaArcAction::MetaArcAction() :
- MetaAction(MetaActionType::ARC)
-{}
-
MetaArcAction::~MetaArcAction()
{}
@@ -397,10 +367,6 @@ void MetaArcAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maEndPt, fScaleX, fScaleY );
}
-MetaPieAction::MetaPieAction() :
- MetaAction(MetaActionType::PIE)
-{}
-
MetaPieAction::~MetaPieAction()
{}
@@ -439,10 +405,6 @@ void MetaPieAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maEndPt, fScaleX, fScaleY );
}
-MetaChordAction::MetaChordAction() :
- MetaAction(MetaActionType::CHORD)
-{}
-
MetaChordAction::~MetaChordAction()
{}
@@ -478,10 +440,6 @@ void MetaChordAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maEndPt, fScaleX, fScaleY );
}
-MetaPolyLineAction::MetaPolyLineAction() :
- MetaAction(MetaActionType::POLYLINE)
-{}
-
MetaPolyLineAction::~MetaPolyLineAction()
{}
@@ -523,10 +481,6 @@ void MetaPolyLineAction::Scale( double fScaleX, double fScaleY )
ImplScaleLineInfo( maLineInfo, fScaleX, fScaleY );
}
-MetaPolygonAction::MetaPolygonAction() :
- MetaAction(MetaActionType::POLYGON)
-{}
-
MetaPolygonAction::~MetaPolygonAction()
{}
@@ -555,10 +509,6 @@ void MetaPolygonAction::Scale( double fScaleX, double fScaleY )
ImplScalePoly( maPoly, fScaleX, fScaleY );
}
-MetaPolyPolygonAction::MetaPolyPolygonAction() :
- MetaAction(MetaActionType::POLYPOLYGON)
-{}
-
MetaPolyPolygonAction::~MetaPolyPolygonAction()
{}
@@ -588,12 +538,6 @@ void MetaPolyPolygonAction::Scale( double fScaleX, double fScaleY )
ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
}
-MetaTextAction::MetaTextAction() :
- MetaAction ( MetaActionType::TEXT ),
- mnIndex ( 0 ),
- mnLen ( 0 )
-{}
-
MetaTextAction::~MetaTextAction()
{}
@@ -629,12 +573,6 @@ void MetaTextAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
}
-MetaTextArrayAction::MetaTextArrayAction() :
- MetaAction ( MetaActionType::TEXTARRAY ),
- mnIndex ( 0 ),
- mnLen ( 0 )
-{}
-
MetaTextArrayAction::MetaTextArrayAction(const MetaTextArrayAction& rAction)
: MetaAction(MetaActionType::TEXTARRAY)
, maStartPt(rAction.maStartPt)
@@ -737,13 +675,6 @@ void MetaTextArrayAction::Scale( double fScaleX, double fScaleY )
}
}
-MetaStretchTextAction::MetaStretchTextAction() :
- MetaAction ( MetaActionType::STRETCHTEXT ),
- mnWidth ( 0 ),
- mnIndex ( 0 ),
- mnLen ( 0 )
-{}
-
MetaStretchTextAction::~MetaStretchTextAction()
{}
@@ -798,10 +729,6 @@ void MetaStretchTextAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
mnWidth = basegfx::fround<sal_uInt32>(mnWidth * fabs(fScaleX));
}
-MetaTextRectAction::MetaTextRectAction() :
- MetaAction ( MetaActionType::TEXTRECT ),
- mnStyle ( DrawTextFlags::NONE )
-{}
MetaTextRectAction::~MetaTextRectAction()
{}
@@ -837,14 +764,6 @@ void MetaTextRectAction::Scale( double fScaleX, double fScaleY )
ImplScaleRect( maRect, fScaleX, fScaleY );
}
-MetaTextLineAction::MetaTextLineAction() :
- MetaAction ( MetaActionType::TEXTLINE ),
- mnWidth ( 0 ),
- meStrikeout ( STRIKEOUT_NONE ),
- meUnderline ( LINESTYLE_NONE ),
- meOverline ( LINESTYLE_NONE )
-{}
-
MetaTextLineAction::~MetaTextLineAction()
{}
@@ -889,10 +808,6 @@ void MetaTextLineAction::Scale( double fScaleX, double fScaleY )
mnWidth = basegfx::fround<tools::Long>(mnWidth * fabs(fScaleX));
}
-MetaBmpAction::MetaBmpAction() :
- MetaAction(MetaActionType::BMP)
-{}
-
MetaBmpAction::~MetaBmpAction()
{}
@@ -925,10 +840,6 @@ void MetaBmpAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
}
-MetaBmpScaleAction::MetaBmpScaleAction() :
- MetaAction(MetaActionType::BMPSCALE)
-{}
-
MetaBmpScaleAction::~MetaBmpScaleAction()
{}
@@ -1012,10 +923,6 @@ void MetaBmpScaleAction::Scale( double fScaleX, double fScaleY )
maSz = aRectangle.GetSize();
}
-MetaBmpScalePartAction::MetaBmpScalePartAction() :
- MetaAction(MetaActionType::BMPSCALEPART)
-{}
-
MetaBmpScalePartAction::~MetaBmpScalePartAction()
{}
@@ -1059,10 +966,6 @@ void MetaBmpScalePartAction::Scale( double fScaleX, double fScaleY )
maDstSz = aRectangle.GetSize();
}
-MetaBmpExAction::MetaBmpExAction() :
- MetaAction(MetaActionType::BMPEX)
-{}
-
MetaBmpExAction::~MetaBmpExAction()
{}
@@ -1092,10 +995,6 @@ void MetaBmpExAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
}
-MetaBmpExScaleAction::MetaBmpExScaleAction() :
- MetaAction(MetaActionType::BMPEXSCALE)
-{}
-
MetaBmpExScaleAction::~MetaBmpExScaleAction()
{}
@@ -1135,10 +1034,6 @@ void MetaBmpExScaleAction::Scale( double fScaleX, double fScaleY )
maSz = aRectangle.GetSize();
}
-MetaBmpExScalePartAction::MetaBmpExScalePartAction() :
- MetaAction(MetaActionType::BMPEXSCALEPART)
-{}
-
MetaBmpExScalePartAction::~MetaBmpExScalePartAction()
{}
@@ -1179,10 +1074,6 @@ void MetaBmpExScalePartAction::Scale( double fScaleX, double fScaleY )
maDstSz = aRectangle.GetSize();
}
-MetaMaskAction::MetaMaskAction() :
- MetaAction(MetaActionType::MASK)
-{}
-
MetaMaskAction::~MetaMaskAction()
{}
@@ -1217,10 +1108,6 @@ void MetaMaskAction::Scale( double fScaleX, double fScaleY )
ImplScalePoint( maPt, fScaleX, fScaleY );
}
-MetaMaskScaleAction::MetaMaskScaleAction() :
- MetaAction(MetaActionType::MASKSCALE)
-{}
-
MetaMaskScaleAction::~MetaMaskScaleAction()
{}
@@ -1259,10 +1146,6 @@ void MetaMaskScaleAction::Scale( double fScaleX, double fScaleY )
maSz = aRectangle.GetSize();
}
-MetaMaskScalePartAction::MetaMaskScalePartAction() :
- MetaAction(MetaActionType::MASKSCALEPART)
-{}
-
MetaMaskScalePartAction::~MetaMaskScalePartAction()
{}
@@ -1305,10 +1188,6 @@ void MetaMaskScalePartAction::Scale( double fScaleX, double fScaleY )
maDstSz = aRectangle.GetSize();
}
-MetaGradientAction::MetaGradientAction() :
- MetaAction(MetaActionType::GRADIENT)
-{}
-
MetaGradientAction::~MetaGradientAction()
{}
@@ -1338,10 +1217,6 @@ void MetaGradientAction::Scale( double fScaleX, double fScaleY )
ImplScaleRect( maRect, fScaleX, fScaleY );
}
-MetaGradientExAction::MetaGradientExAction() :
- MetaAction ( MetaActionType::GRADIENTEX )
-{}
-
MetaGradientExAction::MetaGradientExAction( tools::PolyPolygon aPolyPoly, Gradient aGradient ) :
MetaAction ( MetaActionType::GRADIENTEX ),
maPolyPoly (std::move( aPolyPoly )),
@@ -1375,10 +1250,6 @@ void MetaGradientExAction::Scale( double fScaleX, double fScaleY )
ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
}
-MetaHatchAction::MetaHatchAction() :
- MetaAction(MetaActionType::HATCH)
-{}
-
MetaHatchAction::~MetaHatchAction()
{}
@@ -1414,10 +1285,6 @@ void MetaHatchAction::Scale( double fScaleX, double fScaleY )
ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
}
-MetaWallpaperAction::MetaWallpaperAction() :
- MetaAction(MetaActionType::WALLPAPER)
-{}
-
MetaWallpaperAction::~MetaWallpaperAction()
{}
@@ -1448,11 +1315,6 @@ void MetaWallpaperAction::Scale( double fScaleX, double fScaleY )
ImplScaleRect( maRect, fScaleX, fScaleY );
}
-MetaClipRegionAction::MetaClipRegionAction() :
- MetaAction ( MetaActionType::CLIPREGION ),
- mbClip ( false )
-{}
-
MetaClipRegionAction::~MetaClipRegionAction()
{}
@@ -1485,10 +1347,6 @@ void MetaClipRegionAction::Scale( double fScaleX, double fScaleY )
maRegion.Scale( fScaleX, fScaleY );
}
-MetaISectRectClipRegionAction::MetaISectRectClipRegionAction() :
- MetaAction(MetaActionType::ISECTRECTCLIPREGION)
-{}
-
MetaISectRectClipRegionAction::~MetaISectRectClipRegionAction()
{}
@@ -1517,10 +1375,6 @@ void MetaISectRectClipRegionAction::Scale( double fScaleX, double fScaleY )
ImplScaleRect( maRect, fScaleX, fScaleY );
}
-MetaISectRegionClipRegionAction::MetaISectRegionClipRegionAction() :
- MetaAction(MetaActionType::ISECTREGIONCLIPREGION)
-{}
-
MetaISectRegionClipRegionAction::~MetaISectRegionClipRegionAction()
{}
@@ -1553,12 +1407,6 @@ void MetaISectRegionClipRegionAction::Scale( double fScaleX, double fScaleY )
maRegion.Scale( fScaleX, fScaleY );
}
-MetaMoveClipRegionAction::MetaMoveClipRegionAction() :
- MetaAction ( MetaActionType::MOVECLIPREGION ),
- mnHorzMove ( 0 ),
- mnVertMove ( 0 )
-{}
-
MetaMoveClipRegionAction::~MetaMoveClipRegionAction()
{}
@@ -1586,11 +1434,6 @@ void MetaMoveClipRegionAction::Scale( double fScaleX, double fScaleY )
mnVertMove = basegfx::fround<tools::Long>(mnVertMove * fScaleY);
}
-MetaLineColorAction::MetaLineColorAction() :
- MetaAction ( MetaActionType::LINECOLOR ),
- mbSet ( false )
-{}
-
MetaLineColorAction::~MetaLineColorAction()
{}
@@ -1613,11 +1456,6 @@ rtl::Reference<MetaAction> MetaLineColorAction::Clone() const
return new MetaLineColorAction( *this );
}
-MetaFillColorAction::MetaFillColorAction() :
- MetaAction ( MetaActionType::FILLCOLOR ),
- mbSet ( false )
-{}
-
MetaFillColorAction::~MetaFillColorAction()
{}
@@ -1640,10 +1478,6 @@ rtl::Reference<MetaAction> MetaFillColorAction::Clone() const
return new MetaFillColorAction( *this );
}
-MetaTextColorAction::MetaTextColorAction() :
- MetaAction(MetaActionType::TEXTCOLOR)
-{}
-
MetaTextColorAction::~MetaTextColorAction()
{}
@@ -1662,11 +1496,6 @@ rtl::Reference<MetaAction> MetaTextColorAction::Clone() const
return new MetaTextColorAction( *this );
}
-MetaTextFillColorAction::MetaTextFillColorAction() :
- MetaAction ( MetaActionType::TEXTFILLCOLOR ),
- mbSet ( false )
-{}
-
MetaTextFillColorAction::~MetaTextFillColorAction()
{}
@@ -1689,11 +1518,6 @@ rtl::Reference<MetaAction> MetaTextFillColorAction::Clone() const
return new MetaTextFillColorAction( *this );
}
-MetaTextLineColorAction::MetaTextLineColorAction() :
- MetaAction ( MetaActionType::TEXTLINECOLOR ),
- mbSet ( false )
-{}
-
MetaTextLineColorAction::~MetaTextLineColorAction()
{}
@@ -1716,11 +1540,6 @@ rtl::Reference<MetaAction> MetaTextLineColorAction::Clone() const
return new MetaTextLineColorAction( *this );
}
-MetaOverlineColorAction::MetaOverlineColorAction() :
- MetaAction ( MetaActionType::OVERLINECOLOR ),
- mbSet ( false )
-{}
-
MetaOverlineColorAction::~MetaOverlineColorAction()
{}
@@ -1743,11 +1562,6 @@ rtl::Reference<MetaAction> MetaOverlineColorAction::Clone() const
return new MetaOverlineColorAction( *this );
}
-MetaTextAlignAction::MetaTextAlignAction() :
- MetaAction ( MetaActionType::TEXTALIGN ),
- maAlign ( ALIGN_TOP )
-{}
-
MetaTextAlignAction::~MetaTextAlignAction()
{}
@@ -1796,10 +1610,6 @@ void MetaMapModeAction::Scale( double fScaleX, double fScaleY )
maMapMode.SetOrigin( aPoint );
}
-MetaFontAction::MetaFontAction() :
- MetaAction(MetaActionType::FONT)
-{}
-
MetaFontAction::~MetaFontAction()
{}
@@ -1837,11 +1647,6 @@ void MetaFontAction::Scale( double fScaleX, double fScaleY )
maFont.SetFontSize( aSize );
}
-MetaPushAction::MetaPushAction() :
- MetaAction ( MetaActionType::PUSH ),
- mnFlags ( vcl::PushFlags::NONE )
-{}
-
MetaPushAction::~MetaPushAction()
{}
@@ -1877,11 +1682,6 @@ rtl::Reference<MetaAction> MetaPopAction::Clone() const
return new MetaPopAction( *this );
}
-MetaRasterOpAction::MetaRasterOpAction() :
- MetaAction ( MetaActionType::RASTEROP ),
- meRasterOp ( RasterOp::OverPaint )
-{}
-
MetaRasterOpAction::~MetaRasterOpAction()
{}
@@ -1901,11 +1701,6 @@ rtl::Reference<MetaAction> MetaRasterOpAction::Clone() const
return new MetaRasterOpAction( *this );
}
-MetaTransparentAction::MetaTransparentAction() :
- MetaAction ( MetaActionType::Transparent ),
- mnTransPercent ( 0 )
-{}
-
MetaTransparentAction::~MetaTransparentAction()
{}
@@ -1936,10 +1731,6 @@ void MetaTransparentAction::Scale( double fScaleX, double fScaleY )
ImplScalePoly( maPolyPoly[ i ], fScaleX, fScaleY );
}
-MetaFloatTransparentAction::MetaFloatTransparentAction() :
- MetaAction(MetaActionType::FLOATTRANSPARENT)
-{}
-
MetaFloatTransparentAction::~MetaFloatTransparentAction()
{}
@@ -1977,10 +1768,6 @@ void MetaFloatTransparentAction::Scale( double fScaleX, double fScaleY )
maSize = aRectangle.GetSize();
}
-MetaEPSAction::MetaEPSAction() :
- MetaAction(MetaActionType::EPS)
-{}
-
MetaEPSAction::~MetaEPSAction()
{}
@@ -2016,11 +1803,6 @@ void MetaEPSAction::Scale( double fScaleX, double fScaleY )
maSize = aRectangle.GetSize();
}
-MetaRefPointAction::MetaRefPointAction() :
- MetaAction ( MetaActionType::REFPOINT ),
- mbSet ( false )
-{}
-
MetaRefPointAction::~MetaRefPointAction()
{}
@@ -2043,13 +1825,6 @@ rtl::Reference<MetaAction> MetaRefPointAction::Clone() const
return new MetaRefPointAction( *this );
}
-MetaCommentAction::MetaCommentAction() :
- MetaAction ( MetaActionType::COMMENT ),
- mnValue ( 0 )
-{
- ImplInitDynamicData( nullptr, 0UL );
-}
-
MetaCommentAction::MetaCommentAction( const MetaCommentAction& rAct ) :
MetaAction ( MetaActionType::COMMENT ),
maComment ( rAct.maComment ),
@@ -2215,11 +1990,6 @@ void MetaCommentAction::Scale( double fXScale, double fYScale )
}
}
-MetaLayoutModeAction::MetaLayoutModeAction() :
- MetaAction ( MetaActionType::LAYOUTMODE ),
- mnLayoutMode( vcl::text::ComplexTextLayoutFlags::Default )
-{}
-
MetaLayoutModeAction::~MetaLayoutModeAction()
{}
@@ -2238,11 +2008,6 @@ rtl::Reference<MetaAction> MetaLayoutModeAction::Clone() const
return new MetaLayoutModeAction( *this );
}
-MetaTextLanguageAction::MetaTextLanguageAction() :
- MetaAction ( MetaActionType::TEXTLANGUAGE ),
- meTextLanguage( LANGUAGE_DONTKNOW )
-{}
-
MetaTextLanguageAction::~MetaTextLanguageAction()
{}
diff --git a/vcl/source/gdi/pdfbuildin_fonts.cxx b/vcl/source/pdf/pdfbuildin_fonts.cxx
index 823c429a5977..823c429a5977 100644
--- a/vcl/source/gdi/pdfbuildin_fonts.cxx
+++ b/vcl/source/pdf/pdfbuildin_fonts.cxx
diff --git a/vcl/source/treelist/svtabbx.cxx b/vcl/source/treelist/svtabbx.cxx
index 8607d40a1cfb..ebed8e79ac8e 100644
--- a/vcl/source/treelist/svtabbx.cxx
+++ b/vcl/source/treelist/svtabbx.cxx
@@ -1100,10 +1100,10 @@ rtl::Reference<comphelper::OAccessible> SvHeaderTabListBox::CreateAccessible()
if (m_xAccessible.is())
return m_xAccessible;
- Reference< XAccessible > xAccParent = GetAccessibleParent();
- if ( xAccParent.is() )
+ rtl::Reference<comphelper::OAccessible> pAccParent = GetAccessibleParent();
+ if (pAccParent.is())
{
- m_xAccessible = new AccessibleTabListBox(xAccParent, *this);
+ m_xAccessible = new AccessibleTabListBox(pAccParent, *this);
return m_xAccessible;
}
return nullptr;
diff --git a/vcl/source/window/accessibility.cxx b/vcl/source/window/accessibility.cxx
index 52ab05b313d0..e65b4940c22f 100644
--- a/vcl/source/window/accessibility.cxx
+++ b/vcl/source/window/accessibility.cxx
@@ -679,44 +679,4 @@ bool Window::IsAccessibilityEventsSuppressed()
} /* namespace vcl */
-uno::Reference<accessibility::XAccessibleEditableText>
-FindFocusedEditableText(uno::Reference<accessibility::XAccessibleContext> const& xContext)
-{
- if (!xContext.is())
- return uno::Reference<accessibility::XAccessibleEditableText>();
-
- sal_Int64 nState = xContext->getAccessibleStateSet();
- if (nState & accessibility::AccessibleStateType::FOCUSED)
- {
- uno::Reference<accessibility::XAccessibleEditableText> xText(xContext, uno::UNO_QUERY);
- if (xText.is())
- return xText;
- if (nState & accessibility::AccessibleStateType::MANAGES_DESCENDANTS)
- return uno::Reference<accessibility::XAccessibleEditableText>();
- }
-
- bool bSafeToIterate = true;
- sal_Int64 nCount = xContext->getAccessibleChildCount();
- if (nCount < 0 || nCount > SAL_MAX_UINT16 /* slow enough for anyone */)
- bSafeToIterate = false;
- if (!bSafeToIterate)
- return uno::Reference<accessibility::XAccessibleEditableText>();
-
- for (sal_Int64 i = 0; i < xContext->getAccessibleChildCount(); ++i)
- {
- uno::Reference<accessibility::XAccessible> xChild = xContext->getAccessibleChild(i);
- if (!xChild.is())
- continue;
- uno::Reference<accessibility::XAccessibleContext> xChildContext
- = xChild->getAccessibleContext();
- if (!xChildContext.is())
- continue;
- uno::Reference<accessibility::XAccessibleEditableText> xText
- = FindFocusedEditableText(xChildContext);
- if (xText.is())
- return xText;
- }
- return uno::Reference<accessibility::XAccessibleEditableText>();
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/cursor.cxx b/vcl/source/window/cursor.cxx
index 6c9d7577aa41..2437fc321348 100644
--- a/vcl/source/window/cursor.cxx
+++ b/vcl/source/window/cursor.cxx
@@ -241,7 +241,38 @@ void vcl::Cursor::ImplDoShow( bool bDrawDirect, bool bRestore )
}
}
-void vcl::Cursor::LOKNotify( vcl::Window* pWindow, const OUString& rAction )
+namespace
+{
+
+tools::Rectangle calcualteCursorRect(Point const& rPosition, Size const rSize, vcl::Window* pWindow, vcl::Window* pParent)
+{
+ Point aPositionPixel = pWindow->LogicToPixel(rPosition);
+ const tools::Long nX = pWindow->GetOutOffXPixel() + aPositionPixel.X() - pParent->GetOutOffXPixel();
+ const tools::Long nY = pWindow->GetOutOffYPixel() + aPositionPixel.Y() - pParent->GetOutOffYPixel();
+
+ Size aSizePixel = pWindow->LogicToPixel(rSize);
+ if (!aSizePixel.Width())
+ aSizePixel.setWidth( pWindow->GetSettings().GetStyleSettings().GetCursorSize() );
+
+ Point aPosition(nX, nY);
+
+ if (pWindow->IsRTLEnabled() && pWindow->GetOutDev() && pParent->GetOutDev()
+ && !pWindow->GetOutDev()->ImplIsAntiparallel())
+ pParent->GetOutDev()->ReMirror(aPosition);
+
+ if (!pWindow->IsRTLEnabled() && pWindow->GetOutDev() && pParent->GetOutDev()
+ && pWindow->GetOutDev()->ImplIsAntiparallel())
+ {
+ pWindow->GetOutDev()->ReMirror(aPosition);
+ pParent->GetOutDev()->ReMirror(aPosition);
+ }
+
+ return tools::Rectangle(aPosition, aSizePixel);
+}
+
+} // end anonymous namespace
+
+void vcl::Cursor::LOKNotify(vcl::Window* pWindow, const OUString& rAction)
{
VclPtr<vcl::Window> pParent = pWindow->GetParentWithLOKNotifier();
if (!pParent)
@@ -251,39 +282,40 @@ void vcl::Cursor::LOKNotify( vcl::Window* pWindow, const OUString& rAction )
assert(mpData && "Require ImplCursorData");
assert(comphelper::LibreOfficeKit::isActive());
- if (comphelper::LibreOfficeKit::isDialogPainting())
- return;
-
const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
- std::vector<vcl::LOKPayloadItem> aItems;
- if (rAction == "cursor_visible")
- aItems.emplace_back("visible", mpData->mbCurVisible ? "true" : "false");
- else if (rAction == "cursor_invalidate")
- {
- const tools::Long nX = pWindow->GetOutOffXPixel() + pWindow->LogicToPixel(GetPos()).X() - pParent->GetOutOffXPixel();
- const tools::Long nY = pWindow->GetOutOffYPixel() + pWindow->LogicToPixel(GetPos()).Y() - pParent->GetOutOffYPixel();
- Size aSize = pWindow->LogicToPixel(GetSize());
- if (!aSize.Width())
- aSize.setWidth( pWindow->GetSettings().GetStyleSettings().GetCursorSize() );
-
- Point aPos(nX, nY);
- if (pWindow->IsRTLEnabled() && pWindow->GetOutDev() && pParent->GetOutDev()
- && !pWindow->GetOutDev()->ImplIsAntiparallel())
- pParent->GetOutDev()->ReMirror(aPos);
-
- if (!pWindow->IsRTLEnabled() && pWindow->GetOutDev() && pParent->GetOutDev()
- && pWindow->GetOutDev()->ImplIsAntiparallel())
+ if (pWindow->IsFormControl() || (pWindow->GetParent() && pWindow->GetParent()->IsFormControl()))
+ {
+ if (rAction == "cursor_invalidate")
{
- pWindow->GetOutDev()->ReMirror(aPos);
- pParent->GetOutDev()->ReMirror(aPos);
+ tools::Rectangle aRect;
+ if (pWindow->IsFormControl())
+ aRect = calcualteCursorRect(GetPos(), GetSize(), pWindow, pWindow->GetParent());
+ else
+ aRect = calcualteCursorRect(GetPos(), GetSize(), pWindow, pWindow->GetParent()->GetParent());
+
+ OutputDevice* pDevice = mpData->mpWindow->GetOutDev();
+ const tools::Rectangle aRectTwip = pDevice->PixelToLogic(aRect, MapMode(MapUnit::MapTwip));
+ pNotifier->notifyCursorInvalidation(&aRectTwip, true);
}
-
- const tools::Rectangle aRect(aPos, aSize);
- aItems.emplace_back("rectangle", aRect.toString());
}
+ else
+ {
+ if (comphelper::LibreOfficeKit::isDialogPainting())
+ return;
- pNotifier->notifyWindow(pParent->GetLOKWindowId(), rAction, aItems);
+ std::vector<vcl::LOKPayloadItem> aItems;
+ if (rAction == "cursor_visible")
+ {
+ aItems.emplace_back("visible", mpData->mbCurVisible ? "true" : "false");
+ }
+ else if (rAction == "cursor_invalidate")
+ {
+ const tools::Rectangle aRect = calcualteCursorRect(GetPos(), GetSize(), pWindow, pParent);
+ aItems.emplace_back("rectangle", aRect.toString());
+ }
+ pNotifier->notifyWindow(pParent->GetLOKWindowId(), rAction, aItems);
+ }
}
bool vcl::Cursor::ImplDoHide( bool bSuspend )
diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx
index 9ecd35cf39c3..e01a1cc0ddfd 100644
--- a/vcl/source/window/paint.cxx
+++ b/vcl/source/window/paint.cxx
@@ -1228,6 +1228,12 @@ void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
pNotifier->notifyWindow(GetLOKWindowId(), u"invalidate"_ustr, aPayload);
}
+ else if (GetParent() && GetParent()->IsFormControl())
+ {
+ const VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier();
+ if (pParent)
+ pParent->GetLOKNotifier()->notifyInvalidation(pRectangle);
+ }
// Added for dialog items. Pass invalidation to the parent window.
else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
{
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
index e6fc3d032f62..f4a830888684 100644
--- a/vcl/source/window/window.cxx
+++ b/vcl/source/window/window.cxx
@@ -62,6 +62,7 @@
#include <dndeventdispatcher.hxx>
#include <com/sun/star/accessibility/AccessibleRelation.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/accessibility/XAccessibleEditableText.hpp>
#include <com/sun/star/awt/XVclWindowPeer.hpp>
@@ -3801,6 +3802,46 @@ namespace
{
using namespace com::sun::star;
+ uno::Reference<accessibility::XAccessibleEditableText>
+ lcl_FindFocusedEditableText(uno::Reference<accessibility::XAccessibleContext> const& xContext)
+ {
+ if (!xContext.is())
+ return uno::Reference<accessibility::XAccessibleEditableText>();
+
+ sal_Int64 nState = xContext->getAccessibleStateSet();
+ if (nState & accessibility::AccessibleStateType::FOCUSED)
+ {
+ uno::Reference<accessibility::XAccessibleEditableText> xText(xContext, uno::UNO_QUERY);
+ if (xText.is())
+ return xText;
+ if (nState & accessibility::AccessibleStateType::MANAGES_DESCENDANTS)
+ return uno::Reference<accessibility::XAccessibleEditableText>();
+ }
+
+ bool bSafeToIterate = true;
+ sal_Int64 nCount = xContext->getAccessibleChildCount();
+ if (nCount < 0 || nCount > SAL_MAX_UINT16 /* slow enough for anyone */)
+ bSafeToIterate = false;
+ if (!bSafeToIterate)
+ return uno::Reference<accessibility::XAccessibleEditableText>();
+
+ for (sal_Int64 i = 0; i < xContext->getAccessibleChildCount(); ++i)
+ {
+ uno::Reference<accessibility::XAccessible> xChild = xContext->getAccessibleChild(i);
+ if (!xChild.is())
+ continue;
+ uno::Reference<accessibility::XAccessibleContext> xChildContext
+ = xChild->getAccessibleContext();
+ if (!xChildContext.is())
+ continue;
+ uno::Reference<accessibility::XAccessibleEditableText> xText
+ = lcl_FindFocusedEditableText(xChildContext);
+ if (xText.is())
+ return xText;
+ }
+ return uno::Reference<accessibility::XAccessibleEditableText>();
+ }
+
uno::Reference<accessibility::XAccessibleEditableText> lcl_GetxText(vcl::Window *pFocusWin)
{
uno::Reference<accessibility::XAccessibleEditableText> xText;
@@ -3808,7 +3849,7 @@ namespace
{
rtl::Reference<comphelper::OAccessible> pAccessible = pFocusWin->GetAccessible();
if (pAccessible.is())
- xText = FindFocusedEditableText(pAccessible);
+ xText = lcl_FindFocusedEditableText(pAccessible);
}
catch(const uno::Exception&)
{
diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx
index 7b1946360a47..93a81bb259a6 100644
--- a/vcl/source/window/window2.cxx
+++ b/vcl/source/window/window2.cxx
@@ -1045,6 +1045,17 @@ WindowType Window::GetType() const
return WindowType::NONE;
}
+bool Window::IsFormControl() const
+{
+ return mpWindowImpl ? mpWindowImpl->mbIsFormControl : false;
+}
+
+void Window::SetFormControl(bool bFormControl)
+{
+ if (mpWindowImpl)
+ mpWindowImpl->mbIsFormControl = bFormControl;
+}
+
Dialog* Window::GetParentDialog() const
{
const vcl::Window *pWindow = this;
diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx
index 801ef8499d9f..a75eb6ada250 100644
--- a/vcl/source/window/winproc.cxx
+++ b/vcl/source/window/winproc.cxx
@@ -2552,48 +2552,41 @@ static bool ImplHandleShowDialog( vcl::Window* pWindow, ShowDialogId nDialogId )
return ImplCallCommand( pWindow, CommandEventId::ShowDialog, &aCmdData );
}
-static void ImplHandleSurroundingTextRequest( vcl::Window *pWindow,
- OUString& rText,
- Selection &rSelRange )
+static void ImplHandleSalSurroundingTextRequest( vcl::Window *pWindow,
+ SalSurroundingTextRequestEvent *pEvt )
{
vcl::Window* pChild = ImplGetKeyInputWindow( pWindow );
-
if ( !pChild )
{
- rText.clear();
- rSelRange.setMin( 0 );
- rSelRange.setMax( 0 );
- }
- else
- {
- rText = pChild->GetSurroundingText();
- Selection aSel = pChild->GetSurroundingTextSelection();
- rSelRange.setMin( aSel.Min() );
- rSelRange.setMax( aSel.Max() );
+ pEvt->maText.clear();
+ pEvt->mnStart = 0;
+ pEvt->mnEnd = 0;
+ return;
}
-}
-static void ImplHandleSalSurroundingTextRequest( vcl::Window *pWindow,
- SalSurroundingTextRequestEvent *pEvt )
-{
- Selection aSelRange;
- ImplHandleSurroundingTextRequest( pWindow, pEvt->maText, aSelRange );
+ pEvt->maText = pChild->GetSurroundingText();
+ Selection aSelRange = pChild->GetSurroundingTextSelection();
- aSelRange.Normalize();
+ sal_uLong nSelectionAnchorPos = 0;
+ sal_uLong nCursorPos = 0;
if( aSelRange.Min() < 0 )
- pEvt->mnStart = 0;
+ nSelectionAnchorPos = 0;
else if( aSelRange.Min() > pEvt->maText.getLength() )
- pEvt->mnStart = pEvt->maText.getLength();
+ nSelectionAnchorPos = pEvt->maText.getLength();
else
- pEvt->mnStart = aSelRange.Min();
+ nSelectionAnchorPos = aSelRange.Min();
if( aSelRange.Max() < 0 )
- pEvt->mnStart = 0;
+ nCursorPos = 0;
else if( aSelRange.Max() > pEvt->maText.getLength() )
- pEvt->mnEnd = pEvt->maText.getLength();
+ nCursorPos = pEvt->maText.getLength();
else
- pEvt->mnEnd = aSelRange.Max();
+ nCursorPos = aSelRange.Max();
+
+ pEvt->mnCursorPos = nCursorPos;
+ pEvt->mnStart = std::min(nSelectionAnchorPos, nCursorPos);
+ pEvt->mnEnd = std::max(nSelectionAnchorPos, nCursorPos);
}
static void ImplHandleSalDeleteSurroundingTextRequest( vcl::Window *pWindow,
diff --git a/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx b/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx
index 5bbf94d7b74f..5fc439952722 100644
--- a/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx
+++ b/vcl/unx/gtk3/fpicker/SalGtkPicker.cxx
@@ -20,8 +20,6 @@
#include <com/sun/star/frame/TerminationVetoException.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
-#include <com/sun/star/accessibility/XAccessibleContext.hpp>
-#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <utility>