summaryrefslogtreecommitdiffstats
path: root/filter/source/msfilter
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /filter/source/msfilter
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'filter/source/msfilter')
-rw-r--r--filter/source/msfilter/countryid.cxx319
-rw-r--r--filter/source/msfilter/dffpropset.cxx1360
-rw-r--r--filter/source/msfilter/dffrecordheader.cxx43
-rw-r--r--filter/source/msfilter/escherex.cxx5295
-rw-r--r--filter/source/msfilter/eschesdo.cxx1237
-rw-r--r--filter/source/msfilter/eschesdo.hxx138
-rw-r--r--filter/source/msfilter/mscodec.cxx642
-rw-r--r--filter/source/msfilter/msdffimp.cxx7610
-rw-r--r--filter/source/msfilter/msfilter.component26
-rw-r--r--filter/source/msfilter/msocximex.cxx146
-rw-r--r--filter/source/msfilter/msoleexp.cxx340
-rw-r--r--filter/source/msfilter/mstoolbar.cxx824
-rw-r--r--filter/source/msfilter/msvbahelper.cxx768
-rw-r--r--filter/source/msfilter/rtfutil.cxx401
-rw-r--r--filter/source/msfilter/svdfppt.cxx7832
-rw-r--r--filter/source/msfilter/svxmsbas2.cxx80
-rw-r--r--filter/source/msfilter/util.cxx1340
-rw-r--r--filter/source/msfilter/viscache.hxx52
18 files changed, 28453 insertions, 0 deletions
diff --git a/filter/source/msfilter/countryid.cxx b/filter/source/msfilter/countryid.cxx
new file mode 100644
index 000000000..9ad504ab3
--- /dev/null
+++ b/filter/source/msfilter/countryid.cxx
@@ -0,0 +1,319 @@
+/* -*- 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/.
+ *
+ * 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 <filter/msfilter/countryid.hxx>
+
+#include <algorithm>
+#include <sal/macros.h>
+
+
+namespace msfilter {
+
+// Mapping table ==============================================================
+
+namespace {
+
+
+/** Table entry for Windows country ID <-> language type conversion.
+
+ The first member is the Windows country ID, as defined in the header.
+
+ The second member contains the corresponding language type for each country
+ ID. This must be a full language, not only the primary language type.
+
+ The last bool flag defines, if the sub language type should be evaluated to
+ find the country ID from a language. If not set, all languages map to the
+ country which contain the given primary language type.
+
+ Example: The language entry (COUNTRY_USA,LANGUAGE_ENGLISH_US,false) maps
+ the country ID for USA to the language LANGUAGE_ENGLISH_US. The clear sub
+ language flag causes all english languages LANGUAGE_ENGLISH_*** to map to
+ this country ID by default. To map the special case LANGUAGE_ENGLISH_EIRE
+ to the country ID COUNTRY_IRELAND, the sub language flag must be set in the
+ respective table entry, here (COUNTRY_IRELAND,LANGUAGE_ENGLISH_EIRE,true).
+ */
+struct CountryEntry
+{
+ CountryId meCountry; /// Windows country ID.
+ LanguageType meLanguage; /// Corresponding language type.
+ bool mbUseSubLang; /// false = Primary only, true = Primary and sub language.
+};
+
+
+/** Table for Windows country ID <-> language type conversion.
+
+ To map the same language to different country IDs, some of the entries
+ should contain a set sub language flag (see description of CountryEntry).
+ All table entries with a set flag take priority over the entry with the
+ same primary language, but cleared sub language flag, regardless of the
+ position in the table.
+
+ To map different languages to the same country ID, several entries with the
+ same country ID may be inserted. In this case the conversion to a language
+ is done with the first found entry (starting from top) containing the given
+ country ID.
+
+ For now all entries are sorted by country ID, but this is not required.
+ */
+const CountryEntry pTable[] =
+{
+ { COUNTRY_USA, LANGUAGE_ENGLISH_US, false },
+ { COUNTRY_DOMINICAN_REPUBLIC, LANGUAGE_SPANISH_DOMINICAN_REPUBLIC, true },
+ { COUNTRY_JAMAICA, LANGUAGE_ENGLISH_JAMAICA, true },
+ { COUNTRY_PUERTO_RICO, LANGUAGE_SPANISH_PUERTO_RICO, true },
+ { COUNTRY_TRINIDAD_Y_TOBAGO, LANGUAGE_ENGLISH_TRINIDAD, true },
+ { COUNTRY_CANADA, LANGUAGE_ENGLISH_CAN, true },
+ { COUNTRY_CANADA, LANGUAGE_FRENCH_CANADIAN, true },
+ { COUNTRY_RUSSIA, LANGUAGE_RUSSIAN, false },
+ { COUNTRY_KAZAKHSTAN, LANGUAGE_KAZAKH, false },
+ { COUNTRY_TATARSTAN, LANGUAGE_TATAR, false },
+ { COUNTRY_EGYPT, LANGUAGE_ARABIC_EGYPT, true },
+ { COUNTRY_SOUTH_AFRICA, LANGUAGE_AFRIKAANS, false },
+ { COUNTRY_SOUTH_AFRICA, LANGUAGE_ENGLISH_SAFRICA, true },
+ { COUNTRY_SOUTH_AFRICA, LANGUAGE_TSONGA, false },
+ { COUNTRY_SOUTH_AFRICA, LANGUAGE_VENDA, false },
+ { COUNTRY_SOUTH_AFRICA, LANGUAGE_XHOSA, false },
+ { COUNTRY_SOUTH_AFRICA, LANGUAGE_ZULU, false },
+ { COUNTRY_GREECE, LANGUAGE_GREEK, false },
+ { COUNTRY_NETHERLANDS, LANGUAGE_DUTCH, false },
+ { COUNTRY_NETHERLANDS, LANGUAGE_FRISIAN_NETHERLANDS, false },
+ { COUNTRY_BELGIUM, LANGUAGE_DUTCH_BELGIAN, true },
+ { COUNTRY_BELGIUM, LANGUAGE_FRENCH_BELGIAN, true },
+ { COUNTRY_FRANCE, LANGUAGE_FRENCH, false },
+ { COUNTRY_SPAIN, LANGUAGE_SPANISH_MODERN, false },
+ { COUNTRY_SPAIN, LANGUAGE_SPANISH_DATED, false },
+ { COUNTRY_SPAIN, LANGUAGE_CATALAN, false },
+ { COUNTRY_SPAIN, LANGUAGE_BASQUE, false },
+ { COUNTRY_SPAIN, LANGUAGE_GALICIAN, false },
+ { COUNTRY_HUNGARY, LANGUAGE_HUNGARIAN, false },
+ { COUNTRY_ITALY, LANGUAGE_ITALIAN, false },
+ { COUNTRY_ROMANIA, LANGUAGE_ROMANIAN, false },
+ { COUNTRY_SWITZERLAND, LANGUAGE_GERMAN_SWISS, true },
+ { COUNTRY_SWITZERLAND, LANGUAGE_FRENCH_SWISS, true },
+ { COUNTRY_SWITZERLAND, LANGUAGE_ITALIAN_SWISS, true },
+ { COUNTRY_SWITZERLAND, LANGUAGE_RHAETO_ROMAN, false },
+ { COUNTRY_AUSTRIA, LANGUAGE_GERMAN_AUSTRIAN, true },
+ { COUNTRY_UNITED_KINGDOM, LANGUAGE_ENGLISH_UK, true },
+ { COUNTRY_UNITED_KINGDOM, LANGUAGE_GAELIC_SCOTLAND, true },
+ { COUNTRY_UNITED_KINGDOM, LANGUAGE_WELSH, false },
+ { COUNTRY_DENMARK, LANGUAGE_DANISH, false },
+ { COUNTRY_SWEDEN, LANGUAGE_SWEDISH, false },
+ { COUNTRY_SWEDEN, LANGUAGE_SAMI_LAPPISH, false },
+ { COUNTRY_NORWAY, LANGUAGE_NORWEGIAN_BOKMAL, false },
+ { COUNTRY_POLAND, LANGUAGE_POLISH, false },
+ { COUNTRY_GERMANY, LANGUAGE_GERMAN, false },
+ { COUNTRY_GERMANY, LANGUAGE_SORBIAN, false },
+ { COUNTRY_PERU, LANGUAGE_SPANISH_PERU, true },
+ { COUNTRY_MEXICO, LANGUAGE_SPANISH_MEXICAN, true },
+ { COUNTRY_ARGENTINA, LANGUAGE_SPANISH_ARGENTINA, true },
+ { COUNTRY_BRAZIL, LANGUAGE_PORTUGUESE_BRAZILIAN, true },
+ { COUNTRY_CHILE, LANGUAGE_SPANISH_CHILE, true },
+ { COUNTRY_COLOMBIA, LANGUAGE_SPANISH_COLOMBIA, true },
+ { COUNTRY_VENEZUELA, LANGUAGE_SPANISH_VENEZUELA, true },
+ { COUNTRY_MALAYSIA, LANGUAGE_MALAY_MALAYSIA, false },
+ { COUNTRY_AUSTRALIA, LANGUAGE_ENGLISH_AUS, true },
+ { COUNTRY_INDONESIA, LANGUAGE_INDONESIAN, false },
+ { COUNTRY_PHILIPPINES, LANGUAGE_ENGLISH_PHILIPPINES, true },
+ { COUNTRY_NEW_ZEALAND, LANGUAGE_MAORI_NEW_ZEALAND, false },
+ { COUNTRY_NEW_ZEALAND, LANGUAGE_ENGLISH_NZ, true },
+ { COUNTRY_SINGAPORE, LANGUAGE_CHINESE_SINGAPORE, true },
+ { COUNTRY_THAILAND, LANGUAGE_THAI, false },
+ { COUNTRY_JAPAN, LANGUAGE_JAPANESE, false },
+ { COUNTRY_SOUTH_KOREA, LANGUAGE_KOREAN, false },
+ { COUNTRY_VIET_NAM, LANGUAGE_VIETNAMESE, false },
+ { COUNTRY_PR_CHINA, LANGUAGE_CHINESE_SIMPLIFIED, false },
+ { COUNTRY_TIBET, LANGUAGE_TIBETAN, false },
+ { COUNTRY_TURKEY, LANGUAGE_TURKISH, false },
+ { COUNTRY_INDIA, LANGUAGE_HINDI, false },
+ { COUNTRY_INDIA, LANGUAGE_URDU_INDIA, true },
+ { COUNTRY_INDIA, LANGUAGE_PUNJABI, false },
+ { COUNTRY_INDIA, LANGUAGE_GUJARATI, false },
+ { COUNTRY_INDIA, LANGUAGE_ODIA, false },
+ { COUNTRY_INDIA, LANGUAGE_TAMIL, false },
+ { COUNTRY_INDIA, LANGUAGE_TELUGU, false },
+ { COUNTRY_INDIA, LANGUAGE_KANNADA, false },
+ { COUNTRY_INDIA, LANGUAGE_MALAYALAM, false },
+ { COUNTRY_INDIA, LANGUAGE_ASSAMESE, false },
+ { COUNTRY_INDIA, LANGUAGE_MARATHI, false },
+ { COUNTRY_INDIA, LANGUAGE_SANSKRIT, false },
+ { COUNTRY_INDIA, LANGUAGE_KONKANI, false },
+ { COUNTRY_INDIA, LANGUAGE_MANIPURI, false },
+ { COUNTRY_INDIA, LANGUAGE_SINDHI, false },
+ { COUNTRY_INDIA, LANGUAGE_KASHMIRI, false },
+ { COUNTRY_PAKISTAN, LANGUAGE_URDU_PAKISTAN, false },
+ { COUNTRY_MYANMAR, LANGUAGE_BURMESE, false },
+ { COUNTRY_MOROCCO, LANGUAGE_ARABIC_MOROCCO, true },
+ { COUNTRY_ALGERIA, LANGUAGE_ARABIC_ALGERIA, true },
+ { COUNTRY_TUNISIA, LANGUAGE_ARABIC_TUNISIA, true },
+ { COUNTRY_LIBYA, LANGUAGE_ARABIC_LIBYA, true },
+ { COUNTRY_SENEGAL, LANGUAGE_FRENCH_SENEGAL, true },
+ { COUNTRY_MALI, LANGUAGE_FRENCH_MALI, true },
+ { COUNTRY_COTE_D_IVOIRE, LANGUAGE_FRENCH_COTE_D_IVOIRE, true },
+ { COUNTRY_CAMEROON, LANGUAGE_FRENCH_CAMEROON, true },
+ { COUNTRY_ZAIRE, LANGUAGE_FRENCH_ZAIRE, true },
+ { COUNTRY_RWANDA, LANGUAGE_KINYARWANDA_RWANDA, false },
+ { COUNTRY_KENYA, LANGUAGE_SWAHILI, false },
+ { COUNTRY_REUNION, LANGUAGE_FRENCH_REUNION, true },
+ { COUNTRY_ZIMBABWE, LANGUAGE_ENGLISH_ZIMBABWE, true },
+ { COUNTRY_LESOTHO, LANGUAGE_SESOTHO, false },
+ { COUNTRY_BOTSWANA, LANGUAGE_TSWANA, false },
+ { COUNTRY_FAEROE_ISLANDS, LANGUAGE_FAEROESE, false },
+ { COUNTRY_PORTUGAL, LANGUAGE_PORTUGUESE, false },
+ { COUNTRY_LUXEMBOURG, LANGUAGE_GERMAN_LUXEMBOURG, true },
+ { COUNTRY_LUXEMBOURG, LANGUAGE_FRENCH_LUXEMBOURG, true },
+ { COUNTRY_IRELAND, LANGUAGE_ENGLISH_EIRE, true },
+ { COUNTRY_IRELAND, LANGUAGE_GAELIC_IRELAND, true },
+ { COUNTRY_ICELAND, LANGUAGE_ICELANDIC, false },
+ { COUNTRY_ALBANIA, LANGUAGE_ALBANIAN, false },
+ { COUNTRY_MALTA, LANGUAGE_MALTESE, false },
+ { COUNTRY_FINLAND, LANGUAGE_FINNISH, false },
+ { COUNTRY_FINLAND, LANGUAGE_SWEDISH_FINLAND, true },
+ { COUNTRY_BULGARIA, LANGUAGE_BULGARIAN, false },
+ { COUNTRY_LITHUANIA, LANGUAGE_LITHUANIAN, false },
+ { COUNTRY_LATVIA, LANGUAGE_LATVIAN, false },
+ { COUNTRY_ESTONIA, LANGUAGE_ESTONIAN, false },
+ { COUNTRY_MOLDOVA, LANGUAGE_ROMANIAN_MOLDOVA, true },
+ { COUNTRY_MOLDOVA, LANGUAGE_RUSSIAN_MOLDOVA, true },
+ { COUNTRY_ARMENIA, LANGUAGE_ARMENIAN, false },
+ { COUNTRY_BELARUS, LANGUAGE_BELARUSIAN, false },
+ { COUNTRY_MONACO, LANGUAGE_FRENCH_MONACO, true },
+ { COUNTRY_UKRAINE, LANGUAGE_UKRAINIAN, false },
+ { COUNTRY_SERBIA, LANGUAGE_SERBIAN_LATIN_SAM, false },
+ { COUNTRY_CROATIA, LANGUAGE_CROATIAN, true }, // sub type of LANGUAGE_SERBIAN
+ { COUNTRY_SLOVENIA, LANGUAGE_SLOVENIAN, false },
+ { COUNTRY_MACEDONIA, LANGUAGE_MACEDONIAN, false },
+ { COUNTRY_CZECH, LANGUAGE_CZECH, false },
+ { COUNTRY_SLOVAK, LANGUAGE_SLOVAK, false },
+ { COUNTRY_LIECHTENSTEIN, LANGUAGE_GERMAN_LIECHTENSTEIN, true },
+ { COUNTRY_BELIZE, LANGUAGE_ENGLISH_BELIZE, true },
+ { COUNTRY_GUATEMALA, LANGUAGE_SPANISH_GUATEMALA, true },
+ { COUNTRY_EL_SALVADOR, LANGUAGE_SPANISH_EL_SALVADOR, true },
+ { COUNTRY_HONDURAS, LANGUAGE_SPANISH_HONDURAS, true },
+ { COUNTRY_NICARAGUA, LANGUAGE_SPANISH_NICARAGUA, true },
+ { COUNTRY_COSTA_RICA, LANGUAGE_SPANISH_COSTARICA, true },
+ { COUNTRY_PANAMA, LANGUAGE_SPANISH_PANAMA, true },
+ { COUNTRY_BOLIVIA, LANGUAGE_SPANISH_BOLIVIA, true },
+ { COUNTRY_ECUADOR, LANGUAGE_SPANISH_ECUADOR, true },
+ { COUNTRY_PARAGUAY, LANGUAGE_SPANISH_PARAGUAY, true },
+ { COUNTRY_URUGUAY, LANGUAGE_SPANISH_URUGUAY, true },
+ { COUNTRY_BRUNEI_DARUSSALAM, LANGUAGE_MALAY_BRUNEI_DARUSSALAM, true },
+ { COUNTRY_HONG_KONG, LANGUAGE_CHINESE_HONGKONG, true },
+ { COUNTRY_MACAU, LANGUAGE_CHINESE_MACAU, true },
+ { COUNTRY_CAMBODIA, LANGUAGE_KHMER, false },
+ { COUNTRY_LAOS, LANGUAGE_LAO, false },
+ { COUNTRY_BANGLADESH, LANGUAGE_BENGALI, false },
+ { COUNTRY_TAIWAN, LANGUAGE_CHINESE_TRADITIONAL, true },
+ { COUNTRY_MALDIVES, LANGUAGE_DHIVEHI, false },
+ { COUNTRY_LEBANON, LANGUAGE_ARABIC_LEBANON, true },
+ { COUNTRY_JORDAN, LANGUAGE_ARABIC_JORDAN, true },
+ { COUNTRY_SYRIA, LANGUAGE_ARABIC_SYRIA, true },
+ { COUNTRY_IRAQ, LANGUAGE_ARABIC_IRAQ, true },
+ { COUNTRY_KUWAIT, LANGUAGE_ARABIC_KUWAIT, true },
+ { COUNTRY_SAUDI_ARABIA, LANGUAGE_ARABIC_SAUDI_ARABIA, true },
+ { COUNTRY_YEMEN, LANGUAGE_ARABIC_YEMEN, true },
+ { COUNTRY_OMAN, LANGUAGE_ARABIC_OMAN, true },
+ { COUNTRY_UAE, LANGUAGE_ARABIC_UAE, true },
+ { COUNTRY_ISRAEL, LANGUAGE_HEBREW, false },
+ { COUNTRY_BAHRAIN, LANGUAGE_ARABIC_BAHRAIN, true },
+ { COUNTRY_QATAR, LANGUAGE_ARABIC_QATAR, true },
+ { COUNTRY_MONGOLIA, LANGUAGE_MONGOLIAN_CYRILLIC_MONGOLIA, false },
+ { COUNTRY_NEPAL, LANGUAGE_NEPALI, false },
+ { COUNTRY_IRAN, LANGUAGE_FARSI, false },
+ { COUNTRY_TAJIKISTAN, LANGUAGE_TAJIK, false },
+ { COUNTRY_TURKMENISTAN, LANGUAGE_TURKMEN, false },
+ { COUNTRY_AZERBAIJAN, LANGUAGE_AZERI_LATIN, false },
+ { COUNTRY_GEORGIA, LANGUAGE_GEORGIAN, false },
+ { COUNTRY_KYRGYZSTAN, LANGUAGE_KIRGHIZ, false },
+ { COUNTRY_UZBEKISTAN, LANGUAGE_UZBEK_LATIN, false }
+};
+
+const CountryEntry * const pEnd = pTable + SAL_N_ELEMENTS( pTable );
+
+/** Predicate comparing a country ID with the member of a CountryEntry. */
+struct CountryEntryPred_Country
+{
+ CountryId meCountry;
+
+ explicit CountryEntryPred_Country( CountryId eCountry ) :
+ meCountry( eCountry ) {}
+
+ bool operator()( const CountryEntry& rCmp ) const
+ { return rCmp.meCountry == meCountry; }
+};
+
+/** Predicate comparing a language type with the member of a CountryEntry.
+
+ Compares by primary language only, if the passed CountryEntry allows it
+ (the member mbUseSubLang is cleared), otherwise by full language type. */
+struct CountryEntryPred_Language
+{
+ LanguageType meLanguage;
+
+ explicit CountryEntryPred_Language( LanguageType eLanguage ) :
+ meLanguage( eLanguage ) {}
+
+ bool operator()( const CountryEntry& rCmp ) const;
+};
+
+bool CountryEntryPred_Language::operator()( const CountryEntry& rCmp ) const
+{
+ // rCmp.mbUseSubLang==true -> compare full language type
+ // rCmp.mbUseSubLang==false -> compare primary language only
+ return rCmp.mbUseSubLang ? (meLanguage == rCmp.meLanguage) :
+ (primary(meLanguage) == primary(rCmp.meLanguage));
+}
+
+} // namespace
+
+// Country ID <-> Language type conversion ====================================
+
+CountryId ConvertLanguageToCountry( LanguageType eLanguage )
+{
+ // country of a found primary language type
+ CountryId ePrimCountry = COUNTRY_DONTKNOW;
+
+ // find an exact match and a primary-language-only match, in one pass
+ const CountryEntry* pEntry = pTable;
+ do
+ {
+ pEntry = std::find_if( pEntry, pEnd, CountryEntryPred_Language( eLanguage ) );
+ if( pEntry != pEnd )
+ {
+ if( pEntry->mbUseSubLang )
+ return pEntry->meCountry; // exact match found -> return
+ if( ePrimCountry == COUNTRY_DONTKNOW )
+ ePrimCountry = pEntry->meCountry;
+ ++pEntry; // one entry forward for next find_if() call
+ }
+ }
+ while( pEntry != pEnd );
+
+ return ePrimCountry;
+}
+
+LanguageType ConvertCountryToLanguage( CountryId eCountry )
+{
+ // just find the first occurrence of eCountry and return the language type
+ const CountryEntry* pEntry = std::find_if( pTable, pEnd, CountryEntryPred_Country( eCountry ) );
+ return (pEntry != pEnd) ? pEntry->meLanguage : LANGUAGE_DONTKNOW;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/dffpropset.cxx b/filter/source/msfilter/dffpropset.cxx
new file mode 100644
index 000000000..e6ef672b0
--- /dev/null
+++ b/filter/source/msfilter/dffpropset.cxx
@@ -0,0 +1,1360 @@
+/* -*- 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/.
+ *
+ * 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 <algorithm>
+#include <filter/msfilter/dffpropset.hxx>
+#include <filter/msfilter/dffrecordheader.hxx>
+#include <sal/log.hxx>
+#include <svx/msdffdef.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/stream.hxx>
+
+const DffPropSetEntry mso_PropSetDefaults[] = {
+
+// 0
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+
+// 64
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0 }, // DFF_Prop_LockAgainstGrouping
+
+// 128
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x0010 }, // DFF_Prop_FitTextToShape
+
+// 192
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0 }, // DFF_Prop_gtextFStrikethrough
+
+//256
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0 }, // DFF_Prop_pictureActive
+
+// 320
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x0039 }, // DFF_Prop_fFillOK
+
+// 384
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0xffffff }, // DFF_Prop_fillColor
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x001c }, // DFF_Prop_fNoFillHitTest
+
+// 448
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x001e }, // DFF_Prop_fNoLineDrawDash
+
+// 512
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0 }, // DFF_Prop_fshadowObscured
+
+// 576
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0 }, // DFF_Prop_fPerspective
+
+// 640
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x0001 }, // DFF_Prop_fc3DLightFace
+
+// 704
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x0016 }, // DFF_Prop_fc3DFillHarsh
+
+// 768
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0 }, // DFF_Prop_fBackground
+
+// 832
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x0010 }, // DFF_Prop_fCalloutLengthSpecified
+
+// 896
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { true, false, false, true }, 0, 0x0001 }, // DFF_Prop_fPrint
+
+// 960
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 },
+{ { false, false, false, false }, 0, 0 }
+
+};
+
+DffPropSet::DffPropSet()
+{
+ mpPropSetEntries = reinterpret_cast< DffPropSetEntry* >( new sal_uInt8[ 1024 * sizeof( DffPropSetEntry ) ] );
+}
+
+DffPropSet::~DffPropSet()
+{
+ delete[] reinterpret_cast< sal_uInt8* >( mpPropSetEntries );
+}
+
+void DffPropSet::ReadPropSet( SvStream& rIn, bool bSetUninitializedOnly )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+
+ if ( !bSetUninitializedOnly )
+ {
+ InitializePropSet( aHd.nRecType );
+ maOffsets.clear();
+ }
+
+ sal_uInt32 nPropCount = aHd.nRecInstance;
+
+ sal_uInt32 nComplexDataFilePos = rIn.Tell() + ( nPropCount * 6 );
+
+ const size_t nMaxPossibleRecords = rIn.remainingSize() / (sizeof(sal_uInt16) + sizeof(sal_uInt32));
+ if (nPropCount > nMaxPossibleRecords)
+ {
+ SAL_WARN("filter.ms", "Parsing error: " << nMaxPossibleRecords <<
+ " max possible entries, but " << nPropCount << " claimed, truncating");
+ nPropCount = nMaxPossibleRecords;
+ }
+
+ for (sal_uInt32 nPropNum = 0; nPropNum < nPropCount; ++nPropNum)
+ {
+ sal_uInt16 nTmp(0);
+ sal_uInt32 nContent(0);
+ rIn.ReadUInt16( nTmp )
+ .ReadUInt32( nContent );
+
+ sal_uInt32 nRecType = nTmp & 0x3fff;
+
+ if ( nRecType > 0x3ff )
+ break;
+ if ( ( nRecType & 0x3f ) == 0x3f )
+ {
+ if ( bSetUninitializedOnly )
+ {
+ sal_uInt32 nCurrentFlags = mpPropSetEntries[ nRecType ].nContent;
+ sal_uInt32 nMergeFlags = nContent;
+
+ nMergeFlags &= ( nMergeFlags >> 16 ) | 0xffff0000; // clearing low word
+ nMergeFlags &= ( ( nCurrentFlags & 0xffff0000 ) // remove already hard set
+ | ( nCurrentFlags >> 16 ) ) ^ 0xffffffff; // attributes from mergeflags
+ nCurrentFlags &= ( ( nMergeFlags & 0xffff0000 ) // apply zero master bits
+ | ( nMergeFlags >> 16 ) ) ^ 0xffffffff;
+ nCurrentFlags |= static_cast<sal_uInt16>(nMergeFlags); // apply filled master bits
+ mpPropSetEntries[ nRecType ].nContent = nCurrentFlags;
+ mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr |= static_cast< sal_uInt16 >( nContent >> 16 );
+ }
+ else
+ {
+ // clear flags that have to be cleared
+ mpPropSetEntries[ nRecType ].nContent &= ( ( nContent >> 16 ) ^ 0xffffffff );
+ // set flags that have to be set
+ mpPropSetEntries[ nRecType ].nContent |= nContent;
+ mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr = static_cast< sal_uInt16 >( nContent >> 16 );
+ }
+ }
+ else
+ {
+ bool bSetProperty = !bSetUninitializedOnly || ( !IsProperty( nRecType ) || !IsHardAttribute( nRecType ) );
+
+ DffPropFlags aPropFlag = { true, false, false, false };
+ if ( nTmp & 0x4000 )
+ aPropFlag.bBlip = true;
+ if ( nTmp & 0x8000 )
+ aPropFlag.bComplex = true;
+ if ( aPropFlag.bComplex && nContent && ( nComplexDataFilePos < aHd.GetRecEndFilePos() ) )
+ {
+ // normally nContent is the complete size of the complex property,
+ // but this is not always true for IMsoArrays ( what the hell is a IMsoArray ? )
+
+ // I love special treatments :-(
+ if ( ( nRecType == DFF_Prop_pVertices ) || ( nRecType == DFF_Prop_pSegmentInfo )
+ || ( nRecType == DFF_Prop_fillShadeColors ) || ( nRecType == DFF_Prop_lineDashStyle )
+ || ( nRecType == DFF_Prop_pWrapPolygonVertices ) || ( nRecType == DFF_Prop_connectorPoints )
+ || ( nRecType == DFF_Prop_Handles ) || ( nRecType == DFF_Prop_pFormulas )
+ || ( nRecType == DFF_Prop_textRectangles ) )
+ {
+ // now check if the current content size is possible, or 6 bytes too small
+ sal_uInt32 nOldPos = rIn.Tell();
+
+ sal_Int16 nNumElem(0), nNumElemReserved(0), nSize(0);
+ if (checkSeek(rIn, nComplexDataFilePos))
+ rIn.ReadInt16(nNumElem).ReadInt16(nNumElemReserved).ReadInt16(nSize);
+ if (nNumElemReserved >= nNumElem)
+ {
+ // the size of these array elements is nowhere defined,
+ // what if the size is negative ?
+ // ok, we will make it positive and shift it.
+ // for -16 this works
+ if ( nSize < 0 )
+ nSize = ( -nSize ) >> 2;
+ sal_uInt32 nDataSize = static_cast<sal_uInt32>( nSize * nNumElem );
+
+ // sometimes the content size is 6 bytes too small (array header information is missing )
+ if ( nDataSize == nContent )
+ nContent += 6;
+
+ // check if array fits into the PropertyContainer
+ if ( ( nComplexDataFilePos + nContent ) > aHd.GetRecEndFilePos() )
+ nContent = 0;
+ }
+ else
+ nContent = 0;
+ rIn.Seek( nOldPos );
+ }
+ if ( nContent )
+ {
+ if ( bSetProperty )
+ {
+ mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr = static_cast< sal_uInt16 >( maOffsets.size() );
+ maOffsets.push_back( nComplexDataFilePos ); // insert the filepos of this property;
+ }
+ nComplexDataFilePos += nContent; // store filepos, that is used for the next complex property
+ }
+ else // a complex property needs content
+ aPropFlag.bSet = false; // otherwise something is wrong
+ }
+ if ( bSetProperty )
+ {
+ // tdf#130262: ignore negative values for distances (maybe this list needs to be extended)
+ // LO does not allow negative values but [MS-ODRAW] does not forbid them
+ if ( nRecType == DFF_Prop_dxWrapDistLeft || nRecType == DFF_Prop_dxWrapDistRight
+ || nRecType == DFF_Prop_dyWrapDistTop || nRecType == DFF_Prop_dyWrapDistBottom )
+ {
+ if ( static_cast<sal_Int32>(nContent) < 0 )
+ {
+ break;
+ }
+ }
+
+ mpPropSetEntries[ nRecType ].nContent = nContent;
+ mpPropSetEntries[ nRecType ].aFlags = aPropFlag;
+ }
+ }
+ }
+ aHd.SeekToEndOfRecord( rIn );
+}
+
+SvStream& ReadDffPropSet( SvStream& rIn, DffPropSet& rRec )
+{
+ rRec.ReadPropSet( rIn, false );
+ return rIn;
+}
+
+SvStream& operator|=( SvStream& rIn, DffPropSet& rRec )
+{
+ rRec.ReadPropSet( rIn, true );
+ return rIn;
+}
+
+void DffPropSet::InitializePropSet( sal_uInt16 nPropSetType ) const
+{
+ /*
+ cmc:
+ " Boolean properties are grouped in bitfields by property set; note that
+ the Boolean properties in each property set are contiguous. They are saved
+ under the property ID of the last Boolean property in the set, and are
+ placed in the value field in reverse order starting with the last property
+ in the low bit. "
+
+ e.g.
+
+ fEditedWrap
+ fBehindDocument
+ fOnDblClickNotify
+ fIsButton
+ fOneD
+ fHidden
+ fPrint
+
+ are all part of a group and all are by default false except for fPrint,
+ which equates to a default bit sequence for the group of 0000001 -> 0x1
+
+ If at a later stage word sets fBehindDocument away from the default it
+ will be done by having a property named fPrint whose bitsequence will have
+ the fBehindDocument bit set. e.g. a DFF_Prop_fPrint with value 0x200020
+ has set bit 6 on so as to enable fBehindDocument (as well as disabling
+ everything else)
+ */
+ if ( nPropSetType == DFF_msofbtOPT )
+ {
+ memcpy( mpPropSetEntries, mso_PropSetDefaults, 0x400 * sizeof( DffPropSetEntry ) );
+ }
+ else
+ {
+ memset( mpPropSetEntries, 0, 0x400 * sizeof( DffPropSetEntry ) );
+ }
+}
+
+bool DffPropSet::IsHardAttribute( sal_uInt32 nId ) const
+{
+ bool bRetValue = true;
+ nId &= 0x3ff;
+ if ( ( nId & 0x3f ) >= 48 ) // is this a flag id
+ bRetValue = (mpPropSetEntries[nId | 0x3f].nComplexIndexOrFlagsHAttr
+ & (1 << (0xf - (nId & 0xf)))) != 0;
+ else
+ bRetValue = !mpPropSetEntries[ nId ].aFlags.bSoftAttr;
+ return bRetValue;
+};
+
+sal_uInt32 DffPropSet::GetPropertyValue( sal_uInt32 nId, sal_uInt32 nDefault ) const
+{
+ nId &= 0x3ff;
+ return ( mpPropSetEntries[ nId ].aFlags.bSet ) ? mpPropSetEntries[ nId ].nContent : nDefault;
+};
+
+bool DffPropSet::GetPropertyBool( sal_uInt32 nId ) const
+{
+ sal_uInt32 nBaseId = nId | 31; // base ID to get the sal_uInt32 property value
+ sal_uInt32 nMask = 1 << (nBaseId - nId); // bit mask of the boolean property
+
+ sal_uInt32 nPropValue = GetPropertyValue( nBaseId, 0 );
+ return (nPropValue & nMask) != 0;
+}
+
+OUString DffPropSet::GetPropertyString( sal_uInt32 nId, SvStream& rStrm ) const
+{
+ sal_uInt64 const nOldPos = rStrm.Tell();
+ OUStringBuffer aBuffer;
+ sal_uInt32 nBufferSize = GetPropertyValue( nId, 0 );
+ if( (nBufferSize > 0) && SeekToContent( nId, rStrm ) )
+ {
+ sal_Int32 nStrLen = static_cast< sal_Int32 >( nBufferSize / 2 );
+ //clip initial size of buffer to something sane in case of silly length
+ //strings. If there really is a silly amount of data available it still
+ //works out ok of course
+ aBuffer.ensureCapacity(std::min(nStrLen,static_cast<sal_Int32>(8192)));
+ for( sal_Int32 nCharIdx = 0; nCharIdx < nStrLen; ++nCharIdx )
+ {
+ sal_uInt16 nChar = 0;
+ rStrm.ReadUInt16( nChar );
+ if( nChar > 0 )
+ aBuffer.append( static_cast< sal_Unicode >( nChar ) );
+ else
+ break;
+ }
+ }
+ rStrm.Seek( nOldPos );
+ return aBuffer.makeStringAndClear();
+}
+
+bool DffPropSet::SeekToContent( sal_uInt32 nRecType, SvStream& rStrm ) const
+{
+ nRecType &= 0x3ff;
+ if ( mpPropSetEntries[ nRecType ].aFlags.bSet )
+ {
+ if ( mpPropSetEntries[ nRecType ].aFlags.bComplex )
+ {
+ sal_uInt16 nIndex = mpPropSetEntries[ nRecType ].nComplexIndexOrFlagsHAttr;
+ if ( nIndex < maOffsets.size() )
+ {
+ return checkSeek(rStrm, maOffsets[nIndex]);
+ }
+ }
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/dffrecordheader.cxx b/filter/source/msfilter/dffrecordheader.cxx
new file mode 100644
index 000000000..c94bec53b
--- /dev/null
+++ b/filter/source/msfilter/dffrecordheader.cxx
@@ -0,0 +1,43 @@
+/* -*- 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/.
+ *
+ * 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 <filter/msfilter/dffrecordheader.hxx>
+
+bool ReadDffRecordHeader(SvStream& rIn, DffRecordHeader& rRec)
+{
+ rRec.nFilePos = rIn.Tell();
+ sal_uInt16 nTmp(0);
+ rIn.ReadUInt16(nTmp);
+ rRec.nImpVerInst = nTmp;
+ rRec.nRecVer = sal::static_int_cast<sal_uInt8>(nTmp & 0x000F);
+ rRec.nRecInstance = nTmp >> 4;
+ rRec.nRecType = 0;
+ rIn.ReadUInt16(rRec.nRecType);
+ rRec.nRecLen = 0;
+ rIn.ReadUInt32(rRec.nRecLen);
+
+ // preserving overflow, optimally we would check
+ // the record size against the parent header
+ if (rRec.nRecLen > (SAL_MAX_UINT32 - rRec.nFilePos))
+ rIn.SetError(SVSTREAM_FILEFORMAT_ERROR);
+
+ return rIn.good();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx
new file mode 100644
index 000000000..5f84a0df7
--- /dev/null
+++ b/filter/source/msfilter/escherex.cxx
@@ -0,0 +1,5295 @@
+/* -*- 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/.
+ *
+ * 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 "eschesdo.hxx"
+#include <o3tl/any.hxx>
+#include <o3tl/string_view.hxx>
+#include <svx/svdxcgv.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/xflftrit.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <filter/msfilter/util.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <editeng/outlobj.hxx>
+#include <utility>
+#include <vcl/graph.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/debug.hxx>
+#include <tools/stream.hxx>
+#include <tools/zcodec.hxx>
+#include <tools/urlobj.hxx>
+#include <svx/svdopath.hxx>
+#include <stdlib.h>
+#include <vcl/graphicfilter.hxx>
+#include <svx/EnhancedCustomShapeTypeNames.hxx>
+#include <svx/EnhancedCustomShapeGeometry.hxx>
+#include <svx/EnhancedCustomShapeFunctionParser.hxx>
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/awt/GradientStyle.hpp>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/LineJoint.hpp>
+#include <com/sun/star/drawing/LineCap.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/drawing/ConnectorType.hpp>
+#include <com/sun/star/drawing/CircleKind.hpp>
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/drawing/FlagSequence.hpp>
+#include <com/sun/star/drawing/PolygonFlags.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <com/sun/star/drawing/TextFitToSizeType.hpp>
+#include <vcl/hatch.hxx>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/drawing/Position3D.hpp>
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/string.hxx>
+#include <vcl/virdev.hxx>
+#include <rtl/crc.h>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+#include <memory>
+
+using namespace css;
+
+EscherExContainer::EscherExContainer( SvStream& rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance ) :
+ rStrm ( rSt )
+{
+ rStrm.WriteUInt32( ( 0xf | ( nInstance << 4 ) ) | ( nRecType << 16 ) ).WriteUInt32( 0 );
+ nContPos = rStrm.Tell();
+}
+EscherExContainer::~EscherExContainer()
+{
+ sal_uInt32 nPos = rStrm.Tell();
+ sal_uInt32 nSize= nPos - nContPos;
+ if ( nSize )
+ {
+ rStrm.Seek( nContPos - 4 );
+ rStrm.WriteUInt32( nSize );
+ rStrm.Seek( nPos );
+ }
+}
+
+EscherExAtom::EscherExAtom( SvStream& rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance, const sal_uInt8 nVersion ) :
+ rStrm ( rSt )
+{
+ rStrm.WriteUInt32( ( nVersion | ( nInstance << 4 ) ) | ( nRecType << 16 ) ).WriteUInt32( 0 );
+ nContPos = rStrm.Tell();
+}
+EscherExAtom::~EscherExAtom()
+{
+ sal_uInt32 nPos = rStrm.Tell();
+ sal_uInt32 nSize= nPos - nContPos;
+ if ( nSize )
+ {
+ rStrm.Seek( nContPos - 4 );
+ rStrm.WriteUInt32( nSize );
+ rStrm.Seek( nPos );
+ }
+}
+
+EscherExClientRecord_Base::~EscherExClientRecord_Base()
+{
+}
+
+EscherExClientAnchor_Base::~EscherExClientAnchor_Base()
+{
+}
+
+EscherPropertyContainer::EscherPropertyContainer(
+ EscherGraphicProvider * pGraphProv, SvStream * pPiOutStrm,
+ tools::Rectangle * pBoundRect):
+ pGraphicProvider(pGraphProv),
+ pPicOutStrm(pPiOutStrm),
+ pShapeBoundRect(pBoundRect),
+ nCountCount(0),
+ nCountSize(0),
+ bHasComplexData(false)
+{
+ pSortStruct.reserve(64);
+}
+
+EscherPropertyContainer::EscherPropertyContainer()
+ : EscherPropertyContainer(nullptr, nullptr, nullptr)
+{}
+
+EscherPropertyContainer::EscherPropertyContainer(
+ EscherGraphicProvider& rGraphProv,
+ SvStream* pPiOutStrm,
+ tools::Rectangle& rBoundRect ) :
+ EscherPropertyContainer(&rGraphProv, pPiOutStrm, &rBoundRect)
+{}
+
+EscherPropertyContainer::~EscherPropertyContainer()
+{
+};
+
+void EscherPropertyContainer::AddOpt(
+ sal_uInt16 nPropID,
+ bool bBlib,
+ sal_uInt32 nSizeReduction,
+ SvMemoryStream& rStream)
+{
+ sal_uInt8 const* pBuf(static_cast<sal_uInt8 const *>(rStream.GetData()));
+ const sal_uInt64 nSize(rStream.GetSize());
+ std::vector<sal_uInt8> aBuf;
+ aBuf.reserve(nSize);
+
+ for(sal_uInt64 a(0); a < nSize; a++)
+ {
+ aBuf.push_back(*pBuf++);
+ }
+
+ sal_uInt32 nPropValue(static_cast<sal_uInt32>(nSize));
+
+ if(0 != nSizeReduction && nPropValue > nSizeReduction)
+ {
+ nPropValue -= nSizeReduction;
+ }
+
+ AddOpt(nPropID, bBlib, nPropValue, aBuf);
+}
+
+void EscherPropertyContainer::AddOpt(
+ sal_uInt16 nPropID,
+ sal_uInt32 nPropValue,
+ bool bBlib)
+{
+ AddOpt(nPropID, bBlib, nPropValue, std::vector<sal_uInt8>());
+}
+
+void EscherPropertyContainer::AddOpt(
+ sal_uInt16 nPropID,
+ const OUString& rString)
+{
+ std::vector<sal_uInt8> aBuf;
+ aBuf.reserve(rString.getLength() * 2 + 2);
+
+ for(sal_Int32 i(0); i < rString.getLength(); i++)
+ {
+ const sal_Unicode nUnicode(rString[i]);
+ aBuf.push_back(static_cast<sal_uInt8>(nUnicode));
+ aBuf.push_back(static_cast<sal_uInt8>(nUnicode >> 8));
+ }
+
+ aBuf.push_back(0);
+ aBuf.push_back(0);
+
+ AddOpt(nPropID, true, aBuf.size(), aBuf);
+}
+
+void EscherPropertyContainer::AddOpt(
+ sal_uInt16 nPropID,
+ bool bBlib,
+ sal_uInt32 nPropValue,
+ const std::vector<sal_uInt8>& rProp)
+{
+ if ( bBlib ) // bBlib is only valid when fComplex = 0
+ nPropID |= 0x4000;
+ if ( !rProp.empty() )
+ nPropID |= 0x8000; // fComplex = sal_True;
+
+ for( size_t i = 0; i < pSortStruct.size(); i++ )
+ {
+ if ( ( pSortStruct[ i ].nPropId &~0xc000 ) == ( nPropID &~0xc000 ) ) // check, whether the Property only gets replaced
+ {
+ pSortStruct[ i ].nPropId = nPropID;
+ if ( !pSortStruct[ i ].nProp.empty() )
+ {
+ nCountSize -= pSortStruct[ i ].nProp.size();
+ }
+ pSortStruct[ i ].nProp = rProp;
+ pSortStruct[ i ].nPropValue = nPropValue;
+ if ( !rProp.empty() )
+ nCountSize += rProp.size();
+ return;
+ }
+ }
+ nCountCount++;
+ nCountSize += 6;
+ pSortStruct.emplace_back();
+ pSortStruct.back().nPropId = nPropID; // insert property
+ pSortStruct.back().nProp = rProp;
+ pSortStruct.back().nPropValue = nPropValue;
+
+ if ( !rProp.empty() )
+ {
+ nCountSize += rProp.size();
+ bHasComplexData = true;
+ }
+}
+
+bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId, sal_uInt32& rPropValue ) const
+{
+ EscherPropSortStruct aPropStruct;
+
+ if ( GetOpt( nPropId, aPropStruct ) )
+ {
+ rPropValue = aPropStruct.nPropValue;
+ return true;
+ }
+ return false;
+}
+
+bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId, EscherPropSortStruct& rPropValue ) const
+{
+ for( size_t i = 0; i < pSortStruct.size(); i++ )
+ {
+ if ( ( pSortStruct[ i ].nPropId &~0xc000 ) == ( nPropId &~0xc000 ) )
+ {
+ rPropValue = pSortStruct[ i ];
+ return true;
+ }
+ }
+ return false;
+}
+
+const EscherProperties & EscherPropertyContainer::GetOpts() const
+{
+ return pSortStruct;
+}
+
+extern "C" {
+
+static int EscherPropSortFunc( const void* p1, const void* p2 )
+{
+ sal_Int16 nID1 = static_cast<EscherPropSortStruct const *>(p1)->nPropId &~0xc000;
+ sal_Int16 nID2 = static_cast<EscherPropSortStruct const *>(p2)->nPropId &~0xc000;
+
+ if( nID1 < nID2 )
+ return -1;
+ else if( nID1 > nID2 )
+ return 1;
+ else
+ return 0;
+}
+
+}
+
+void EscherPropertyContainer::Commit( SvStream& rSt, sal_uInt16 nVersion, sal_uInt16 nRecType )
+{
+ rSt.WriteUInt16( ( nCountCount << 4 ) | ( nVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nCountSize );
+ if ( pSortStruct.empty() )
+ return;
+
+ qsort( pSortStruct.data(), pSortStruct.size(), sizeof( EscherPropSortStruct ), EscherPropSortFunc );
+
+ for ( size_t i = 0; i < pSortStruct.size(); i++ )
+ {
+ sal_uInt32 nPropValue = pSortStruct[ i ].nPropValue;
+ sal_uInt16 nPropId = pSortStruct[ i ].nPropId;
+
+ rSt.WriteUInt16( nPropId )
+ .WriteUInt32( nPropValue );
+ }
+ if ( bHasComplexData )
+ {
+ for ( size_t i = 0; i < pSortStruct.size(); i++ )
+ {
+ if ( !pSortStruct[ i ].nProp.empty() )
+ rSt.WriteBytes(
+ pSortStruct[i].nProp.data(),
+ pSortStruct[i].nProp.size());
+ }
+ }
+}
+
+bool EscherPropertyContainer::IsFontWork() const
+{
+ sal_uInt32 nTextPathFlags = 0;
+ GetOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags );
+ return ( nTextPathFlags & 0x4000 ) != 0;
+}
+
+sal_uInt32 EscherPropertyContainer::ImplGetColor( const sal_uInt32 nSOColor, bool bSwap )
+{
+ if ( bSwap )
+ {
+ sal_uInt32 nColor = nSOColor & 0xff00; // green
+ nColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red
+ nColor |= static_cast<sal_uInt8>( nSOColor >> 16 ); // blue
+ return nColor;
+ }
+ else
+ return nSOColor & 0xffffff;
+}
+
+sal_uInt32 EscherPropertyContainer::GetGradientColor(
+ const awt::Gradient* pGradient,
+ sal_uInt32 nStartColor )
+{
+ sal_uInt32 nIntensity = 100;
+ Color aColor;
+
+ if ( pGradient )
+ {
+ if ( nStartColor & 1 )
+ {
+ nIntensity = pGradient->StartIntensity;
+ aColor = Color(ColorTransparency, pGradient->StartColor);
+ }
+ else
+ {
+ nIntensity = pGradient->EndIntensity;
+ aColor = Color(ColorTransparency, pGradient->EndColor);
+ }
+ }
+ sal_uInt32 nRed = ( aColor.GetRed() * nIntensity ) / 100;
+ sal_uInt32 nGreen = ( ( aColor.GetGreen() * nIntensity ) / 100 ) << 8;
+ sal_uInt32 nBlue = ( ( aColor.GetBlue() * nIntensity ) / 100 ) << 16;
+ return nRed | nGreen | nBlue;
+}
+
+void EscherPropertyContainer::CreateGradientProperties(
+ const awt::Gradient & rGradient )
+{
+ sal_uInt32 nFillType = ESCHER_FillShadeScale;
+ sal_uInt32 nAngle = 0;
+ sal_uInt32 nFillFocus = 0;
+ sal_uInt32 nFillLR = 0;
+ sal_uInt32 nFillTB = 0;
+ sal_uInt32 nFirstColor = 0;
+ bool bWriteFillTo = false;
+
+ switch ( rGradient.Style )
+ {
+ case awt::GradientStyle_LINEAR :
+ case awt::GradientStyle_AXIAL :
+ {
+ nFillType = ESCHER_FillShadeScale;
+ nAngle = (rGradient.Angle * 0x10000) / 10;
+ nFillFocus = (sal::static_int_cast<int>(rGradient.Style) ==
+ sal::static_int_cast<int>(GradientStyle::Linear)) ? 0 : 50;
+ }
+ break;
+ case awt::GradientStyle_RADIAL :
+ case awt::GradientStyle_ELLIPTICAL :
+ case awt::GradientStyle_SQUARE :
+ case awt::GradientStyle_RECT :
+ {
+ nFillLR = (rGradient.XOffset * 0x10000) / 100;
+ nFillTB = (rGradient.YOffset * 0x10000) / 100;
+ if ( ((nFillLR > 0) && (nFillLR < 0x10000)) || ((nFillTB > 0) && (nFillTB < 0x10000)) )
+ nFillType = ESCHER_FillShadeShape;
+ else
+ nFillType = ESCHER_FillShadeCenter;
+ nFirstColor = 1;
+ bWriteFillTo = true;
+ }
+ break;
+ case awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE : break;
+ }
+ AddOpt( ESCHER_Prop_fillType, nFillType );
+ AddOpt( ESCHER_Prop_fillAngle, nAngle );
+ AddOpt( ESCHER_Prop_fillColor, GetGradientColor( &rGradient, nFirstColor ) );
+ AddOpt( ESCHER_Prop_fillBackColor, GetGradientColor( &rGradient, nFirstColor ^ 1 ) );
+ AddOpt( ESCHER_Prop_fillFocus, nFillFocus );
+ if ( bWriteFillTo )
+ {
+ AddOpt( ESCHER_Prop_fillToLeft, nFillLR );
+ AddOpt( ESCHER_Prop_fillToTop, nFillTB );
+ AddOpt( ESCHER_Prop_fillToRight, nFillLR );
+ AddOpt( ESCHER_Prop_fillToBottom, nFillTB );
+ }
+}
+
+void EscherPropertyContainer::CreateGradientProperties(
+ const uno::Reference<beans::XPropertySet> & rXPropSet , bool bTransparentGradient)
+{
+ uno::Any aAny;
+ awt::Gradient const * pGradient = nullptr;
+
+ sal_uInt32 nFillType = ESCHER_FillShadeScale;
+ sal_Int32 nAngle = 0;
+ sal_uInt32 nFillFocus = 0;
+ sal_uInt32 nFillLR = 0;
+ sal_uInt32 nFillTB = 0;
+ sal_uInt32 nFirstColor = 0;// like the control var nChgColors in import logic
+ bool bWriteFillTo = false;
+
+ // Transparency gradient: Means the third setting in transparency page is set
+ if (bTransparentGradient && EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "FillTransparenceGradient" ) )
+ {
+ pGradient = o3tl::doAccess<awt::Gradient>(aAny);
+
+ uno::Any aAnyTemp;
+ if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAnyTemp, rXPropSet, "FillStyle" ) )
+ {
+ drawing::FillStyle eFS;
+ if ( ! ( aAnyTemp >>= eFS ) )
+ eFS = drawing::FillStyle_SOLID;
+ // solid and transparency
+ if ( eFS == drawing::FillStyle_SOLID)
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAnyTemp, rXPropSet, "FillColor" ) )
+ {
+ const_cast<awt::Gradient *>(pGradient)->StartColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAnyTemp), false );
+ const_cast<awt::Gradient *>(pGradient)->EndColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAnyTemp), false );
+ }
+ }
+ // gradient and transparency.
+ else if( eFS == drawing::FillStyle_GRADIENT )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "FillGradient" ) )
+ pGradient = o3tl::doAccess<awt::Gradient>(aAny);
+ }
+ }
+
+ }
+ // Not transparency gradient
+ else if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "FillGradient" ) )
+ {
+ pGradient = o3tl::doAccess<awt::Gradient>(aAny);
+ }
+
+ if ( pGradient )
+ {
+ switch ( pGradient->Style )
+ {
+ case awt::GradientStyle_LINEAR :
+ case awt::GradientStyle_AXIAL :
+ {
+ nFillType = ESCHER_FillShadeScale;
+ nAngle = pGradient->Angle;
+ while ( nAngle > 0 ) nAngle -= 3600;
+ while ( nAngle <= -3600 ) nAngle += 3600;
+ // Value of the real number = Integral + (Fractional / 65536.0)
+ nAngle = ( nAngle * 0x10000) / 10;
+
+ nFillFocus = (pGradient->Style == awt::GradientStyle_LINEAR) ?
+ ( pGradient->XOffset + pGradient->YOffset )/2 : -50;
+ if( !nFillFocus )
+ nFirstColor=nFirstColor ^ 1;
+ if ( !nAngle )
+ nFirstColor=nFirstColor ^ 1;
+ }
+ break;
+ case awt::GradientStyle_RADIAL :
+ case awt::GradientStyle_ELLIPTICAL :
+ case awt::GradientStyle_SQUARE :
+ case awt::GradientStyle_RECT :
+ {
+ // according to the import logic and rect type fill** value
+ nFillLR = (pGradient->XOffset * 0x10000) / 100;
+ nFillTB = (pGradient->YOffset * 0x10000) / 100;
+ if ( ((nFillLR > 0) && (nFillLR < 0x10000)) || ((nFillTB > 0) && (nFillTB < 0x10000)) )
+ nFillType = ESCHER_FillShadeShape;
+ else
+ nFillType = ESCHER_FillShadeCenter;
+ nFirstColor = 1;
+ bWriteFillTo = true;
+ }
+ break;
+ default: break;
+ }
+ }
+
+ AddOpt( ESCHER_Prop_fillType, nFillType );
+ AddOpt( ESCHER_Prop_fillAngle, nAngle );
+ AddOpt( ESCHER_Prop_fillColor, GetGradientColor( pGradient, nFirstColor ) );
+ AddOpt( ESCHER_Prop_fillBackColor, GetGradientColor( pGradient, nFirstColor ^ 1 ) );
+ AddOpt( ESCHER_Prop_fillFocus, nFillFocus );
+ if ( bWriteFillTo )
+ {
+ // according to rect type fillTo** value
+ if(nFillLR)
+ {
+ AddOpt( ESCHER_Prop_fillToLeft, nFillLR );
+ AddOpt( ESCHER_Prop_fillToRight, nFillLR );
+ }
+ if(nFillTB)
+ {
+ AddOpt( ESCHER_Prop_fillToTop, nFillTB );
+ AddOpt( ESCHER_Prop_fillToBottom, nFillTB );
+ }
+ }
+
+ // Transparency gradient
+ if (bTransparentGradient && EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "FillTransparenceGradient" ) )
+ {
+ pGradient = o3tl::doAccess<awt::Gradient>(aAny);
+ if ( pGradient )
+ {
+ sal_uInt32 nBlue = GetGradientColor( pGradient, nFirstColor ) >> 16;
+ AddOpt( ESCHER_Prop_fillOpacity,( ( 100 - ( nBlue * 100 / 255 ) ) << 16 ) / 100 );
+ nBlue = GetGradientColor( pGradient, nFirstColor ^ 1 ) >>16 ;
+ AddOpt( ESCHER_Prop_fillBackOpacity,( ( 100 - ( nBlue * 100 / 255 ) ) << 16 )/ 100 );
+ }
+ }
+}
+
+void EscherPropertyContainer::CreateFillProperties(
+ const uno::Reference<beans::XPropertySet> & rXPropSet,
+ bool bEdge , const uno::Reference<drawing::XShape> & rXShape )
+{
+ if ( rXShape.is() )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rXShape);
+ if ( pObj )
+ {
+ const SfxItemSet& aAttr( pObj->GetMergedItemSet() );
+ // transparency with gradient. Means the third setting in transparency page is set
+ bool bTransparentGradient = ( aAttr.GetItemState( XATTR_FILLFLOATTRANSPARENCE ) == SfxItemState::SET ) &&
+ aAttr.Get( XATTR_FILLFLOATTRANSPARENCE ).IsEnabled();
+ CreateFillProperties( rXPropSet, bEdge, bTransparentGradient );
+ }
+ }
+}
+
+void EscherPropertyContainer::CreateFillProperties(
+ const uno::Reference<beans::XPropertySet> & rXPropSet,
+ bool bEdge , bool bTransparentGradient)
+
+{
+ uno::Any aAny;
+ AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
+ AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ static const OUStringLiteral aPropName( u"FillStyle" );
+
+ if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, aPropName ) )
+ {
+ drawing::FillStyle eFS;
+ if ( ! ( aAny >>= eFS ) )
+ eFS = drawing::FillStyle_SOLID;
+ sal_uInt32 nFillBackColor = 0;
+ switch( eFS )
+ {
+ case drawing::FillStyle_GRADIENT :
+ {
+ CreateGradientProperties( rXPropSet , bTransparentGradient );
+ AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
+ }
+ break;
+
+ case drawing::FillStyle_BITMAP :
+ {
+ CreateGraphicProperties(rXPropSet, "FillBitmap", true);
+ AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
+ AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
+ }
+ break;
+ case drawing::FillStyle_HATCH :
+ {
+ CreateGraphicProperties( rXPropSet, "FillHatch", true );
+ }
+ break;
+ case drawing::FillStyle_SOLID :
+ default:
+ {
+ if ( bTransparentGradient )
+ CreateGradientProperties( rXPropSet , bTransparentGradient );
+ else
+ {
+ beans::PropertyState ePropState = EscherPropertyValueHelper::GetPropertyState(
+ rXPropSet, aPropName );
+ if ( ePropState == beans::PropertyState_DIRECT_VALUE )
+ AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid );
+
+ if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "FillColor" ) )
+ {
+ sal_uInt32 nFillColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
+ nFillBackColor = nFillColor ^ 0xffffff;
+ AddOpt( ESCHER_Prop_fillColor, nFillColor );
+ }
+ AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100010 );
+ AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
+ }
+ break;
+ }
+ case drawing::FillStyle_NONE :
+ AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
+ break;
+ }
+ if ( eFS != drawing::FillStyle_NONE )
+ {
+ sal_uInt16 nTransparency = ( EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "FillTransparence", true ) )
+ ? *o3tl::doAccess<sal_Int16>(aAny) : 0;
+ if ( nTransparency )
+ AddOpt( ESCHER_Prop_fillOpacity, ( ( 100 - nTransparency ) << 16 ) / 100 );
+ }
+ }
+ CreateLineProperties( rXPropSet, bEdge );
+}
+
+void EscherPropertyContainer::CreateTextProperties(
+ const uno::Reference< beans::XPropertySet > & rXPropSet, sal_uInt32 nTextId,
+ const bool bIsCustomShape, const bool bIsTextFrame )
+{
+ uno::Any aAny;
+ text::WritingMode eWM( text::WritingMode_LR_TB );
+ drawing::TextVerticalAdjust eVA( drawing::TextVerticalAdjust_TOP );
+ drawing::TextHorizontalAdjust eHA( drawing::TextHorizontalAdjust_LEFT );
+
+ sal_Int32 nLeft ( 0 );
+ sal_Int32 nTop ( 0 );
+ sal_Int32 nRight ( 0 );
+ sal_Int32 nBottom ( 0 );
+
+ // used with normal shapes:
+ bool bAutoGrowWidth ( false );
+ const bool bAutoGrowHeight ( false ); //#ii63936 not setting autogrowheight, because minframeheight would be ignored
+ // used with ashapes:
+ bool bWordWrap ( false );
+ bool bAutoGrowSize ( false );
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWritingMode", true ) )
+ aAny >>= eWM;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextVerticalAdjust", true ) )
+ aAny >>= eVA;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextHorizontalAdjust", true ) )
+ aAny >>= eHA;
+ if ( bIsCustomShape )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWordWrap" ) )
+ aAny >>= bWordWrap;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", true ) )
+ aAny >>= bAutoGrowSize;
+ }
+ else if ( bIsTextFrame )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowWidth", true ) )
+ aAny >>= bAutoGrowWidth;
+
+// i63936 not setting autogrowheight, because otherwise
+// the minframeheight of the text will be ignored
+//
+// if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", sal_True ) )
+// aAny >>= bAutoGrowHeight;
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextLeftDistance" ) )
+ aAny >>= nLeft;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextUpperDistance" ) )
+ aAny >>= nTop;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextRightDistance" ) )
+ aAny >>= nRight;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextLowerDistance" ) )
+ aAny >>= nBottom;
+
+ ESCHER_AnchorText eAnchor = ESCHER_AnchorTop;
+ ESCHER_WrapMode eWrapMode = ESCHER_WrapSquare;
+ sal_uInt32 nTextAttr = 0x40004; // rotate text with shape
+
+ if ( eWM == text::WritingMode_TB_RL )
+ { // vertical writing
+ switch ( eHA )
+ {
+ case drawing::TextHorizontalAdjust_LEFT :
+ eAnchor = ESCHER_AnchorBottom;
+ break;
+ case drawing::TextHorizontalAdjust_CENTER :
+ eAnchor = ESCHER_AnchorMiddle;
+ break;
+ default :
+ case drawing::TextHorizontalAdjust_BLOCK :
+ case drawing::TextHorizontalAdjust_RIGHT :
+ eAnchor = ESCHER_AnchorTop;
+ break;
+ }
+ if ( eVA == drawing::TextVerticalAdjust_CENTER )
+ {
+ switch ( eAnchor )
+ {
+ case ESCHER_AnchorMiddle :
+ eAnchor = ESCHER_AnchorMiddleCentered;
+ break;
+ case ESCHER_AnchorBottom :
+ eAnchor = ESCHER_AnchorBottomCentered;
+ break;
+ default :
+ case ESCHER_AnchorTop :
+ eAnchor = ESCHER_AnchorTopCentered;
+ break;
+ }
+ }
+ if ( bIsCustomShape )
+ {
+ if ( bWordWrap )
+ eWrapMode = ESCHER_WrapSquare;
+ else
+ eWrapMode = ESCHER_WrapNone;
+ if ( bAutoGrowSize )
+ nTextAttr |= 0x20002;
+ }
+ else
+ {
+ if ( bAutoGrowHeight )
+ eWrapMode = ESCHER_WrapNone;
+ if ( bAutoGrowWidth )
+ nTextAttr |= 0x20002;
+ }
+
+ AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflTtoBA ); // rotate text within shape by 90
+ }
+ else
+ { // normal from left to right
+ switch ( eVA )
+ {
+ case drawing::TextVerticalAdjust_CENTER :
+ eAnchor = ESCHER_AnchorMiddle;
+ break;
+
+ case drawing::TextVerticalAdjust_BOTTOM :
+ eAnchor = ESCHER_AnchorBottom;
+ break;
+
+ default :
+ case drawing::TextVerticalAdjust_TOP :
+ eAnchor = ESCHER_AnchorTop;
+ break;
+ }
+ if ( eHA == drawing::TextHorizontalAdjust_CENTER )
+ {
+ switch( eAnchor )
+ {
+ case ESCHER_AnchorMiddle :
+ eAnchor = ESCHER_AnchorMiddleCentered;
+ break;
+ case ESCHER_AnchorBottom :
+ eAnchor = ESCHER_AnchorBottomCentered;
+ break;
+ case ESCHER_AnchorTop :
+ eAnchor = ESCHER_AnchorTopCentered;
+ break;
+ default: break;
+ }
+ }
+ if ( bIsCustomShape )
+ {
+ if ( bWordWrap )
+ eWrapMode = ESCHER_WrapSquare;
+ else
+ eWrapMode = ESCHER_WrapNone;
+ if ( bAutoGrowSize )
+ nTextAttr |= 0x20002;
+ }
+ else
+ {
+ if ( bAutoGrowWidth )
+ eWrapMode = ESCHER_WrapNone;
+ if ( bAutoGrowHeight )
+ nTextAttr |= 0x20002;
+ }
+ }
+ AddOpt( ESCHER_Prop_dxTextLeft, nLeft * 360 );
+ AddOpt( ESCHER_Prop_dxTextRight, nRight * 360 );
+ AddOpt( ESCHER_Prop_dyTextTop, nTop * 360 );
+ AddOpt( ESCHER_Prop_dyTextBottom, nBottom * 360 );
+
+ AddOpt( ESCHER_Prop_WrapText, eWrapMode );
+ AddOpt( ESCHER_Prop_AnchorText, eAnchor );
+ AddOpt( ESCHER_Prop_FitTextToShape, nTextAttr );
+
+ if ( nTextId )
+ AddOpt( ESCHER_Prop_lTxid, nTextId );
+
+ // n#404221: In case of rotation we need to write the txtflTextFlow
+ // attribute too.
+ // fdo#58204: not custom shapes (TODO: other cases when it doesn't work?)
+ if (!bIsTextFrame || bIsCustomShape)
+ return;
+
+ sal_uInt16 nAngle = EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "RotateAngle", true ) ?
+ static_cast<sal_uInt16>( ( *o3tl::doAccess<sal_Int32>(aAny) ) + 5 ) / 10 : 0;
+ if (nAngle==900)
+ {
+ AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflBtoT );
+ }
+ if (nAngle==2700)
+ {
+ AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflTtoBA );
+ }
+}
+
+bool EscherPropertyContainer::GetLineArrow( const bool bLineStart,
+ const uno::Reference<beans::XPropertySet> & rXPropSet,
+ ESCHER_LineEnd& reLineEnd, sal_Int32& rnArrowLength, sal_Int32& rnArrowWidth )
+{
+ const OUString sLine ( bLineStart ? OUString("LineStart") : OUString("LineEnd") );
+ const OUString sLineName ( bLineStart ? OUString("LineStartName") : OUString("LineEndName") );
+
+ bool bIsArrow = false;
+
+ uno::Any aAny;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, sLine ) )
+ {
+ tools::PolyPolygon aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aAny ) );
+ if ( aPolyPoly.Count() && aPolyPoly[ 0 ].GetSize() )
+ {
+ bIsArrow = true;
+
+ reLineEnd = ESCHER_LineArrowEnd;
+ rnArrowLength = 1;
+ rnArrowWidth = 1;
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, sLineName ) )
+ {
+ OUString aArrowStartName = *o3tl::doAccess<OUString>(aAny);
+ sal_uInt16 nWhich = bLineStart ? sal_uInt16(XATTR_LINESTART) : sal_uInt16(XATTR_LINEEND);
+
+ // remove extra space separated number
+ sal_Int32 nPos = aArrowStartName.lastIndexOf(' ');
+ if (nPos > -1 && aArrowStartName.lastIndexOf(' ', nPos) > -1)
+ aArrowStartName = aArrowStartName.copy(0, nPos);
+
+ OUString aApiName = SvxUnogetApiNameForItem(nWhich, aArrowStartName);
+ bool bIsMapped = true;
+ if ( !aApiName.isEmpty() )
+ {
+
+ // TODO: calculate the best option for ArrowLength and ArrowWidth
+ if ( aApiName == "Arrow concave" )
+ reLineEnd = ESCHER_LineArrowStealthEnd;
+ else if ( aApiName == "Square 45" )
+ reLineEnd = ESCHER_LineArrowDiamondEnd;
+ else if ( aApiName == "Small Arrow" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else if ( aApiName == "Dimension Lines" )
+ {
+ rnArrowLength = 0;
+ rnArrowWidth = 2;
+ reLineEnd = ESCHER_LineArrowOvalEnd;
+ }
+ else if ( aApiName == "Double Arrow" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else if ( aApiName == "Rounded short Arrow" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else if ( aApiName == "Symmetric Arrow" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else if ( aApiName == "Line Arrow" )
+ reLineEnd = ESCHER_LineArrowOpenEnd;
+ else if ( aApiName == "Rounded large Arrow" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else if ( aApiName == "Circle" )
+ reLineEnd = ESCHER_LineArrowOvalEnd;
+ else if ( aApiName == "Square" )
+ reLineEnd = ESCHER_LineArrowDiamondEnd;
+ else if ( aApiName == "Arrow" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else
+ bIsMapped = false;
+
+ }
+ if ( !bIsMapped && comphelper::string::getTokenCount(aArrowStartName, ' ') == 2 )
+ {
+ sal_Int32 nIdx{ 0 };
+ std::u16string_view aArrowName( o3tl::getToken(aArrowStartName, 0, ' ', nIdx ) );
+ if ( aArrowName == u"msArrowEnd" )
+ reLineEnd = ESCHER_LineArrowEnd;
+ else if ( aArrowName == u"msArrowOpenEnd" )
+ reLineEnd = ESCHER_LineArrowOpenEnd;
+ else if ( aArrowName == u"msArrowStealthEnd" )
+ reLineEnd = ESCHER_LineArrowStealthEnd;
+ else if ( aArrowName == u"msArrowDiamondEnd" )
+ reLineEnd = ESCHER_LineArrowDiamondEnd;
+ else if ( aArrowName == u"msArrowOvalEnd" )
+ reLineEnd = ESCHER_LineArrowOvalEnd;
+ else
+ nIdx = -1;
+
+ // now we have the arrow, and try to determine the arrow size;
+ if ( nIdx>0 )
+ {
+ std::u16string_view aArrowSize = o3tl::getToken(aArrowStartName, 0, ' ', nIdx );
+ sal_Int32 nArrowSize = o3tl::toInt32(aArrowSize);
+ rnArrowWidth = ( nArrowSize - 1 ) / 3;
+ rnArrowLength = nArrowSize - ( rnArrowWidth * 3 ) - 1;
+ }
+ }
+ }
+ }
+ }
+ return bIsArrow;
+}
+
+void EscherPropertyContainer::CreateLineProperties(
+ const uno::Reference<beans::XPropertySet> & rXPropSet, bool bEdge )
+{
+ uno::Any aAny;
+ sal_uInt32 nLineFlags = 0x80008;
+
+ ESCHER_LineEnd eLineEnd;
+ sal_Int32 nArrowLength;
+ sal_Int32 nArrowWidth;
+
+ bool bSwapLineEnds = false;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "CircleKind", true ) )
+ {
+ drawing::CircleKind eCircleKind;
+ if ( aAny >>= eCircleKind )
+ {
+ if ( eCircleKind == drawing::CircleKind_ARC )
+ bSwapLineEnds = true;
+ }
+ }
+ if ( GetLineArrow( !bSwapLineEnds, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) )
+ {
+ AddOpt( ESCHER_Prop_lineStartArrowLength, nArrowLength );
+ AddOpt( ESCHER_Prop_lineStartArrowWidth, nArrowWidth );
+ AddOpt( ESCHER_Prop_lineStartArrowhead, eLineEnd );
+ nLineFlags |= 0x100010;
+ }
+ if ( GetLineArrow( bSwapLineEnds, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) )
+ {
+ AddOpt( ESCHER_Prop_lineEndArrowLength, nArrowLength );
+ AddOpt( ESCHER_Prop_lineEndArrowWidth, nArrowWidth );
+ AddOpt( ESCHER_Prop_lineEndArrowhead, eLineEnd );
+ nLineFlags |= 0x100010;
+ }
+
+ // support LineCaps
+ if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, "LineCap"))
+ {
+ drawing::LineCap aLineCap(drawing::LineCap_BUTT);
+
+ if(aAny >>= aLineCap)
+ {
+ switch (aLineCap)
+ {
+ default: /* drawing::LineCap_BUTT */
+ {
+ AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapFlat);
+ break;
+ }
+ case drawing::LineCap_ROUND:
+ {
+ AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapRound);
+ break;
+ }
+ case drawing::LineCap_SQUARE:
+ {
+ AddOpt(ESCHER_Prop_lineEndCapStyle, ESCHER_LineEndCapSquare);
+ break;
+ }
+ }
+ }
+ }
+
+ sal_uInt32 nLineWidth = ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineWidth" ) )
+ ? *o3tl::doAccess<sal_uInt32>(aAny) : 0;
+ if ( nLineWidth > 1 )
+ AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 ); // 100TH MM -> PT , 1PT = 12700 EMU
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineStyle" ) )
+ {
+ drawing::LineStyle eLS;
+ if ( aAny >>= eLS )
+ {
+ switch ( eLS )
+ {
+ case drawing::LineStyle_NONE :
+ AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); // 80000
+ break;
+
+ case drawing::LineStyle_DASH :
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineDash" ) )
+ {
+ ESCHER_LineDashing eDash = ESCHER_LineSolid;
+ auto pLineDash = o3tl::doAccess<drawing::LineDash>(aAny);
+ switch ( pLineDash->Style )
+ {
+ case drawing::DashStyle_ROUND :
+ case drawing::DashStyle_ROUNDRELATIVE :
+ AddOpt( ESCHER_Prop_lineEndCapStyle, 0 ); // set Style Round
+ break;
+ default : break;
+ }
+ // Try to detect exact prstDash styles. Use a similar method as in oox export.
+ // Map it to a roughly fitting prstDash in other cases.
+ bool bIsConverted = false;
+ bool bIsRelative = pLineDash->Style == drawing::DashStyle_RECTRELATIVE
+ || pLineDash->Style == drawing::DashStyle_ROUNDRELATIVE;
+ sal_Int16 nDashes = pLineDash->Dashes;
+ sal_Int16 nDots = pLineDash->Dots;
+ sal_Int32 nDashLen = pLineDash->DashLen;
+ sal_Int32 nDotLen = pLineDash->DotLen;
+ sal_Int32 nDistance = pLineDash->Distance;
+
+ // Caution! The names are misleading. "dot" is always the first dash and "dash"
+ // the second one, regardless of the actual length. All prstDash
+ // definitions start with the longer dash and have exact one longer dash.
+ // Preset line style definitions for binary format are the same as for OOXML.
+ if (bIsRelative && nDots == 1)
+ {
+ // I'm not sure that LO always uses 100%, because in case of absolute values, LO
+ // sets length to 0 but treats it as 100%, if the attribute is missing in ODF.
+ // So to be sure set 100% explicitly in case of relative too.
+ if (nDashes > 0 && nDashLen == 0)
+ nDashLen = 100;
+ if (nDotLen == 0)
+ nDotLen = 100;
+ bIsConverted = true;
+ if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
+ eDash = ESCHER_LineDotGEL;
+ else if (nDotLen == 400 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
+ eDash = ESCHER_LineDashGEL;
+ else if (nDotLen == 400 && nDashes == 1 && nDashLen == 100 && nDistance == 300)
+ eDash = ESCHER_LineDashDotGEL;
+ else if (nDotLen == 800 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
+ eDash = ESCHER_LineLongDashGEL;
+ else if (nDotLen == 800 && nDashes == 1 && nDashLen == 100 && nDistance == 300)
+ eDash = ESCHER_LineLongDashDotGEL;
+ else if (nDotLen == 800 && nDashes == 2 && nDashLen == 100 && nDistance == 300)
+ eDash = ESCHER_LineLongDashDotDotGEL;
+ else if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 100)
+ eDash = ESCHER_LineDotSys;
+ else if (nDotLen == 300 && nDashes == 0 && nDashLen == 0 && nDistance == 100)
+ eDash = ESCHER_LineDashSys;
+ else if (nDotLen == 300 && nDashes == 1 && nDashLen == 100 && nDistance == 100)
+ eDash = ESCHER_LineDashDotSys;
+ else if (nDotLen == 300 && nDashes == 2 && nDashLen == 100 && nDistance == 100)
+ eDash = ESCHER_LineDashDotDotSys;
+ else
+ bIsConverted = false;
+ }
+
+ if (!bIsConverted)
+ { // Map the style roughly to preset line styles.
+ if (((!(pLineDash->Dots)) || (!(pLineDash->Dashes)))
+ || (pLineDash->DotLen == pLineDash->DashLen))
+ {
+ sal_Int32 nLen = pLineDash->DotLen;
+ if (pLineDash->Dashes)
+ nLen = pLineDash->DashLen;
+ if (nLen >= nDistance)
+ eDash = ESCHER_LineLongDashGEL;
+ else if (pLineDash->Dots)
+ eDash = ESCHER_LineDotSys;
+ else
+ eDash = ESCHER_LineDashGEL;
+ }
+ else // X Y
+ {
+ if (pLineDash->Dots != pLineDash->Dashes)
+ {
+ if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance))
+ eDash = ESCHER_LineLongDashDotDotGEL;
+ else
+ eDash = ESCHER_LineDashDotDotSys;
+ }
+ else // X Y Y
+ {
+ if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance))
+ eDash = ESCHER_LineLongDashDotGEL;
+ else
+ eDash = ESCHER_LineDashDotGEL;
+ }
+ }
+ }
+ AddOpt( ESCHER_Prop_lineDashing, eDash );
+ }
+ }
+ [[fallthrough]];
+ case drawing::LineStyle_SOLID :
+ default:
+ {
+ AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+ }
+ break;
+ }
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineColor" ) )
+ {
+ sal_uInt32 nLineColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
+ AddOpt( ESCHER_Prop_lineColor, nLineColor );
+ AddOpt( ESCHER_Prop_lineBackColor, nLineColor ^ 0xffffff );
+ }
+ }
+
+ ESCHER_LineJoin eLineJoin = ESCHER_LineJoinMiter;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineJoint", true ) )
+ {
+ drawing::LineJoint eLJ;
+ if ( aAny >>= eLJ )
+ {
+ switch ( eLJ )
+ {
+ case drawing::LineJoint_NONE :
+ case drawing::LineJoint_BEVEL :
+ eLineJoin = ESCHER_LineJoinBevel;
+ break;
+ default:
+ case drawing::LineJoint_MIDDLE :
+ case drawing::LineJoint_MITER :
+ eLineJoin = ESCHER_LineJoinMiter;
+ break;
+ case drawing::LineJoint_ROUND :
+ eLineJoin = ESCHER_LineJoinRound;
+ break;
+ }
+ }
+ }
+ AddOpt( ESCHER_Prop_lineJoinStyle, eLineJoin );
+
+ if ( EscherPropertyValueHelper::GetPropertyValue(
+ aAny, rXPropSet, "LineTransparence", true ) )
+ {
+ sal_Int16 nTransparency = 0;
+ if ( aAny >>= nTransparency )
+ AddOpt( ESCHER_Prop_lineOpacity, ( ( 100 - nTransparency ) << 16 ) / 100 );
+ }
+
+
+ if ( !bEdge )
+ {
+ AddOpt( ESCHER_Prop_fFillOK, 0x1001 );
+ AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
+ }
+}
+
+static Size lcl_SizeToEmu(Size aPrefSize, const MapMode& aPrefMapMode)
+{
+ Size aRetSize;
+ if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
+ aRetSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
+ else
+ aRetSize = OutputDevice::LogicToLogic(aPrefSize, aPrefMapMode, MapMode(MapUnit::Map100thMM));
+ return aRetSize;
+}
+
+void EscherPropertyContainer::ImplCreateGraphicAttributes( const uno::Reference<beans::XPropertySet> & rXPropSet,
+ sal_uInt32 nBlibId, bool bCreateCroppingAttributes )
+{
+ uno::Any aAny;
+
+ sal_uInt32 nPicFlags = 0;
+ drawing::ColorMode eColorMode( drawing::ColorMode_STANDARD );
+ sal_Int16 nLuminance = 0;
+ sal_Int32 nContrast = 0;
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "GraphicColorMode" ) )
+ aAny >>= eColorMode;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustLuminance" ) )
+ aAny >>= nLuminance;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustContrast" ) )
+ {
+ sal_Int16 nC = sal_Int16();
+ aAny >>= nC;
+ nContrast = nC;
+ }
+
+ if ( eColorMode == drawing::ColorMode_WATERMARK )
+ {
+ eColorMode = drawing::ColorMode_STANDARD;
+ nLuminance += 70;
+ if ( nLuminance > 100 )
+ nLuminance = 100;
+ nContrast -= 70;
+ if ( nContrast < -100 )
+ nContrast = -100;
+ }
+ if ( eColorMode == drawing::ColorMode_GREYS )
+ nPicFlags |= 0x40004;
+ else if ( eColorMode == drawing::ColorMode_MONO )
+ nPicFlags |= 0x60006;
+
+ if ( nContrast )
+ {
+ nContrast += 100;
+ if ( nContrast == 100)
+ nContrast = 0x10000;
+ else if ( nContrast < 100 )
+ {
+ nContrast *= 0x10000;
+ nContrast /= 100;
+ }
+ else if ( nContrast < 200 )
+ nContrast = ( 100 * 0x10000 ) / ( 200 - nContrast );
+ else
+ nContrast = 0x7fffffff;
+ AddOpt( ESCHER_Prop_pictureContrast, nContrast );
+ }
+ if ( nLuminance )
+ AddOpt( ESCHER_Prop_pictureBrightness, nLuminance * 327 );
+ if ( nPicFlags )
+ AddOpt( ESCHER_Prop_pictureActive, nPicFlags );
+
+ if ( !(bCreateCroppingAttributes && pGraphicProvider) )
+ return;
+
+ Size aPrefSize;
+ MapMode aPrefMapMode;
+ if ( !pGraphicProvider->GetPrefSize( nBlibId, aPrefSize, aPrefMapMode ) )
+ return;
+
+ Size aCropSize(lcl_SizeToEmu(aPrefSize, aPrefMapMode));
+ if ( !(aCropSize.Width() && aCropSize.Height()) )
+ return;
+
+ if ( !EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "GraphicCrop" ) )
+ return;
+
+ text::GraphicCrop aGraphCrop;
+ if ( !(aAny >>= aGraphCrop) )
+ return;
+
+ if ( aGraphCrop.Left )
+ {
+ sal_uInt32 nLeft = ( aGraphCrop.Left * 65536 ) / aCropSize.Width();
+ AddOpt( ESCHER_Prop_cropFromLeft, nLeft );
+ }
+ if ( aGraphCrop.Top )
+ {
+ sal_uInt32 nTop = ( aGraphCrop.Top * 65536 ) / aCropSize.Height();
+ AddOpt( ESCHER_Prop_cropFromTop, nTop );
+ }
+ if ( aGraphCrop.Right )
+ {
+ sal_uInt32 nRight = ( aGraphCrop.Right * 65536 ) / aCropSize.Width();
+ AddOpt( ESCHER_Prop_cropFromRight, nRight );
+ }
+ if ( aGraphCrop.Bottom )
+ {
+ sal_uInt32 nBottom = ( aGraphCrop.Bottom * 65536 ) / aCropSize.Height();
+ AddOpt( ESCHER_Prop_cropFromBottom, nBottom );
+ }
+}
+
+void EscherPropertyContainer::CreateShapeProperties( const uno::Reference<drawing::XShape> & rXShape )
+{
+ uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
+ if ( !aXPropSet.is() )
+ return;
+
+ bool bVisible = false;
+ bool bPrintable = false;
+ uno::Any aAny;
+ sal_uInt32 nShapeAttr = 0;
+ if (EscherPropertyValueHelper::GetPropertyValue(aAny, aXPropSet, "Visible", true) && (aAny >>= bVisible))
+ {
+ if ( !bVisible )
+ nShapeAttr |= 0x20002; // set fHidden = true
+ }
+ // This property (fPrint) isn't used in Excel anymore, leaving it for legacy reasons
+ // one change, based on XLSX: hidden implies not printed, let's not export the fPrint property in that case
+ if (bVisible && EscherPropertyValueHelper::GetPropertyValue(aAny, aXPropSet, "Printable", true) && (aAny >>= bPrintable))
+ {
+ if ( !bPrintable )
+ nShapeAttr |= 0x10000; // set fPrint = false;
+ }
+ if ( nShapeAttr )
+ AddOpt( ESCHER_Prop_fPrint, nShapeAttr );
+}
+
+bool EscherPropertyContainer::CreateOLEGraphicProperties(const uno::Reference<drawing::XShape> & rXShape)
+{
+ bool bRetValue = false;
+
+ if ( rXShape.is() )
+ {
+ SdrObject* pObject = SdrObject::getSdrObjectFromXShape(rXShape); // SJ: leaving unoapi, because currently there is
+ if (auto pOle2Obj = dynamic_cast<const SdrOle2Obj*>(pObject)) // no access to the native graphic object
+ {
+ const Graphic* pGraphic = pOle2Obj->GetGraphic();
+ if (pGraphic)
+ {
+ Graphic aGraphic(*pGraphic);
+ GraphicObject aGraphicObject(aGraphic);
+ bRetValue = CreateGraphicProperties(rXShape, aGraphicObject);
+ }
+ }
+ }
+ return bRetValue;
+}
+
+bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference<drawing::XShape> & rXShape, const GraphicObject& rGraphicObj)
+{
+ bool bRetValue = false;
+ OString aUniqueId(rGraphicObj.GetUniqueID());
+ if ( !aUniqueId.isEmpty() )
+ {
+ AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture );
+ uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
+
+ if ( pGraphicProvider && pPicOutStrm && pShapeBoundRect && aXPropSet.is() )
+ {
+ uno::Any aAny;
+ std::unique_ptr<awt::Rectangle> pVisArea;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "VisibleArea" ) )
+ {
+ pVisArea.reset(new awt::Rectangle);
+ aAny >>= *pVisArea;
+ }
+ sal_uInt32 nBlibId = pGraphicProvider->GetBlibID( *pPicOutStrm, rGraphicObj, pVisArea.get() );
+ if ( nBlibId )
+ {
+ AddOpt( ESCHER_Prop_pib, nBlibId, true );
+ ImplCreateGraphicAttributes( aXPropSet, nBlibId, false );
+ bRetValue = true;
+ }
+ }
+ }
+ return bRetValue;
+}
+
+bool EscherPropertyContainer::CreateMediaGraphicProperties(const uno::Reference<drawing::XShape> & rXShape)
+{
+ bool bRetValue = false;
+ if ( rXShape.is() )
+ {
+ SdrObject* pSdrObject(SdrObject::getSdrObjectFromXShape(rXShape)); // SJ: leaving unoapi, because currently there is
+ if (auto pSdrMediaObj = dynamic_cast<const SdrMediaObj*>(pSdrObject)) // no access to the native graphic object
+ {
+ GraphicObject aGraphicObject(pSdrMediaObj->getSnapshot());
+ bRetValue = CreateGraphicProperties(rXShape, aGraphicObject);
+ }
+ }
+ return bRetValue;
+}
+
+bool EscherPropertyContainer::ImplCreateEmbeddedBmp(GraphicObject const & rGraphicObject)
+{
+ if (rGraphicObject.GetType() != GraphicType::NONE)
+ {
+ EscherGraphicProvider aProvider;
+ SvMemoryStream aMemStrm;
+
+ if (aProvider.GetBlibID( aMemStrm, rGraphicObject))
+ {
+ AddOpt(ESCHER_Prop_fillBlip, true, 0, aMemStrm);
+ return true;
+ }
+ }
+ return false;
+}
+
+void EscherPropertyContainer::CreateEmbeddedBitmapProperties(
+ uno::Reference<awt::XBitmap> const & rxBitmap, drawing::BitmapMode eBitmapMode )
+{
+ uno::Reference<graphic::XGraphic> xGraphic(rxBitmap, uno::UNO_QUERY);
+ if (!xGraphic.is())
+ return;
+ const Graphic aGraphic(xGraphic);
+ if (aGraphic.IsNone())
+ return;
+ const GraphicObject aGraphicObject(aGraphic);
+ if (aGraphicObject.GetType() == GraphicType::NONE)
+ return;
+ if (ImplCreateEmbeddedBmp(aGraphicObject))
+ {
+ // bitmap mode property
+ bool bRepeat = eBitmapMode == drawing::BitmapMode_REPEAT;
+ AddOpt( ESCHER_Prop_fillType, bRepeat ? ESCHER_FillTexture : ESCHER_FillPicture );
+ }
+}
+
+namespace {
+
+Graphic lclDrawHatch( const drawing::Hatch& rHatch, const Color& rBackColor, bool bFillBackground, const tools::Rectangle& rRect )
+{
+ // #i121183# For hatch, do no longer create a bitmap with the fixed size of 28x28 pixels. Also
+ // do not create a bitmap in page size, that would explode file sizes (and have no good quality).
+ // Better use a MetaFile graphic in page size; thus we have good quality due to vector format and
+ // no bit file sizes.
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ GDIMetaFile aMtf;
+
+ pVDev->SetOutputSizePixel(Size(2, 2));
+ pVDev->EnableOutput(false);
+ pVDev->SetMapMode(MapMode(MapUnit::Map100thMM));
+ aMtf.Clear();
+ aMtf.Record(pVDev);
+ pVDev->SetLineColor();
+ pVDev->SetFillColor(bFillBackground ? rBackColor : COL_TRANSPARENT);
+ pVDev->DrawRect(rRect);
+ pVDev->DrawHatch(tools::PolyPolygon(rRect), Hatch(static_cast<HatchStyle>(rHatch.Style), Color(ColorTransparency, rHatch.Color), rHatch.Distance,
+ Degree10(rHatch.Angle)));
+ aMtf.Stop();
+ aMtf.WindStart();
+ aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
+ aMtf.SetPrefSize(rRect.GetSize());
+
+ return Graphic(aMtf);
+}
+
+} // namespace
+
+void EscherPropertyContainer::CreateEmbeddedHatchProperties(const drawing::Hatch& rHatch, const Color& rBackColor, bool bFillBackground )
+{
+ const tools::Rectangle aRect(pShapeBoundRect ? *pShapeBoundRect : tools::Rectangle(Point(0,0), Size(28000, 21000)));
+ Graphic aGraphic(lclDrawHatch(rHatch, rBackColor, bFillBackground, aRect));
+ GraphicObject aGraphicObject(aGraphic);
+
+ if (ImplCreateEmbeddedBmp(aGraphicObject))
+ AddOpt( ESCHER_Prop_fillType, ESCHER_FillTexture );
+}
+
+bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference<beans::XPropertySet> & rXPropSet,
+ const OUString& rSource,
+ const bool bCreateFillBitmap,
+ const bool bCreateCroppingAttributes,
+ const bool bFillBitmapModeAllowed,
+ const bool bOOxmlExport )
+{
+ bool bRetValue = false;
+ bool bCreateFillStyles = false;
+
+ std::unique_ptr<GraphicAttr> pGraphicAttr;
+ uno::Reference<graphic::XGraphic> xGraphic;
+
+ uno::Any aAny;
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, rSource ) )
+ {
+ bool bMirrored = false;
+ bool bRotate = true;
+ bool bIsGraphicMtf = false;
+ sal_Int16 nTransparency(0);
+ sal_Int16 nRed(0);
+ sal_Int16 nGreen(0);
+ sal_Int16 nBlue(0);
+ double fGamma(1.0);
+ drawing::BitmapMode eBitmapMode(drawing::BitmapMode_NO_REPEAT);
+ OUString aGraphicUrl;
+
+ sal_uInt16 nAngle = 0;
+ if ( rSource == "MetaFile" )
+ {
+ auto & aSeq = *o3tl::doAccess<uno::Sequence<sal_Int8>>(aAny);
+ const sal_Int8* pArray = aSeq.getConstArray();
+ sal_uInt32 nArrayLength = aSeq.getLength();
+
+ // the metafile is already rotated
+ bRotate = false;
+
+ if (pArray && nArrayLength)
+ {
+ Graphic aGraphic;
+ SvMemoryStream aStream(const_cast<sal_Int8 *>(pArray), nArrayLength, StreamMode::READ);
+ ErrCode nErrCode = GraphicConverter::Import(aStream, aGraphic, ConvertDataFormat::WMF);
+ if ( nErrCode == ERRCODE_NONE )
+ {
+ xGraphic = aGraphic.GetXGraphic();
+ bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile;
+ }
+ }
+ }
+ else if (rSource == "Bitmap" || rSource == "FillBitmap")
+ {
+ auto xBitmap = aAny.get<uno::Reference<awt::XBitmap>>();
+ if (xBitmap.is())
+ {
+ xGraphic.set(xBitmap, uno::UNO_QUERY);
+ Graphic aGraphic(xGraphic);
+ bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile;
+ }
+ }
+ else if ( rSource == "Graphic" )
+ {
+ xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>();
+ bCreateFillStyles = true;
+ }
+ else if ( rSource == "FillHatch" )
+ {
+ drawing::Hatch aHatch;
+ if ( aAny >>= aHatch )
+ {
+ Color aBackColor;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillColor" ) )
+ {
+ aBackColor = Color(ColorTransparency, ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny), false ));
+ }
+ bool bFillBackground = false;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBackground", true ) )
+ {
+ aAny >>= bFillBackground;
+ }
+
+ const tools::Rectangle aRect(Point(0, 0), pShapeBoundRect ? pShapeBoundRect->GetSize() : Size(28000, 21000));
+ Graphic aGraphic(lclDrawHatch(aHatch, aBackColor, bFillBackground, aRect));
+ xGraphic = aGraphic.GetXGraphic();
+ eBitmapMode = drawing::BitmapMode_REPEAT;
+ bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile;
+ }
+ }
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "IsMirrored", true ) )
+ aAny >>= bMirrored;
+
+ // #121074# transparency of graphic is not supported in MS formats, get and apply it
+ // in the GetTransformedGraphic call in GetBlibID
+ if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, "Transparency"))
+ {
+ aAny >>= nTransparency;
+ }
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustRed" ) )
+ {
+ aAny >>= nRed;
+ }
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustGreen" ) )
+ {
+ aAny >>= nGreen;
+ }
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustBlue" ) )
+ {
+ aAny >>= nBlue;
+ }
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "Gamma" ) )
+ {
+ aAny >>= fGamma;
+ }
+
+ if ( bCreateFillBitmap && bFillBitmapModeAllowed )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapMode", true ) )
+ aAny >>= eBitmapMode;
+ }
+ else
+ {
+ nAngle = bRotate && EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "RotateAngle", true )
+ ? static_cast<sal_uInt16>( ( *o3tl::doAccess<sal_Int32>(aAny) ) + 5 ) / 10
+ : 0;
+ }
+
+ if (xGraphic.is())
+ {
+ Graphic aGraphic(xGraphic);
+ aGraphicUrl = aGraphic.getOriginURL();
+ }
+
+ if (!aGraphicUrl.isEmpty())
+ {
+ bool bConverted = false;
+
+ // externally, linked graphic? convert to embedded
+ // one, if transformations are needed. this is because
+ // everything < msoxp cannot even handle rotated
+ // bitmaps.
+ // And check whether the graphic link target is
+ // actually supported by mso.
+ INetURLObject aTmp( aGraphicUrl );
+ GraphicDescriptor aDescriptor(aTmp);
+ (void)aDescriptor.Detect();
+ const GraphicFileFormat nFormat = aDescriptor.GetFileFormat();
+
+ // can MSO handle it?
+ if ( bMirrored || nAngle || nTransparency || nRed || nGreen || nBlue || (1.0 != fGamma) ||
+ (nFormat != GraphicFileFormat::BMP &&
+ nFormat != GraphicFileFormat::GIF &&
+ nFormat != GraphicFileFormat::JPG &&
+ nFormat != GraphicFileFormat::PNG &&
+ nFormat != GraphicFileFormat::TIF &&
+ nFormat != GraphicFileFormat::PCT &&
+ nFormat != GraphicFileFormat::WMF &&
+ nFormat != GraphicFileFormat::EMF) )
+ {
+ std::unique_ptr<SvStream> pIn(::utl::UcbStreamHelper::CreateStream(
+ aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
+ if ( pIn )
+ {
+ Graphic aGraphic;
+ ErrCode nErrCode = GraphicConverter::Import( *pIn, aGraphic );
+
+ if ( nErrCode == ERRCODE_NONE )
+ {
+ xGraphic = aGraphic.GetXGraphic();
+ bConverted = true;
+ }
+ // else: simply keep the graphic link
+ }
+ }
+
+ if (!bConverted && pGraphicProvider )
+ {
+ const OUString& rBaseURI( pGraphicProvider->GetBaseURI() );
+ INetURLObject aBaseURI( rBaseURI );
+ if( aBaseURI.GetProtocol() == aTmp.GetProtocol() )
+ {
+ OUString aRelUrl( INetURLObject::GetRelURL( rBaseURI, aGraphicUrl ) );
+ if ( !aRelUrl.isEmpty() )
+ aGraphicUrl = aRelUrl;
+ }
+ }
+ }
+
+ if (!aGraphicUrl.isEmpty() || xGraphic.is())
+ {
+ if(bMirrored || nTransparency || nRed || nGreen || nBlue || (1.0 != fGamma))
+ {
+ pGraphicAttr.reset(new GraphicAttr);
+
+ if(bMirrored)
+ {
+ pGraphicAttr->SetMirrorFlags(BmpMirrorFlags::Horizontal);
+ }
+
+ if(nTransparency)
+ {
+ pGraphicAttr->SetAlpha(255 - (nTransparency * 255) / 100);
+ }
+
+ if(nRed)
+ {
+ pGraphicAttr->SetChannelR(nRed);
+ }
+
+ if(nGreen)
+ {
+ pGraphicAttr->SetChannelG(nGreen);
+ }
+
+ if(nBlue)
+ {
+ pGraphicAttr->SetChannelB(nBlue);
+ }
+
+ if(1.0 != fGamma)
+ {
+ pGraphicAttr->SetGamma(fGamma);
+ }
+ }
+
+ if(nAngle && bIsGraphicMtf)
+ {
+ AddOpt( ESCHER_Prop_Rotation, ( ( (static_cast<sal_Int32>(nAngle) << 16 ) / 10 ) + 0x8000 ) &~ 0xffff );
+ }
+
+ if ( eBitmapMode == drawing::BitmapMode_REPEAT )
+ {
+ sal_Int32 nSizeX = 0,nSizeY = 0,nOffsetX = 0,nOffsetY = 0,nPosOffsetX = 0,nPosOffsetY = 0;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapSizeX", true ) )
+ {
+ aAny >>= nSizeX;
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapSizeY", true ) )
+ {
+ aAny >>= nSizeY;
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapOffsetX", true ) )
+ {
+ aAny >>= nOffsetX;
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapOffsetY", true ) )
+ {
+ aAny >>= nOffsetY;
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapPositionOffsetX", true ) )
+ {
+ aAny >>= nPosOffsetX;
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapPositionOffsetY", true ) )
+ {
+ aAny >>= nPosOffsetY;
+ }
+ if(nSizeX == -100 && nSizeY == -100 && nOffsetX == 0 && nOffsetY == 0 && nPosOffsetX == 0 && nPosOffsetY == 0)
+ AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture );
+ else
+ AddOpt( ESCHER_Prop_fillType, ESCHER_FillTexture );
+ }
+ else
+ AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture );
+
+ if (xGraphic.is())
+ {
+ Graphic aGraphic(xGraphic);
+ if (!aGraphic.getOriginURL().isEmpty())
+ {
+ AddOpt(ESCHER_Prop_pibName, aGraphicUrl);
+ sal_uInt32 nPibFlags = 0;
+ GetOpt(ESCHER_Prop_pibFlags, nPibFlags);
+ AddOpt(ESCHER_Prop_pibFlags, ESCHER_BlipFlagLinkToFile | ESCHER_BlipFlagFile | ESCHER_BlipFlagDoNotSave | nPibFlags);
+ }
+ else if (pGraphicProvider && pPicOutStrm && pShapeBoundRect) // write out embedded graphic
+ {
+ GraphicObject aGraphicObject(aGraphic);
+ const sal_uInt32 nBlibId(pGraphicProvider->GetBlibID(*pPicOutStrm, aGraphicObject, nullptr, pGraphicAttr.get()));
+
+ if(nBlibId)
+ {
+ if(bCreateFillBitmap)
+ {
+ AddOpt(ESCHER_Prop_fillBlip, nBlibId, true);
+ }
+ else
+ {
+ AddOpt( ESCHER_Prop_pib, nBlibId, true );
+ ImplCreateGraphicAttributes( rXPropSet, nBlibId, bCreateCroppingAttributes );
+ }
+
+ bRetValue = true;
+ }
+ }
+ else
+ {
+ EscherGraphicProvider aProvider;
+ SvMemoryStream aMemStrm;
+ GraphicObject aGraphicObject(aGraphic);
+
+ if (aProvider.GetBlibID(aMemStrm, aGraphicObject, nullptr, pGraphicAttr.get(), bOOxmlExport))
+ {
+ AddOpt(ESCHER_Prop_fillBlip, true, 0, aMemStrm);
+ bRetValue = true;
+ }
+ }
+ }
+ }
+ }
+ pGraphicAttr.reset();
+ if ( bCreateFillStyles )
+ CreateFillProperties( rXPropSet, true );
+
+ return bRetValue;
+}
+
+tools::PolyPolygon EscherPropertyContainer::GetPolyPolygon( const uno::Reference< drawing::XShape > & rXShape )
+{
+ tools::PolyPolygon aRetPolyPoly;
+ uno::Reference< beans::XPropertySet > aXPropSet;
+ uno::Any aAny( rXShape->queryInterface(
+ cppu::UnoType<beans::XPropertySet>::get()));
+
+ if ( aAny >>= aXPropSet )
+ {
+ bool bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygonBezier", true );
+ if ( !bHasProperty )
+ bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygon", true );
+ if ( !bHasProperty )
+ bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "Polygon", true );
+ if ( bHasProperty )
+ aRetPolyPoly = GetPolyPolygon( aAny );
+ }
+ return aRetPolyPoly;
+}
+
+// adapting to basegfx::B2DPolyPolygon now, has no sense to do corrections in the
+// old tools::PolyPolygon creation code. Convert to that at return time
+tools::PolyPolygon EscherPropertyContainer::GetPolyPolygon( const uno::Any& rAny )
+{
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(auto pBCC = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(rAny))
+ {
+ aRetval = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pBCC);
+ }
+ else if(auto pCC = o3tl::tryAccess<drawing::PointSequenceSequence>(rAny))
+ {
+ aRetval = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pCC);
+ }
+ else if(auto pC = o3tl::tryAccess<drawing::PointSequence>(rAny))
+ {
+ aRetval.append(basegfx::utils::UnoPointSequenceToB2DPolygon(*pC));
+ }
+
+ basegfx::B2DPolyPolygon aRetval2;
+
+ for(sal_uInt32 a(0); a < aRetval.count(); a++)
+ {
+ if(0 != aRetval.getB2DPolygon(a).count())
+ {
+ aRetval2.append(aRetval.getB2DPolygon(a));
+ }
+ }
+
+ return tools::PolyPolygon(aRetval2);
+}
+
+bool EscherPropertyContainer::CreatePolygonProperties(
+ const uno::Reference<beans::XPropertySet> & rXPropSet,
+ sal_uInt32 nFlags,
+ bool bBezier,
+ awt::Rectangle& rGeoRect,
+ tools::Polygon const * pPolygon )
+{
+ tools::PolyPolygon aPolyPolygon;
+
+ if(nullptr != pPolygon)
+ {
+ aPolyPolygon.Insert(*pPolygon);
+ }
+ else
+ {
+ uno::Any aAny;
+
+ if(EscherPropertyValueHelper::GetPropertyValue(
+ aAny,
+ rXPropSet,
+ bBezier ? OUString("PolyPolygonBezier") : OUString("PolyPolygon"),
+ true))
+ {
+ aPolyPolygon = GetPolyPolygon(aAny);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if(0 == aPolyPolygon.Count())
+ {
+ return false;
+ }
+
+ if(0 != (nFlags & ESCHER_CREATEPOLYGON_LINE))
+ {
+ if((1 == aPolyPolygon.Count()) && (2 == aPolyPolygon[0].GetSize()))
+ {
+ const tools::Polygon& rPoly(aPolyPolygon[0]);
+
+ rGeoRect = awt::Rectangle(
+ rPoly[0].X(),
+ rPoly[0].Y(),
+ rPoly[1].X() - rPoly[0].X(),
+ rPoly[1].Y() - rPoly[0].Y());
+
+ return true;
+ }
+
+ return false;
+ }
+
+ const tools::Rectangle aRect(aPolyPolygon.GetBoundRect());
+
+ rGeoRect = awt::Rectangle(
+ aRect.Left(),
+ aRect.Top(),
+ aRect.GetWidth(),
+ aRect.GetHeight());
+
+ const sal_uInt16 nPolyCount(aPolyPolygon.Count());
+ sal_uInt32 nTotalPoints(0);
+
+ std::vector< sal_uInt8 > aVertices
+ {
+ 0, 0, 0, 0,
+ static_cast<sal_uInt8>(0xf0),
+ static_cast<sal_uInt8>(0xff)
+ };
+
+ std::vector< sal_uInt8 > aSegments
+ {
+ 0, 0, 0, 0,
+ static_cast<sal_uInt8>(2),
+ static_cast<sal_uInt8>(0)
+ };
+
+ for(sal_uInt16 j(0); j < nPolyCount; ++j)
+ {
+ const tools::Polygon aPolygon(aPolyPolygon[j]);
+ const sal_uInt16 nPoints(aPolygon.GetSize());
+
+ if(0 == nPoints)
+ {
+ continue;
+ }
+
+ // Polygon start
+ aSegments.push_back(static_cast<sal_uInt8>(0x0));
+ aSegments.push_back(static_cast<sal_uInt8>(0x40));
+
+ sal_uInt16 nSegmentIgnoreCounter(0);
+
+ // write points from polygon to buffer
+ for(sal_uInt16 i(0); i < nPoints; ++i)
+ {
+ Point aPoint(aPolygon[i]);
+
+ aPoint.AdjustX(-(rGeoRect.X));
+ aPoint.AdjustY(-(rGeoRect.Y));
+
+ aVertices.push_back(static_cast<sal_uInt8>(aPoint.X()));
+ aVertices.push_back(static_cast<sal_uInt8>(aPoint.X() >> 8));
+ aVertices.push_back(static_cast<sal_uInt8>(aPoint.Y()));
+ aVertices.push_back(static_cast<sal_uInt8>(aPoint.Y() >> 8));
+
+ nTotalPoints++;
+
+ if(0 != nSegmentIgnoreCounter)
+ {
+ nSegmentIgnoreCounter--;
+ }
+ else
+ {
+ aSegments.push_back(static_cast<sal_uInt8>(0));
+
+ if(bBezier)
+ {
+ aSegments.push_back(static_cast<sal_uInt8>(0xb3));
+ }
+ else
+ {
+ aSegments.push_back(static_cast<sal_uInt8>(0xac));
+ }
+
+ if(i + 1 == nPoints)
+ {
+ if(nPolyCount > 1)
+ {
+ // end of polygon
+ aSegments.push_back(static_cast<sal_uInt8>(1));
+ aSegments.push_back(static_cast<sal_uInt8>(0x60));
+ }
+ }
+ else
+ {
+ aSegments.push_back(static_cast<sal_uInt8>(1));
+
+ if(PolyFlags::Control == aPolygon.GetFlags(i + 1))
+ {
+ aSegments.push_back(static_cast<sal_uInt8>(0x20));
+ nSegmentIgnoreCounter = 2;
+ }
+ else
+ {
+ aSegments.push_back(static_cast<sal_uInt8>(0));
+ }
+ }
+ }
+ }
+ }
+
+ if(0 == nTotalPoints || aSegments.size() < 6 || aVertices.size() < 6)
+ return false;
+
+ // Little endian
+ aVertices[0] = static_cast<sal_uInt8>(nTotalPoints);
+ aVertices[1] = static_cast<sal_uInt8>(nTotalPoints >> 8);
+ aVertices[2] = static_cast<sal_uInt8>(nTotalPoints);
+ aVertices[3] = static_cast<sal_uInt8>(nTotalPoints >> 8);
+
+ aSegments.push_back(static_cast<sal_uInt8>(0));
+ aSegments.push_back(static_cast<sal_uInt8>(0x80));
+
+ const sal_uInt32 nSegmentBufSize(aSegments.size() - 6);
+ aSegments[0] = static_cast<sal_uInt8>(nSegmentBufSize >> 1);
+ aSegments[1] = static_cast<sal_uInt8>(nSegmentBufSize >> 9);
+ aSegments[2] = static_cast<sal_uInt8>(nSegmentBufSize >> 1);
+ aSegments[3] = static_cast<sal_uInt8>(nSegmentBufSize >> 9);
+
+ AddOpt(
+ ESCHER_Prop_geoRight,
+ rGeoRect.Width);
+ AddOpt(
+ ESCHER_Prop_geoBottom,
+ rGeoRect.Height);
+ AddOpt(
+ ESCHER_Prop_shapePath,
+ ESCHER_ShapeComplex);
+ AddOpt(
+ ESCHER_Prop_pVertices,
+ true,
+ aVertices.size() - 6,
+ aVertices);
+ AddOpt(
+ ESCHER_Prop_pSegmentInfo,
+ true,
+ aSegments.size(),
+ aSegments);
+
+ return true;
+}
+
+
+/*
+in MS,the connector including 9 types :
+"straightConnector1",
+"bentConnector2","bentConnector3","bentConnector4","bentConnector5"
+"curvedConnector2","curvedConnector3","curvedConnector4","curvedConnector5"
+in AOO,including 4 types:"standard","lines","line","curve"
+when save as MS file, the connector must be convert to corresponding type.
+"line" and "lines" <-> "straightConnector1"
+"standard" <-> "bentConnector2-5"
+"curve" <-> "curvedConnector2-5"
+*/
+static sal_Int32 lcl_GetAdjustValueCount( const XPolygon& rPoly )
+{
+ int nRet = 0;
+ switch ( rPoly.GetSize() )
+ {
+ case 2 :
+ case 3:
+ nRet = 0;
+ break;
+ case 4:
+ nRet = 1;
+ break;
+ case 5:
+ nRet = 2;
+ break;
+ default:
+ if ( rPoly.GetSize()>=6 )
+ nRet = 3;
+ break;
+ }
+ return nRet;
+}
+
+// Adjust value decide the position which connector should turn a corner
+static sal_Int32 lcl_GetConnectorAdjustValue ( const XPolygon& rPoly, sal_uInt16 nIndex )
+{
+ sal_uInt16 k = rPoly.GetSize();
+ OSL_ASSERT ( k >= ( 3 + nIndex ) );
+
+ Point aPt;
+ Point aStart = rPoly[0];
+ Point aEnd = rPoly[k-1];
+ if ( aEnd.Y() == aStart.Y() )
+ aEnd.setY( aStart.Y() +4 );
+ if ( aEnd.X() == aStart.X() )
+ aEnd.setX( aStart.X() +4 );
+
+ bool bVertical = ( rPoly[1].X()-aStart.X() ) == 0 ;
+ // vertical and horizon alternate
+ if ( nIndex%2 == 1 ) bVertical = !bVertical;
+ aPt = rPoly[ nIndex + 1];
+
+ sal_Int32 nAdjustValue;
+ if ( bVertical )
+ nAdjustValue = ( aPt.Y()-aStart.Y())* 21600 /(aEnd.Y()-aStart.Y());
+ else
+ nAdjustValue = ( aPt.X()-aStart.X() )* 21600 /(aEnd.X()-aStart.X());
+
+ return nAdjustValue;
+}
+
+
+static void lcl_Rotate(Degree100 nAngle, Point center, Point& pt)
+{
+ nAngle = NormAngle36000(nAngle);
+
+ int cs, sn;
+ switch (nAngle.get())
+ {
+ case 0:
+ cs =1;
+ sn =0;
+ break;
+ case 9000:
+ cs =0;
+ sn =1;
+ break;
+ case 18000:
+ cs = -1;
+ sn = 0;
+ break;
+ case 27000:
+ cs = 0;
+ sn = -1;
+ break;
+ default:
+ return;
+ }
+ sal_Int32 x0 =pt.X()-center.X();
+ sal_Int32 y0 =pt.Y()-center.Y();
+ pt.setX(center.X()+ x0*cs-y0*sn );
+ pt.setY(center.Y()+ y0*cs+x0*sn );
+}
+/*
+ FlipV defines that the shape will be flipped vertically about the center of its bounding box.
+Generally, draw the connector from top to bottom, from left to right when meet the adjust value,
+but when (X1>X2 or Y1>Y2),the draw director must be reverse, FlipV or FlipH should be set to true.
+*/
+static bool lcl_GetAngle(tools::Polygon &rPoly, ShapeFlag& rShapeFlags,sal_Int32& nAngle )
+{
+ Point aStart = rPoly[0];
+ Point aEnd = rPoly[rPoly.GetSize()-1];
+ nAngle = ( rPoly[1].X() == aStart.X() ) ? 9000: 0 ;
+ Point p1(aStart.X(),aStart.Y());
+ Point p2(aEnd.X(),aEnd.Y());
+ if ( nAngle )
+ {
+ Point center((aEnd.X()+aStart.X())>>1,(aEnd.Y()+aStart.Y())>>1);
+ lcl_Rotate(Degree100(-nAngle), center,p1);
+ lcl_Rotate(Degree100(-nAngle), center,p2);
+ }
+ if ( p1.X() > p2.X() )
+ {
+ if ( nAngle )
+ rShapeFlags |= ShapeFlag::FlipV;
+ else
+ rShapeFlags |= ShapeFlag::FlipH;
+
+ }
+ if ( p1.Y() > p2.Y() )
+ {
+ if ( nAngle )
+ rShapeFlags |= ShapeFlag::FlipH;
+ else
+ rShapeFlags |= ShapeFlag::FlipV;
+ }
+
+ if ( (rShapeFlags&ShapeFlag::FlipH) && (rShapeFlags&ShapeFlag::FlipV) )
+ {
+ rShapeFlags &= ~ShapeFlag( ShapeFlag::FlipH | ShapeFlag::FlipV );
+ nAngle +=18000;
+ }
+
+ if ( nAngle )
+ {
+ // Set angle properties
+ nAngle *= 655;
+ nAngle += 0x8000;
+ nAngle &=~0xffff; // round nAngle to whole number of degrees
+ return true;
+ }
+ return false;
+}
+bool EscherPropertyContainer::CreateConnectorProperties(
+ const uno::Reference<drawing::XShape> & rXShape,
+ EscherSolverContainer& rSolverContainer, awt::Rectangle& rGeoRect,
+ sal_uInt16& rShapeType, ShapeFlag& rShapeFlags )
+{
+ bool bRetValue = false;
+ rShapeType = 0;
+ rShapeFlags = ShapeFlag::NONE;
+
+ if ( rXShape.is() )
+ {
+ uno::Reference<beans::XPropertySet> aXPropSet;
+ uno::Reference<drawing::XShape> aShapeA, aShapeB;
+ uno::Any aAny( rXShape->queryInterface( cppu::UnoType<beans::XPropertySet>::get()));
+ if ( aAny >>= aXPropSet )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeKind", true ) )
+ {
+ drawing::ConnectorType eCt;
+ aAny >>= eCt;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeStartPoint" ) )
+ {
+ awt::Point aStartPoint = *o3tl::doAccess<awt::Point>(aAny);
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeEndPoint" ) )
+ {
+ awt::Point aEndPoint = *o3tl::doAccess<awt::Point>(aAny);
+
+ rShapeFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Connector;
+ rGeoRect = awt::Rectangle( aStartPoint.X, aStartPoint.Y,
+ ( aEndPoint.X - aStartPoint.X ) + 1, ( aEndPoint.Y - aStartPoint.Y ) + 1 );
+ // set standard's FLIP in below code
+ if ( eCt != drawing::ConnectorType_STANDARD)
+ {
+ if ( rGeoRect.Height < 0 ) // justify
+ {
+ rShapeFlags |= ShapeFlag::FlipV;
+ rGeoRect.Y = aEndPoint.Y;
+ rGeoRect.Height = -rGeoRect.Height;
+ }
+ if ( rGeoRect.Width < 0 )
+ {
+ rShapeFlags |= ShapeFlag::FlipH;
+ rGeoRect.X = aEndPoint.X;
+ rGeoRect.Width = -rGeoRect.Width;
+ }
+ }
+ sal_uInt32 nAdjustValue1, nAdjustValue2;
+ nAdjustValue1 = nAdjustValue2 = 0x2a30;
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeStartConnection" ) )
+ aAny >>= aShapeA;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeEndConnection" ) )
+ aAny >>= aShapeB;
+ rSolverContainer.AddConnector( rXShape, aStartPoint, aShapeA, aEndPoint, aShapeB );
+ switch ( eCt )
+ {
+ case drawing::ConnectorType_CURVE :
+ {
+ rShapeType = ESCHER_ShpInst_CurvedConnector3;
+ AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleCurved );
+ AddOpt( ESCHER_Prop_adjustValue, nAdjustValue1 );
+ AddOpt( ESCHER_Prop_adjust2Value, -static_cast<sal_Int32>(nAdjustValue2) );
+ }
+ break;
+
+ case drawing::ConnectorType_STANDARD :// Connector 2->5
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygonBezier" ) )
+ {
+ tools::PolyPolygon aPolyPolygon = GetPolyPolygon( aAny );
+ tools::Polygon aPoly;
+ if ( aPolyPolygon.Count() > 0 )
+ {
+ AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleBent );
+ aPoly = aPolyPolygon[ 0 ];
+ sal_Int32 nAdjCount = lcl_GetAdjustValueCount( aPoly );
+ rShapeType = static_cast<sal_uInt16>( ESCHER_ShpInst_BentConnector2 + nAdjCount);
+ for ( sal_Int32 i = 0 ; i < nAdjCount; ++ i)
+ AddOpt( static_cast<sal_uInt16>( ESCHER_Prop_adjustValue+i) , lcl_GetConnectorAdjustValue( aPoly, i ) );
+ }
+ sal_Int32 nAngle=0;
+ if (lcl_GetAngle(aPoly,rShapeFlags,nAngle ))
+ {
+ AddOpt( ESCHER_Prop_Rotation, nAngle );
+ }
+ }
+ else
+ {
+ rShapeType = ESCHER_ShpInst_BentConnector3;
+ AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleBent );
+ }
+ }
+ break;
+ default:
+ case drawing::ConnectorType_LINE :
+ case drawing::ConnectorType_LINES : // Connector 2->5
+ {
+ rShapeType = ESCHER_ShpInst_StraightConnector1;
+ AddOpt( ESCHER_Prop_cxstyle, ESCHER_cxstyleStraight );
+ }
+ break;
+ }
+ CreateLineProperties( aXPropSet, false );
+ bRetValue = true;
+ }
+ }
+ }
+ }
+ }
+ return bRetValue;
+}
+
+void EscherPropertyContainer::CreateShadowProperties(
+ const uno::Reference<beans::XPropertySet> & rXPropSet )
+{
+ uno::Any aAny;
+
+ sal_uInt32 nLineFlags = 0; // default : shape has no line
+ sal_uInt32 nFillFlags = 0x10; // shape is filled
+
+ GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+ GetOpt( ESCHER_Prop_fNoFillHitTest, nFillFlags );
+
+ sal_uInt32 nDummy;
+ bool bGraphic = GetOpt( DFF_Prop_pib, nDummy ) || GetOpt( DFF_Prop_pibName, nDummy ) || GetOpt( DFF_Prop_pibFlags, nDummy );
+
+ sal_uInt32 nShadowFlags = 0x20000;
+ if ( ( nLineFlags & 8 ) || ( nFillFlags & 0x10 ) || bGraphic )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "Shadow", true ) )
+ {
+ bool bHasShadow = false; // shadow is possible only if at least a fillcolor, linecolor or graphic is set
+ if ( (aAny >>= bHasShadow) && bHasShadow )
+ {
+ nShadowFlags |= 2;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowColor" ) )
+ AddOpt( ESCHER_Prop_shadowColor, ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) );
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowXDistance" ) )
+ AddOpt( ESCHER_Prop_shadowOffsetX, *o3tl::doAccess<sal_Int32>(aAny) * 360 );
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowYDistance" ) )
+ AddOpt( ESCHER_Prop_shadowOffsetY, *o3tl::doAccess<sal_Int32>(aAny) * 360 );
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowTransparence" ) )
+ AddOpt( ESCHER_Prop_shadowOpacity, 0x10000 - (static_cast<sal_uInt32>(*o3tl::doAccess<sal_uInt16>(aAny)) * 655 ) );
+ }
+ }
+ }
+ AddOpt( ESCHER_Prop_fshadowObscured, nShadowFlags );
+}
+
+sal_Int32 EscherPropertyContainer::GetValueForEnhancedCustomShapeParameter( const drawing::EnhancedCustomShapeParameter& rParameter,
+ const std::vector< sal_Int32 >& rEquationOrder, bool bAdjustTrans )
+{
+ sal_Int32 nValue = 0;
+ if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ if ( rParameter.Value >>= fValue )
+ nValue = static_cast<sal_Int32>(fValue);
+ }
+ else
+ rParameter.Value >>= nValue;
+
+ switch( rParameter.Type )
+ {
+ case drawing::EnhancedCustomShapeParameterType::EQUATION :
+ {
+ size_t nIndex = static_cast<size_t>(nValue);
+ OSL_ASSERT(nIndex < rEquationOrder.size());
+ if ( nIndex < rEquationOrder.size() )
+ {
+ nValue = static_cast<sal_uInt16>(rEquationOrder[ nIndex ]);
+ nValue |= sal_uInt32(0x80000000);
+ }
+ }
+ break;
+ case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT:
+ {
+ if(bAdjustTrans)
+ {
+ sal_uInt32 nAdjustValue = 0;
+ bool bGot = GetOpt(static_cast<sal_uInt16>( DFF_Prop_adjustValue + nValue ), nAdjustValue);
+ if(bGot) nValue = static_cast<sal_Int32>(nAdjustValue);
+ }
+ }
+ break;
+ case drawing::EnhancedCustomShapeParameterType::NORMAL :
+ default:
+ break;
+/* not sure if it is allowed to set following values
+(but they are not yet used)
+ case drawing::EnhancedCustomShapeParameterType::BOTTOM :
+ case drawing::EnhancedCustomShapeParameterType::RIGHT :
+ case drawing::EnhancedCustomShapeParameterType::TOP :
+ case drawing::EnhancedCustomShapeParameterType::LEFT :
+*/
+ }
+ return nValue;
+}
+
+static bool GetValueForEnhancedCustomShapeHandleParameter( sal_Int32& nRetValue, const drawing::EnhancedCustomShapeParameter& rParameter )
+{
+ bool bSpecial = false;
+ nRetValue = 0;
+ if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ if ( rParameter.Value >>= fValue )
+ nRetValue = static_cast<sal_Int32>(fValue);
+ }
+ else
+ rParameter.Value >>= nRetValue;
+
+ switch( rParameter.Type )
+ {
+ case drawing::EnhancedCustomShapeParameterType::EQUATION :
+ {
+ nRetValue += 3;
+ bSpecial = true;
+ }
+ break;
+ case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
+ {
+ nRetValue += 0x100;
+ bSpecial = true;
+ }
+ break;
+ case drawing::EnhancedCustomShapeParameterType::TOP :
+ case drawing::EnhancedCustomShapeParameterType::LEFT :
+ {
+ nRetValue = 0;
+ bSpecial = true;
+ }
+ break;
+ case drawing::EnhancedCustomShapeParameterType::RIGHT :
+ case drawing::EnhancedCustomShapeParameterType::BOTTOM :
+ {
+ nRetValue = 1;
+ bSpecial = true;
+ }
+ break;
+ case drawing::EnhancedCustomShapeParameterType::NORMAL :
+ {
+
+ }
+ break;
+ }
+ return bSpecial;
+}
+
+static void ConvertEnhancedCustomShapeEquation(
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ std::vector< EnhancedCustomShapeEquation >& rEquations,
+ std::vector< sal_Int32 >& rEquationOrder )
+{
+ uno::Sequence< OUString > sEquationSource;
+ const SdrCustomShapeGeometryItem& rGeometryItem =
+ rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "Equations" );
+ if ( pAny )
+ *pAny >>= sEquationSource;
+ sal_Int32 nEquationSourceCount = sEquationSource.getLength();
+ if ( !(nEquationSourceCount && (nEquationSourceCount <= 128)) )
+ return;
+
+ sal_Int32 i;
+ for ( i = 0; i < nEquationSourceCount; i++ )
+ {
+ EnhancedCustomShape2d aCustomShape2d(
+ const_cast< SdrObjCustomShape& >(rSdrObjCustomShape));
+ try
+ {
+ std::shared_ptr< EnhancedCustomShape::ExpressionNode > aExpressNode(
+ EnhancedCustomShape::FunctionParser::parseFunction(
+ sEquationSource[ i ], aCustomShape2d));
+ drawing::EnhancedCustomShapeParameter aPara( aExpressNode->fillNode( rEquations, nullptr, 0 ) );
+ if ( aPara.Type != drawing::EnhancedCustomShapeParameterType::EQUATION )
+ {
+ EnhancedCustomShapeEquation aEquation;
+ aEquation.nOperation = 0;
+ EnhancedCustomShape::FillEquationParameter( aPara, 0, aEquation );
+ rEquations.push_back( aEquation );
+ }
+ }
+ catch ( const EnhancedCustomShape::ParseError& )
+ {
+ EnhancedCustomShapeEquation aEquation; // ups, we should not be here,
+ aEquation.nOperation = 0; // creating a default equation with value 1
+ aEquation.nPara[ 0 ] = 1; // hoping that this will not break anything
+ rEquations.push_back( aEquation );
+ }
+ catch ( ... )
+ {
+ EnhancedCustomShapeEquation aEquation; // #i112309# EnhancedCustomShape::Parse error
+ aEquation.nOperation = 0; // not caught on linux platform
+ aEquation.nPara[ 0 ] = 1;
+ rEquations.push_back( aEquation );
+ }
+ rEquationOrder.push_back( rEquations.size() - 1 );
+ }
+ // now updating our old equation indices, they are marked with a bit in the hiword of nOperation
+ for (auto & equation : rEquations)
+ {
+ sal_uInt32 nMask = 0x20000000;
+ for( i = 0; i < 3; i++ )
+ {
+ if ( equation.nOperation & nMask )
+ {
+ equation.nOperation ^= nMask;
+ const size_t nIndex(equation.nPara[ i ] & 0x3ff);
+
+ // #i124661# check index access, there are cases where this is out of bound leading
+ // to errors up to crashes when executed
+ if(nIndex < rEquationOrder.size())
+ {
+ equation.nPara[ i ] = rEquationOrder[ nIndex ] | 0x400;
+ }
+ else
+ {
+ OSL_ENSURE(false, "Attempted out of bound access to rEquationOrder of CustomShape (!)");
+ }
+ }
+ nMask <<= 1;
+ }
+ }
+}
+
+bool EscherPropertyContainer::IsDefaultObject(
+ const SdrObjCustomShape& rSdrObjCustomShape,
+ const MSO_SPT eShapeType)
+{
+ switch(eShapeType)
+ {
+ // if the custom shape is not default shape of ppt, return false;
+ case mso_sptTearDrop:
+ return false;
+
+ default:
+ break;
+ }
+
+ return rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Equations )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Viewbox )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Path )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Gluepoints )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Segments )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchX )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchY )
+ && rSdrObjCustomShape.IsDefaultGeometry( SdrObjCustomShape::DefaultType::TextFrames );
+}
+
+void EscherPropertyContainer::LookForPolarHandles( const MSO_SPT eShapeType, sal_Int32& nAdjustmentsWhichNeedsToBeConverted )
+{
+ const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eShapeType );
+ if ( !(pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles) )
+ return;
+
+ sal_Int32 k, nkCount = pDefCustomShape->nHandles;
+ const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
+ for ( k = 0; k < nkCount; k++, pData++ )
+ {
+ if ( pData->nFlags & SvxMSDffHandleFlags::POLAR )
+ {
+ if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) )
+ nAdjustmentsWhichNeedsToBeConverted |= ( 1 << k );
+ }
+ }
+}
+
+bool EscherPropertyContainer::GetAdjustmentValue( const drawing::EnhancedCustomShapeAdjustmentValue & rkProp, sal_Int32 nIndex, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, sal_Int32& nValue )
+{
+ if ( rkProp.State != beans::PropertyState_DIRECT_VALUE )
+ return false;
+
+ bool bUseFixedFloat = ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << nIndex ) ) != 0;
+ if ( rkProp.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
+ {
+ double fValue(0.0);
+ rkProp.Value >>= fValue;
+ if ( bUseFixedFloat )
+ fValue *= 65536.0;
+ nValue = static_cast<sal_Int32>(fValue);
+ }
+ else
+ {
+ rkProp.Value >>= nValue;
+ if ( bUseFixedFloat )
+ nValue <<= 16;
+ }
+
+ return true;
+}
+
+void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeType, const uno::Reference< drawing::XShape > & rXShape )
+{
+ uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
+ if ( !aXPropSet.is() )
+ return;
+
+ SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(rXShape));
+ if(!pSdrObjCustomShape)
+ {
+ return;
+ }
+
+ SdrObjCustomShape& rSdrObjCustomShape = *pSdrObjCustomShape;
+ uno::Any aGeoPropSet = aXPropSet->getPropertyValue( "CustomShapeGeometry" );
+ uno::Sequence< beans::PropertyValue > aGeoPropSeq;
+ if ( !(aGeoPropSet >>= aGeoPropSeq) )
+ return;
+
+ static const OUStringLiteral sViewBox ( u"ViewBox" );
+ static const OUStringLiteral sTextRotateAngle ( u"TextRotateAngle" );
+ static const OUStringLiteral sExtrusion ( u"Extrusion" );
+ static const OUStringLiteral sEquations ( u"Equations" );
+ static const OUStringLiteral sPath ( u"Path" );
+ static const OUStringLiteral sTextPath ( u"TextPath" );
+ static const OUStringLiteral sHandles ( u"Handles" );
+ static const OUStringLiteral sAdjustmentValues ( u"AdjustmentValues" );
+
+ bool bAdjustmentValuesProp = false;
+ uno::Any aAdjustmentValuesProp;
+ bool bPathCoordinatesProp = false;
+ uno::Any aPathCoordinatesProp;
+
+ sal_Int32 nAdjustmentsWhichNeedsToBeConverted = 0;
+ uno::Sequence< beans::PropertyValues > aHandlesPropSeq;
+ bool bPredefinedHandlesUsed = true;
+ const bool bIsDefaultObject(
+ IsDefaultObject(
+ rSdrObjCustomShape,
+ eShapeType));
+
+ // convert property "Equations" into std::vector< EnhancedCustomShapeEquationEquation >
+ std::vector< EnhancedCustomShapeEquation > aEquations;
+ std::vector< sal_Int32 > aEquationOrder;
+ ConvertEnhancedCustomShapeEquation(
+ rSdrObjCustomShape,
+ aEquations,
+ aEquationOrder);
+
+ sal_Int32 i, nCount = aGeoPropSeq.getLength();
+ for ( i = 0; i < nCount; i++ )
+ {
+ const beans::PropertyValue& rProp = aGeoPropSeq[ i ];
+ if ( rProp.Name == sViewBox )
+ {
+ if ( !bIsDefaultObject )
+ {
+ awt::Rectangle aViewBox;
+ if ( rProp.Value >>= aViewBox )
+ {
+ AddOpt( DFF_Prop_geoLeft, aViewBox.X );
+ AddOpt( DFF_Prop_geoTop, aViewBox.Y );
+ AddOpt( DFF_Prop_geoRight, aViewBox.X + aViewBox.Width );
+ AddOpt( DFF_Prop_geoBottom,aViewBox.Y + aViewBox.Height );
+ }
+ }
+ }
+ else if ( rProp.Name == sTextRotateAngle )
+ {
+ double f = 0;
+ if ( rProp.Value >>= f )
+ {
+ double fTextRotateAngle = fmod( f, 360.0 );
+ if ( fTextRotateAngle < 0 )
+ fTextRotateAngle = 360 + fTextRotateAngle;
+ if ( ( fTextRotateAngle < 271.0 ) && ( fTextRotateAngle > 269.0 ) )
+ AddOpt( DFF_Prop_cdirFont, mso_cdir90 );
+ else if ( ( fTextRotateAngle < 181.0 ) && ( fTextRotateAngle > 179.0 ) )
+ AddOpt( DFF_Prop_cdirFont, mso_cdir180 );
+ else if ( ( fTextRotateAngle < 91.0 ) && ( fTextRotateAngle > 79.0 ) )
+ AddOpt( DFF_Prop_cdirFont, mso_cdir270 );
+ }
+ }
+ else if ( rProp.Name == sExtrusion )
+ {
+ uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
+ if ( rProp.Value >>= aExtrusionPropSeq )
+ {
+ sal_uInt32 nLightFaceFlagsOrg, nLightFaceFlags;
+ sal_uInt32 nFillHarshFlagsOrg, nFillHarshFlags;
+ nLightFaceFlagsOrg = nLightFaceFlags = 0x000001;
+ nFillHarshFlagsOrg = nFillHarshFlags = 0x00001e;
+ if ( GetOpt( DFF_Prop_fc3DLightFace, nLightFaceFlags ) )
+ nLightFaceFlagsOrg = nLightFaceFlags;
+ if ( GetOpt( DFF_Prop_fc3DFillHarsh, nFillHarshFlags ) )
+ nFillHarshFlagsOrg = nFillHarshFlags;
+
+ sal_Int32 r, nrCount = aExtrusionPropSeq.getLength();
+ for ( r = 0; r < nrCount; r++ )
+ {
+ const beans::PropertyValue& rrProp = aExtrusionPropSeq[ r ];
+
+ if ( rrProp.Name == sExtrusion )
+ {
+ bool bExtrusionOn;
+ if ( rrProp.Value >>= bExtrusionOn )
+ {
+ nLightFaceFlags |= 0x80000;
+ if ( bExtrusionOn )
+ nLightFaceFlags |= 8;
+ else
+ nLightFaceFlags &=~8;
+ }
+ }
+ else if ( rrProp.Name == "Brightness" )
+ {
+ double fExtrusionBrightness = 0;
+ if ( rrProp.Value >>= fExtrusionBrightness )
+ AddOpt( DFF_Prop_c3DAmbientIntensity, static_cast<sal_Int32>( fExtrusionBrightness * 655.36 ) );
+ }
+ else if ( rrProp.Name == "Depth" )
+ {
+ double fDepth = 0;
+ double fFraction = 0;
+ drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
+ if ( ( rrProp.Value >>= aDepthParaPair ) && ( aDepthParaPair.First.Value >>= fDepth ) && ( aDepthParaPair.Second.Value >>= fFraction ) )
+ {
+ double fForeDepth = fDepth * fFraction;
+ double fBackDepth = fDepth - fForeDepth;
+
+ fBackDepth *= 360.0;
+ AddOpt( DFF_Prop_c3DExtrudeBackward, static_cast<sal_Int32>(fBackDepth) );
+
+ if ( fForeDepth != 0.0 )
+ {
+ fForeDepth *= 360.0;
+ AddOpt( DFF_Prop_c3DExtrudeForward, static_cast<sal_Int32>(fForeDepth) );
+ }
+ }
+ }
+ else if ( rrProp.Name == "Diffusion" )
+ {
+ double fExtrusionDiffusion = 0;
+ if ( rrProp.Value >>= fExtrusionDiffusion )
+ AddOpt( DFF_Prop_c3DDiffuseAmt, static_cast<sal_Int32>( fExtrusionDiffusion * 655.36 ) );
+ }
+ else if ( rrProp.Name == "NumberOfLineSegments" )
+ {
+ sal_Int32 nExtrusionNumberOfLineSegments = 0;
+ if ( rrProp.Value >>= nExtrusionNumberOfLineSegments )
+ AddOpt( DFF_Prop_c3DTolerance, nExtrusionNumberOfLineSegments );
+ }
+ else if ( rrProp.Name == "LightFace" )
+ {
+ bool bExtrusionLightFace;
+ if ( rrProp.Value >>= bExtrusionLightFace )
+ {
+ nLightFaceFlags |= 0x10000;
+ if ( bExtrusionLightFace )
+ nLightFaceFlags |= 1;
+ else
+ nLightFaceFlags &=~1;
+ }
+ }
+ else if ( rrProp.Name == "FirstLightHarsh" )
+ {
+ bool bExtrusionFirstLightHarsh;
+ if ( rrProp.Value >>= bExtrusionFirstLightHarsh )
+ {
+ nFillHarshFlags |= 0x20000;
+ if ( bExtrusionFirstLightHarsh )
+ nFillHarshFlags |= 2;
+ else
+ nFillHarshFlags &=~2;
+ }
+ }
+ else if ( rrProp.Name == "SecondLightHarsh" )
+ {
+ bool bExtrusionSecondLightHarsh;
+ if ( rrProp.Value >>= bExtrusionSecondLightHarsh )
+ {
+ nFillHarshFlags |= 0x10000;
+ if ( bExtrusionSecondLightHarsh )
+ nFillHarshFlags |= 1;
+ else
+ nFillHarshFlags &=~1;
+ }
+ }
+ else if ( rrProp.Name == "FirstLightLevel" )
+ {
+ double fExtrusionFirstLightLevel = 0;
+ if ( rrProp.Value >>= fExtrusionFirstLightLevel )
+ AddOpt( DFF_Prop_c3DKeyIntensity, static_cast<sal_Int32>( fExtrusionFirstLightLevel * 655.36 ) );
+ }
+ else if ( rrProp.Name == "SecondLightLevel" )
+ {
+ double fExtrusionSecondLightLevel = 0;
+ if ( rrProp.Value >>= fExtrusionSecondLightLevel )
+ AddOpt( DFF_Prop_c3DFillIntensity, static_cast<sal_Int32>( fExtrusionSecondLightLevel * 655.36 ) );
+ }
+ else if ( rrProp.Name == "FirstLightDirection" )
+ {
+ drawing::Direction3D aExtrusionFirstLightDirection;
+ if ( rrProp.Value >>= aExtrusionFirstLightDirection )
+ {
+ AddOpt( DFF_Prop_c3DKeyX, static_cast<sal_Int32>(aExtrusionFirstLightDirection.DirectionX) );
+ AddOpt( DFF_Prop_c3DKeyY, static_cast<sal_Int32>(aExtrusionFirstLightDirection.DirectionY) );
+ AddOpt( DFF_Prop_c3DKeyZ, static_cast<sal_Int32>(aExtrusionFirstLightDirection.DirectionZ) );
+ }
+ }
+ else if ( rrProp.Name == "SecondLightDirection" )
+ {
+ drawing::Direction3D aExtrusionSecondLightPosition;
+ if ( rrProp.Value >>= aExtrusionSecondLightPosition )
+ {
+ AddOpt( DFF_Prop_c3DFillX, static_cast<sal_Int32>(aExtrusionSecondLightPosition.DirectionX) );
+ AddOpt( DFF_Prop_c3DFillY, static_cast<sal_Int32>(aExtrusionSecondLightPosition.DirectionY) );
+ AddOpt( DFF_Prop_c3DFillZ, static_cast<sal_Int32>(aExtrusionSecondLightPosition.DirectionZ) );
+ }
+ }
+ else if ( rrProp.Name == "Metal" )
+ {
+ bool bExtrusionMetal;
+ if ( rrProp.Value >>= bExtrusionMetal )
+ {
+ nLightFaceFlags |= 0x40000;
+ if ( bExtrusionMetal )
+ nLightFaceFlags |= 4;
+ else
+ nLightFaceFlags &=~4;
+ }
+ }
+ else if ( rrProp.Name == "ShadeMode" )
+ {
+ drawing::ShadeMode eExtrusionShadeMode;
+ if ( rrProp.Value >>= eExtrusionShadeMode )
+ {
+ sal_uInt32 nRenderMode;
+ switch( eExtrusionShadeMode )
+ {
+ default:
+ case drawing::ShadeMode_FLAT :
+ case drawing::ShadeMode_PHONG :
+ case drawing::ShadeMode_SMOOTH :
+ nRenderMode = mso_FullRender;
+ break;
+ case drawing::ShadeMode_DRAFT :
+ {
+ nRenderMode = mso_Wireframe;
+ }
+ break;
+ }
+ AddOpt( DFF_Prop_c3DRenderMode, nRenderMode );
+ }
+ }
+ else if ( rrProp.Name == "RotateAngle" )
+ {
+ double fExtrusionAngleX = 0;
+ double fExtrusionAngleY = 0;
+ drawing::EnhancedCustomShapeParameterPair aRotateAnglePair;
+ if ( ( rrProp.Value >>= aRotateAnglePair ) && ( aRotateAnglePair.First.Value >>= fExtrusionAngleX ) && ( aRotateAnglePair.Second.Value >>= fExtrusionAngleY ) )
+ {
+ fExtrusionAngleX *= 65536;
+ fExtrusionAngleY *= 65536;
+ AddOpt( DFF_Prop_c3DXRotationAngle, static_cast<sal_Int32>(fExtrusionAngleX) );
+ AddOpt( DFF_Prop_c3DYRotationAngle, static_cast<sal_Int32>(fExtrusionAngleY) );
+ }
+ }
+ else if ( rrProp.Name == "RotationCenter" )
+ {
+ drawing::Direction3D aExtrusionRotationCenter;
+ if ( rrProp.Value >>= aExtrusionRotationCenter )
+ {
+ // tdf#145904 X- and Y-component is fraction, Z-component in EMU
+ AddOpt( DFF_Prop_c3DRotationCenterX, static_cast<sal_Int32>( aExtrusionRotationCenter.DirectionX * 65536.0 ) );
+ AddOpt( DFF_Prop_c3DRotationCenterY, static_cast<sal_Int32>( aExtrusionRotationCenter.DirectionY * 65536.0 ) );
+ AddOpt( DFF_Prop_c3DRotationCenterZ, static_cast<sal_Int32>( aExtrusionRotationCenter.DirectionZ * 360.0 ) );
+ nFillHarshFlags &=~8; // don't use AutoRotationCenter;
+ }
+ }
+ else if ( rrProp.Name == "Shininess" )
+ {
+ double fExtrusionShininess = 0;
+ if ( rrProp.Value >>= fExtrusionShininess )
+ {
+ // ODF to MS Office conversion invers to msdffimp.cxx
+ fExtrusionShininess = basegfx::fround(fExtrusionShininess / 10.0);
+ AddOpt( DFF_Prop_c3DShininess, static_cast<sal_Int32>(fExtrusionShininess) );
+ }
+ }
+ else if ( rrProp.Name == "Skew" )
+ {
+ double fSkewAmount = 0;
+ double fSkewAngle = 0;
+ drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
+ if ( ( rrProp.Value >>= aSkewParaPair ) && ( aSkewParaPair.First.Value >>= fSkewAmount ) && ( aSkewParaPair.Second.Value >>= fSkewAngle ) )
+ {
+ AddOpt( DFF_Prop_c3DSkewAmount, static_cast<sal_Int32>(fSkewAmount) );
+ AddOpt( DFF_Prop_c3DSkewAngle, static_cast<sal_Int32>( fSkewAngle * 65536 ) );
+ }
+ }
+ else if ( rrProp.Name == "Specularity" )
+ {
+ double fExtrusionSpecularity = 0;
+ if ( rrProp.Value >>= fExtrusionSpecularity )
+ AddOpt( DFF_Prop_c3DSpecularAmt, static_cast<sal_Int32>( fExtrusionSpecularity * 655.36 ) );
+ }
+ else if ( rrProp.Name == "ProjectionMode" )
+ {
+ drawing::ProjectionMode eExtrusionProjectionMode;
+ if ( rrProp.Value >>= eExtrusionProjectionMode )
+ {
+ nFillHarshFlags |= 0x40000;
+ if ( eExtrusionProjectionMode == drawing::ProjectionMode_PARALLEL )
+ nFillHarshFlags |= 4;
+ else
+ nFillHarshFlags &=~4;
+ }
+ }
+ else if ( rrProp.Name == "ViewPoint" )
+ {
+ drawing::Position3D aExtrusionViewPoint;
+ if ( rrProp.Value >>= aExtrusionViewPoint )
+ {
+ aExtrusionViewPoint.PositionX *= 360.0;
+ aExtrusionViewPoint.PositionY *= 360.0;
+ aExtrusionViewPoint.PositionZ *= 360.0;
+ AddOpt( DFF_Prop_c3DXViewpoint, static_cast<sal_Int32>(aExtrusionViewPoint.PositionX) );
+ AddOpt( DFF_Prop_c3DYViewpoint, static_cast<sal_Int32>(aExtrusionViewPoint.PositionY) );
+ AddOpt( DFF_Prop_c3DZViewpoint, static_cast<sal_Int32>(aExtrusionViewPoint.PositionZ) );
+ }
+ }
+ else if ( rrProp.Name == "Origin" )
+ {
+ double fExtrusionOriginX = 0;
+ double fExtrusionOriginY = 0;
+ drawing::EnhancedCustomShapeParameterPair aOriginPair;
+ if ( ( rrProp.Value >>= aOriginPair ) && ( aOriginPair.First.Value >>= fExtrusionOriginX ) && ( aOriginPair.Second.Value >>= fExtrusionOriginY ) )
+ {
+ AddOpt( DFF_Prop_c3DOriginX, static_cast<sal_Int32>( fExtrusionOriginX * 65536 ) );
+ AddOpt( DFF_Prop_c3DOriginY, static_cast<sal_Int32>( fExtrusionOriginY * 65536 ) );
+ }
+ }
+ else if ( rrProp.Name == "Color" )
+ {
+ bool bExtrusionColor;
+ if ( rrProp.Value >>= bExtrusionColor )
+ {
+ nLightFaceFlags |= 0x20000;
+ if ( bExtrusionColor )
+ {
+ nLightFaceFlags |= 2;
+ uno::Any aFillColor2;
+ if ( EscherPropertyValueHelper::GetPropertyValue( aFillColor2, aXPropSet, "FillColor2", true ) )
+ {
+ sal_uInt32 nFillColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aFillColor2) );
+ AddOpt( DFF_Prop_c3DExtrusionColor, nFillColor );
+ }
+ }
+ else
+ nLightFaceFlags &=~2;
+ }
+ }
+ }
+ if ( nLightFaceFlags != nLightFaceFlagsOrg )
+ AddOpt( DFF_Prop_fc3DLightFace, nLightFaceFlags );
+ if ( nFillHarshFlags != nFillHarshFlagsOrg )
+ AddOpt( DFF_Prop_fc3DFillHarsh, nFillHarshFlags );
+ }
+ }
+ else if ( rProp.Name == sEquations )
+ {
+ if ( !bIsDefaultObject )
+ {
+ sal_uInt16 nElements = static_cast<sal_uInt16>(aEquations.size());
+ if ( nElements )
+ {
+ sal_uInt16 nElementSize = 8;
+ sal_uInt32 nStreamSize = nElementSize * nElements + 6;
+ SvMemoryStream aMemStrm( nStreamSize );
+ aMemStrm.WriteUInt16( nElements )
+ .WriteUInt16( nElements )
+ .WriteUInt16( nElementSize );
+
+ for (auto const& equation : aEquations)
+ {
+ aMemStrm.WriteUInt16( equation.nOperation )
+ .WriteInt16(
+ std::clamp(
+ equation.nPara[ 0 ], sal_Int32(SAL_MIN_INT16),
+ sal_Int32(SAL_MAX_INT16)) )
+ .WriteInt16(
+ std::clamp(
+ equation.nPara[ 1 ], sal_Int32(SAL_MIN_INT16),
+ sal_Int32(SAL_MAX_INT16)) )
+ .WriteInt16(
+ std::clamp(
+ equation.nPara[ 2 ], sal_Int32(SAL_MIN_INT16),
+ sal_Int32(SAL_MAX_INT16)) );
+ }
+
+ AddOpt(DFF_Prop_pFormulas, true, 6, aMemStrm);
+ }
+ else
+ {
+ AddOpt(DFF_Prop_pFormulas, 0, true);
+ }
+ }
+ }
+ else if ( rProp.Name == sPath )
+ {
+ uno::Sequence< beans::PropertyValue > aPathPropSeq;
+ if ( rProp.Value >>= aPathPropSeq )
+ {
+ sal_uInt32 nPathFlags, nPathFlagsOrg;
+ nPathFlagsOrg = nPathFlags = 0x39;
+ if ( GetOpt( DFF_Prop_fFillOK, nPathFlags ) )
+ nPathFlagsOrg = nPathFlags;
+
+ sal_Int32 r, nrCount = aPathPropSeq.getLength();
+ for ( r = 0; r < nrCount; r++ )
+ {
+ const beans::PropertyValue& rrProp = aPathPropSeq[ r ];
+
+ if ( rrProp.Name == "ExtrusionAllowed" )
+ {
+ bool bExtrusionAllowed;
+ if ( rrProp.Value >>= bExtrusionAllowed )
+ {
+ nPathFlags |= 0x100000;
+ if ( bExtrusionAllowed )
+ nPathFlags |= 16;
+ else
+ nPathFlags &=~16;
+ }
+ }
+ else if ( rrProp.Name == "ConcentricGradientFillAllowed" )
+ {
+ bool bConcentricGradientFillAllowed;
+ if ( rrProp.Value >>= bConcentricGradientFillAllowed )
+ {
+ nPathFlags |= 0x20000;
+ if ( bConcentricGradientFillAllowed )
+ nPathFlags |= 2;
+ else
+ nPathFlags &=~2;
+ }
+ }
+ else if ( rrProp.Name == "TextPathAllowed" )
+ {
+ bool bTextPathAllowed;
+ if ( rrProp.Value >>= bTextPathAllowed )
+ {
+ nPathFlags |= 0x40000;
+ if ( bTextPathAllowed )
+ nPathFlags |= 4;
+ else
+ nPathFlags &=~4;
+ }
+ }
+ else if ( rrProp.Name == "Coordinates" )
+ {
+ if ( !bIsDefaultObject )
+ {
+ aPathCoordinatesProp = rrProp.Value;
+ bPathCoordinatesProp = true;
+ }
+ }
+ else if ( rrProp.Name == "GluePoints" )
+ {
+ if ( !bIsDefaultObject )
+ {
+ uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aGluePoints;
+ if ( rrProp.Value >>= aGluePoints )
+ {
+ // creating the vertices
+ sal_uInt16 nElements = static_cast<sal_uInt16>(aGluePoints.getLength());
+ if ( nElements )
+ {
+ sal_uInt16 j, nElementSize = 8;
+ sal_uInt32 nStreamSize = nElementSize * nElements + 6;
+ SvMemoryStream aMemStrm( nStreamSize );
+ aMemStrm.WriteUInt16( nElements )
+ .WriteUInt16( nElements )
+ .WriteUInt16( nElementSize );
+ for( j = 0; j < nElements; j++ )
+ {
+ sal_Int32 X = GetValueForEnhancedCustomShapeParameter( aGluePoints[ j ].First, aEquationOrder );
+ sal_Int32 Y = GetValueForEnhancedCustomShapeParameter( aGluePoints[ j ].Second, aEquationOrder );
+ aMemStrm.WriteInt32( X )
+ .WriteInt32( Y );
+ }
+
+ AddOpt(DFF_Prop_connectorPoints, true, 6, aMemStrm); // -6
+ }
+ else
+ {
+ AddOpt(DFF_Prop_connectorPoints, 0, true);
+ }
+ }
+ }
+ }
+ else if ( rrProp.Name == "GluePointType" )
+ {
+ sal_Int16 nGluePointType = sal_Int16();
+ if ( rrProp.Value >>= nGluePointType )
+ AddOpt( DFF_Prop_connectorType, static_cast<sal_uInt16>(nGluePointType) );
+ }
+ else if ( rrProp.Name == "Segments" )
+ {
+ if ( !bIsDefaultObject )
+ {
+ uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
+ if ( rrProp.Value >>= aSegments )
+ {
+ // creating seginfo
+ if ( aSegments.hasElements() )
+ {
+ sal_uInt16 j, nElements = static_cast<sal_uInt16>(aSegments.getLength());
+ sal_uInt16 nElementSize = 2;
+ sal_uInt32 nStreamSize = nElementSize * nElements + 6;
+ SvMemoryStream aMemStrm( nStreamSize );
+ aMemStrm.WriteUInt16( nElements )
+ .WriteUInt16( nElements )
+ .WriteUInt16( nElementSize );
+ for ( j = 0; j < nElements; j++ )
+ {
+ // The segment type is stored in the upper 3 bits
+ // and segment count is stored in the lower 13
+ // bits.
+ //
+ // If the segment type is msopathEscape, the lower 13 bits
+ // are divided in a 5 bit escape code and 8 bit
+ // vertex count (not segment count!)
+ sal_uInt16 nVal = static_cast<sal_uInt16>(aSegments[ j ].Count);
+ switch( aSegments[ j ].Command )
+ {
+ case drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN :
+ case drawing::EnhancedCustomShapeSegmentCommand::LINETO :
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
+ nVal = (msopathMoveTo << 13);
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
+ {
+ nVal |= (msopathCurveTo << 13);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
+ {
+ nVal = 1;
+ nVal |= (msopathClose << 13);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
+ {
+ nVal = (msopathEnd << 13);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
+ {
+ nVal = (msopathEscape << 13) | (10 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
+ {
+ nVal = (msopathEscape << 13) | (11 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
+ {
+ nVal *= 3;
+ nVal |= (msopathEscape << 13) | (1 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
+ {
+ nVal *= 3;
+ nVal |= (msopathEscape << 13) | (2 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
+ {
+ nVal <<= 2;
+ nVal |= (msopathEscape << 13) | (3 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ARC :
+ {
+ nVal <<= 2;
+ nVal |= (msopathEscape << 13) | (4 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
+ {
+ nVal <<= 2;
+ nVal |= (msopathEscape << 13) | (5 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
+ {
+ nVal <<= 2;
+ nVal |= (msopathEscape << 13) | (6 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
+ {
+ nVal |= (msopathEscape << 13) | (7 << 8);
+ }
+ break;
+ case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
+ {
+ nVal |= (msopathEscape << 13) | (8 << 8);
+ }
+ break;
+ }
+ aMemStrm.WriteUInt16( nVal );
+ }
+
+ AddOpt(DFF_Prop_pSegmentInfo, false, 6, aMemStrm);
+ }
+ else
+ {
+ AddOpt(DFF_Prop_pSegmentInfo, 0, true);
+ }
+ }
+ }
+ }
+ else if ( rrProp.Name == "StretchX" )
+ {
+ if ( !bIsDefaultObject )
+ {
+ sal_Int32 nStretchX = 0;
+ if ( rrProp.Value >>= nStretchX )
+ AddOpt( DFF_Prop_stretchPointX, nStretchX );
+ }
+ }
+ else if ( rrProp.Name == "StretchY" )
+ {
+ if ( !bIsDefaultObject )
+ {
+ sal_Int32 nStretchY = 0;
+ if ( rrProp.Value >>= nStretchY )
+ AddOpt( DFF_Prop_stretchPointY, nStretchY );
+ }
+ }
+ else if ( rrProp.Name == "TextFrames" )
+ {
+ if ( !bIsDefaultObject )
+ {
+ uno::Sequence<drawing::EnhancedCustomShapeTextFrame> aPathTextFrames;
+ if ( rrProp.Value >>= aPathTextFrames )
+ {
+ if ( aPathTextFrames.hasElements() )
+ {
+ sal_uInt16 j, nElements = static_cast<sal_uInt16>(aPathTextFrames.getLength());
+ sal_uInt16 nElementSize = 16;
+ sal_uInt32 nStreamSize = nElementSize * nElements + 6;
+ SvMemoryStream aMemStrm( nStreamSize );
+ aMemStrm.WriteUInt16( nElements )
+ .WriteUInt16( nElements )
+ .WriteUInt16( nElementSize );
+ for ( j = 0; j < nElements; j++ )
+ {
+ sal_Int32 nLeft = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].TopLeft.First, aEquationOrder );
+ sal_Int32 nTop = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].TopLeft.Second, aEquationOrder );
+ sal_Int32 nRight = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].BottomRight.First, aEquationOrder );
+ sal_Int32 nBottom = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].BottomRight.Second, aEquationOrder );
+
+ aMemStrm.WriteInt32( nLeft )
+ .WriteInt32( nTop )
+ .WriteInt32( nRight )
+ .WriteInt32( nBottom );
+ }
+
+ AddOpt(DFF_Prop_textRectangles, true, 6, aMemStrm);
+ }
+ else
+ {
+ AddOpt(DFF_Prop_textRectangles, 0, true);
+ }
+ }
+ }
+ }
+ }
+ if ( nPathFlags != nPathFlagsOrg )
+ AddOpt( DFF_Prop_fFillOK, nPathFlags );
+ }
+ }
+ else if ( rProp.Name == sTextPath )
+ {
+ uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
+ if ( rProp.Value >>= aTextPathPropSeq )
+ {
+ sal_uInt32 nTextPathFlagsOrg, nTextPathFlags;
+ nTextPathFlagsOrg = nTextPathFlags = 0xffff1000; // default
+ if ( GetOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags ) )
+ nTextPathFlagsOrg = nTextPathFlags;
+
+ sal_Int32 r, nrCount = aTextPathPropSeq.getLength();
+ for ( r = 0; r < nrCount; r++ )
+ {
+ const beans::PropertyValue& rrProp = aTextPathPropSeq[ r ];
+
+ if ( rrProp.Name == sTextPath )
+ {
+ bool bTextPathOn;
+ if ( rrProp.Value >>= bTextPathOn )
+ {
+ nTextPathFlags |= 0x40000000;
+ if ( bTextPathOn )
+ {
+ nTextPathFlags |= 0x4000;
+
+ sal_uInt32 nPathFlags = 0x39;
+ GetOpt( DFF_Prop_fFillOK, nPathFlags ); // SJ: can be removed if we are supporting the TextPathAllowed property in XML
+ nPathFlags |= 0x40004;
+ AddOpt( DFF_Prop_fFillOK, nPathFlags );
+ }
+ else
+ nTextPathFlags &=~0x4000;
+ }
+ }
+ else if ( rrProp.Name == "TextPathMode" )
+ {
+ drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
+ if ( rrProp.Value >>= eTextPathMode )
+ {
+ nTextPathFlags |= 0x05000000;
+ nTextPathFlags &=~0x500; // TextPathMode_NORMAL
+ if ( eTextPathMode == drawing::EnhancedCustomShapeTextPathMode_PATH )
+ nTextPathFlags |= 0x100;
+ else if ( eTextPathMode == drawing::EnhancedCustomShapeTextPathMode_SHAPE )
+ nTextPathFlags |= 0x500;
+ }
+ }
+ else if ( rrProp.Name == "ScaleX" )
+ {
+ bool bTextPathScaleX;
+ if ( rrProp.Value >>= bTextPathScaleX )
+ {
+ nTextPathFlags |= 0x00400000;
+ if ( bTextPathScaleX )
+ nTextPathFlags |= 0x40;
+ else
+ nTextPathFlags &=~0x40;
+ }
+ }
+ else if ( rrProp.Name == "SameLetterHeights" )
+ {
+ bool bSameLetterHeights;
+ if ( rrProp.Value >>= bSameLetterHeights )
+ {
+ nTextPathFlags |= 0x00800000;
+ if ( bSameLetterHeights )
+ nTextPathFlags |= 0x80;
+ else
+ nTextPathFlags &=~0x80;
+ }
+ }
+ }
+ if ( nTextPathFlags & 0x4000 ) // Is FontWork ?
+ {
+ // FontWork Text
+ OUString aText;
+ uno::Reference< text::XSimpleText > xText( rXShape, uno::UNO_QUERY );
+ if ( xText.is() )
+ aText = xText->getString();
+ if ( aText.isEmpty() )
+ aText = "your text"; // TODO: moving into a resource
+ AddOpt( DFF_Prop_gtextUNICODE, aText );
+
+ // FontWork Font
+ OUString aFontName;
+ uno::Any aAny = aXPropSet->getPropertyValue( "CharFontName" );
+ aAny >>= aFontName;
+ if ( aFontName.isEmpty() )
+ aFontName = "Arial Black";
+ AddOpt( DFF_Prop_gtextFont, aFontName );
+
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharScaleWidth", true ) )
+ {
+ sal_Int16 nCharScaleWidth = 100;
+ if ( aAny >>= nCharScaleWidth )
+ {
+ if ( nCharScaleWidth != 100 )
+ {
+ sal_Int32 nVal = nCharScaleWidth * 655;
+ AddOpt( DFF_Prop_gtextSpacing, nVal );
+ }
+ }
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharHeight", true ) )
+ {
+ float fCharHeight = 0.0;
+ if ( aAny >>= fCharHeight )
+ {
+ sal_Int32 nTextSize = static_cast< sal_Int32 > ( fCharHeight * 65536 );
+ AddOpt(ESCHER_Prop_gtextSize, nTextSize);
+ }
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharKerning", true ) )
+ {
+ sal_Int16 nCharKerning = sal_Int16();
+ if ( aAny >>= nCharKerning )
+ {
+ nTextPathFlags |= 0x10000000;
+ if ( nCharKerning )
+ nTextPathFlags |= 0x1000;
+ else
+ nTextPathFlags &=~0x1000;
+ }
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharPosture", true ) )
+ {
+ awt::FontSlant eFontSlant;
+ if ( aAny >>= eFontSlant )
+ {
+ nTextPathFlags |= 0x100010;
+ if ( eFontSlant != awt::FontSlant_NONE )
+ nTextPathFlags |= 0x10;
+ else
+ nTextPathFlags &=~0x10;
+ }
+ }
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharWeight", true ) )
+ {
+ float fFontWidth = 0;
+ if ( aAny >>= fFontWidth )
+ {
+ nTextPathFlags |= 0x200020;
+ if ( fFontWidth > awt::FontWeight::NORMAL )
+ nTextPathFlags |= 0x20;
+ else
+ nTextPathFlags &=~0x20;
+ }
+ }
+ // export gTextAlign attr
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "TextHorizontalAdjust", true ) )
+ {
+ MSO_GeoTextAlign gTextAlign = mso_alignTextCenter;
+ drawing::TextHorizontalAdjust eHA( drawing::TextHorizontalAdjust_LEFT );
+ aAny >>= eHA;
+ switch( eHA )
+ {
+ case drawing::TextHorizontalAdjust_LEFT :
+ gTextAlign = mso_alignTextLeft;
+ break;
+ case drawing::TextHorizontalAdjust_CENTER:
+ gTextAlign = mso_alignTextCenter;
+ break;
+ case drawing::TextHorizontalAdjust_RIGHT:
+ gTextAlign = mso_alignTextRight;
+ break;
+ case drawing::TextHorizontalAdjust_BLOCK:
+ {
+ drawing::TextFitToSizeType const eFTS(
+ rSdrObjCustomShape.GetMergedItem( SDRATTR_TEXT_FITTOSIZE ).GetValue() );
+ if (eFTS == drawing::TextFitToSizeType_ALLLINES ||
+ eFTS == drawing::TextFitToSizeType_PROPORTIONAL)
+ {
+ gTextAlign = mso_alignTextStretch;
+ }
+ else
+ {
+ gTextAlign = mso_alignTextWordJust;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ AddOpt(DFF_Prop_gtextAlign,gTextAlign);
+ }
+ }
+ if((nTextPathFlags & 0x4000) != 0) // Is Font work
+ {
+ OutlinerParaObject* pOutlinerParaObject(rSdrObjCustomShape.GetOutlinerParaObject());
+ if ( pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical() )
+ nTextPathFlags |= 0x2000;
+ }
+
+ // Use gtextFStretch for Watermark like MSO does
+ nTextPathFlags |= use_gtextFBestFit | gtextFBestFit
+ | use_gtextFStretch | gtextFStretch
+ | use_gtextFShrinkFit | gtextFShrinkFit;
+
+ if ( nTextPathFlags != nTextPathFlagsOrg )
+ AddOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags );
+ }
+ }
+ else if ( rProp.Name == sHandles )
+ {
+ if ( !bIsDefaultObject )
+ {
+ bPredefinedHandlesUsed = false;
+ if ( rProp.Value >>= aHandlesPropSeq )
+ {
+ sal_uInt16 nElements = static_cast<sal_uInt16>(aHandlesPropSeq.getLength());
+ if ( nElements )
+ {
+ sal_uInt16 k, nElementSize = 36;
+ sal_uInt32 nStreamSize = nElementSize * nElements + 6;
+ SvMemoryStream aMemStrm( nStreamSize );
+ aMemStrm.WriteUInt16( nElements )
+ .WriteUInt16( nElements )
+ .WriteUInt16( nElementSize );
+
+ for ( k = 0; k < nElements; k++ )
+ {
+ sal_uInt32 nFlags = 0;
+ sal_Int32 nXPosition = 0;
+ sal_Int32 nYPosition = 0;
+ sal_Int32 nXMap = 0;
+ sal_Int32 nYMap = 0;
+ sal_Int32 nXRangeMin = 0x80000000;
+ sal_Int32 nXRangeMax = 0x7fffffff;
+ sal_Int32 nYRangeMin = 0x80000000;
+ sal_Int32 nYRangeMax = 0x7fffffff;
+
+ const uno::Sequence< beans::PropertyValue >& rPropSeq = aHandlesPropSeq[ k ];
+ for ( const beans::PropertyValue& rPropVal: rPropSeq )
+ {
+ if ( rPropVal.Name == "Position" )
+ {
+ drawing::EnhancedCustomShapeParameterPair aPosition;
+ if ( rPropVal.Value >>= aPosition )
+ {
+ GetValueForEnhancedCustomShapeHandleParameter( nXPosition, aPosition.First );
+ GetValueForEnhancedCustomShapeHandleParameter( nYPosition, aPosition.Second );
+ }
+ }
+ else if ( rPropVal.Name == "MirroredX" )
+ {
+ bool bMirroredX;
+ if ( rPropVal.Value >>= bMirroredX )
+ {
+ if ( bMirroredX )
+ nFlags |= 1;
+ }
+ }
+ else if ( rPropVal.Name == "MirroredY" )
+ {
+ bool bMirroredY;
+ if ( rPropVal.Value >>= bMirroredY )
+ {
+ if ( bMirroredY )
+ nFlags |= 2;
+ }
+ }
+ else if ( rPropVal.Name == "Switched" )
+ {
+ bool bSwitched;
+ if ( rPropVal.Value >>= bSwitched )
+ {
+ if ( bSwitched )
+ nFlags |= 4;
+ }
+ }
+ else if ( rPropVal.Name == "Polar" )
+ {
+ drawing::EnhancedCustomShapeParameterPair aPolar;
+ if ( rPropVal.Value >>= aPolar )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nXMap, aPolar.First ) )
+ nFlags |= 0x800;
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nYMap, aPolar.Second ) )
+ nFlags |= 0x1000;
+ nFlags |= 8;
+ }
+ }
+ else if ( rPropVal.Name == "RadiusRangeMinimum" )
+ {
+ nYRangeMin = sal_Int32(0xff4c0000); // the range of angles seems to be a not
+ nYRangeMax = sal_Int32(0x00b40000); // used feature, so we are defaulting this
+
+ drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
+ if ( rPropVal.Value >>= aRadiusRangeMinimum )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin, aRadiusRangeMinimum ) )
+ nFlags |= 0x80;
+ nFlags |= 0x2000;
+ }
+ }
+ else if ( rPropVal.Name == "RadiusRangeMaximum" )
+ {
+ nYRangeMin = sal_Int32(0xff4c0000); // the range of angles seems to be a not
+ nYRangeMax = sal_Int32(0x00b40000); // used feature, so we are defaulting this
+
+ drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
+ if ( rPropVal.Value >>= aRadiusRangeMaximum )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax, aRadiusRangeMaximum ) )
+ nFlags |= 0x100;
+ nFlags |= 0x2000;
+ }
+ }
+ else if ( rPropVal.Name == "RangeXMinimum" )
+ {
+ drawing::EnhancedCustomShapeParameter aXRangeMinimum;
+ if ( rPropVal.Value >>= aXRangeMinimum )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin, aXRangeMinimum ) )
+ nFlags |= 0x80;
+ nFlags |= 0x20;
+ }
+ }
+ else if ( rPropVal.Name == "RangeXMaximum" )
+ {
+ drawing::EnhancedCustomShapeParameter aXRangeMaximum;
+ if ( rPropVal.Value >>= aXRangeMaximum )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax, aXRangeMaximum ) )
+ nFlags |= 0x100;
+ nFlags |= 0x20;
+ }
+ }
+ else if ( rPropVal.Name == "RangeYMinimum" )
+ {
+ drawing::EnhancedCustomShapeParameter aYRangeMinimum;
+ if ( rPropVal.Value >>= aYRangeMinimum )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMin, aYRangeMinimum ) )
+ nFlags |= 0x200;
+ nFlags |= 0x20;
+ }
+ }
+ else if ( rPropVal.Name == "RangeYMaximum" )
+ {
+ drawing::EnhancedCustomShapeParameter aYRangeMaximum;
+ if ( rPropVal.Value >>= aYRangeMaximum )
+ {
+ if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMax, aYRangeMaximum ) )
+ nFlags |= 0x400;
+ nFlags |= 0x20;
+ }
+ }
+ }
+ aMemStrm.WriteUInt32( nFlags )
+ .WriteInt32( nXPosition )
+ .WriteInt32( nYPosition )
+ .WriteInt32( nXMap )
+ .WriteInt32( nYMap )
+ .WriteInt32( nXRangeMin )
+ .WriteInt32( nXRangeMax )
+ .WriteInt32( nYRangeMin )
+ .WriteInt32( nYRangeMax );
+
+ if ( nFlags & 8 )
+ nAdjustmentsWhichNeedsToBeConverted |= ( 1 << ( nYPosition - 0x100 ) );
+ }
+
+ AddOpt(DFF_Prop_Handles, true, 6, aMemStrm);
+ }
+ else
+ {
+ AddOpt(DFF_Prop_Handles, 0, true);
+ }
+ }
+ }
+ }
+ else if ( rProp.Name == sAdjustmentValues )
+ {
+ // it is required, that the information which handle is polar has already be read,
+ // so we are able to change the polar value to a fixed float
+ aAdjustmentValuesProp = rProp.Value;
+ bAdjustmentValuesProp = true;
+ }
+ }
+ if ( bAdjustmentValuesProp )
+ {
+ uno::Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentSeq;
+ if ( aAdjustmentValuesProp >>= aAdjustmentSeq )
+ {
+ if ( bPredefinedHandlesUsed )
+ LookForPolarHandles( eShapeType, nAdjustmentsWhichNeedsToBeConverted );
+
+ sal_Int32 k, nValue = 0, nAdjustmentValues = aAdjustmentSeq.getLength();
+ for ( k = 0; k < nAdjustmentValues; k++ )
+ if( GetAdjustmentValue( aAdjustmentSeq[ k ], k, nAdjustmentsWhichNeedsToBeConverted, nValue ) )
+ AddOpt( static_cast<sal_uInt16>( DFF_Prop_adjustValue + k ), static_cast<sal_uInt32>(nValue) );
+ }
+ }
+ if( !bPathCoordinatesProp )
+ return;
+
+ uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
+ if ( !(aPathCoordinatesProp >>= aCoordinates) )
+ return;
+
+ // creating the vertices
+ if (aCoordinates.hasElements())
+ {
+ sal_uInt16 j, nElements = static_cast<sal_uInt16>(aCoordinates.getLength());
+ sal_uInt16 nElementSize = 8;
+ sal_uInt32 nStreamSize = nElementSize * nElements + 6;
+ SvMemoryStream aMemStrm( nStreamSize );
+ aMemStrm.WriteUInt16( nElements )
+ .WriteUInt16( nElements )
+ .WriteUInt16( nElementSize );
+ for( j = 0; j < nElements; j++ )
+ {
+ sal_Int32 X = GetValueForEnhancedCustomShapeParameter( aCoordinates[ j ].First, aEquationOrder, true );
+ sal_Int32 Y = GetValueForEnhancedCustomShapeParameter( aCoordinates[ j ].Second, aEquationOrder, true );
+ aMemStrm.WriteInt32( X )
+ .WriteInt32( Y );
+ }
+
+ AddOpt(DFF_Prop_pVertices, true, 6, aMemStrm); // -6
+ }
+ else
+ {
+ AddOpt(DFF_Prop_pVertices, 0, true);
+ }
+}
+
+MSO_SPT EscherPropertyContainer::GetCustomShapeType( const uno::Reference< drawing::XShape > & rXShape, ShapeFlag& nMirrorFlags, OUString& rShapeType, bool bOOXML )
+{
+ MSO_SPT eShapeType = mso_sptNil;
+ nMirrorFlags = ShapeFlag::NONE;
+ uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
+ if ( aXPropSet.is() )
+ {
+ try
+ {
+ uno::Any aGeoPropSet = aXPropSet->getPropertyValue( "CustomShapeGeometry" );
+ uno::Sequence< beans::PropertyValue > aGeoPropSeq;
+ if ( aGeoPropSet >>= aGeoPropSeq )
+ {
+ sal_Int32 i, nCount = aGeoPropSeq.getLength();
+ for ( i = 0; i < nCount; i++ )
+ {
+ const beans::PropertyValue& rProp = aGeoPropSeq[ i ];
+ if ( rProp.Name == "Type" )
+ {
+ if ( rProp.Value >>= rShapeType )
+ {
+ if (bOOXML)
+ {
+ // In case of VML export, try to handle the
+ // ooxml- prefix in rShapeType. If that fails,
+ // just do the same as the binary export.
+ eShapeType = msfilter::util::GETVMLShapeType(rShapeType);
+ if (eShapeType == mso_sptNil)
+ eShapeType = EnhancedCustomShapeTypeNames::Get(rShapeType);
+ }
+ else
+ eShapeType = EnhancedCustomShapeTypeNames::Get( rShapeType );
+ }
+ }
+ else if ( rProp.Name == "MirroredX" )
+ {
+ bool bMirroredX;
+ if ( ( rProp.Value >>= bMirroredX ) && bMirroredX )
+ nMirrorFlags |= ShapeFlag::FlipH;
+ }
+ else if ( rProp.Name == "MirroredY" )
+ {
+ bool bMirroredY;
+ if ( ( rProp.Value >>= bMirroredY ) && bMirroredY )
+ nMirrorFlags |= ShapeFlag::FlipV;
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ return eShapeType;
+}
+
+
+// Implement for form control export
+bool EscherPropertyContainer::CreateBlipPropertiesforOLEControl(const uno::Reference<beans::XPropertySet> & rXPropSet,
+ const uno::Reference<drawing::XShape> & rXShape)
+{
+ SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rXShape);
+ if ( !pShape )
+ return false;
+
+ const Graphic aGraphic(SdrExchangeView::GetObjGraphic(*pShape));
+ const GraphicObject aGraphicObject(aGraphic);
+
+ if (!aGraphicObject.GetUniqueID().isEmpty())
+ {
+ if ( pGraphicProvider && pPicOutStrm && pShapeBoundRect )
+ {
+ sal_uInt32 nBlibId = pGraphicProvider->GetBlibID(*pPicOutStrm, aGraphicObject);
+ if ( nBlibId )
+ {
+ AddOpt( ESCHER_Prop_pib, nBlibId, true );
+ ImplCreateGraphicAttributes( rXPropSet, nBlibId, false );
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+EscherPersistTable::EscherPersistTable()
+{
+}
+
+EscherPersistTable::~EscherPersistTable()
+{
+}
+
+bool EscherPersistTable::PtIsID( sal_uInt32 nID )
+{
+ for(auto const & pPtr : maPersistTable) {
+ if ( pPtr->mnID == nID ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void EscherPersistTable::PtInsert( sal_uInt32 nID, sal_uInt32 nOfs )
+{
+ maPersistTable.push_back( std::make_unique<EscherPersistEntry>( nID, nOfs ) );
+}
+
+void EscherPersistTable::PtDelete( sal_uInt32 nID )
+{
+ auto it = std::find_if(maPersistTable.begin(), maPersistTable.end(),
+ [&nID](const std::unique_ptr<EscherPersistEntry>& rxEntry) { return rxEntry->mnID == nID; });
+ if (it != maPersistTable.end())
+ maPersistTable.erase( it );
+}
+
+sal_uInt32 EscherPersistTable::PtGetOffsetByID( sal_uInt32 nID )
+{
+ for(auto const & pPtr : maPersistTable) {
+ if ( pPtr->mnID == nID ) {
+ return pPtr->mnOffset;
+ }
+ }
+ return 0;
+};
+
+void EscherPersistTable::PtReplace( sal_uInt32 nID, sal_uInt32 nOfs )
+{
+ for(auto const & pPtr : maPersistTable) {
+ if ( pPtr->mnID == nID ) {
+ pPtr->mnOffset = nOfs;
+ return;
+ }
+ }
+}
+
+void EscherPersistTable::PtReplaceOrInsert( sal_uInt32 nID, sal_uInt32 nOfs )
+{
+ for(auto const & pPtr : maPersistTable) {
+ if ( pPtr->mnID == nID ) {
+ pPtr->mnOffset = nOfs;
+ return;
+ }
+ }
+ PtInsert( nID, nOfs );
+}
+
+bool EscherPropertyValueHelper::GetPropertyValue(
+ uno::Any& rAny,
+ const uno::Reference<beans::XPropertySet> & rXPropSet,
+ const OUString& rString,
+ bool bTestPropertyAvailability)
+{
+ bool bRetValue = true;
+ if ( bTestPropertyAvailability )
+ {
+ bRetValue = false;
+ try
+ {
+ uno::Reference<beans::XPropertySetInfo>
+ aXPropSetInfo( rXPropSet->getPropertySetInfo() );
+ if ( aXPropSetInfo.is() )
+ bRetValue = aXPropSetInfo->hasPropertyByName( rString );
+ }
+ catch( const uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ if ( bRetValue )
+ {
+ try
+ {
+ rAny = rXPropSet->getPropertyValue( rString );
+ if ( !rAny.hasValue() )
+ bRetValue = false;
+ }
+ catch( const uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ return bRetValue;
+}
+
+beans::PropertyState EscherPropertyValueHelper::GetPropertyState(
+ const uno::Reference<beans::XPropertySet> & rXPropSet,
+ const OUString& rPropertyName )
+{
+ beans::PropertyState eRetValue = beans::PropertyState_AMBIGUOUS_VALUE;
+ try
+ {
+ uno::Reference<beans::XPropertyState> aXPropState
+ ( rXPropSet, uno::UNO_QUERY );
+ if ( aXPropState.is() )
+ eRetValue = aXPropState->getPropertyState( rPropertyName );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ return eRetValue;
+}
+
+EscherBlibEntry::EscherBlibEntry( sal_uInt32 nPictureOffset, const GraphicObject& rObject, const OString& rId,
+ const GraphicAttr* pGraphicAttr ) :
+ maPrefMapMode ( rObject.GetPrefMapMode() ),
+ maPrefSize ( rObject.GetPrefSize() ),
+ mnPictureOffset ( nPictureOffset ),
+ mnRefCount ( 1 ),
+ mnSizeExtra ( 0 ),
+ mbIsEmpty ( true )
+{
+ mbIsNativeGraphicPossible = ( pGraphicAttr == nullptr );
+ meBlibType = UNKNOWN;
+ mnSize = 0;
+
+ sal_uInt32 nLen = static_cast<sal_uInt32>(rId.getLength());
+ const char* pData = rId.getStr();
+ GraphicType eType( rObject.GetType() );
+ if (!(nLen && (eType != GraphicType::NONE)))
+ return;
+
+ mnIdentifier[ 0 ] = rtl_crc32( 0,pData, nLen );
+ mnIdentifier[ 1 ] = 0;
+
+ if ( pGraphicAttr )
+ {
+ if ( pGraphicAttr->IsSpecialDrawMode()
+ || pGraphicAttr->IsMirrored()
+ || pGraphicAttr->IsCropped()
+ || pGraphicAttr->IsRotated()
+ || pGraphicAttr->IsTransparent()
+ || pGraphicAttr->IsAdjusted() )
+ {
+ SvMemoryStream aSt( sizeof( GraphicAttr ) );
+ aSt.WriteUInt16( static_cast<sal_uInt16>(pGraphicAttr->GetDrawMode()) )
+ .WriteUInt32( static_cast<sal_uInt32>(pGraphicAttr->GetMirrorFlags()) )
+ .WriteInt32( pGraphicAttr->GetLeftCrop() )
+ .WriteInt32( pGraphicAttr->GetTopCrop() )
+ .WriteInt32( pGraphicAttr->GetRightCrop() )
+ .WriteInt32( pGraphicAttr->GetBottomCrop() )
+ .WriteUInt16( pGraphicAttr->GetRotation().get() )
+ .WriteInt16( pGraphicAttr->GetLuminance() )
+ .WriteInt16( pGraphicAttr->GetContrast() )
+ .WriteInt16( pGraphicAttr->GetChannelR() )
+ .WriteInt16( pGraphicAttr->GetChannelG() )
+ .WriteInt16( pGraphicAttr->GetChannelB() )
+ .WriteDouble( pGraphicAttr->GetGamma() );
+ aSt.WriteBool( pGraphicAttr->IsInvert() )
+ .WriteUChar( 255 - pGraphicAttr->GetAlpha() ); // transparency
+ mnIdentifier[ 1 ] = rtl_crc32( 0, aSt.GetData(), aSt.Tell() );
+ }
+ else
+ mbIsNativeGraphicPossible = true;
+ }
+ sal_uInt32 i, nTmp, n1, n2;
+ n1 = n2 = 0;
+ for ( i = 0; i < nLen; i++ )
+ {
+ nTmp = n2 >> 28; // rotating 4 bit
+ n2 <<= 4;
+ n2 |= n1 >> 28;
+ n1 <<= 4;
+ n1 |= nTmp;
+ n1 ^= *pData++ - '0';
+ }
+ mnIdentifier[ 2 ] = n1;
+ mnIdentifier[ 3 ] = n2;
+ mbIsEmpty = false;
+};
+
+void EscherBlibEntry::WriteBlibEntry( SvStream& rSt, bool bWritePictureOffset, sal_uInt32 nResize )
+{
+ sal_uInt32 nPictureOffset = bWritePictureOffset ? mnPictureOffset : 0;
+
+ rSt.WriteUInt32( ( ESCHER_BSE << 16 ) | ( ( static_cast<sal_uInt16>(meBlibType) << 4 ) | 2 ) )
+ .WriteUInt32( 36 + nResize )
+ .WriteUChar( meBlibType );
+
+ switch ( meBlibType )
+ {
+ case EMF :
+ case WMF : // converting EMF/WMF on OS2 to Pict
+ rSt.WriteUChar( PICT );
+ break;
+ default:
+ rSt.WriteUChar( meBlibType );
+ }
+
+ rSt.WriteBytes(&mnIdentifier[0], 16);
+ rSt.WriteUInt16( 0 )
+ .WriteUInt32( mnSize + mnSizeExtra )
+ .WriteUInt32( mnRefCount )
+ .WriteUInt32( nPictureOffset )
+ .WriteUInt32( 0 );
+}
+
+EscherBlibEntry::~EscherBlibEntry()
+{
+};
+
+bool EscherBlibEntry::operator==( const EscherBlibEntry& rEscherBlibEntry ) const
+{
+ for ( int i = 0; i < 3; i++ )
+ {
+ if ( mnIdentifier[ i ] != rEscherBlibEntry.mnIdentifier[ i ] )
+ return false;
+ }
+ return true;
+}
+
+EscherGraphicProvider::EscherGraphicProvider( EscherGraphicProviderFlags nFlags ) :
+ mnFlags ( nFlags )
+{
+}
+
+EscherGraphicProvider::~EscherGraphicProvider()
+{
+}
+
+void EscherGraphicProvider::SetNewBlipStreamOffset( sal_Int32 nOffset )
+{
+ for( size_t i = 0; i < mvBlibEntrys.size(); i++ )
+ {
+ mvBlibEntrys[ i ]->mnPictureOffset += nOffset;
+ }
+}
+
+sal_uInt32 EscherGraphicProvider::ImplInsertBlib( EscherBlibEntry* p_EscherBlibEntry )
+{
+ mvBlibEntrys.push_back( std::unique_ptr<EscherBlibEntry>(p_EscherBlibEntry) );
+ return mvBlibEntrys.size();
+}
+
+sal_uInt32 EscherGraphicProvider::GetBlibStoreContainerSize( SvStream const * pMergePicStreamBSE ) const
+{
+ sal_uInt32 nSize = 44 * mvBlibEntrys.size() + 8;
+ if ( pMergePicStreamBSE )
+ {
+ for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
+ nSize += mvBlibEntrys[ i ]->mnSize + mvBlibEntrys[ i ]->mnSizeExtra;
+ }
+ return nSize;
+}
+
+void EscherGraphicProvider::WriteBlibStoreEntry(SvStream& rSt,
+ sal_uInt32 nBlipId, sal_uInt32 nResize)
+{
+ if (nBlipId > mvBlibEntrys.size() || nBlipId == 0)
+ return;
+ mvBlibEntrys[nBlipId-1]->WriteBlibEntry(rSt, true/*bWritePictureOffSet*/, nResize);
+}
+
+void EscherGraphicProvider::WriteBlibStoreContainer( SvStream& rSt, SvStream* pMergePicStreamBSE )
+{
+ sal_uInt32 nSize = GetBlibStoreContainerSize( pMergePicStreamBSE );
+ if ( !nSize )
+ return;
+
+ rSt.WriteUInt32( ( ESCHER_BstoreContainer << 16 ) | 0x1f )
+ .WriteUInt32( nSize - 8 );
+
+ if ( pMergePicStreamBSE )
+ {
+ sal_uInt32 nBlipSize, nOldPos = pMergePicStreamBSE->Tell();
+ const sal_uInt32 nBuf = 0x40000; // 256KB buffer
+ std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ nBuf ]);
+
+ for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
+ {
+ EscherBlibEntry* pBlibEntry = mvBlibEntrys[ i ].get();
+
+ ESCHER_BlibType nBlibType = pBlibEntry->meBlibType;
+ nBlipSize = pBlibEntry->mnSize + pBlibEntry->mnSizeExtra;
+ pBlibEntry->WriteBlibEntry( rSt, false, nBlipSize );
+
+ // BLIP
+ pMergePicStreamBSE->Seek( pBlibEntry->mnPictureOffset );
+ sal_uInt16 n16;
+ // record version and instance
+ pMergePicStreamBSE->ReadUInt16( n16 );
+ rSt.WriteUInt16( n16 );
+ // record type
+ pMergePicStreamBSE->ReadUInt16( n16 );
+ rSt.WriteUInt16( ESCHER_BlipFirst + nBlibType );
+ DBG_ASSERT( n16 == ESCHER_BlipFirst + nBlibType , "EscherGraphicProvider::WriteBlibStoreContainer: BLIP record types differ" );
+ sal_uInt32 n32;
+ // record size
+ pMergePicStreamBSE->ReadUInt32( n32 );
+ nBlipSize -= 8;
+ rSt.WriteUInt32( nBlipSize );
+ DBG_ASSERT( nBlipSize == n32, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP sizes differ" );
+ // record
+ while ( nBlipSize )
+ {
+ sal_uInt32 nBytes = std::min( nBlipSize, nBuf );
+ pMergePicStreamBSE->ReadBytes(pBuf.get(), nBytes);
+ rSt.WriteBytes(pBuf.get(), nBytes);
+ nBlipSize -= nBytes;
+ }
+ }
+ pMergePicStreamBSE->Seek( nOldPos );
+ }
+ else
+ {
+ for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
+ mvBlibEntrys[ i ]->WriteBlibEntry( rSt, true );
+ }
+}
+
+bool EscherGraphicProvider::GetPrefSize( const sal_uInt32 nBlibId, Size& rPrefSize, MapMode& rPrefMapMode )
+{
+ bool bInRange = nBlibId && ( ( nBlibId - 1 ) < mvBlibEntrys.size() );
+ if ( bInRange )
+ {
+ EscherBlibEntry* pEntry = mvBlibEntrys[ nBlibId - 1 ].get();
+ rPrefSize = pEntry->maPrefSize;
+ rPrefMapMode = pEntry->maPrefMapMode;
+ }
+ return bInRange;
+}
+
+sal_uInt32 EscherGraphicProvider::GetBlibID( SvStream& rPicOutStrm, GraphicObject const & rGraphicObject,
+ const awt::Rectangle* pVisArea,
+ const GraphicAttr* pGraphicAttr, const bool bOOxmlExport )
+{
+ sal_uInt32 nBlibId = 0;
+
+ std::unique_ptr<EscherBlibEntry> p_EscherBlibEntry( new EscherBlibEntry( rPicOutStrm.Tell(), rGraphicObject, rGraphicObject.GetUniqueID(), pGraphicAttr ) );
+ if ( !p_EscherBlibEntry->IsEmpty() )
+ {
+ for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
+ {
+ if ( *( mvBlibEntrys[ i ] ) == *p_EscherBlibEntry )
+ {
+ mvBlibEntrys[ i ]->mnRefCount++;
+ return i + 1;
+ }
+ }
+
+ bool bUseNativeGraphic( false );
+
+ Graphic aGraphic(rGraphicObject.GetTransformedGraphic(pGraphicAttr));
+ GfxLink aGraphicLink;
+ SvMemoryStream aStream;
+
+ const sal_uInt8* pGraphicAry = nullptr;
+
+ if ( p_EscherBlibEntry->mbIsNativeGraphicPossible && aGraphic.IsGfxLink() )
+ {
+ aGraphicLink = aGraphic.GetGfxLink();
+
+ p_EscherBlibEntry->mnSize = aGraphicLink.GetDataSize();
+ pGraphicAry = aGraphicLink.GetData();
+
+ if ( p_EscherBlibEntry->mnSize && pGraphicAry )
+ {
+ switch ( aGraphicLink.GetType() )
+ {
+ case GfxLinkType::NativeJpg : p_EscherBlibEntry->meBlibType = PEG; break;
+ case GfxLinkType::NativePng : p_EscherBlibEntry->meBlibType = PNG; break;
+
+ // #i15508# added BMP type for better exports; need to check this
+ // checked - does not work that way, so keep out for now. It may
+ // work somehow with direct DIB data, but that would need to be checked
+ // carefully
+ // for more comments please check RtfAttributeOutput::FlyFrameGraphic
+ //
+ // case GfxLinkType::NativeBmp : p_EscherBlibEntry->meBlibType = DIB; break;
+
+ case GfxLinkType::NativeWmf :
+ {
+ if ( aGraphicLink.IsEMF() )
+ {
+ p_EscherBlibEntry->meBlibType = EMF;
+ }
+ else if ( pGraphicAry && ( p_EscherBlibEntry->mnSize > 0x2c ) )
+ {
+ p_EscherBlibEntry->meBlibType = WMF;
+ if ( ( pGraphicAry[ 0 ] == 0xd7 ) && ( pGraphicAry[ 1 ] == 0xcd )
+ && ( pGraphicAry[ 2 ] == 0xc6 ) && ( pGraphicAry[ 3 ] == 0x9a ) )
+ { // we have to get rid of the metafileheader
+ pGraphicAry += 22;
+ p_EscherBlibEntry->mnSize -= 22;
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+ if ( p_EscherBlibEntry->meBlibType != UNKNOWN )
+ bUseNativeGraphic = true;
+ }
+ }
+ if ( !bUseNativeGraphic )
+ {
+ GraphicType eGraphicType = aGraphic.GetType();
+ if ( ( eGraphicType == GraphicType::Bitmap ) || ( eGraphicType == GraphicType::GdiMetafile ) )
+ {
+ ErrCode nErrCode;
+ if ( !aGraphic.IsAnimated() )
+ nErrCode = GraphicConverter::Export( aStream, aGraphic, ( eGraphicType == GraphicType::Bitmap ) ? ConvertDataFormat::PNG : ConvertDataFormat::EMF );
+ else
+ { // to store an animation, a gif has to be included into the msOG chunk of a png #I5583#
+ GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
+ SvMemoryStream aGIFStream;
+ const char* const pString = "MSOFFICE9.0";
+ aGIFStream.WriteBytes(pString, strlen(pString));
+ nErrCode = rFilter.ExportGraphic( aGraphic, u"", aGIFStream,
+ rFilter.GetExportFormatNumberForShortName( u"GIF" ) );
+ SAL_WARN_IF(
+ nErrCode != ERRCODE_NONE, "filter.ms",
+ "ExportGraphic to GIF failed with " << nErrCode);
+ if (nErrCode == ERRCODE_NONE)
+ {
+ sal_uInt32 nGIFSreamLen = aGIFStream.Tell();
+ uno::Sequence<sal_Int8> aGIFSeq( nGIFSreamLen );
+ sal_Int8* pSeq = aGIFSeq.getArray();
+ aGIFStream.Seek( STREAM_SEEK_TO_BEGIN );
+ aGIFStream.ReadBytes(pSeq, nGIFSreamLen);
+ beans::PropertyValue aChunkProp, aFilterProp;
+ aChunkProp.Name = "msOG";
+ aChunkProp.Value <<= aGIFSeq;
+ uno::Sequence<beans::PropertyValue> aAdditionalChunkSequence{ aChunkProp };
+ aFilterProp.Name = "AdditionalChunks";
+ aFilterProp.Value <<= aAdditionalChunkSequence;
+ uno::Sequence<beans::PropertyValue> aFilterData{ aFilterProp };
+ nErrCode = rFilter.ExportGraphic( aGraphic, u"", aStream,
+ rFilter.GetExportFormatNumberForShortName( u"PNG" ), &aFilterData );
+ }
+ }
+ if ( nErrCode == ERRCODE_NONE )
+ {
+ p_EscherBlibEntry->meBlibType = ( eGraphicType == GraphicType::Bitmap ) ? PNG : EMF;
+ p_EscherBlibEntry->mnSize = aStream.TellEnd();
+ pGraphicAry = static_cast<sal_uInt8 const *>(aStream.GetData());
+ }
+ }
+ }
+
+ ESCHER_BlibType eBlibType = p_EscherBlibEntry->meBlibType;
+ if ( p_EscherBlibEntry->mnSize && pGraphicAry && ( eBlibType != UNKNOWN ) )
+ {
+ sal_uInt32 nExtra, nAtomSize = 0;
+ sal_uInt32 nInstance, nUncompressedSize = p_EscherBlibEntry->mnSize;
+
+ if ( mnFlags & EscherGraphicProviderFlags::UseInstances )
+ {
+ rPicOutStrm.WriteUInt32( 0x7f90000 | static_cast<sal_uInt16>( mvBlibEntrys.size() << 4 ) )
+ .WriteUInt32( 0 );
+ nAtomSize = rPicOutStrm.Tell();
+ if ( eBlibType == PNG )
+ rPicOutStrm.WriteUInt16( 0x0606 );
+ else if ( eBlibType == WMF )
+ rPicOutStrm.WriteUInt16( 0x0403 );
+ else if ( eBlibType == EMF )
+ rPicOutStrm.WriteUInt16( 0x0402 );
+ else if ( eBlibType == PEG )
+ rPicOutStrm.WriteUInt16( 0x0505 );
+ }
+
+ // fdo#69607 do not compress WMF files if we are in OOXML export
+ if ( ( eBlibType == PEG ) || ( eBlibType == PNG ) // || ( eBlibType == DIB )) // #i15508#
+ || ( ( ( eBlibType == WMF ) || ( eBlibType == EMF ) ) && bOOxmlExport ) )
+ {
+ nExtra = 17;
+ p_EscherBlibEntry->mnSizeExtra = nExtra + 8;
+
+ // #i15508# type see SvxMSDffManager::GetBLIPDirect (checked, does not work this way)
+ // see RtfAttributeOutput::FlyFrameGraphic for more comments
+ // maybe it would work with direct DIB data, but that would need thorough testing
+ if( eBlibType == PNG )
+ {
+ nInstance = 0xf01e6e00;
+ }
+ else // if( eBlibType == PEG )
+ {
+ nInstance = 0xf01d46a0;
+ }
+ //else // eBlibType == DIB
+ //{
+ // nInstance = 0xf01d7A80;
+ //}
+
+ // #i15508#
+ //nInstance = ( eBlibType == PNG ) ? 0xf01e6e00 : 0xf01d46a0;
+
+
+ rPicOutStrm.WriteUInt32( nInstance ).WriteUInt32( p_EscherBlibEntry->mnSize + nExtra );
+ rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16);
+ rPicOutStrm.WriteUChar( 0xff );
+ rPicOutStrm.WriteBytes(pGraphicAry, p_EscherBlibEntry->mnSize);
+ }
+ else
+ {
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression();
+ SvMemoryStream aDestStrm;
+ aZCodec.Write( aDestStrm, pGraphicAry, p_EscherBlibEntry->mnSize );
+ aZCodec.EndCompression();
+ p_EscherBlibEntry->mnSize = aDestStrm.TellEnd();
+ pGraphicAry = static_cast<sal_uInt8 const *>(aDestStrm.GetData());
+ if ( p_EscherBlibEntry->mnSize && pGraphicAry )
+ {
+ nExtra = eBlibType == WMF ? 0x42 : 0x32; // !EMF -> no change
+ p_EscherBlibEntry->mnSizeExtra = nExtra + 8;
+ nInstance = ( eBlibType == WMF ) ? 0xf01b2170 : 0xf01a3d40; // !EMF -> no change
+ rPicOutStrm.WriteUInt32( nInstance ).WriteUInt32( p_EscherBlibEntry->mnSize + nExtra );
+ if ( eBlibType == WMF ) // !EMF -> no change
+ rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16);
+ rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16);
+
+ /*
+ ##913##
+ For Word the stored size of the graphic is critical the
+ metafile boundaries must match the actual graphics
+ boundaries, and the width and height must be in EMU's
+
+ If you don't do it this way then objects edited in the
+ msoffice app may show strange behaviour as the size jumps
+ around, and the original size and scaling factor in word
+ will be a very strange figure
+ */
+ sal_uInt32 nPrefWidth = p_EscherBlibEntry->maPrefSize.Width();
+ sal_uInt32 nPrefHeight = p_EscherBlibEntry->maPrefSize.Height();
+ sal_uInt32 nWidth, nHeight;
+ if ( pVisArea )
+ {
+ nWidth = pVisArea->Width * 360;
+ nHeight = pVisArea->Height * 360;
+ }
+ else
+ {
+ Size aPrefSize(lcl_SizeToEmu(p_EscherBlibEntry->maPrefSize, p_EscherBlibEntry->maPrefMapMode));
+ nWidth = aPrefSize.Width() * 360;
+ nHeight = aPrefSize.Height() * 360;
+ }
+ rPicOutStrm.WriteUInt32( nUncompressedSize ) // WMFSize without FileHeader
+ .WriteInt32( 0 ) // since we can't find out anymore what the original size of
+ .WriteInt32( 0 ) // the WMF (without Fileheader) was we write 10cm / x
+ .WriteUInt32( nPrefWidth )
+ .WriteUInt32( nPrefHeight )
+ .WriteUInt32( nWidth )
+ .WriteUInt32( nHeight )
+ .WriteUInt32( p_EscherBlibEntry->mnSize )
+ .WriteUInt16( 0xfe00 ); // compression Flags
+ rPicOutStrm.WriteBytes(pGraphicAry, p_EscherBlibEntry->mnSize);
+ }
+ }
+ if ( nAtomSize )
+ {
+ sal_uInt32 nPos = rPicOutStrm.Tell();
+ rPicOutStrm.Seek( nAtomSize - 4 );
+ rPicOutStrm.WriteUInt32( nPos - nAtomSize );
+ rPicOutStrm.Seek( nPos );
+ }
+ nBlibId = ImplInsertBlib( p_EscherBlibEntry.release() );
+ }
+ }
+ return nBlibId;
+}
+
+namespace {
+
+struct EscherConnectorRule
+{
+ sal_uInt32 nRuleId;
+ sal_uInt32 nShapeA; // SPID of shape A
+ sal_uInt32 nShapeB; // SPID of shape B
+ sal_uInt32 nShapeC; // SPID of connector shape
+ sal_uInt32 ncptiA; // Connection site Index of shape A
+ sal_uInt32 ncptiB; // Connection site Index of shape B
+};
+
+}
+
+struct EscherShapeListEntry
+{
+ uno::Reference<drawing::XShape>aXShape;
+ sal_uInt32 n_EscherId;
+
+ EscherShapeListEntry(uno::Reference<drawing::XShape> xShape, sal_uInt32 nId)
+ : aXShape(std::move(xShape))
+ , n_EscherId(nId)
+ {}
+};
+
+sal_uInt32 EscherConnectorListEntry::GetClosestPoint( const tools::Polygon& rPoly, const awt::Point& rPoint )
+{
+ sal_uInt16 nCount = rPoly.GetSize();
+ sal_uInt16 nClosest = nCount;
+ double fDist = sal_uInt32(0xffffffff);
+ while( nCount-- )
+ {
+ double fDistance = hypot( rPoint.X - rPoly[ nCount ].X(), rPoint.Y - rPoly[ nCount ].Y() );
+ if ( fDistance < fDist )
+ {
+ nClosest = nCount;
+ fDist = fDistance;
+ }
+ }
+ return nClosest;
+};
+
+
+// for rectangles for ellipses for polygons
+//
+// nRule = 0 ->Top 0 ->Top nRule = index to a (Poly)Polygon point
+// 1 ->Left 2 ->Left
+// 2 ->Bottom 4 ->Bottom
+// 3 ->Right 6 ->Right
+
+sal_uInt32 EscherConnectorListEntry::GetConnectorRule( bool bFirst )
+{
+ sal_uInt32 nRule = 0;
+
+ uno::Any aAny;
+ awt::Point aRefPoint( bFirst ? maPointA : maPointB );
+ uno::Reference<drawing::XShape>
+ aXShape( bFirst ? mXConnectToA : mXConnectToB );
+
+ OUString aString(aXShape->getShapeType());
+ OStringBuffer aBuf(OUStringToOString(aString, RTL_TEXTENCODING_UTF8));
+ aBuf.remove( 0, 13 ); // removing "com.sun.star."
+ sal_Int16 nPos = aBuf.toString().indexOf("Shape");
+ aBuf.remove(nPos, 5);
+ OString aType = aBuf.makeStringAndClear();
+
+ uno::Reference<beans::XPropertySet>
+ aPropertySet( aXShape, uno::UNO_QUERY );
+
+ if ((aType == "drawing.PolyPolygon") || (aType == "drawing.PolyLine"))
+ {
+ if ( aPropertySet.is() )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet, "PolyPolygon" ) )
+ {
+ auto pSourcePolyPolygon =
+ o3tl::doAccess<drawing::PointSequenceSequence>(aAny);
+ sal_Int32 nOuterSequenceCount = pSourcePolyPolygon->getLength();
+ drawing::PointSequence const * pOuterSequence = pSourcePolyPolygon->getConstArray();
+
+ if ( pOuterSequence )
+ {
+ sal_Int32 a, b, nIndex = 0;
+ sal_uInt32 nDistance = 0xffffffff;
+ for( a = 0; a < nOuterSequenceCount; a++ )
+ {
+ drawing::PointSequence const * pInnerSequence = pOuterSequence++;
+ if ( pInnerSequence )
+ {
+ awt::Point const * pArray = pInnerSequence->getConstArray();
+ if ( pArray )
+ {
+ for ( b = 0; b < pInnerSequence->getLength(); b++, nIndex++, pArray++ )
+ {
+ sal_uInt32 nDist = static_cast<sal_uInt32>(hypot( aRefPoint.X - pArray->X, aRefPoint.Y - pArray->Y ));
+ if ( nDist < nDistance )
+ {
+ nRule = nIndex;
+ nDistance = nDist;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ((aType == "drawing.OpenBezier") || (aType == "drawing.OpenFreeHand") || (aType == "drawing.PolyLinePath")
+ || (aType == "drawing.ClosedBezier") || ( aType == "drawing.ClosedFreeHand") || (aType == "drawing.PolyPolygonPath") )
+ {
+ uno::Reference<beans::XPropertySet>
+ aPropertySet2( aXShape, uno::UNO_QUERY );
+ if ( aPropertySet2.is() )
+ {
+ if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet2, "PolyPolygonBezier" ) )
+ {
+ auto pSourcePolyPolygon =
+ o3tl::doAccess<drawing::PolyPolygonBezierCoords>(aAny);
+ sal_Int32 nOuterSequenceCount = pSourcePolyPolygon->Coordinates.getLength();
+
+ // get pointer of inner sequences
+ drawing::PointSequence const * pOuterSequence =
+ pSourcePolyPolygon->Coordinates.getConstArray();
+ drawing::FlagSequence const * pOuterFlags =
+ pSourcePolyPolygon->Flags.getConstArray();
+
+ if ( pOuterSequence && pOuterFlags )
+ {
+ sal_Int32 a, b, nIndex = 0;
+ sal_uInt32 nDistance = 0xffffffff;
+
+ for ( a = 0; a < nOuterSequenceCount; a++ )
+ {
+ drawing::PointSequence const * pInnerSequence = pOuterSequence++;
+ drawing::FlagSequence const * pInnerFlags = pOuterFlags++;
+ if ( pInnerSequence && pInnerFlags )
+ {
+ awt::Point const * pArray = pInnerSequence->getConstArray();
+ drawing::PolygonFlags const * pFlags = pInnerFlags->getConstArray();
+ if ( pArray && pFlags )
+ {
+ for ( b = 0; b < pInnerSequence->getLength(); b++, pArray++ )
+ {
+ drawing::PolygonFlags ePolyFlags = *pFlags++;
+ if ( ePolyFlags == drawing::PolygonFlags_CONTROL )
+ continue;
+ sal_uInt32 nDist = static_cast<sal_uInt32>(hypot( aRefPoint.X - pArray->X, aRefPoint.Y - pArray->Y ));
+ if ( nDist < nDistance )
+ {
+ nRule = nIndex;
+ nDistance = nDist;
+ }
+ nIndex++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ bool bRectangularConnection = true;
+
+ if (aType == "drawing.Custom")
+ {
+ if (auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(aXShape)))
+ {
+ const SdrCustomShapeGeometryItem& rGeometryItem =
+ pSdrObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+
+ OUString sShapeType;
+ const uno::Any* pType = rGeometryItem.GetPropertyValueByName( "Type" );
+ if ( pType )
+ *pType >>= sShapeType;
+ MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
+
+ uno::Any* pGluePointType = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( "Path", "GluePointType" );
+
+ sal_Int16 nGluePointType = sal_Int16();
+ if ( !( pGluePointType &&
+ ( *pGluePointType >>= nGluePointType ) ) )
+ nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType );
+
+ if ( nGluePointType == drawing::EnhancedCustomShapeGluePointType::CUSTOM )
+ {
+ const SdrGluePointList* pList = pSdrObjCustomShape->GetGluePointList();
+ if ( pList )
+ {
+ tools::Polygon aPoly;
+ sal_uInt16 nNum, nCnt = pList->GetCount();
+ if ( nCnt )
+ {
+ for ( nNum = 0; nNum < nCnt; nNum++ )
+ {
+ const SdrGluePoint& rGP = (*pList)[ nNum ];
+ Point aPt(rGP.GetAbsolutePos(*pSdrObjCustomShape));
+ aPoly.Insert( POLY_APPEND, aPt );
+ }
+ nRule = GetClosestPoint( aPoly, aRefPoint );
+ bRectangularConnection = false;
+ }
+ }
+ }
+ else if ( nGluePointType == drawing::EnhancedCustomShapeGluePointType::SEGMENTS )
+ {
+ tools::PolyPolygon aPolyPoly;
+ SdrObjectUniquePtr pTemporaryConvertResultObject(pSdrObjCustomShape->DoConvertToPolyObj(true, true));
+ SdrPathObj* pSdrPathObj(dynamic_cast< SdrPathObj* >(pTemporaryConvertResultObject.get()));
+
+ if(pSdrPathObj)
+ {
+ // #i74631# use explicit constructor here. Also XPolyPolygon is not necessary,
+ // reducing to PolyPolygon
+ aPolyPoly = tools::PolyPolygon(pSdrPathObj->GetPathPoly());
+ }
+
+ // do *not* forget to delete the temporary used SdrObject - possible memory leak (!)
+ pTemporaryConvertResultObject.reset();
+ pSdrPathObj = nullptr;
+
+ if(0 != aPolyPoly.Count())
+ {
+ sal_Int16 nIndex = 0;
+ sal_uInt16 a, b;
+ sal_uInt32 nDistance = 0xffffffff;
+
+ for ( a = 0; a < aPolyPoly.Count(); a++ )
+ {
+ const tools::Polygon& rPoly = aPolyPoly.GetObject( a );
+ for ( b = 0; b < rPoly.GetSize(); b++ )
+ {
+ if ( rPoly.GetFlags( b ) != PolyFlags::Normal )
+ continue;
+ const Point& rPt = rPoly[ b ];
+ sal_uInt32 nDist = static_cast<sal_uInt32>(hypot( aRefPoint.X - rPt.X(), aRefPoint.Y - rPt.Y() ));
+ if ( nDist < nDistance )
+ {
+ nRule = nIndex;
+ nDistance = nDist;
+ }
+ nIndex++;
+ }
+ }
+
+ if ( nDistance != 0xffffffff )
+ bRectangularConnection = false;
+ }
+ }
+ }
+ }
+ if ( bRectangularConnection )
+ {
+ awt::Point aPoint( aXShape->getPosition() );
+ awt::Size aSize( aXShape->getSize() );
+
+ tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
+ Point aCenter( aRect.Center() );
+ tools::Polygon aPoly( 4 );
+
+ aPoly[ 0 ] = Point( aCenter.X(), aRect.Top() );
+ aPoly[ 1 ] = Point( aRect.Left(), aCenter.Y() );
+ aPoly[ 2 ] = Point( aCenter.X(), aRect.Bottom() );
+ aPoly[ 3 ] = Point( aRect.Right(), aCenter.Y() );
+
+ sal_Int32 nAngle = ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet, "RotateAngle", true ) )
+ ? *o3tl::doAccess<sal_Int32>(aAny) : 0;
+ if ( nAngle )
+ aPoly.Rotate( aRect.TopLeft(), Degree10(static_cast<sal_Int16>( ( nAngle + 5 ) / 10 )) );
+ nRule = GetClosestPoint( aPoly, aRefPoint );
+
+ if (aType == "drawing.Ellipse")
+ nRule <<= 1; // In PPT an ellipse has 8 ways to connect
+ }
+ }
+ return nRule;
+}
+
+EscherSolverContainer::EscherSolverContainer()
+{
+}
+
+EscherSolverContainer::~EscherSolverContainer()
+{
+}
+
+void EscherSolverContainer::AddShape( const uno::Reference<drawing::XShape> & rXShape, sal_uInt32 nId )
+{
+ maShapeList.push_back( std::make_unique<EscherShapeListEntry>( rXShape, nId ) );
+}
+
+void EscherSolverContainer::AddConnector(
+ const uno::Reference<drawing::XShape> & rConnector,
+ const awt::Point& rPA,
+ uno::Reference<drawing::XShape> const & rConA,
+ const awt::Point& rPB,
+ uno::Reference<drawing::XShape> const & rConB
+)
+{
+ maConnectorList.push_back( std::make_unique<EscherConnectorListEntry>( rConnector, rPA, rConA, rPB, rConB ) );
+}
+
+sal_uInt32 EscherSolverContainer::GetShapeId( const uno::Reference<drawing::XShape> & rXShape ) const
+{
+ for (auto const & pPtr : maShapeList)
+ {
+ if ( rXShape == pPtr->aXShape )
+ return pPtr->n_EscherId;
+ }
+ return 0;
+}
+
+void EscherSolverContainer::WriteSolver( SvStream& rStrm )
+{
+ sal_uInt32 nCount = maConnectorList.size();
+ if ( !nCount )
+ return;
+
+ sal_uInt32 nRecHdPos, nCurrentPos, nSize;
+ rStrm .WriteUInt16( ( nCount << 4 ) | 0xf ) // open an ESCHER_SolverContainer
+ .WriteUInt16( ESCHER_SolverContainer )
+ .WriteUInt32( 0 );
+
+ nRecHdPos = rStrm.Tell() - 4;
+
+ EscherConnectorRule aConnectorRule;
+ aConnectorRule.nRuleId = 2;
+ for (auto const & pPtr : maConnectorList)
+ {
+ aConnectorRule.ncptiA = aConnectorRule.ncptiB = 0xffffffff;
+ aConnectorRule.nShapeC = GetShapeId( pPtr->mXConnector );
+ aConnectorRule.nShapeA = GetShapeId( pPtr->mXConnectToA );
+ aConnectorRule.nShapeB = GetShapeId( pPtr->mXConnectToB );
+
+ if ( aConnectorRule.nShapeC )
+ {
+ if ( aConnectorRule.nShapeA )
+ aConnectorRule.ncptiA = pPtr->GetConnectorRule( true );
+ if ( aConnectorRule.nShapeB )
+ aConnectorRule.ncptiB = pPtr->GetConnectorRule( false );
+ }
+ rStrm .WriteUInt32( ( ESCHER_ConnectorRule << 16 ) | 1 ) // atom hd
+ .WriteUInt32( 24 )
+ .WriteUInt32( aConnectorRule.nRuleId )
+ .WriteUInt32( aConnectorRule.nShapeA )
+ .WriteUInt32( aConnectorRule.nShapeB )
+ .WriteUInt32( aConnectorRule.nShapeC )
+ .WriteUInt32( aConnectorRule.ncptiA )
+ .WriteUInt32( aConnectorRule.ncptiB );
+
+ aConnectorRule.nRuleId += 2;
+ }
+
+ nCurrentPos = rStrm.Tell(); // close the ESCHER_SolverContainer
+ nSize = ( nCurrentPos - nRecHdPos ) - 4;
+ rStrm.Seek( nRecHdPos );
+ rStrm.WriteUInt32( nSize );
+ rStrm.Seek( nCurrentPos );
+}
+
+EscherExGlobal::EscherExGlobal() :
+ EscherGraphicProvider( EscherGraphicProviderFlags::NONE ),
+ mpPicStrm( nullptr ),
+ mbHasDggCont( false ),
+ mbPicStrmQueried( false )
+{
+}
+
+EscherExGlobal::~EscherExGlobal()
+{
+}
+
+sal_uInt32 EscherExGlobal::GenerateDrawingId()
+{
+ // new drawing starts a new cluster in the cluster table (cluster identifiers are one-based)
+ sal_uInt32 nClusterId = static_cast< sal_uInt32 >( maClusterTable.size() + 1 );
+ // drawing identifiers are one-based
+ sal_uInt32 nDrawingId = static_cast< sal_uInt32 >( maDrawingInfos.size() + 1 );
+ // prepare new entries in the tables
+ maClusterTable.emplace_back( nDrawingId );
+ maDrawingInfos.emplace_back( nClusterId );
+ // return the new drawing identifier
+ return nDrawingId;
+}
+
+sal_uInt32 EscherExGlobal::GenerateShapeId( sal_uInt32 nDrawingId, bool bIsInSpgr )
+{
+ // drawing identifier is one-based
+ // make sure the drawing is valid (bnc#656503)
+ if ( nDrawingId == 0 )
+ return 0;
+ // create index from the identifier
+ size_t nDrawingIdx = nDrawingId - 1;
+ OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GenerateShapeId - invalid drawing ID" );
+ if( nDrawingIdx >= maDrawingInfos.size() )
+ return 0;
+ DrawingInfo& rDrawingInfo = maDrawingInfos[ nDrawingIdx ];
+
+ // cluster identifier in drawing info struct is one-based
+ ClusterEntry* pClusterEntry = &maClusterTable[ rDrawingInfo.mnClusterId - 1 ];
+
+ // check cluster overflow, create new cluster entry
+ if( pClusterEntry->mnNextShapeId == DFF_DGG_CLUSTER_SIZE )
+ {
+ // start a new cluster in the cluster table
+ maClusterTable.emplace_back( nDrawingId );
+ pClusterEntry = &maClusterTable.back();
+ // new size of maClusterTable is equal to one-based identifier of the new cluster
+ rDrawingInfo.mnClusterId = static_cast< sal_uInt32 >( maClusterTable.size() );
+ }
+
+ // build shape identifier from cluster identifier and next free cluster shape identifier
+ rDrawingInfo.mnLastShapeId = static_cast< sal_uInt32 >( rDrawingInfo.mnClusterId * DFF_DGG_CLUSTER_SIZE + pClusterEntry->mnNextShapeId );
+ // update free shape identifier in cluster entry
+ ++pClusterEntry->mnNextShapeId;
+ /* Old code has counted the shapes only, if we are in a SPGRCONTAINER. Is
+ this really intended? Maybe it's always true... */
+ if( bIsInSpgr )
+ ++rDrawingInfo.mnShapeCount;
+
+ // return the new shape identifier
+ return rDrawingInfo.mnLastShapeId;
+}
+
+sal_uInt32 EscherExGlobal::GetDrawingShapeCount( sal_uInt32 nDrawingId ) const
+{
+ size_t nDrawingIdx = nDrawingId - 1;
+ OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GetDrawingShapeCount - invalid drawing ID" );
+ return (nDrawingIdx < maDrawingInfos.size()) ? maDrawingInfos[ nDrawingIdx ].mnShapeCount : 0;
+}
+
+sal_uInt32 EscherExGlobal::GetLastShapeId( sal_uInt32 nDrawingId ) const
+{
+ size_t nDrawingIdx = nDrawingId - 1;
+ OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GetLastShapeId - invalid drawing ID" );
+ return (nDrawingIdx < maDrawingInfos.size()) ? maDrawingInfos[ nDrawingIdx ].mnLastShapeId : 0;
+}
+
+sal_uInt32 EscherExGlobal::GetDggAtomSize() const
+{
+ // 8 bytes header, 16 bytes fixed DGG data, 8 bytes for each cluster
+ return static_cast< sal_uInt32 >( 24 + 8 * maClusterTable.size() );
+}
+
+void EscherExGlobal::WriteDggAtom( SvStream& rStrm ) const
+{
+ sal_uInt32 nDggSize = GetDggAtomSize();
+
+ // write the DGG record header (do not include the 8 bytes of the header in the data size)
+ rStrm.WriteUInt32( ESCHER_Dgg << 16 ).WriteUInt32( nDggSize - 8 );
+
+ // calculate and write the fixed DGG data
+ sal_uInt32 nShapeCount = 0;
+ sal_uInt32 nLastShapeId = 0;
+ for (auto const& drawingInfo : maDrawingInfos)
+ {
+ nShapeCount += drawingInfo.mnShapeCount;
+ nLastShapeId = ::std::max( nLastShapeId, drawingInfo.mnLastShapeId );
+ }
+ // the non-existing cluster with index #0 is counted too
+ sal_uInt32 nClusterCount = static_cast< sal_uInt32 >( maClusterTable.size() + 1 );
+ sal_uInt32 nDrawingCount = static_cast< sal_uInt32 >( maDrawingInfos.size() );
+ rStrm.WriteUInt32( nLastShapeId ).WriteUInt32( nClusterCount ).WriteUInt32( nShapeCount ).WriteUInt32( nDrawingCount );
+
+ // write the cluster table
+ for (auto const& elem : maClusterTable)
+ rStrm.WriteUInt32( elem.mnDrawingId ).WriteUInt32( elem.mnNextShapeId );
+}
+
+SvStream* EscherExGlobal::QueryPictureStream()
+{
+ if( !mbPicStrmQueried )
+ {
+ mpPicStrm = ImplQueryPictureStream();
+ mbPicStrmQueried = true;
+ }
+ return mpPicStrm;
+}
+
+SvStream* EscherExGlobal::ImplQueryPictureStream()
+{
+ return nullptr;
+}
+
+namespace {
+
+// Implementation of an empty stream that silently succeeds, but does nothing.
+//
+// In fact, this is a hack. The right solution is to abstract EscherEx to be
+// able to work without SvStream; but at the moment it is better to live with
+// this I guess.
+class SvNullStream : public SvStream
+{
+protected:
+ virtual std::size_t GetData( void* pData, std::size_t nSize ) override { memset( pData, 0, nSize ); return nSize; }
+ virtual std::size_t PutData( const void*, std::size_t nSize ) override { return nSize; }
+ virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override { return nPos; }
+ virtual void SetSize( sal_uInt64 ) override {}
+ virtual void FlushData() override {}
+
+public:
+ SvNullStream() {}
+};
+
+}
+
+EscherEx::EscherEx(std::shared_ptr<EscherExGlobal> xGlobal, SvStream* pOutStrm, bool bOOXML)
+ : mxGlobal(std::move(xGlobal))
+ , mpOutStrm(pOutStrm)
+ , mbOwnsStrm(false)
+ , mnCurrentDg(0)
+ , mnCountOfs(0)
+ , mnGroupLevel(0)
+ , mnHellLayerId(SDRLAYER_NOTFOUND)
+ , mbEscherSpgr(false)
+ , mbEscherDg(false)
+ , mbOOXML(bOOXML)
+{
+ if (!mpOutStrm)
+ {
+ mpOutStrm = new SvNullStream();
+ mbOwnsStrm = true;
+ }
+ mnStrmStartOfs = mpOutStrm->Tell();
+ mpImplEESdrWriter.reset( new ImplEESdrWriter( *this ) );
+}
+
+EscherEx::~EscherEx()
+{
+ if (mbOwnsStrm)
+ delete mpOutStrm;
+}
+
+void EscherEx::Flush( SvStream* pPicStreamMergeBSE /* = NULL */ )
+{
+ if ( !mxGlobal->HasDggContainer() )
+ return;
+
+ // store the current stream position at ESCHER_Persist_CurrentPosition key
+ PtReplaceOrInsert( ESCHER_Persist_CurrentPosition, mpOutStrm->Tell() );
+ if ( DoSeek( ESCHER_Persist_Dgg ) )
+ {
+ /* The DGG record is still not written. ESCHER_Persist_Dgg seeks
+ to the place where the complete record has to be inserted. */
+ InsertAtCurrentPos( mxGlobal->GetDggAtomSize() );
+ mxGlobal->WriteDggAtom( *mpOutStrm );
+
+ if ( mxGlobal->HasGraphics() )
+ {
+ /* Calculate the total size of the BSTORECONTAINER including
+ all BSE records containing the picture data contained in
+ the passed in pPicStreamMergeBSE. */
+ sal_uInt32 nBSCSize = mxGlobal->GetBlibStoreContainerSize( pPicStreamMergeBSE );
+ if ( nBSCSize > 0 )
+ {
+ InsertAtCurrentPos( nBSCSize );
+ mxGlobal->WriteBlibStoreContainer( *mpOutStrm, pPicStreamMergeBSE );
+ }
+ }
+
+ /* Forget the stream position stored for the DGG which is invalid
+ after the call to InsertAtCurrentPos() anyway. */
+ PtDelete( ESCHER_Persist_Dgg );
+ }
+ // seek to initial position (may be different due to inserted DGG and BLIPs)
+ mpOutStrm->Seek( PtGetOffsetByID( ESCHER_Persist_CurrentPosition ) );
+}
+
+void EscherEx::InsertAtCurrentPos( sal_uInt32 nBytes )
+{
+ sal_uInt32 nSize, nType, nSource, nBufSize, nToCopy, nCurPos = mpOutStrm->Tell();
+
+ // adjust persist table
+ for(auto const & pPtr : maPersistTable) {
+ sal_uInt32 nOfs = pPtr->mnOffset;
+ if ( nOfs >= nCurPos ) {
+ pPtr->mnOffset += nBytes;
+ }
+ }
+
+ // adapt container and atom sizes
+ mpOutStrm->Seek( mnStrmStartOfs );
+ while ( mpOutStrm->Tell() < nCurPos )
+ {
+ mpOutStrm->ReadUInt32( nType ).ReadUInt32( nSize );
+ sal_uInt32 nEndOfRecord = mpOutStrm->Tell() + nSize;
+ bool bContainer = (nType & 0x0F) == 0x0F;
+ /* Expand the record, if the insertion position is inside, or if the
+ position is at the end of a container (expands always), or at the
+ end of an atom and bExpandEndOfAtom is set. */
+ if ( (nCurPos < nEndOfRecord) || ((nCurPos == nEndOfRecord) && bContainer) )
+ {
+ mpOutStrm->SeekRel( -4 );
+ mpOutStrm->WriteUInt32( nSize + nBytes );
+ if ( !bContainer )
+ mpOutStrm->SeekRel( nSize );
+ }
+ else
+ mpOutStrm->SeekRel( nSize );
+ }
+ for (auto & offset : mOffsets)
+ {
+ if ( offset > nCurPos )
+ offset += nBytes;
+ }
+ nSource = mpOutStrm->TellEnd();
+ nToCopy = nSource - nCurPos; // increase the size of the stream by nBytes
+ std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ 0x40000 ]); // 256KB Buffer
+ while ( nToCopy )
+ {
+ nBufSize = ( nToCopy >= 0x40000 ) ? 0x40000 : nToCopy;
+ nToCopy -= nBufSize;
+ nSource -= nBufSize;
+ mpOutStrm->Seek( nSource );
+ mpOutStrm->ReadBytes(pBuf.get(), nBufSize);
+ mpOutStrm->Seek( nSource + nBytes );
+ mpOutStrm->WriteBytes(pBuf.get(), nBufSize);
+ }
+ mpOutStrm->Seek( nCurPos );
+}
+
+void EscherEx::InsertPersistOffset( sal_uInt32 nKey, sal_uInt32 nOffset )
+{
+ PtInsert( ESCHER_Persist_PrivateEntry | nKey, nOffset );
+}
+
+void EscherEx::ReplacePersistOffset( sal_uInt32 nKey, sal_uInt32 nOffset )
+{
+ PtReplace( ESCHER_Persist_PrivateEntry | nKey, nOffset );
+}
+
+void EscherEx::SetEditAs( const OUString& rEditAs )
+{
+ mEditAs = rEditAs;
+}
+
+sal_uInt32 EscherEx::GetPersistOffset( sal_uInt32 nKey )
+{
+ return PtGetOffsetByID( ESCHER_Persist_PrivateEntry | nKey );
+}
+
+bool EscherEx::DoSeek( sal_uInt32 nKey )
+{
+ sal_uInt32 nPos = PtGetOffsetByID( nKey );
+ if ( nPos )
+ mpOutStrm->Seek( nPos );
+ else
+ {
+ if (! PtIsID( nKey ) )
+ return false;
+ mpOutStrm->Seek( 0 );
+ }
+ return true;
+}
+
+bool EscherEx::SeekToPersistOffset( sal_uInt32 nKey )
+{
+ return DoSeek( ESCHER_Persist_PrivateEntry | nKey );
+}
+
+void EscherEx::InsertAtPersistOffset( sal_uInt32 nKey, sal_uInt32 nValue )
+{
+ sal_uInt32 nOldPos = mpOutStrm->Tell();
+ bool bRetValue = SeekToPersistOffset( nKey );
+ if ( bRetValue )
+ {
+ mpOutStrm->WriteUInt32( nValue );
+ mpOutStrm->Seek( nOldPos );
+ }
+}
+
+void EscherEx::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
+{
+ mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | 0xf ).WriteUInt16( nEscherContainer ).WriteUInt32( 0 );
+ mOffsets.push_back( mpOutStrm->Tell() - 4 );
+ mRecTypes.push_back( nEscherContainer );
+ switch( nEscherContainer )
+ {
+ case ESCHER_DggContainer :
+ {
+ mxGlobal->SetDggContainer();
+ mnCurrentDg = 0;
+ /* Remember the current position as start position of the DGG
+ record and BSTORECONTAINER, but do not write them actually.
+ This will be done later in Flush() when the number of drawings,
+ the size and contents of the FIDCL cluster table, and the size
+ of the BLIP container are known. */
+ PtReplaceOrInsert( ESCHER_Persist_Dgg, mpOutStrm->Tell() );
+ }
+ break;
+
+ case ESCHER_DgContainer :
+ {
+ if ( mxGlobal->HasDggContainer() )
+ {
+ if ( !mbEscherDg )
+ {
+ mbEscherDg = true;
+ mnCurrentDg = mxGlobal->GenerateDrawingId();
+ AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg );
+ PtReplaceOrInsert( ESCHER_Persist_Dg | mnCurrentDg, mpOutStrm->Tell() );
+ mpOutStrm->WriteUInt32( 0 ) // The number of shapes in this drawing
+ .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG
+ }
+ }
+ }
+ break;
+
+ case ESCHER_SpgrContainer :
+ {
+ if ( mbEscherDg )
+ {
+ mbEscherSpgr = true;
+ }
+ }
+ break;
+
+ case ESCHER_SpContainer :
+ {
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void EscherEx::CloseContainer()
+{
+ sal_uInt32 nSize, nPos = mpOutStrm->Tell();
+ nSize = ( nPos - mOffsets.back() ) - 4;
+ mpOutStrm->Seek( mOffsets.back() );
+ mpOutStrm->WriteUInt32( nSize );
+
+ switch( mRecTypes.back() )
+ {
+ case ESCHER_DgContainer :
+ {
+ if ( mbEscherDg )
+ {
+ mbEscherDg = false;
+ if ( DoSeek( ESCHER_Persist_Dg | mnCurrentDg ) )
+ mpOutStrm->WriteUInt32( mxGlobal->GetDrawingShapeCount( mnCurrentDg ) ).WriteUInt32( mxGlobal->GetLastShapeId( mnCurrentDg ) );
+ }
+ }
+ break;
+
+ case ESCHER_SpgrContainer :
+ {
+ if ( mbEscherSpgr )
+ {
+ mbEscherSpgr = false;
+
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ mOffsets.pop_back();
+ mRecTypes.pop_back();
+ mpOutStrm->Seek( nPos );
+}
+
+void EscherEx::BeginAtom()
+{
+ mnCountOfs = mpOutStrm->Tell();
+ mpOutStrm->WriteUInt32( 0 ).WriteUInt32( 0 ); // record header will be written later
+}
+
+void EscherEx::EndAtom( sal_uInt16 nRecType, int nRecVersion, int nRecInstance )
+{
+ sal_uInt32 nOldPos = mpOutStrm->Tell();
+ mpOutStrm->Seek( mnCountOfs );
+ sal_uInt32 nSize = nOldPos - mnCountOfs;
+ mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | ( nRecVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nSize - 8 );
+ mpOutStrm->Seek( nOldPos );
+}
+
+void EscherEx::AddAtom( sal_uInt32 nAtomSize, sal_uInt16 nRecType, int nRecVersion, int nRecInstance )
+{
+ mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | ( nRecVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nAtomSize );
+}
+
+void EscherEx::AddChildAnchor( const tools::Rectangle& rRect )
+{
+ AddAtom( 16, ESCHER_ChildAnchor );
+ mpOutStrm ->WriteInt32( rRect.Left() )
+ .WriteInt32( rRect.Top() )
+ .WriteInt32( rRect.Right() )
+ .WriteInt32( rRect.Bottom() );
+}
+
+void EscherEx::AddClientAnchor( const tools::Rectangle& rRect )
+{
+ AddAtom( 8, ESCHER_ClientAnchor );
+ mpOutStrm->WriteInt16( rRect.Top() )
+ .WriteInt16( rRect.Left() )
+ .WriteInt16( rRect.GetWidth() + rRect.Left() )
+ .WriteInt16( rRect.GetHeight() + rRect.Top() );
+}
+
+EscherExHostAppData* EscherEx::EnterAdditionalTextGroup()
+{
+ return nullptr;
+}
+
+sal_uInt32 EscherEx::EnterGroup( const OUString& rShapeName, const tools::Rectangle* pBoundRect )
+{
+ tools::Rectangle aRect;
+ if( pBoundRect )
+ aRect = *pBoundRect;
+
+ OpenContainer( ESCHER_SpgrContainer );
+ OpenContainer( ESCHER_SpContainer );
+ AddAtom( 16, ESCHER_Spgr, 1 );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel,
+ mpOutStrm->Tell() );
+ mpOutStrm ->WriteInt32( aRect.Left() ) // Bounding box for the grouped shapes to which they will be attached
+ .WriteInt32( aRect.Top() )
+ .WriteInt32( aRect.IsWidthEmpty() ? aRect.Left() : aRect.Right() )
+ .WriteInt32( aRect.IsHeightEmpty() ? aRect.Top() : aRect.Bottom() );
+
+ sal_uInt32 nShapeId = GenerateShapeId();
+ if ( !mnGroupLevel )
+ AddShape( ESCHER_ShpInst_Min, ShapeFlag::Group | ShapeFlag::Patriarch, nShapeId );
+ else
+ {
+ AddShape( ESCHER_ShpInst_Min, ShapeFlag::Group | ShapeFlag::HaveAnchor, nShapeId );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x00040004 );
+ aPropOpt.AddOpt( ESCHER_Prop_dxWrapDistLeft, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_dxWrapDistRight, 0 );
+
+ // #i51348# shape name
+ if( rShapeName.getLength() > 0 )
+ aPropOpt.AddOpt( ESCHER_Prop_wzName, rShapeName );
+
+ Commit( aPropOpt, aRect );
+ if ( mnGroupLevel > 1 )
+ AddChildAnchor( aRect );
+
+ EscherExHostAppData* pAppData = mpImplEESdrWriter->ImplGetHostData();
+ if( pAppData )
+ {
+ if ( mnGroupLevel <= 1 )
+ pAppData->WriteClientAnchor( *this, aRect );
+ pAppData->WriteClientData( *this );
+ }
+ }
+ CloseContainer(); // ESCHER_SpContainer
+ mnGroupLevel++;
+ return nShapeId;
+}
+
+sal_uInt32 EscherEx::EnterGroup( const tools::Rectangle* pBoundRect )
+{
+ return EnterGroup( OUString(), pBoundRect );
+}
+
+void EscherEx::SetGroupSnapRect( sal_uInt32 nGroupLevel, const tools::Rectangle& rRect )
+{
+ if ( nGroupLevel )
+ {
+ sal_uInt32 nCurrentPos = mpOutStrm->Tell();
+ if ( DoSeek( ESCHER_Persist_Grouping_Snap | ( nGroupLevel - 1 ) ) )
+ {
+ mpOutStrm ->WriteInt32( rRect.Left() ) // Bounding box for the grouped shapes to which they will be attached
+ .WriteInt32( rRect.Top() )
+ .WriteInt32( rRect.Right() )
+ .WriteInt32( rRect.Bottom() );
+ mpOutStrm->Seek( nCurrentPos );
+ }
+ }
+}
+
+void EscherEx::SetGroupLogicRect( sal_uInt32 nGroupLevel, const tools::Rectangle& rRect )
+{
+ if ( nGroupLevel )
+ {
+ sal_uInt32 nCurrentPos = mpOutStrm->Tell();
+ if ( DoSeek( ESCHER_Persist_Grouping_Logic | ( nGroupLevel - 1 ) ) )
+ {
+ mpOutStrm->WriteInt16( rRect.Top() ).WriteInt16( rRect.Left() ).WriteInt16( rRect.Right() ).WriteInt16( rRect.Bottom() );
+ mpOutStrm->Seek( nCurrentPos );
+ }
+ }
+}
+
+void EscherEx::LeaveGroup()
+{
+ --mnGroupLevel;
+ PtDelete( ESCHER_Persist_Grouping_Snap | mnGroupLevel );
+ PtDelete( ESCHER_Persist_Grouping_Logic | mnGroupLevel );
+ CloseContainer();
+}
+
+void EscherEx::AddShape( sal_uInt32 nShpInstance, ShapeFlag nFlags, sal_uInt32 nShapeID )
+{
+ AddAtom( 8, ESCHER_Sp, 2, nShpInstance );
+
+ if ( !nShapeID )
+ nShapeID = GenerateShapeId();
+
+ if (nFlags ^ ShapeFlag::Group) // no pure group shape
+ {
+ if ( mnGroupLevel > 1 )
+ nFlags |= ShapeFlag::Child; // this not a topmost shape
+ }
+ mpOutStrm->WriteUInt32( nShapeID ).WriteUInt32( static_cast<sal_uInt32>(nFlags) );
+}
+
+void EscherEx::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& )
+{
+ rProps.Commit( GetStream() );
+}
+
+sal_uInt32 EscherEx::GetColor( const sal_uInt32 nSOColor )
+{
+ sal_uInt32 nColor = nSOColor & 0xff00; // Green
+ nColor |= static_cast<sal_uInt8>(nSOColor) << 16; // Red
+ nColor |= static_cast<sal_uInt8>( nSOColor >> 16 ); // Blue
+ return nColor;
+}
+
+sal_uInt32 EscherEx::GetColor( const Color& rSOColor )
+{
+ sal_uInt32 nColor = ( rSOColor.GetRed() << 16 );
+ nColor |= ( rSOColor.GetGreen() << 8 );
+ nColor |= rSOColor.GetBlue();
+ nColor = GetColor( nColor );
+ return nColor;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/eschesdo.cxx b/filter/source/msfilter/eschesdo.cxx
new file mode 100644
index 000000000..d052b5968
--- /dev/null
+++ b/filter/source/msfilter/eschesdo.cxx
@@ -0,0 +1,1237 @@
+/* -*- 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/.
+ *
+ * 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 <memory>
+#include "eschesdo.hxx"
+#include <o3tl/any.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/poly.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <svx/fmdpage.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/drawing/CircleKind.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <comphelper/extract.hxx>
+#include <com/sun/star/drawing/HomogenMatrix3.hpp>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::task;
+
+constexpr o3tl::Length geUnitsSrc(o3tl::Length::mm100);
+// PowerPoint: 576 dpi, WinWord: 1440 dpi, Excel: 1440 dpi
+constexpr o3tl::Length geUnitsDest(o3tl::Length::twip);
+
+ImplEESdrWriter::ImplEESdrWriter( EscherEx& rEx )
+ : mpEscherEx(&rEx)
+ , mpPicStrm(nullptr)
+ , mpHostAppData(nullptr)
+ , mbIsTitlePossible(false)
+ , mpSdrPage( nullptr )
+{
+}
+
+
+
+Point ImplEESdrWriter::ImplMapPoint( const Point& rPoint )
+{
+ return o3tl::convert( rPoint, geUnitsSrc, geUnitsDest );
+}
+
+Size ImplEESdrWriter::ImplMapSize( const Size& rSize )
+{
+ Size aRetSize( o3tl::convert( rSize, geUnitsSrc, geUnitsDest ) );
+
+ if ( !aRetSize.Width() )
+ aRetSize.AdjustWidth( 1 );
+ if ( !aRetSize.Height() )
+ aRetSize.AdjustHeight( 1 );
+ return aRetSize;
+}
+
+void ImplEESdrWriter::ImplFlipBoundingBox( ImplEESdrObject& rObj, EscherPropertyContainer& rPropOpt )
+{
+ sal_Int32 nAngle = rObj.GetAngle();
+ tools::Rectangle aRect( rObj.GetRect() );
+
+ // for position calculations, we normalize the angle between 0 and 90 degrees
+ if ( nAngle < 0 )
+ nAngle = ( 36000 + nAngle ) % 36000;
+ if ( nAngle % 18000 == 0 )
+ nAngle = 0;
+ while ( nAngle > 9000 )
+ nAngle = ( 18000 - ( nAngle % 18000 ) );
+
+ double fVal = basegfx::deg2rad<100>(nAngle);
+ double fCos = cos( fVal );
+ double fSin = sin( fVal );
+
+ double nWidthHalf = static_cast<double>(aRect.GetWidth()) / 2;
+ double nHeightHalf = static_cast<double>(aRect.GetHeight()) / 2;
+
+ // fdo#70838:
+ // when you rotate an object, the top-left corner of its bounding box is moved
+ // nXDiff and nYDiff pixels. To get their values we use these equations:
+ //
+ // fSin * nHeightHalf + fCos * nWidthHalf == nXDiff + nWidthHalf
+ // fSin * nWidthHalf + fCos * nHeightHalf == nYDiff + nHeightHalf
+
+ double nXDiff = fSin * nHeightHalf + fCos * nWidthHalf - nWidthHalf;
+ double nYDiff = fSin * nWidthHalf + fCos * nHeightHalf - nHeightHalf;
+
+ aRect.Move( static_cast<sal_Int32>(nXDiff), static_cast<sal_Int32>(nYDiff) );
+
+ // calculate the proper angle value to be saved
+ nAngle = rObj.GetAngle();
+ if ( nAngle < 0 )
+ nAngle = ( 36000 + nAngle ) % 36000;
+ else
+ nAngle = ( 36000 - ( nAngle % 36000 ) );
+
+ nAngle *= 655;
+ nAngle += 0x8000;
+ nAngle &=~0xffff; // nAngle round to full degrees
+ rPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle );
+
+ rObj.SetAngle( nAngle );
+ rObj.SetRect( aRect );
+}
+
+
+sal_uInt32 ImplEESdrWriter::ImplWriteShape( ImplEESdrObject& rObj,
+ EscherSolverContainer& rSolverContainer,
+ const bool bOOxmlExport )
+{
+ sal_uInt32 nShapeID = 0;
+ sal_uInt16 nShapeType = 0;
+ bool bDontWriteText = false; // if a metafile is written as shape replacement, then the text is already part of the metafile
+ bool bAdditionalText = false;
+ sal_uInt32 nGrpShapeID = 0;
+ auto addShape = [this, &rObj, &rSolverContainer, &nShapeID, &nShapeType](sal_uInt16 nType, ShapeFlag nFlags)
+ {
+ nShapeType = nType;
+ nShapeID = mpEscherEx->GenerateShapeId();
+ rObj.SetShapeId( nShapeID );
+ mpEscherEx->AddShape( nType, nFlags, nShapeID );
+ rSolverContainer.AddShape( rObj.GetShapeRef(), nShapeID );
+ };
+
+ do {
+ mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : nullptr );
+ if ( mpHostAppData && mpHostAppData->DontWriteShape() )
+ break;
+
+ // #i51348# get shape name
+ OUString aShapeName;
+ if( const SdrObject* pSdrObj = rObj.GetSdrObject() )
+ if (!pSdrObj->GetName().isEmpty())
+ aShapeName = pSdrObj->GetName();
+ uno::Reference< drawing::XShape> xShape = rObj.GetShapeRef();
+ if (xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ if (xPropertySet.is())
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ uno::Reference< XPropertySetInfo > xPropInfo = xPropertySet->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName( "InteropGrabBag" ) )
+ {
+ xPropertySet->getPropertyValue( "InteropGrabBag" ) >>= aGrabBag;
+ for (const beans::PropertyValue& rProp : std::as_const(aGrabBag))
+ {
+ if (rProp.Name == "mso-edit-as")
+ {
+ OUString rEditAs;
+ rProp.Value >>= rEditAs;
+ mpEscherEx->SetEditAs(rEditAs);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if( rObj.GetType() == "drawing.Group" )
+ {
+ Reference< XIndexAccess > xXIndexAccess( rObj.GetShapeRef(), UNO_QUERY );
+
+ if( xXIndexAccess.is() && 0 != xXIndexAccess->getCount() )
+ {
+ nShapeID = mpEscherEx->EnterGroup( aShapeName, &rObj.GetRect() );
+ nShapeType = ESCHER_ShpInst_Min;
+
+ for( sal_uInt32 n = 0, nCnt = xXIndexAccess->getCount();
+ n < nCnt; ++n )
+ {
+ ImplEESdrObject aObj( *o3tl::doAccess<Reference<XShape>>(
+ xXIndexAccess->getByIndex( n )) );
+ if( aObj.IsValid() )
+ {
+ aObj.SetOOXML(bOOxmlExport);
+ ImplWriteShape( aObj, rSolverContainer, bOOxmlExport );
+ }
+ }
+ mpEscherEx->LeaveGroup();
+ }
+ break;
+ }
+ rObj.SetAngle( rObj.ImplGetInt32PropertyValue( "RotateAngle" ));
+
+ if( ( rObj.ImplGetPropertyValue( "IsFontwork" ) &&
+ ::cppu::any2bool( rObj.GetUsrAny() ) ) ||
+ rObj.GetType() == "drawing.Measure" )
+ {
+ rObj.SetType("drawing.dontknow");
+ }
+
+ const css::awt::Size aSize100thmm( rObj.GetShapeRef()->getSize() );
+ const css::awt::Point aPoint100thmm( rObj.GetShapeRef()->getPosition() );
+ tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
+ if ( !mpPicStrm )
+ mpPicStrm = mpEscherEx->QueryPictureStream();
+ EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm );
+
+ // #i51348# shape name
+ if (!aShapeName.isEmpty())
+ aPropOpt.AddOpt( ESCHER_Prop_wzName, aShapeName );
+ if ( InteractionInfo* pInteraction = mpHostAppData ? mpHostAppData->GetInteractionInfo():nullptr )
+ {
+ const std::unique_ptr< SvMemoryStream >& pMemStrm = pInteraction->getHyperlinkRecord();
+ if (pMemStrm)
+ {
+ aPropOpt.AddOpt(ESCHER_Prop_pihlShape, false, 0, *pMemStrm);
+ }
+ aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080008 );
+ }
+
+ if ( rObj.GetType() == "drawing.Custom" )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag nMirrorFlags;
+
+ OUString sCustomShapeType;
+ MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( rObj.GetShapeRef(), nMirrorFlags, sCustomShapeType, rObj.GetOOXML() );
+ if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" )
+ {
+ addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); // no fill
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); // no linestyle
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rObj.GetShapeRef());
+ if ( pObj )
+ {
+ tools::Rectangle aBound = pObj->GetCurrentBoundRect();
+ Point aPosition( ImplMapPoint( aBound.TopLeft() ) );
+ Size aSize( ImplMapSize( aBound.GetSize() ) );
+ rObj.SetRect( tools::Rectangle( aPosition, aSize ) );
+ rObj.SetAngle( 0 );
+ bDontWriteText = true;
+ }
+ }
+ }
+ else
+ {
+ const Reference< XPropertySet > xPropSet = rObj.mXPropSet;
+ drawing::FillStyle eFS = drawing::FillStyle_NONE;
+ if(xPropSet.is())
+ {
+ uno::Reference< XPropertySetInfo > xPropInfo = xPropSet->getPropertySetInfo();
+ if ( xPropInfo.is() && xPropInfo->hasPropertyByName("FillStyle"))
+ xPropSet->getPropertyValue("FillStyle") >>= eFS;
+ }
+
+ if (eFS == drawing::FillStyle_BITMAP && eShapeType == mso_sptMax)
+ {
+ // We can't map this custom shape to a DOC preset and it has a bitmap fill.
+ // Make sure that at least the bitmap fill is not lost.
+ addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Bitmap", false, true, true, bOOxmlExport ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else
+ {
+ addShape(sal::static_int_cast< sal_uInt16 >(eShapeType),
+ nMirrorFlags | ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor);
+ aPropOpt.CreateCustomShapeProperties( eShapeType, rObj.GetShapeRef() );
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ if ( rObj.ImplGetText() )
+ {
+ if ( !aPropOpt.IsFontWork() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet, mpEscherEx->QueryTextID(
+ rObj.GetShapeRef(), rObj.GetShapeId() ), true, false );
+ }
+ }
+ }
+ }
+ else if ( rObj.GetType() == "drawing.Rectangle" )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ sal_Int32 nRadius = rObj.ImplGetInt32PropertyValue("CornerRadius");
+ if( nRadius )
+ {
+ nRadius = ImplMapSize( Size( nRadius, 0 )).Width();
+ addShape( ESCHER_ShpInst_RoundRectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ sal_Int32 nLength = rObj.GetRect().GetWidth();
+ if ( nLength > rObj.GetRect().GetHeight() )
+ nLength = rObj.GetRect().GetHeight();
+ nLength >>= 1;
+ if ( nRadius >= nLength || nLength == 0 )
+ nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
+ else
+ nRadius = ( 0x2a30 * nRadius ) / nLength;
+ aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
+ }
+ else
+ {
+ addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ }
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ if( rObj.ImplGetText() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet,
+ mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() ), false, false );
+ }
+ else if ( rObj.GetType() == "drawing.Ellipse" )
+ {
+ CircleKind eCircleKind = CircleKind_FULL;
+ PolyStyle ePolyKind = PolyStyle();
+ if ( rObj.ImplGetPropertyValue( "CircleKind" ) )
+ {
+ eCircleKind = *o3tl::doAccess<CircleKind>(rObj.GetUsrAny());
+ switch ( eCircleKind )
+ {
+ case CircleKind_SECTION :
+ {
+ ePolyKind = PolyStyle::Pie;
+ }
+ break;
+ case CircleKind_ARC :
+ {
+ ePolyKind = PolyStyle::Arc;
+ }
+ break;
+
+ case CircleKind_CUT :
+ {
+ ePolyKind = PolyStyle::Chord;
+ }
+ break;
+
+ default:
+ eCircleKind = CircleKind_FULL;
+ }
+ }
+ if ( eCircleKind == CircleKind_FULL )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_Ellipse, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ }
+ else
+ {
+ sal_Int32 nStartAngle, nEndAngle;
+ if ( !rObj.ImplGetPropertyValue( "CircleStartAngle" ) )
+ break;
+ nStartAngle = *o3tl::doAccess<sal_Int32>(rObj.GetUsrAny());
+ if( !rObj.ImplGetPropertyValue( "CircleEndAngle" ) )
+ break;
+ nEndAngle = *o3tl::doAccess<sal_Int32>(rObj.GetUsrAny());
+
+ Point aStart, aEnd, aCenter;
+ aStart.setX( static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 ) );
+ aStart.setY( - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 ) );
+ aEnd.setX( static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 ) );
+ aEnd.setY( - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 ) );
+ const tools::Rectangle& rRect = aRect100thmm;
+ aCenter.setX( rRect.Left() + ( rRect.GetWidth() / 2 ) );
+ aCenter.setY( rRect.Top() + ( rRect.GetHeight() / 2 ) );
+ aStart.AdjustX(aCenter.X() );
+ aStart.AdjustY(aCenter.Y() );
+ aEnd.AdjustX(aCenter.X() );
+ aEnd.AdjustY(aCenter.Y() );
+ tools::Polygon aPolygon( rRect, aStart, aEnd, ePolyKind );
+ if( rObj.GetAngle() )
+ {
+ aPolygon.Rotate( rRect.TopLeft(), Degree10(static_cast<sal_Int16>( rObj.GetAngle() / 10 )) );
+ rObj.SetAngle( 0 );
+ }
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ css::awt::Rectangle aNewRect;
+ switch ( ePolyKind )
+ {
+ case PolyStyle::Pie :
+ case PolyStyle::Chord :
+ {
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon );
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ }
+ break;
+
+ case PolyStyle::Arc :
+ {
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon );
+ aPropOpt.CreateLineProperties( rObj.mXPropSet, false );
+ }
+ break;
+ }
+ rObj.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ),
+ ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) );
+ }
+ if ( rObj.ImplGetText() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet,
+ mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() ), false, false );
+
+ }
+ else if ( rObj.GetType() == "drawing.Control" )
+ {
+ const Reference< XPropertySet > xPropSet = rObj.mXPropSet;
+ const Reference<XPropertySetInfo> xPropInfo = xPropSet.is() ? xPropSet->getPropertySetInfo() : Reference<XPropertySetInfo>();
+ // This code is expected to be called only for DOCX/XLSX formats.
+ if (xPropInfo.is() && bOOxmlExport)
+ {
+ bool bInline = false;
+ if (xPropInfo->hasPropertyByName("AnchorType"))
+ {
+ text::TextContentAnchorType eAnchorType;
+ xPropSet->getPropertyValue("AnchorType") >>= eAnchorType;
+ bInline = eAnchorType == text::TextContentAnchorType_AS_CHARACTER;
+ }
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ if(bInline)
+ {
+ addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ }
+ else
+ {
+ addShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ }
+ }
+ else
+ break;
+ }
+ else if ( rObj.GetType() == "drawing.Connector" )
+ {
+ sal_uInt16 nSpType;
+ ShapeFlag nSpFlags;
+ css::awt::Rectangle aNewRect;
+ if ( ! aPropOpt.CreateConnectorProperties( rObj.GetShapeRef(),
+ rSolverContainer, aNewRect, nSpType, nSpFlags ) )
+ break;
+ rObj.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ),
+ ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) );
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( nSpType, nSpFlags );
+ }
+ else if ( rObj.GetType() == "drawing.Measure" )
+ {
+ break;
+ }
+ else if ( rObj.GetType() == "drawing.Line" )
+ {
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect );
+ //i27942: Poly/Lines/Bezier do not support text.
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag nFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor;
+ if( aNewRect.Height < 0 )
+ nFlags |= ShapeFlag::FlipV;
+ if( aNewRect.Width < 0 )
+ nFlags |= ShapeFlag::FlipH;
+
+ addShape( ESCHER_ShpInst_Line, nFlags );
+ aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
+ aPropOpt.CreateLineProperties( rObj.mXPropSet, false );
+ rObj.SetAngle( 0 );
+ }
+ else if ( rObj.GetType() == "drawing.PolyPolygon" )
+ {
+ if( rObj.ImplHasText() )
+ {
+ nGrpShapeID = ImplEnterAdditionalTextGroup( rObj.GetShapeRef(), &rObj.GetRect() );
+ bAdditionalText = true;
+ }
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect );
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ rObj.SetAngle( 0 );
+ }
+ else if ( rObj.GetType() == "drawing.PolyLine" )
+ {
+ //i27942: Poly/Lines/Bezier do not support text.
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect );
+ aPropOpt.CreateLineProperties( rObj.mXPropSet, false );
+ rObj.SetAngle( 0 );
+ }
+ else if ( rObj.GetType() == "drawing.OpenBezier" )
+ {
+ //i27942: Poly/Lines/Bezier do not support text.
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect );
+ aPropOpt.CreateLineProperties( rObj.mXPropSet, false );
+ rObj.SetAngle( 0 );
+ }
+ else if ( rObj.GetType() == "drawing.ClosedBezier" )
+ {
+ if ( rObj.ImplHasText() )
+ {
+ nGrpShapeID = ImplEnterAdditionalTextGroup( rObj.GetShapeRef(), &rObj.GetRect() );
+ bAdditionalText = true;
+ }
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect );
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ rObj.SetAngle( 0 );
+ }
+ else if ( rObj.GetType() == "drawing.GraphicObject" )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+
+ // a GraphicObject can also be a ClickMe element
+ if( rObj.IsEmptyPresObj() )
+ {
+ addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveMaster | ShapeFlag::HaveAnchor );
+ sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() );
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, 0 );
+ }
+ else
+ {
+ if( rObj.ImplGetText() )
+ {
+ /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
+ have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
+ */
+ addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Graphic", true, true, false ) )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
+ aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ if ( rObj.ImplGetText() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet,
+ mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() ), false, false );
+ }
+ }
+ else
+ {
+ addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Graphic", false, true, true, bOOxmlExport ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ }
+ }
+ else if ( rObj.GetType() == "drawing.Text" )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ aPropOpt.CreateFillProperties( rObj.mXPropSet, true );
+ if( rObj.ImplGetText() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet,
+ mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() ) );
+ }
+ else if ( rObj.GetType() == "drawing.Page" )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x40004 );
+ aPropOpt.AddOpt( ESCHER_Prop_fFillOK, 0x100001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110011 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90008 );
+ aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x10001 );
+ }
+ else if ( rObj.GetType() == "drawing.Frame" )
+ {
+ break;
+ }
+ else if ( rObj.GetType() == "drawing.OLE2" )
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ if( rObj.IsEmptyPresObj() )
+ {
+ addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveMaster | ShapeFlag::HaveAnchor );
+ sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() );
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, 0 );
+ }
+ else
+ {
+ //2do: could be made an option in HostAppData whether OLE object should be written or not
+ const bool bAppOLE = true;
+ addShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | (bAppOLE ? ShapeFlag::OLEShape : ShapeFlag::NONE) );
+ if ( aPropOpt.CreateOLEGraphicProperties( rObj.GetShapeRef() ) )
+ {
+ if ( bAppOLE )
+ { // snooped from Xcl hex dump, nobody knows the trouble I have seen
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 );
+ aPropOpt.AddOpt( ESCHER_Prop_pictureId, 0x00000001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x08000041 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x08000041 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 );
+ aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash,0x00080008 );
+ aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 );
+ }
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ }
+ }
+ else if( '3' == rObj.GetType()[8] &&
+ 'D' == rObj.GetType()[9] ) // drawing.3D
+ {
+ // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
+ if ( !rObj.ImplGetPropertyValue( "Bitmap" ) )
+ break;
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Bitmap", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else if ( rObj.GetType() == "drawing.Caption" )
+ {
+ rObj.SetAngle( 0 );
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else if ( rObj.GetType() == "drawing.dontknow" )
+ {
+ rObj.SetAngle( 0 );
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else
+ {
+ break;
+ }
+ aPropOpt.CreateShadowProperties( rObj.mXPropSet );
+
+ if( SDRLAYER_NOTFOUND != mpEscherEx->GetHellLayerId() &&
+ rObj.ImplGetPropertyValue( "LayerID" ) &&
+ *o3tl::doAccess<sal_Int16>(rObj.GetUsrAny()) == mpEscherEx->GetHellLayerId().get() )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x200020 );
+ }
+
+ {
+ tools::Rectangle aRect( rObj.GetRect() );
+ aRect.Justify();
+ rObj.SetRect( aRect );
+ }
+
+ if( rObj.GetAngle() )
+ ImplFlipBoundingBox( rObj, aPropOpt );
+
+ aPropOpt.CreateShapeProperties( rObj.GetShapeRef() );
+ const SdrObject* sdrObj = rObj.GetSdrObject();
+ mpEscherEx->AddSdrObjectVMLObject(*sdrObj );
+ mpEscherEx->Commit( aPropOpt, rObj.GetRect());
+ if( mpEscherEx->GetGroupLevel() > 1 )
+ mpEscherEx->AddChildAnchor( rObj.GetRect() );
+
+ if ( mpHostAppData )
+ { //! with AdditionalText the App has to control whether these are written or not
+ mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() );
+ mpHostAppData->WriteClientData( *mpEscherEx );
+ if ( !bDontWriteText )
+ mpHostAppData->WriteClientTextbox( *mpEscherEx );
+ }
+ mpEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ if( bAdditionalText )
+ {
+ mpEscherEx->EndShape( nShapeType, nShapeID );
+ ImplWriteAdditionalText( rObj );
+ }
+
+ } while ( false );
+
+ if ( bAdditionalText )
+ mpEscherEx->EndShape( ESCHER_ShpInst_Min, nGrpShapeID );
+ else
+ mpEscherEx->EndShape( nShapeType, nShapeID );
+ return nShapeID;
+}
+
+void ImplEESdrWriter::ImplWriteAdditionalText( ImplEESdrObject& rObj )
+{
+ sal_uInt32 nShapeID = 0;
+ sal_uInt16 nShapeType = 0;
+ do
+ {
+ mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : nullptr );
+ if ( mpHostAppData && mpHostAppData->DontWriteShape() )
+ break;
+
+ const css::awt::Size aSize100thmm( rObj.GetShapeRef()->getSize() );
+ const css::awt::Point aPoint100thmm( rObj.GetShapeRef()->getPosition() );
+ tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
+ if ( !mpPicStrm )
+ mpPicStrm = mpEscherEx->QueryPictureStream();
+ EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm );
+ rObj.SetAngle( rObj.ImplGetInt32PropertyValue( "RotateAngle" ));
+ sal_Int32 nAngle = rObj.GetAngle();
+ if( rObj.GetType() == "drawing.Line" )
+ {
+//2do: this does not work right
+ double fDist = hypot( rObj.GetRect().GetWidth(),
+ rObj.GetRect().GetHeight() );
+ rObj.SetRect( tools::Rectangle( Point(),
+ Point( static_cast<sal_Int32>( fDist ), -1 ) ) );
+
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpEscherEx->AddShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor );
+ if ( rObj.ImplGetText() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet,
+ mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() ) );
+
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text
+ if ( nAngle < 0 )
+ nAngle = ( 36000 + nAngle ) % 36000;
+ if ( nAngle )
+ ImplFlipBoundingBox( rObj, aPropOpt );
+ }
+ else
+ {
+ mpEscherEx->OpenContainer( ESCHER_SpContainer );
+ nShapeID = mpEscherEx->GenerateShapeId();
+ nShapeType = ESCHER_ShpInst_TextBox;
+ mpEscherEx->AddShape( nShapeType, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor, nShapeID );
+ if ( rObj.ImplGetText() )
+ aPropOpt.CreateTextProperties( rObj.mXPropSet,
+ mpEscherEx->QueryTextID( rObj.GetShapeRef(),
+ rObj.GetShapeId() ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
+
+ if( nAngle < 0 )
+ nAngle = ( 36000 + nAngle ) % 36000;
+ else
+ nAngle = ( 36000 - ( nAngle % 36000 ) );
+
+ nAngle *= 655;
+ nAngle += 0x8000;
+ nAngle &=~0xffff; // nAngle round to full degrees
+ aPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle );
+ mpEscherEx->SetGroupSnapRect( mpEscherEx->GetGroupLevel(),
+ rObj.GetRect() );
+ mpEscherEx->SetGroupLogicRect( mpEscherEx->GetGroupLevel(),
+ rObj.GetRect() );
+ }
+ rObj.SetAngle( nAngle );
+ aPropOpt.CreateShapeProperties( rObj.GetShapeRef() );
+ const SdrObject* sdrObj = rObj.GetSdrObject();
+ mpEscherEx->AddSdrObjectVMLObject(*sdrObj );
+ mpEscherEx->Commit( aPropOpt, rObj.GetRect());
+
+ // write the childanchor
+ mpEscherEx->AddChildAnchor( rObj.GetRect() );
+
+#if defined EES_WRITE_EPP
+ // ClientAnchor
+ mpEscherEx->AddClientAnchor( maRect );
+ // ClientTextbox
+ mpEscherEx->OpenContainer( ESCHER_ClientTextbox );
+ mpEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
+ *mpStrm << (sal_uInt32)EPP_TEXTTYPE_Other; // Text in a Shape
+ ImplWriteTextStyleAtom();
+ mpEscherEx->CloseContainer(); // ESCHER_ClientTextBox
+#else // !EES_WRITE_EPP
+ if ( mpHostAppData )
+ { //! the App has to control whether these are written or not
+ mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() );
+ mpHostAppData->WriteClientData( *mpEscherEx );
+ mpHostAppData->WriteClientTextbox( *mpEscherEx );
+ }
+#endif // EES_WRITE_EPP
+ mpEscherEx->CloseContainer(); // ESCHER_SpContainer
+ } while ( false );
+ mpEscherEx->LeaveGroup();
+ mpEscherEx->EndShape( nShapeType, nShapeID );
+}
+
+
+sal_uInt32 ImplEESdrWriter::ImplEnterAdditionalTextGroup( const Reference< XShape >& rShape,
+ const tools::Rectangle* pBoundRect )
+{
+ mpHostAppData = mpEscherEx->EnterAdditionalTextGroup();
+ sal_uInt32 nGrpId = mpEscherEx->EnterGroup( pBoundRect );
+ mpHostAppData = mpEscherEx->StartShape( rShape, pBoundRect );
+ return nGrpId;
+}
+
+
+void ImplEESdrWriter::ImplInitPageValues()
+{
+ mbIsTitlePossible = true; // With more than one title PowerPoint will fail.
+}
+
+void ImplEESdrWriter::ImplWritePage(
+ EscherSolverContainer& rSolverContainer, bool ooxmlExport )
+{
+ ImplInitPageValues();
+
+ const sal_uInt32 nShapes = mXShapes->getCount();
+ for( sal_uInt32 n = 0; n < nShapes; ++n )
+ {
+ ImplEESdrObject aObj( *o3tl::doAccess<Reference<XShape>>(
+ mXShapes->getByIndex( n )) );
+ if( aObj.IsValid() )
+ {
+ ImplWriteShape( aObj, rSolverContainer, ooxmlExport );
+ }
+ }
+}
+
+ImplEESdrWriter::~ImplEESdrWriter()
+{
+ DBG_ASSERT( !mpSolverContainer, "ImplEESdrWriter::~ImplEESdrWriter: unwritten SolverContainer" );
+ Reference<css::lang::XComponent> xComp(mXDrawPage, UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+}
+
+
+bool ImplEESdrWriter::ImplInitPage( const SdrPage& rPage )
+{
+ rtl::Reference<SvxDrawPage> pSvxDrawPage;
+ if ( mpSdrPage != &rPage || !mXDrawPage.is() )
+ {
+ // eventually write SolverContainer of current page, deletes the Solver
+ ImplFlushSolverContainer();
+
+ mpSdrPage = nullptr;
+ Reference<css::lang::XComponent> xOldDrawPage(mXDrawPage, UNO_QUERY);
+ if (xOldDrawPage.is())
+ xOldDrawPage->dispose();
+ mXDrawPage = pSvxDrawPage = new SvxFmDrawPage( const_cast<SdrPage*>(&rPage) );
+ mXShapes = mXDrawPage;
+ if ( !mXShapes.is() )
+ return false;
+ ImplInitPageValues();
+ mpSdrPage = &rPage;
+
+ mpSolverContainer.reset( new EscherSolverContainer );
+ }
+ else
+ pSvxDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>(mXDrawPage);
+
+ return pSvxDrawPage != nullptr;
+}
+
+bool ImplEESdrWriter::ImplInitUnoShapes( const Reference< XShapes >& rxShapes )
+{
+ // eventually write SolverContainer of current page, deletes the Solver
+ ImplFlushSolverContainer();
+
+ if( !rxShapes.is() )
+ return false;
+
+ mpSdrPage = nullptr;
+ mXDrawPage.clear();
+ mXShapes = rxShapes;
+
+ ImplInitPageValues();
+
+ mpSolverContainer.reset( new EscherSolverContainer );
+ return true;
+}
+
+void ImplEESdrWriter::ImplExitPage()
+{
+ // close all groups before the solver container is written
+ while( mpEscherEx->GetGroupLevel() )
+ mpEscherEx->LeaveGroup();
+
+ ImplFlushSolverContainer();
+ mpSdrPage = nullptr; // reset page for next init
+}
+
+
+void ImplEESdrWriter::ImplFlushSolverContainer()
+{
+ if ( mpSolverContainer )
+ {
+ mpSolverContainer->WriteSolver( mpEscherEx->GetStream() );
+ mpSolverContainer.reset();
+ }
+}
+
+void ImplEESdrWriter::ImplWriteCurrentPage(bool ooxmlExport)
+{
+ assert(mpSolverContainer && "ImplEESdrWriter::ImplWriteCurrentPage: no SolverContainer");
+ ImplWritePage( *mpSolverContainer, ooxmlExport );
+ ImplExitPage();
+}
+
+sal_uInt32 ImplEESdrWriter::ImplWriteTheShape( ImplEESdrObject& rObj , bool ooxmlExport )
+{
+ assert(mpSolverContainer && "ImplEESdrWriter::ImplWriteShape: no SolverContainer");
+ return ImplWriteShape( rObj, *mpSolverContainer, ooxmlExport );
+}
+
+void EscherEx::AddSdrPage( const SdrPage& rPage, bool ooxmlExport )
+{
+ if ( mpImplEESdrWriter->ImplInitPage( rPage ) )
+ mpImplEESdrWriter->ImplWriteCurrentPage(ooxmlExport);
+}
+
+void EscherEx::AddUnoShapes( const Reference< XShapes >& rxShapes, bool ooxmlExport )
+{
+ if ( mpImplEESdrWriter->ImplInitUnoShapes( rxShapes ) )
+ mpImplEESdrWriter->ImplWriteCurrentPage(ooxmlExport);
+}
+
+sal_uInt32 EscherEx::AddSdrObject( const SdrObject& rObj, bool ooxmlExport )
+{
+ ImplEESdrObject aObj( *mpImplEESdrWriter, rObj, mbOOXML );
+ if( aObj.IsValid() )
+ return mpImplEESdrWriter->ImplWriteTheShape( aObj, ooxmlExport );
+ return 0;
+}
+
+
+void EscherEx::EndSdrObjectPage()
+{
+ mpImplEESdrWriter->ImplExitPage();
+}
+
+EscherExHostAppData* EscherEx::StartShape( const Reference< XShape >& /* rShape */, const tools::Rectangle* /*pChildAnchor*/ )
+{
+ return nullptr;
+}
+
+void EscherEx::EndShape( sal_uInt16 /* nShapeType */, sal_uInt32 /* nShapeID */ )
+{
+}
+
+sal_uInt32 EscherEx::QueryTextID( const Reference< XShape >&, sal_uInt32 )
+{
+ return 0;
+}
+
+// add a dummy rectangle shape into the escher stream
+sal_uInt32 EscherEx::AddDummyShape()
+{
+ OpenContainer( ESCHER_SpContainer );
+ sal_uInt32 nShapeID = GenerateShapeId();
+ AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor, nShapeID );
+ CloseContainer();
+
+ return nShapeID;
+}
+
+// static
+const SdrObject* EscherEx::GetSdrObject( const Reference< XShape >& rShape )
+{
+ const SdrObject* pRet = SdrObject::getSdrObjectFromXShape( rShape );
+ DBG_ASSERT( pRet, "EscherEx::GetSdrObject: no SdrObj" );
+ return pRet;
+}
+
+
+ImplEESdrObject::ImplEESdrObject( ImplEESdrWriter& rEx,
+ const SdrObject& rObj, bool bOOXML ) :
+ mnShapeId( 0 ),
+ mnTextSize( 0 ),
+ mnAngle( 0 ),
+ mbValid( false ),
+ mbPresObj( false ),
+ mbEmptyPresObj( false ),
+ mbOOXML(bOOXML)
+{
+ SdrPage* pPage = rObj.getSdrPageFromSdrObject();
+ DBG_ASSERT( pPage, "ImplEESdrObject::ImplEESdrObject: no SdrPage" );
+ if( pPage && rEx.ImplInitPage( *pPage ) )
+ {
+ // why not declare a const parameter if the object will
+ // not be modified?
+ mXShape.set( const_cast<SdrObject*>(&rObj)->getUnoShape(), UNO_QUERY );
+ Init();
+ }
+}
+
+ImplEESdrObject::ImplEESdrObject( const Reference< XShape >& rShape ) :
+ mXShape( rShape ),
+ mnShapeId( 0 ),
+ mnTextSize( 0 ),
+ mnAngle( 0 ),
+ mbValid( false ),
+ mbPresObj( false ),
+ mbEmptyPresObj( false ),
+ mbOOXML(false)
+{
+ Init();
+}
+
+
+ImplEESdrObject::~ImplEESdrObject()
+{
+}
+
+static basegfx::B2DRange getUnrotatedGroupBoundRange(const Reference< XShape >& rxShape)
+{
+ basegfx::B2DRange aRetval;
+
+ try
+ {
+ if(rxShape.is())
+ {
+ if(rxShape->getShapeType() == "com.sun.star.drawing.GroupShape")
+ {
+ // it's a group shape, iterate over children
+ const Reference< XIndexAccess > xXIndexAccess(rxShape, UNO_QUERY);
+
+ if(xXIndexAccess.is())
+ {
+ for(sal_uInt32 n(0), nCnt = xXIndexAccess->getCount(); n < nCnt; ++n)
+ {
+ const Reference< XShape > axShape(xXIndexAccess->getByIndex(n), UNO_QUERY);
+
+ if(axShape.is())
+ {
+ // we are calculating the bound for a group, correct rotation for sub-objects
+ // to get the unrotated bounds for the group
+ const basegfx::B2DRange aExtend(getUnrotatedGroupBoundRange(axShape));
+
+ aRetval.expand(aExtend);
+ }
+ }
+ }
+ }
+ else
+ {
+ // iT#s a xShape, get its transformation
+ const Reference< XPropertySet > xPropSet(rxShape, UNO_QUERY);
+
+ if(xPropSet.is())
+ {
+ const Any aAny = xPropSet->getPropertyValue("Transformation");
+
+ if(aAny.hasValue())
+ {
+ HomogenMatrix3 aMatrix;
+
+ if(aAny >>= aMatrix)
+ {
+ basegfx::B2DHomMatrix aHomogenMatrix;
+
+ aHomogenMatrix.set(0, 0, aMatrix.Line1.Column1);
+ aHomogenMatrix.set(0, 1, aMatrix.Line1.Column2);
+ aHomogenMatrix.set(0, 2, aMatrix.Line1.Column3);
+ aHomogenMatrix.set(1, 0, aMatrix.Line2.Column1);
+ aHomogenMatrix.set(1, 1, aMatrix.Line2.Column2);
+ aHomogenMatrix.set(1, 2, aMatrix.Line2.Column3);
+ aHomogenMatrix.set(2, 0, aMatrix.Line3.Column1);
+ aHomogenMatrix.set(2, 1, aMatrix.Line3.Column2);
+ aHomogenMatrix.set(2, 2, aMatrix.Line3.Column3);
+
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+
+ // decompose transformation
+ aHomogenMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // check if rotation needs to be corrected
+ if(!basegfx::fTools::equalZero(fRotate))
+ {
+ // to correct, keep in mind that ppt graphics are rotated around their center
+ const basegfx::B2DPoint aCenter(aHomogenMatrix * basegfx::B2DPoint(0.5, 0.5));
+
+ aHomogenMatrix.translate(-aCenter.getX(), -aCenter.getY());
+ aHomogenMatrix.rotate(-fRotate);
+ aHomogenMatrix.translate(aCenter.getX(), aCenter.getY());
+ }
+
+
+ // check if shear needs to be corrected (always correct shear,
+ // ppt does not know about it)
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ const basegfx::B2DPoint aMinimum(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0));
+
+ aHomogenMatrix.translate(-aMinimum.getX(), -aMinimum.getY());
+ aHomogenMatrix.shearX(-fShearX);
+ aHomogenMatrix.translate(aMinimum.getX(), aMinimum.getY());
+ }
+
+ // create range. It's no longer rotated (or sheared), so use
+ // minimum and maximum values
+ aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0));
+ aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(1.0, 1.0));
+ }
+ }
+ }
+ }
+ }
+ }
+ catch(css::uno::Exception&)
+ {
+ }
+
+ return aRetval;
+}
+
+void ImplEESdrObject::Init()
+{
+ mXPropSet.set( mXShape, UNO_QUERY );
+ if( !mXPropSet.is() )
+ return;
+
+ // detect name first to make below test (is group) work
+ mType = mXShape->getShapeType();
+ (void)mType.startsWith( "com.sun.star.", &mType ); // strip "com.sun.star."
+ (void)mType.endsWith( "Shape", &mType ); // strip "Shape"
+
+ if(GetType() == "drawing.Group")
+ {
+ // if it's a group, the unrotated range is needed for that group
+ const basegfx::B2DRange aUnrotatedRange(getUnrotatedGroupBoundRange(mXShape));
+ const Point aNewP(basegfx::fround(aUnrotatedRange.getMinX()), basegfx::fround(aUnrotatedRange.getMinY()));
+ const Size aNewS(basegfx::fround(aUnrotatedRange.getWidth()), basegfx::fround(aUnrotatedRange.getHeight()));
+
+ SetRect(ImplEESdrWriter::ImplMapPoint(aNewP), ImplEESdrWriter::ImplMapSize(aNewS));
+ }
+ else
+ {
+ // if it's no group, use position and size directly, rotated/sheared or not
+ const Point aOldP(mXShape->getPosition().X, mXShape->getPosition().Y);
+ const Size aOldS(mXShape->getSize().Width, mXShape->getSize().Height);
+
+ SetRect(ImplEESdrWriter::ImplMapPoint(aOldP), ImplEESdrWriter::ImplMapSize(aOldS));
+ }
+
+ if( ImplGetPropertyValue( "IsPresentationObject" ) )
+ mbPresObj = ::cppu::any2bool( mAny );
+
+ if( mbPresObj && ImplGetPropertyValue( "IsEmptyPresentationObject" ) )
+ mbEmptyPresObj = ::cppu::any2bool( mAny );
+
+ mbValid = true;
+}
+
+bool ImplEESdrObject::ImplGetPropertyValue( const OUString& rString )
+{
+ bool bRetValue = false;
+ if( mbValid )
+ {
+ try
+ {
+ mAny = mXPropSet->getPropertyValue( rString );
+ if( mAny.hasValue() )
+ bRetValue = true;
+ }
+ catch( const css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ return bRetValue;
+}
+
+void ImplEESdrObject::SetRect( const Point& rPos, const Size& rSz )
+{
+ maRect = tools::Rectangle( rPos, rSz );
+}
+
+const SdrObject* ImplEESdrObject::GetSdrObject() const
+{
+ return EscherEx::GetSdrObject( mXShape );
+}
+
+// loads and converts text from shape, result is saved in mnTextSize
+sal_uInt32 ImplEESdrObject::ImplGetText()
+{
+ Reference< XText > xXText( mXShape, UNO_QUERY );
+ mnTextSize = 0;
+ if (xXText.is())
+ {
+ try
+ {
+ mnTextSize = xXText->getString().getLength();
+ }
+ catch (const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("filter.ms", "ImplGetText");
+ }
+ }
+ return mnTextSize;
+}
+
+bool ImplEESdrObject::ImplHasText() const
+{
+ Reference< XText > xXText( mXShape, UNO_QUERY );
+ return xXText.is() && !xXText->getString().isEmpty();
+}
+
+
+void ImplEESdrObject::SetOOXML(bool bOOXML)
+{
+ mbOOXML = bOOXML;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/eschesdo.hxx b/filter/source/msfilter/eschesdo.hxx
new file mode 100644
index 000000000..cf46f49b6
--- /dev/null
+++ b/filter/source/msfilter/eschesdo.hxx
@@ -0,0 +1,138 @@
+/* -*- 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/.
+ *
+ * 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 .
+ */
+#pragma once
+#include <filter/msfilter/escherex.hxx>
+#include <o3tl/any.hxx>
+
+
+// fractions of Draw PPTWriter etc.
+
+class ImplEESdrWriter;
+class SdrObject;
+class SdrPage;
+
+class ImplEESdrObject
+{
+ css::uno::Reference< css::drawing::XShape > mXShape;
+ css::uno::Any mAny;
+ tools::Rectangle maRect;
+ OUString mType;
+ sal_uInt32 mnShapeId;
+ sal_uInt32 mnTextSize;
+ sal_Int32 mnAngle;
+ bool mbValid : 1;
+ bool mbPresObj : 1;
+ bool mbEmptyPresObj : 1;
+ bool mbOOXML;
+
+ void Init();
+public:
+ css::uno::Reference< css::beans::XPropertySet > mXPropSet;
+
+ ImplEESdrObject( ImplEESdrWriter& rEx, const SdrObject& rObj, bool bOOXML );
+ ImplEESdrObject( const css::uno::Reference< css::drawing::XShape >& rShape );
+ ~ImplEESdrObject();
+
+ bool ImplGetPropertyValue( const OUString& rString );
+
+ sal_Int32 ImplGetInt32PropertyValue( const OUString& rStr )
+ { return ImplGetPropertyValue( rStr ) ? *o3tl::doAccess<sal_Int32>(mAny) : 0; }
+
+ const css::uno::Reference< css::drawing::XShape >& GetShapeRef() const { return mXShape; }
+ const css::uno::Any& GetUsrAny() const { return mAny; }
+ const OUString& GetType() const { return mType; }
+ void SetType( const OUString& rS ) { mType = rS; }
+
+ const tools::Rectangle& GetRect() const { return maRect; }
+ void SetRect( const Point& rPos, const Size& rSz );
+ void SetRect( const tools::Rectangle& rRect )
+ { maRect = rRect; }
+
+ sal_Int32 GetAngle() const { return mnAngle; }
+ void SetAngle( sal_Int32 nVal ) { mnAngle = nVal; }
+
+ bool IsValid() const { return mbValid; }
+
+ bool IsEmptyPresObj() const { return mbEmptyPresObj; }
+ sal_uInt32 GetShapeId() const { return mnShapeId; }
+ void SetShapeId( sal_uInt32 nVal ) { mnShapeId = nVal; }
+
+ const SdrObject* GetSdrObject() const;
+
+ sal_uInt32 ImplGetText();
+ bool ImplHasText() const;
+ bool GetOOXML() const { return mbOOXML;}
+ void SetOOXML(bool bOOXML);
+};
+
+
+// fractions of the Draw PPTWriter
+
+class EscherEx;
+namespace com::sun::star {
+ namespace drawing {
+ class XDrawPage;
+ class XShape;
+ }
+ namespace task {
+ class XStatusIndicator;
+ }
+}
+class EscherExHostAppData;
+
+class ImplEESdrWriter
+{
+ EscherEx* mpEscherEx;
+ css::uno::Reference< css::drawing::XDrawPage > mXDrawPage;
+ css::uno::Reference< css::drawing::XShapes > mXShapes;
+ SvStream* mpPicStrm;
+ // own extensions
+ EscherExHostAppData* mpHostAppData;
+ bool mbIsTitlePossible;
+ const SdrPage* mpSdrPage;
+ std::unique_ptr<EscherSolverContainer> mpSolverContainer;
+
+ void ImplInitPageValues();
+ void ImplWritePage( EscherSolverContainer& rSolver, bool ooxmlExport );
+ sal_uInt32 ImplWriteShape( ImplEESdrObject& rObj,
+ EscherSolverContainer& rSolver,
+ const bool bOOxmlExport = false ); // returns ShapeID
+ static void ImplFlipBoundingBox( ImplEESdrObject& rObj, EscherPropertyContainer& rPropOpt );
+ void ImplWriteAdditionalText(
+ ImplEESdrObject& rObj );
+ sal_uInt32 ImplEnterAdditionalTextGroup(
+ const css::uno::Reference< css::drawing::XShape >& rShape,
+ const tools::Rectangle* pBoundRect );
+ void ImplFlushSolverContainer();
+
+public:
+ explicit ImplEESdrWriter( EscherEx& rEx );
+ ~ImplEESdrWriter();
+ static Point ImplMapPoint( const Point& rPoint );
+ static Size ImplMapSize( const Size& rSize );
+ EscherExHostAppData* ImplGetHostData() { return mpHostAppData; }
+ bool ImplInitPage( const SdrPage& rPage );
+ bool ImplInitUnoShapes( const css::uno::Reference< css::drawing::XShapes >& rxShapes );
+ void ImplWriteCurrentPage( bool ooxmlExport );
+ sal_uInt32 ImplWriteTheShape( ImplEESdrObject& rObj, bool ooxmlExport );
+ void ImplExitPage();
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/mscodec.cxx b/filter/source/msfilter/mscodec.cxx
new file mode 100644
index 000000000..376a45320
--- /dev/null
+++ b/filter/source/msfilter/mscodec.cxx
@@ -0,0 +1,642 @@
+/* -*- 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/.
+ *
+ * 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 <filter/msfilter/mscodec.hxx>
+
+#include <osl/diagnose.h>
+#include <algorithm>
+#include <string.h>
+#include <tools/solar.h>
+
+#include <comphelper/hash.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/docpasswordhelper.hxx>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <utility>
+
+#define DEBUG_MSO_ENCRYPTION_STD97 0
+
+#if DEBUG_MSO_ENCRYPTION_STD97
+#include <stdio.h>
+#endif
+
+using namespace ::com::sun::star;
+
+namespace msfilter {
+
+
+namespace {
+
+/** Rotates rnValue left by nBits bits. */
+template< typename Type >
+void lclRotateLeft( Type& rnValue, int nBits )
+{
+ OSL_ASSERT(
+ nBits >= 0 &&
+ sal::static_int_cast< unsigned int >(nBits) < sizeof( Type ) * 8 );
+ rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
+}
+
+/** Rotates the lower nWidth bits of rnValue left by nBits bits. */
+template< typename Type >
+void lclRotateLeft( Type& rnValue, sal_uInt8 nBits, sal_uInt8 nWidth )
+{
+ OSL_ASSERT( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8) );
+ Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
+ rnValue = static_cast< Type >(
+ ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
+}
+
+std::size_t lclGetLen( const sal_uInt8* pnPassData, std::size_t nBufferSize )
+{
+ std::size_t nLen = 0;
+ while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
+ return nLen;
+}
+
+sal_uInt16 lclGetKey( const sal_uInt8* pnPassData, std::size_t nBufferSize )
+{
+ std::size_t nLen = lclGetLen( pnPassData, nBufferSize );
+ if( !nLen ) return 0;
+
+ sal_uInt16 nKey = 0;
+ sal_uInt16 nKeyBase = 0x8000;
+ sal_uInt16 nKeyEnd = 0xFFFF;
+ const sal_uInt8* pnChar = pnPassData + nLen - 1;
+ for( std::size_t nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
+ {
+ sal_uInt8 cChar = *pnChar & 0x7F;
+ for( sal_uInt8 nBit = 0; nBit < 8; ++nBit )
+ {
+ lclRotateLeft( nKeyBase, 1 );
+ if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
+ if( cChar & 1 ) nKey ^= nKeyBase;
+ cChar >>= 1;
+ lclRotateLeft( nKeyEnd, 1 );
+ if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
+ }
+ }
+ return nKey ^ nKeyEnd;
+}
+
+sal_uInt16 lclGetHash( const sal_uInt8* pnPassData, std::size_t nBufferSize )
+{
+ std::size_t nLen = lclGetLen( pnPassData, nBufferSize );
+
+ sal_uInt16 nHash = static_cast< sal_uInt16 >( nLen );
+ if( nLen )
+ nHash ^= 0xCE4B;
+
+ const sal_uInt8* pnChar = pnPassData;
+ for( std::size_t nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
+ {
+ sal_uInt16 cChar = *pnChar;
+ sal_uInt8 nRot = static_cast< sal_uInt8 >( (nIndex + 1) % 15 );
+ lclRotateLeft( cChar, nRot, 15 );
+ nHash ^= cChar;
+ }
+ return nHash;
+}
+
+
+} // namespace
+
+
+MSCodec_Xor95::MSCodec_Xor95(int nRotateDistance) :
+ mnOffset( 0 ),
+ mnKey( 0 ),
+ mnHash( 0 ),
+ mnRotateDistance( nRotateDistance )
+{
+}
+
+MSCodec_Xor95::~MSCodec_Xor95()
+{
+ memset( mpnKey, 0, sizeof( mpnKey ) );
+ mnKey = mnHash = 0;
+}
+
+void MSCodec_Xor95::InitKey( const sal_uInt8 pnPassData[ 16 ] )
+{
+ mnKey = lclGetKey( pnPassData, 16 );
+ mnHash = lclGetHash( pnPassData, 16 );
+
+ memcpy( mpnKey, pnPassData, 16 );
+
+ static const sal_uInt8 spnFillChars[] =
+ {
+ 0xBB, 0xFF, 0xFF, 0xBA,
+ 0xFF, 0xFF, 0xB9, 0x80,
+ 0x00, 0xBE, 0x0F, 0x00,
+ 0xBF, 0x0F, 0x00, 0x00
+ };
+
+ std::size_t nLen = lclGetLen( pnPassData, 16 );
+ const sal_uInt8* pnFillChar = spnFillChars;
+ for (std::size_t nIndex = nLen; nIndex < sizeof(mpnKey); ++nIndex, ++pnFillChar)
+ mpnKey[ nIndex ] = *pnFillChar;
+
+ SVBT16 pnOrigKey;
+ ShortToSVBT16( mnKey, pnOrigKey );
+ sal_uInt8* pnKeyChar = mpnKey;
+ for (std::size_t nIndex = 0; nIndex < sizeof(mpnKey); ++nIndex, ++pnKeyChar)
+ {
+ *pnKeyChar ^= pnOrigKey[ nIndex & 0x01 ];
+ lclRotateLeft( *pnKeyChar, mnRotateDistance );
+ }
+}
+
+bool MSCodec_Xor95::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
+{
+ bool bResult = false;
+
+ ::comphelper::SequenceAsHashMap aHashData( aData );
+ uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("XOR95EncryptionKey", uno::Sequence< sal_Int8 >() );
+
+ if ( aKey.getLength() == 16 )
+ {
+ memcpy( mpnKey, aKey.getConstArray(), 16 );
+ bResult = true;
+
+ mnKey = static_cast<sal_uInt16>(aHashData.getUnpackedValueOrDefault("XOR95BaseKey", sal_Int16(0) ));
+ mnHash = static_cast<sal_uInt16>(aHashData.getUnpackedValueOrDefault("XOR95PasswordHash", sal_Int16(0) ));
+ }
+ else
+ OSL_FAIL( "Unexpected key size!" );
+
+ return bResult;
+}
+
+uno::Sequence< beans::NamedValue > MSCodec_Xor95::GetEncryptionData()
+{
+ ::comphelper::SequenceAsHashMap aHashData;
+ // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
+ aHashData[ OUString( "XOR95EncryptionKey" ) ] <<= uno::Sequence<sal_Int8>( reinterpret_cast<sal_Int8*>(mpnKey), 16 );
+ aHashData[ OUString( "XOR95BaseKey" ) ] <<= static_cast<sal_Int16>(mnKey);
+ aHashData[ OUString( "XOR95PasswordHash" ) ] <<= static_cast<sal_Int16>(mnHash);
+
+ return aHashData.getAsConstNamedValueList();
+}
+
+bool MSCodec_Xor95::VerifyKey( sal_uInt16 nKey, sal_uInt16 nHash ) const
+{
+ return (nKey == mnKey) && (nHash == mnHash);
+}
+
+void MSCodec_Xor95::InitCipher()
+{
+ mnOffset = 0;
+}
+
+void MSCodec_XorXLS95::Decode( sal_uInt8* pnData, std::size_t nBytes )
+{
+ const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
+ const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
+
+ for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
+ {
+ lclRotateLeft( *pnData, 3 );
+ *pnData ^= *pnCurrKey;
+ if( pnCurrKey < pnKeyLast ) ++pnCurrKey; else pnCurrKey = mpnKey;
+ }
+
+ // update mnOffset
+ Skip( nBytes );
+}
+
+void MSCodec_XorWord95::Decode( sal_uInt8* pnData, std::size_t nBytes )
+{
+ const sal_uInt8* pnCurrKey = mpnKey + mnOffset;
+ const sal_uInt8* pnKeyLast = mpnKey + 0x0F;
+
+ for( const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
+ {
+ const sal_uInt8 cChar = *pnData ^ *pnCurrKey;
+ if (*pnData && cChar)
+ *pnData = cChar;
+
+ if( pnCurrKey < pnKeyLast )
+ ++pnCurrKey;
+ else
+ pnCurrKey = mpnKey;
+ }
+
+ // update mnOffset
+ Skip( nBytes );
+}
+
+
+void MSCodec_Xor95::Skip( std::size_t nBytes )
+{
+ mnOffset = (mnOffset + nBytes) & 0x0F;
+}
+
+MSCodec97::MSCodec97(size_t nHashLen, OUString aEncKeyName)
+ : m_sEncKeyName(std::move(aEncKeyName))
+ , m_nHashLen(nHashLen)
+ , m_hCipher(rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream))
+ , m_aDocId(16, 0)
+ , m_aDigestValue(nHashLen, 0)
+{
+ assert(m_hCipher != nullptr);
+}
+
+MSCodec_Std97::MSCodec_Std97()
+ : MSCodec97(RTL_DIGEST_LENGTH_MD5, "STD97EncryptionKey")
+{
+ m_hDigest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
+ assert(m_hDigest != nullptr);
+}
+
+MSCodec_CryptoAPI::MSCodec_CryptoAPI()
+ : MSCodec97(RTL_DIGEST_LENGTH_SHA1, "CryptoAPIEncryptionKey")
+{
+}
+
+MSCodec97::~MSCodec97()
+{
+ memset(m_aDigestValue.data(), 0, m_aDigestValue.size());
+ memset(m_aDocId.data(), 0, m_aDocId.size());
+ rtl_cipher_destroy(m_hCipher);
+}
+
+MSCodec_Std97::~MSCodec_Std97()
+{
+ rtl_digest_destroy(m_hDigest);
+}
+
+#if DEBUG_MSO_ENCRYPTION_STD97
+static void lcl_PrintDigest(const sal_uInt8* pDigest, const char* msg)
+{
+ printf("digest: (%s)\n", msg);
+ for (int i = 0; i < 16; ++i)
+ printf("%2.2x ", pDigest[i]);
+ printf("\n");
+}
+#else
+static void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*msg*/)
+{
+}
+#endif
+
+bool MSCodec97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
+{
+#if DEBUG_MSO_ENCRYPTION_STD97
+ fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout);
+#endif
+ bool bResult = false;
+
+ ::comphelper::SequenceAsHashMap aHashData( aData );
+ uno::Sequence<sal_Int8> aKey = aHashData.getUnpackedValueOrDefault(m_sEncKeyName, uno::Sequence<sal_Int8>());
+ const size_t nKeyLen = aKey.getLength();
+ if (nKeyLen == m_nHashLen)
+ {
+ assert(m_aDigestValue.size() == m_nHashLen);
+ memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_nHashLen);
+ uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() );
+ if ( aUniqueID.getLength() == 16 )
+ {
+ assert(m_aDocId.size() == static_cast<size_t>(aUniqueID.getLength()));
+ memcpy(m_aDocId.data(), aUniqueID.getConstArray(), m_aDocId.size());
+ bResult = true;
+ lcl_PrintDigest(m_aDigestValue.data(), "digest value");
+ lcl_PrintDigest(m_aDocId.data(), "DocId value");
+ }
+ else
+ OSL_FAIL( "Unexpected document ID!" );
+ }
+ else
+ OSL_FAIL( "Unexpected key size!" );
+
+ return bResult;
+}
+
+uno::Sequence< beans::NamedValue > MSCodec97::GetEncryptionData()
+{
+ ::comphelper::SequenceAsHashMap aHashData;
+ assert(m_aDigestValue.size() == m_nHashLen);
+ aHashData[m_sEncKeyName] <<= uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8*>(m_aDigestValue.data()), m_nHashLen);
+ aHashData[ OUString( "STD97UniqueID" ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(m_aDocId.data()), m_aDocId.size() );
+
+ return aHashData.getAsConstNamedValueList();
+}
+
+void MSCodec_Std97::InitKey (
+ const sal_uInt16 pPassData[16],
+ const sal_uInt8 pDocId[16])
+{
+#if DEBUG_MSO_ENCRYPTION_STD97
+ fprintf(stdout, "MSCodec_Std97::InitKey: --begin\n");fflush(stdout);
+#endif
+ uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId);
+ // Fill raw digest of above updates into DigestValue.
+
+ const size_t nKeyLen = aKey.getLength();
+ if (m_aDigestValue.size() == nKeyLen)
+ memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_aDigestValue.size());
+ else
+ memset(m_aDigestValue.data(), 0, m_aDigestValue.size());
+
+ lcl_PrintDigest(m_aDigestValue.data(), "digest value");
+
+ memcpy (m_aDocId.data(), pDocId, 16);
+
+ lcl_PrintDigest(m_aDocId.data(), "DocId value");
+}
+
+void MSCodec_CryptoAPI::InitKey (
+ const sal_uInt16 pPassData[16],
+ const sal_uInt8 pDocId[16])
+{
+ sal_uInt32 const saltSize = 16;
+
+ // Prepare initial data -> salt + password (in 16-bit chars)
+ std::vector<sal_uInt8> initialData(pDocId, pDocId + saltSize);
+
+ // Fill PassData into KeyData.
+ for (sal_Int32 nInd = 0; nInd < 16 && pPassData[nInd]; ++nInd)
+ {
+ initialData.push_back(sal::static_int_cast<sal_uInt8>((pPassData[nInd] >> 0) & 0xff));
+ initialData.push_back(sal::static_int_cast<sal_uInt8>((pPassData[nInd] >> 8) & 0xff));
+ }
+
+ // calculate SHA1 hash of initialData
+ std::vector<unsigned char> const sha1(::comphelper::Hash::calculateHash(
+ initialData.data(), initialData.size(),
+ ::comphelper::HashType::SHA1));
+ m_aDigestValue = sha1;
+
+ lcl_PrintDigest(m_aDigestValue.data(), "digest value");
+
+ memcpy(m_aDocId.data(), pDocId, 16);
+
+ lcl_PrintDigest(m_aDocId.data(), "DocId value");
+
+ //generate the old format key while we have the required data
+ m_aStd97Key = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId);
+}
+
+bool MSCodec97::VerifyKey(const sal_uInt8* pSaltData, const sal_uInt8* pSaltDigest)
+{
+ // both the salt data and salt digest (hash) come from the document being imported.
+
+#if DEBUG_MSO_ENCRYPTION_STD97
+ fprintf(stdout, "MSCodec97::VerifyKey: \n");
+ lcl_PrintDigest(pSaltData, "salt data");
+ lcl_PrintDigest(pSaltDigest, "salt hash");
+#endif
+ bool result = false;
+
+ if (InitCipher(0))
+ {
+ std::vector<sal_uInt8> aDigest(m_nHashLen);
+ GetDigestFromSalt(pSaltData, aDigest.data());
+
+ std::vector<sal_uInt8> aBuffer(m_nHashLen);
+ // Decode original SaltDigest into Buffer.
+ rtl_cipher_decode(m_hCipher, pSaltDigest, m_nHashLen, aBuffer.data(), m_nHashLen);
+
+ // Compare Buffer with computed Digest.
+ result = (memcmp(aBuffer.data(), aDigest.data(), m_nHashLen) == 0);
+
+ // Erase Buffer and Digest arrays.
+ rtl_secureZeroMemory(aBuffer.data(), m_nHashLen);
+ rtl_secureZeroMemory(aDigest.data(), m_nHashLen);
+ }
+
+ return result;
+}
+
+void MSCodec_CryptoAPI::GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest)
+{
+ std::vector<sal_uInt8> verifier(16);
+ rtl_cipher_decode(m_hCipher,
+ pSaltData, 16, verifier.data(), verifier.size());
+
+ std::vector<unsigned char> const sha1(::comphelper::Hash::calculateHash(
+ verifier.data(), verifier.size(), ::comphelper::HashType::SHA1));
+ ::std::copy(sha1.begin(), sha1.end(), pDigest);
+}
+
+bool MSCodec_Std97::InitCipher(sal_uInt32 nCounter)
+{
+ sal_uInt8 pKeyData[64] = {}; // 512-bit message block
+
+ // Fill 40 bit of DigestValue into [0..4].
+ memcpy (pKeyData, m_aDigestValue.data(), 5);
+
+ // Fill counter into [5..8].
+ pKeyData[ 5] = sal_uInt8((nCounter >> 0) & 0xff);
+ pKeyData[ 6] = sal_uInt8((nCounter >> 8) & 0xff);
+ pKeyData[ 7] = sal_uInt8((nCounter >> 16) & 0xff);
+ pKeyData[ 8] = sal_uInt8((nCounter >> 24) & 0xff);
+
+ pKeyData[ 9] = 0x80;
+ pKeyData[56] = 0x48;
+
+ // Fill raw digest of KeyData into KeyData.
+ (void)rtl_digest_updateMD5 (
+ m_hDigest, pKeyData, sizeof(pKeyData));
+ (void)rtl_digest_rawMD5 (
+ m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
+
+ // Initialize Cipher with KeyData (for decoding).
+ rtlCipherError result = rtl_cipher_init (
+ m_hCipher, rtl_Cipher_DirectionBoth,
+ pKeyData, RTL_DIGEST_LENGTH_MD5, nullptr, 0);
+
+ // Erase KeyData array and leave.
+ rtl_secureZeroMemory (pKeyData, sizeof(pKeyData));
+
+ return (result == rtl_Cipher_E_None);
+}
+
+bool MSCodec_CryptoAPI::InitCipher(sal_uInt32 nCounter)
+{
+ // data = hash + iterator (4bytes)
+ std::vector<sal_uInt8> aKeyData(m_aDigestValue);
+ aKeyData.push_back(sal_uInt8((nCounter >> 0) & 0xff));
+ aKeyData.push_back(sal_uInt8((nCounter >> 8) & 0xff));
+ aKeyData.push_back(sal_uInt8((nCounter >> 16) & 0xff));
+ aKeyData.push_back(sal_uInt8((nCounter >> 24) & 0xff));
+
+ std::vector<unsigned char> const hash(::comphelper::Hash::calculateHash(
+ aKeyData.data(), aKeyData.size(), ::comphelper::HashType::SHA1));
+
+ rtlCipherError result =
+ rtl_cipher_init(m_hCipher, rtl_Cipher_DirectionDecode,
+ hash.data(), ENCRYPT_KEY_SIZE_AES_128/8, nullptr, 0);
+
+ return (result == rtl_Cipher_E_None);
+}
+
+uno::Sequence<beans::NamedValue> MSCodec_CryptoAPI::GetEncryptionData()
+{
+ ::comphelper::SequenceAsHashMap aHashData(MSCodec97::GetEncryptionData());
+ //add in the old encryption key as well as our new key so saving using the
+ //old crypto scheme can be done without reprompt for the password
+ aHashData[OUString("STD97EncryptionKey")] <<= m_aStd97Key;
+ return aHashData.getAsConstNamedValueList();
+}
+
+void MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] )
+{
+#if DEBUG_MSO_ENCRYPTION_STD97
+ lcl_PrintDigest(nSaltData, "salt data");
+#endif
+ if (InitCipher(0))
+ {
+ sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
+ GetDigestFromSalt(nSaltData, pDigest);
+
+ rtl_cipher_decode (
+ m_hCipher, pDigest, 16, pDigest, sizeof(pDigest));
+
+ memcpy(nSaltDigest, pDigest, 16);
+ }
+}
+
+bool MSCodec97::Encode (
+ const void *pData, std::size_t nDatLen,
+ sal_uInt8 *pBuffer, std::size_t nBufLen)
+{
+ rtlCipherError result = rtl_cipher_encode(
+ m_hCipher, pData, nDatLen, pBuffer, nBufLen);
+
+ return (result == rtl_Cipher_E_None);
+}
+
+bool MSCodec97::Decode (
+ const void *pData, std::size_t nDatLen,
+ sal_uInt8 *pBuffer, std::size_t nBufLen)
+{
+ rtlCipherError result = rtl_cipher_decode(
+ m_hCipher, pData, nDatLen, pBuffer, nBufLen);
+
+ return (result == rtl_Cipher_E_None);
+}
+
+bool MSCodec97::Skip(std::size_t nDatLen)
+{
+ sal_uInt8 pnDummy[ 1024 ];
+ std::size_t nDatLeft = nDatLen;
+ bool bResult = true;
+
+ while (bResult && nDatLeft)
+ {
+ std::size_t nBlockLen = ::std::min< std::size_t >( nDatLeft, sizeof(pnDummy) );
+ bResult = Decode( pnDummy, nBlockLen, pnDummy, nBlockLen );
+ nDatLeft -= nBlockLen;
+ }
+
+ return bResult;
+}
+
+void MSCodec_Std97::GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest)
+{
+ sal_uInt8 pBuffer[64];
+ sal_uInt8 pDigestLocal[16];
+
+ // Decode SaltData into Buffer.
+ rtl_cipher_decode (
+ m_hCipher, pSaltData, 16, pBuffer, sizeof(pBuffer));
+
+ // set the 129th bit to make the buffer 128-bit in length.
+ pBuffer[16] = 0x80;
+
+ // erase the rest of the buffer with zeros.
+ memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
+
+ // set the 441st bit.
+ pBuffer[56] = 0x80;
+
+ // Fill raw digest of Buffer into Digest.
+ rtl_digest_updateMD5 (
+ m_hDigest, pBuffer, sizeof(pBuffer));
+ rtl_digest_rawMD5 (
+ m_hDigest, pDigestLocal, sizeof(pDigestLocal));
+
+ memcpy(pDigest, pDigestLocal, 16);
+}
+
+void MSCodec_Std97::GetEncryptKey (
+ const sal_uInt8 pSalt[16],
+ sal_uInt8 pSaltData[16],
+ sal_uInt8 pSaltDigest[16])
+{
+ if (!InitCipher(0))
+ return;
+
+ sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
+ sal_uInt8 pBuffer[64];
+
+ rtl_cipher_encode (
+ m_hCipher, pSalt, 16, pSaltData, sizeof(pBuffer));
+
+ memcpy( pBuffer, pSalt, 16 );
+
+ pBuffer[16] = 0x80;
+ memset (pBuffer + 17, 0, sizeof(pBuffer) - 17);
+ pBuffer[56] = 0x80;
+
+ rtl_digest_updateMD5 (
+ m_hDigest, pBuffer, sizeof(pBuffer));
+ rtl_digest_rawMD5 (
+ m_hDigest, pDigest, sizeof(pDigest));
+
+ rtl_cipher_encode (
+ m_hCipher, pDigest, 16, pSaltDigest, 16);
+
+ rtl_secureZeroMemory (pBuffer, sizeof(pBuffer));
+ rtl_secureZeroMemory (pDigest, sizeof(pDigest));
+}
+
+void MSCodec97::GetDocId( sal_uInt8 pDocId[16] )
+{
+ assert(m_aDocId.size() == 16);
+ memcpy(pDocId, m_aDocId.data(), 16);
+}
+
+EncryptionStandardHeader::EncryptionStandardHeader()
+{
+ flags = 0;
+ sizeExtra = 0;
+ algId = 0;
+ algIdHash = 0;
+ keyBits = 0;
+ providedType = 0;
+ reserved1 = 0;
+ reserved2 = 0;
+}
+
+EncryptionVerifierAES::EncryptionVerifierAES()
+ : saltSize(SALT_LENGTH)
+ , encryptedVerifierHashSize(comphelper::SHA1_HASH_LENGTH)
+{
+}
+
+EncryptionVerifierRC4::EncryptionVerifierRC4()
+ : saltSize(SALT_LENGTH)
+ , encryptedVerifierHashSize(comphelper::SHA1_HASH_LENGTH)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx
new file mode 100644
index 000000000..66bac102a
--- /dev/null
+++ b/filter/source/msfilter/msdffimp.cxx
@@ -0,0 +1,7610 @@
+/* -*- 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/.
+ *
+ * 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 <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <math.h>
+#include <limits>
+#include <limits.h>
+#include <utility>
+#include <vector>
+
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/file.hxx>
+#include <tools/solar.h>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+
+#include <comphelper/classids.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/seqstream.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <sot/exchange.hxx>
+#include <sot/storinfo.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/wmf.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/BitmapTools.hxx>
+#include "viscache.hxx"
+
+// SvxItem-Mapping. Is needed to successfully include the SvxItem-Header
+#include <editeng/eeitem.hxx>
+#include <editeng/editdata.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#include <tools/zcodec.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <com/sun/star/drawing/Position3D.hpp>
+#include <com/sun/star/drawing/Direction3D.hpp>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/BitmapReadAccess.hxx>
+#include <sot/storage.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xsflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/xlntrit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+#include <svx/xflbmsxy.hxx>
+#include <svx/xflbmsli.hxx>
+#include <editeng/frmdir.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/sxenditm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/sxekitm.hxx>
+#include <svx/xpoly.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/xlnedcit.hxx>
+#include <svx/sdasitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <svx/sdshcitm.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdshtitm.hxx>
+#include <svx/sdsxyitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtcfitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <filter/msfilter/classids.hxx>
+#include <filter/msfilter/msdffimp.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/outlobj.hxx>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+#include <vcl/dibtools.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/EnhancedCustomShapeTypeNames.hxx>
+#include <svx/EnhancedCustomShapeGeometry.hxx>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <svx/EnhancedCustomShape2d.hxx>
+#include <rtl/ustring.hxx>
+#include <svtools/embedhlp.hxx>
+#include <memory>
+
+using namespace ::com::sun::star ;
+using namespace ::com::sun::star::drawing;
+using namespace uno ;
+using namespace beans ;
+using namespace drawing ;
+using namespace container ;
+
+// static counter for OLE-Objects
+static sal_uInt32 nMSOleObjCntr = 0;
+constexpr OUStringLiteral MSO_OLE_Obj = u"MSO_OLE_Obj";
+
+namespace {
+/* Office File Formats - 2.2.23 */
+enum class OfficeArtBlipRecInstance : sal_uInt32
+{
+ EMF = 0x3D4, // defined in section 2.2.24.
+ WMF = 0x216, // defined in section 2.2.25.
+ PICT = 0x542, // as defined in section 2.2.26.
+ JPEG_RGB = 0x46A, // defined in section 2.2.27.
+ JPEG_CMYK = 0x6E2, // defined in section 2.2.27.
+ PNG = 0x6E0, // defined in section 2.2.28.
+ DIB = 0x7A8, // defined in section 2.2.29.
+ TIFF = 0x6E4 // defined in section 2.2.30.
+};
+
+struct SvxMSDffBLIPInfo
+{
+ sal_uLong nFilePos; ///< offset of the BLIP in data stream
+ explicit SvxMSDffBLIPInfo(sal_uLong nFPos)
+ : nFilePos(nFPos)
+ {
+ }
+};
+
+}
+
+/// the following will be sorted by the order of their appearance:
+struct SvxMSDffBLIPInfos : public std::vector<SvxMSDffBLIPInfo> {};
+
+/************************************************************************/
+void Impl_OlePres::Write( SvStream & rStm )
+{
+ WriteClipboardFormat( rStm, SotClipboardFormatId::GDIMETAFILE );
+ rStm.WriteInt32( 4 ); // a TargetDevice that's always empty
+ rStm.WriteUInt32( nAspect );
+ rStm.WriteInt32( -1 ); //L-Index always -1
+ rStm.WriteInt32( nAdvFlags );
+ rStm.WriteInt32( 0 ); //Compression
+ rStm.WriteInt32( aSize.Width() );
+ rStm.WriteInt32( aSize.Height() );
+ sal_uInt64 nPos = rStm.Tell();
+ rStm.WriteInt32( 0 );
+
+ if( nFormat == SotClipboardFormatId::GDIMETAFILE && pMtf )
+ {
+ // Always to 1/100 mm, until Mtf-Solution found
+ // Assumption (no scaling, no origin translation)
+ DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleX() == Fraction( 1, 1 ),
+ "x-scale in the Mtf is wrong" );
+ DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleY() == Fraction( 1, 1 ),
+ "y-scale in the Mtf is wrong" );
+ DBG_ASSERT( pMtf->GetPrefMapMode().GetOrigin() == Point(),
+ "origin-shift in the Mtf is wrong" );
+ MapUnit nMU = pMtf->GetPrefMapMode().GetMapUnit();
+ if( MapUnit::Map100thMM != nMU )
+ {
+ Size aPrefS( pMtf->GetPrefSize() );
+ Size aS = OutputDevice::LogicToLogic(aPrefS, MapMode(nMU), MapMode(MapUnit::Map100thMM));
+
+ pMtf->Scale( Fraction( aS.Width(), aPrefS.Width() ),
+ Fraction( aS.Height(), aPrefS.Height() ) );
+ pMtf->SetPrefMapMode(MapMode(MapUnit::Map100thMM));
+ pMtf->SetPrefSize( aS );
+ }
+ WriteWindowMetafileBits( rStm, *pMtf );
+ }
+ else
+ {
+ OSL_FAIL( "unknown format" );
+ }
+ sal_uInt64 nEndPos = rStm.Tell();
+ rStm.Seek( nPos );
+ rStm.WriteUInt32( nEndPos - nPos - 4 );
+ rStm.Seek( nEndPos );
+}
+
+DffPropertyReader::DffPropertyReader( const SvxMSDffManager& rMan )
+ : rManager(rMan)
+ , mnFix16Angle(0)
+ , mbRotateGranientFillWithAngle(false)
+{
+ InitializePropSet( DFF_msofbtOPT );
+}
+
+void DffPropertyReader::SetDefaultPropSet( SvStream& rStCtrl, sal_uInt32 nOffsDgg ) const
+{
+ const_cast<DffPropertyReader*>(this)->pDefaultPropSet.reset();
+ sal_uInt64 nOldPos = rStCtrl.Tell();
+ bool bOk = checkSeek(rStCtrl, nOffsDgg);
+ DffRecordHeader aRecHd;
+ if (bOk)
+ bOk = ReadDffRecordHeader( rStCtrl, aRecHd );
+ if (bOk && aRecHd.nRecType == DFF_msofbtDggContainer)
+ {
+ if ( SvxMSDffManager::SeekToRec( rStCtrl, DFF_msofbtOPT, aRecHd.GetRecEndFilePos() ) )
+ {
+ const_cast<DffPropertyReader*>(this)->pDefaultPropSet.reset( new DffPropSet );
+ ReadDffPropSet( rStCtrl, *pDefaultPropSet );
+ }
+ }
+ rStCtrl.Seek( nOldPos );
+}
+
+#ifdef DBG_CUSTOMSHAPE
+void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData, sal_uInt32 nShapeId ) const
+#else
+void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData ) const
+#endif
+{
+ sal_uInt64 nFilePos = rIn.Tell();
+ ReadDffPropSet( rIn, const_cast<DffPropertyReader&>(*this) );
+
+ if ( IsProperty( DFF_Prop_hspMaster ) )
+ {
+ if ( rManager.SeekToShape( rIn, pClientData, GetPropertyValue( DFF_Prop_hspMaster, 0 ) ) )
+ {
+ DffRecordHeader aRecHd;
+ bool bOk = ReadDffRecordHeader(rIn, aRecHd);
+ if (bOk && SvxMSDffManager::SeekToRec(rIn, DFF_msofbtOPT, aRecHd.GetRecEndFilePos()))
+ {
+ rIn |= const_cast<DffPropertyReader&>(*this);
+ }
+ }
+ }
+
+ const_cast<DffPropertyReader*>(this)->mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) );
+
+#ifdef DBG_CUSTOMSHAPE
+
+ OUString aURLStr;
+
+ if( osl::FileBase::getFileURLFromSystemPath( OUString("d:\\ashape.dbg"), aURLStr ) == osl::FileBase::E_None )
+ {
+ std::unique_ptr<SvStream> xOut(::utl::UcbStreamHelper::CreateStream( aURLStr, StreamMode::WRITE ));
+
+ if( xOut )
+ {
+ xOut->Seek( STREAM_SEEK_TO_END );
+
+ if ( IsProperty( DFF_Prop_adjustValue ) || IsProperty( DFF_Prop_pVertices ) )
+ {
+ xOut->WriteLine( "" );
+ OString aString("ShapeId: " + OString::number(nShapeId));
+ xOut->WriteLine(aString);
+ }
+ for ( sal_uInt32 i = DFF_Prop_adjustValue; i <= DFF_Prop_adjust10Value; i++ )
+ {
+ if ( IsProperty( i ) )
+ {
+ OString aString("Prop_adjustValue" + OString::number( ( i - DFF_Prop_adjustValue ) + 1 ) +
+ ":" + OString::number(GetPropertyValue(i)) );
+ xOut->WriteLine(aString);
+ }
+ }
+ sal_Int32 i;
+ for ( i = 320; i < 383; i++ )
+ {
+ if ( ( i >= DFF_Prop_adjustValue ) && ( i <= DFF_Prop_adjust10Value ) )
+ continue;
+ if ( IsProperty( i ) )
+ {
+ if ( SeekToContent( i, rIn ) )
+ {
+ sal_Int32 nLen = (sal_Int32)GetPropertyValue( i );
+ if ( nLen )
+ {
+ xOut->WriteLine( "" );
+ OStringBuffer aDesc("Property:" + OString::number(i) +
+ " Size:" + OString::number(nLen));
+ xOut->WriteLine(aDesc.makeStringAndClear());
+ sal_Int16 nNumElem, nNumElemMem, nNumSize;
+ rIn >> nNumElem >> nNumElemMem >> nNumSize;
+ aDesc.append("Entries: " + OString::number(nNumElem) +
+ " Size:" + OString::number(nNumSize));
+ xOut->WriteLine(aDesc.makeStringAndClear());
+ if ( nNumSize < 0 )
+ nNumSize = ( ( -nNumSize ) >> 2 );
+ if ( !nNumSize )
+ nNumSize = 16;
+ nLen -= 6;
+ while ( nLen > 0 )
+ {
+ for ( sal_uInt32 j = 0; nLen && ( j < ( nNumSize >> 1 ) ); j++ )
+ {
+ for ( sal_uInt32 k = 0; k < 2; k++ )
+ {
+ if ( nLen )
+ {
+ sal_uInt8 nVal;
+ rIn >> nVal;
+ if ( ( nVal >> 4 ) > 9 )
+ *xOut << (sal_uInt8)( ( nVal >> 4 ) + 'A' - 10 );
+ else
+ *xOut << (sal_uInt8)( ( nVal >> 4 ) + '0' );
+
+ if ( ( nVal & 0xf ) > 9 )
+ *xOut << (sal_uInt8)( ( nVal & 0xf ) + 'A' - 10 );
+ else
+ *xOut << (sal_uInt8)( ( nVal & 0xf ) + '0' );
+
+ nLen--;
+ }
+ }
+ *xOut << (char)( ' ' );
+ }
+ xOut->WriteLine( OString() );
+ }
+ }
+ }
+ else
+ {
+ OString aString("Property" + OString::number(i) +
+ ":" + OString::number(GetPropertyValue(i)));
+ xOut->WriteLine(aString);
+ }
+ }
+ }
+ }
+ }
+
+#endif
+
+ rIn.Seek( nFilePos );
+}
+
+
+Degree100 DffPropertyReader::Fix16ToAngle( sal_Int32 nContent )
+{
+ Degree100 nAngle(0);
+ if ( nContent )
+ {
+ nAngle = Degree100(( static_cast<sal_Int16>( nContent >> 16) * 100L ) + ( ( ( nContent & 0x0000ffff) * 100L ) >> 16 ));
+ nAngle = NormAngle36000( -nAngle );
+ }
+ return nAngle;
+}
+
+DffPropertyReader::~DffPropertyReader()
+{
+}
+
+static SvStream& operator>>( SvStream& rIn, SvxMSDffConnectorRule& rRule )
+{
+ sal_uInt32 nRuleId;
+ rIn.ReadUInt32( nRuleId )
+ .ReadUInt32( rRule.nShapeA )
+ .ReadUInt32( rRule.nShapeB )
+ .ReadUInt32( rRule.nShapeC )
+ .ReadUInt32( rRule.ncptiA )
+ .ReadUInt32( rRule.ncptiB );
+
+ return rIn;
+}
+
+SvxMSDffSolverContainer::SvxMSDffSolverContainer()
+{
+}
+
+SvxMSDffSolverContainer::~SvxMSDffSolverContainer()
+{
+}
+
+SvStream& ReadSvxMSDffSolverContainer( SvStream& rIn, SvxMSDffSolverContainer& rContainer )
+{
+ DffRecordHeader aHd;
+ bool bOk = ReadDffRecordHeader( rIn, aHd );
+ if (!bOk || aHd.nRecType != DFF_msofbtSolverContainer)
+ return rIn;
+
+ DffRecordHeader aCRule;
+ auto nEndPos = DffPropSet::SanitizeEndPos(rIn, aHd.GetRecEndFilePos());
+ while ( rIn.good() && ( rIn.Tell() < nEndPos ) )
+ {
+ if (!ReadDffRecordHeader(rIn, aCRule))
+ break;
+ if ( aCRule.nRecType == DFF_msofbtConnectorRule )
+ {
+ std::unique_ptr<SvxMSDffConnectorRule> pRule(new SvxMSDffConnectorRule);
+ rIn >> *pRule;
+ rContainer.aCList.push_back( std::move(pRule) );
+ }
+ if (!aCRule.SeekToEndOfRecord(rIn))
+ break;
+ }
+ return rIn;
+}
+
+void SvxMSDffManager::SolveSolver( const SvxMSDffSolverContainer& rSolver )
+{
+ size_t i, nCnt;
+ for ( i = 0, nCnt = rSolver.aCList.size(); i < nCnt; i++ )
+ {
+ SvxMSDffConnectorRule* pPtr = rSolver.aCList[ i ].get();
+ if ( pPtr->pCObj )
+ {
+ for ( int nN = 0; nN < 2; nN++ )
+ {
+ SdrObject* pO;
+ sal_uInt32 nC;
+ ShapeFlag nSpFlags;
+ if ( !nN )
+ {
+ pO = pPtr->pAObj;
+ nC = pPtr->ncptiA;
+ nSpFlags = pPtr->nSpFlagsA;
+ }
+ else
+ {
+ pO = pPtr->pBObj;
+ nC = pPtr->ncptiB;
+ nSpFlags = pPtr->nSpFlagsB;
+ }
+ if ( pO )
+ {
+ SdrGluePoint aGluePoint;
+ Reference< XShape > aXShape( pO->getUnoShape(), UNO_QUERY );
+ Reference< XShape > aXConnector( pPtr->pCObj->getUnoShape(), UNO_QUERY );
+ SdrGluePointList* pList = pO->ForceGluePointList();
+
+ sal_Int32 nId = nC;
+ SdrInventor nInventor = pO->GetObjInventor();
+
+ if( nInventor == SdrInventor::Default )
+ {
+ bool bValidGluePoint = false;
+ SdrObjKind nObjId = pO->GetObjIdentifier();
+ switch( nObjId )
+ {
+ case SdrObjKind::Group :
+ case SdrObjKind::Graphic :
+ case SdrObjKind::Rectangle :
+ case SdrObjKind::Text :
+ case SdrObjKind::Page :
+ case SdrObjKind::TitleText :
+ case SdrObjKind::OutlineText :
+ {
+ if ( nC & 1 )
+ {
+ if ( nSpFlags & ShapeFlag::FlipH )
+ nC ^= 2; // 1 <-> 3
+ }
+ else
+ {
+ if ( nSpFlags & ShapeFlag::FlipV )
+ nC ^= 1; // 0 <-> 2
+ }
+ switch( nC )
+ {
+ case 0 :
+ nId = 0; // SdrAlign::VERT_TOP;
+ break;
+ case 1 :
+ nId = 3; // SdrAlign::HORZ_RIGHT;
+ break;
+ case 2 :
+ nId = 2; // SdrAlign::VERT_BOTTOM;
+ break;
+ case 3 :
+ nId = 1; // SdrAlign::HORZ_LEFT;
+ break;
+ }
+ if ( nId <= 3 )
+ bValidGluePoint = true;
+ }
+ break;
+ case SdrObjKind::Polygon :
+ case SdrObjKind::PolyLine :
+ case SdrObjKind::Line :
+ case SdrObjKind::PathLine :
+ case SdrObjKind::PathFill :
+ case SdrObjKind::FreehandLine :
+ case SdrObjKind::FreehandFill :
+ case SdrObjKind::SplineLine :
+ case SdrObjKind::SplineFill :
+ case SdrObjKind::PathPoly :
+ case SdrObjKind::PathPolyLine :
+ {
+ if (pList)
+ {
+ if (pList->GetCount() > nC )
+ {
+ bValidGluePoint = true;
+ nId = static_cast<sal_Int32>((*pList)[ static_cast<sal_uInt16>(nC)].GetId() + 3 );
+ }
+ else
+ {
+ bool bNotFound = true;
+
+ tools::PolyPolygon aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aXShape ) );
+ sal_uInt16 k, j, nPolySize = aPolyPoly.Count();
+ if ( nPolySize )
+ {
+ tools::Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
+ if ( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
+ {
+ sal_uInt32 nPointCount = 0;
+ for ( k = 0; bNotFound && ( k < nPolySize ); k++ )
+ {
+ const tools::Polygon& rPolygon = aPolyPoly.GetObject( k );
+ for ( j = 0; bNotFound && ( j < rPolygon.GetSize() ); j++ )
+ {
+ PolyFlags eFlags = rPolygon.GetFlags( j );
+ if ( eFlags == PolyFlags::Normal )
+ {
+ if ( nC == nPointCount )
+ {
+ const Point& rPoint = rPolygon.GetPoint( j );
+ double fXRel = rPoint.X() - aBoundRect.Left();
+ double fYRel = rPoint.Y() - aBoundRect.Top();
+ sal_Int32 nWidth = aBoundRect.GetWidth();
+ if ( !nWidth )
+ nWidth = 1;
+ sal_Int32 nHeight= aBoundRect.GetHeight();
+ if ( !nHeight )
+ nHeight = 1;
+ fXRel /= static_cast<double>(nWidth);
+ fXRel *= 10000;
+ fYRel /= static_cast<double>(nHeight);
+ fYRel *= 10000;
+ aGluePoint.SetPos( Point( static_cast<sal_Int32>(fXRel), static_cast<sal_Int32>(fYRel) ) );
+ aGluePoint.SetPercent( true );
+ aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT );
+ aGluePoint.SetEscDir( SdrEscapeDirection::SMART );
+ nId = static_cast<sal_Int32>((*pList)[ pList->Insert( aGluePoint ) ].GetId() + 3 );
+ bNotFound = false;
+ }
+ nPointCount++;
+ }
+ }
+ }
+ }
+ }
+ if ( !bNotFound )
+ {
+ bValidGluePoint = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case SdrObjKind::CustomShape :
+ {
+ const SfxPoolItem& aCustomShape = static_cast<SdrObjCustomShape*>(pO)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ SdrCustomShapeGeometryItem aGeometryItem( static_cast<const SdrCustomShapeGeometryItem&>(aCustomShape) );
+ static const OUStringLiteral sPath( u"Path" );
+ sal_Int16 nGluePointType = EnhancedCustomShapeGluePointType::SEGMENTS;
+ css::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sPath, "GluePointType" );
+ if ( pAny )
+ *pAny >>= nGluePointType;
+ else
+ {
+ OUString sShapeType;
+ pAny = aGeometryItem.GetPropertyValueByName( "Type" );
+ if ( pAny )
+ *pAny >>= sShapeType;
+ MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
+ nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType );
+ }
+ if ( nGluePointType == EnhancedCustomShapeGluePointType::CUSTOM )
+ {
+ if ( pList && ( pList->GetCount() > nC ) )
+ {
+ bValidGluePoint = true;
+ nId = static_cast<sal_Int32>((*pList)[ static_cast<sal_uInt16>(nC)].GetId() + 3 );
+ }
+ }
+ else if ( nGluePointType == EnhancedCustomShapeGluePointType::RECT )
+ {
+ if ( nC & 1 )
+ {
+ if ( nSpFlags & ShapeFlag::FlipH )
+ nC ^= 2; // 1 <-> 3
+ }
+ else
+ {
+ if ( nSpFlags & ShapeFlag::FlipV )
+ nC ^= 1; // 0 <-> 2
+ }
+ switch( nC )
+ {
+ case 0 :
+ nId = 0; // SdrAlign::VERT_TOP;
+ break;
+ case 1 :
+ nId = 3; // SdrAlign::HORZ_RIGHT;
+ break;
+ case 2 :
+ nId = 2; // SdrAlign::VERT_BOTTOM;
+ break;
+ case 3 :
+ nId = 1; // SdrAlign::HORZ_LEFT;
+ break;
+ }
+ if ( nId <= 3 )
+ bValidGluePoint = true;
+ }
+ else if ( nGluePointType == EnhancedCustomShapeGluePointType::SEGMENTS )
+ {
+ sal_uInt32 nPt = nC;
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, "Segments" );
+ if ( pAny && (*pAny >>= aSegments) )
+ {
+ nPt = 0;
+ for ( sal_Int32 k = 1; nC && ( k < aSegments.getLength() ); k++ )
+ {
+ sal_Int16 j, nCnt2 = aSegments[ k ].Count;
+ if ( aSegments[ k ].Command != EnhancedCustomShapeSegmentCommand::UNKNOWN )
+ {
+ for ( j = 0; nC && ( j < nCnt2 ); j++ )
+ {
+ switch( aSegments[ k ].Command )
+ {
+ case EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
+ case EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
+ case EnhancedCustomShapeSegmentCommand::LINETO :
+ case EnhancedCustomShapeSegmentCommand::MOVETO :
+ {
+ nC--;
+ nPt++;
+ }
+ break;
+ case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
+ case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
+ break;
+
+ case EnhancedCustomShapeSegmentCommand::CURVETO :
+ {
+ nC--;
+ nPt += 3;
+ }
+ break;
+
+ case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
+ case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
+ {
+ nC--;
+ nPt += 3;
+ }
+ break;
+ case EnhancedCustomShapeSegmentCommand::ARCTO :
+ case EnhancedCustomShapeSegmentCommand::ARC :
+ case EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
+ case EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
+ {
+ nC--;
+ nPt += 4;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
+ if ( pAny )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
+ *pAny >>= aCoordinates;
+ if ( nPt < o3tl::make_unsigned(aCoordinates.getLength()) )
+ {
+ nId = 4;
+ css::drawing::EnhancedCustomShapeParameterPair& rPara = aCoordinates.getArray()[ nPt ];
+ sal_Int32 nX = 0, nY = 0;
+ if ( ( rPara.First.Value >>= nX ) && ( rPara.Second.Value >>= nY ) )
+ {
+ static const OUStringLiteral sGluePoints( u"GluePoints" );
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
+ if ( pAny )
+ *pAny >>= aGluePoints;
+ sal_Int32 nGluePoints = aGluePoints.getLength();
+ aGluePoints.realloc( nGluePoints + 1 );
+ auto pGluePoints = aGluePoints.getArray();
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].First, nX );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].Second, nY );
+ PropertyValue aProp;
+ aProp.Name = sGluePoints;
+ aProp.Value <<= aGluePoints;
+ aGeometryItem.SetPropertyValue( sPath, aProp );
+ bValidGluePoint = true;
+ static_cast<SdrObjCustomShape*>(pO)->SetMergedItem( aGeometryItem );
+ SdrGluePointList* pLst = pO->ForceGluePointList();
+ if ( pLst->GetCount() > nGluePoints )
+ nId = static_cast<sal_Int32>((*pLst)[ static_cast<sal_uInt16>(nGluePoints) ].GetId() + 3 );
+ }
+ }
+ }
+ }
+ }
+ break;
+ default: ;
+ }
+ if ( bValidGluePoint )
+ {
+ Reference< XPropertySet > xPropSet( aXConnector, UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ if ( nN )
+ {
+ OUString aPropName( "EndShape" );
+ SetPropValue( Any(aXShape), xPropSet, aPropName );
+ aPropName = "EndGluePointIndex";
+ SetPropValue( Any(nId), xPropSet, aPropName );
+ }
+ else
+ {
+ OUString aPropName( "StartShape" );
+ SetPropValue( Any(aXShape), xPropSet, aPropName );
+ aPropName = "StartGluePointIndex";
+ SetPropValue( Any(nId), xPropSet, aPropName );
+ }
+
+ // Not sure what this is good for, repaint or broadcast of object change.
+ //( Thus I am adding repaint here
+ pO->SetChanged();
+ pO->BroadcastObjectChange();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static basegfx::B2DPolyPolygon GetLineArrow( const sal_Int32 nLineWidth, const sal_uInt32 eLineEnd,
+ const sal_uInt32 eLineWidth, const sal_uInt32 eLineLength,
+ sal_Int32& rnArrowWidth, bool& rbArrowCenter,
+ OUString& rsArrowName, bool bScaleArrow )
+{
+ basegfx::B2DPolyPolygon aRetPolyPoly;
+ // 70 100mm = 2pt = 40 twip. In MS, line width less than 2pt has the same size arrow as 2pt
+ //If the unit is twip. Make all use this unit especially the critical value 70/40.
+ sal_Int32 nLineWidthCritical = bScaleArrow ? 40 : 70;
+ double fLineWidth = nLineWidth < nLineWidthCritical ? nLineWidthCritical : nLineWidth;
+
+ double fLengthMul, fWidthMul;
+ sal_Int32 nLineNumber;
+ switch( eLineLength )
+ {
+ default :
+ case mso_lineMediumLenArrow : fLengthMul = 3.0; nLineNumber = 2; break;
+ case mso_lineShortArrow : fLengthMul = 2.0; nLineNumber = 1; break;
+ case mso_lineLongArrow : fLengthMul = 5.0; nLineNumber = 3; break;
+ }
+ switch( eLineWidth )
+ {
+ default :
+ case mso_lineMediumWidthArrow : fWidthMul = 3.0; nLineNumber += 3; break;
+ case mso_lineNarrowArrow : fWidthMul = 2.0; break;
+ case mso_lineWideArrow : fWidthMul = 5.0; nLineNumber += 6; break;
+ }
+
+ rbArrowCenter = false;
+ OUStringBuffer aArrowName;
+ switch ( eLineEnd )
+ {
+ case mso_lineArrowEnd :
+ {
+ basegfx::B2DPolygon aTriangle;
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, 0.0 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth ));
+ aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
+ aTriangle.setClosed(true);
+ aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
+ aArrowName.append("msArrowEnd ");
+ }
+ break;
+
+ case mso_lineArrowOpenEnd :
+ {
+ switch( eLineLength )
+ {
+ default :
+ case mso_lineMediumLenArrow : fLengthMul = 4.5; break;
+ case mso_lineShortArrow : fLengthMul = 3.5; break;
+ case mso_lineLongArrow : fLengthMul = 6.0; break;
+ }
+ switch( eLineWidth )
+ {
+ default :
+ case mso_lineMediumWidthArrow : fWidthMul = 4.5; break;
+ case mso_lineNarrowArrow : fWidthMul = 3.5; break;
+ case mso_lineWideArrow : fWidthMul = 6.0; break;
+ }
+ basegfx::B2DPolygon aTriangle;
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth * 0.91 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.85, fLengthMul * fLineWidth ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, fLengthMul * fLineWidth * 0.36 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.15, fLengthMul * fLineWidth ));
+ aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.91 ));
+ aTriangle.setClosed(true);
+ aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
+ aArrowName.append("msArrowOpenEnd ");
+ }
+ break;
+ case mso_lineArrowStealthEnd :
+ {
+ basegfx::B2DPolygon aTriangle;
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth * 0.60 ));
+ aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
+ aTriangle.setClosed(true);
+ aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
+ aArrowName.append("msArrowStealthEnd ");
+ }
+ break;
+ case mso_lineArrowDiamondEnd :
+ {
+ basegfx::B2DPolygon aTriangle;
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth * 0.50 ));
+ aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth ));
+ aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.50 ));
+ aTriangle.setClosed(true);
+ aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
+ rbArrowCenter = true;
+ aArrowName.append("msArrowDiamondEnd ");
+ }
+ break;
+ case mso_lineArrowOvalEnd :
+ {
+ aRetPolyPoly = basegfx::B2DPolyPolygon(
+ XPolygon(
+ Point( static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ), 0 ),
+ static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ),
+ static_cast<sal_Int32>( fLengthMul * fLineWidth * 0.50 ),
+ 0_deg100, 36000_deg100 ).getB2DPolygon() );
+ rbArrowCenter = true;
+ aArrowName.append("msArrowOvalEnd ");
+ }
+ break;
+ default: break;
+ }
+ aArrowName.append(nLineNumber);
+ rsArrowName = aArrowName.makeStringAndClear();
+ rnArrowWidth = static_cast<sal_Int32>( fLineWidth * fWidthMul );
+
+ return aRetPolyPoly;
+}
+
+void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eShapeType ) const // #i28269#
+{
+ sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
+
+ if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( eShapeType ))
+ {
+ nLineFlags &= ~0x08;
+ }
+
+ if ( nLineFlags & 8 )
+ {
+ // Line Attributes
+ sal_Int32 nLineWidth = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_lineWidth, 9525 ));
+
+ // support LineCap
+ auto eLineCap = GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapFlat);
+
+ switch(eLineCap)
+ {
+ default: /* case mso_lineEndCapFlat */
+ {
+ // no need to set, it is the default. If this changes, this needs to be activated
+ // rSet.Put(XLineCapItem(css::drawing::LineCap_BUTT));
+ break;
+ }
+ case mso_lineEndCapRound:
+ {
+ rSet.Put(XLineCapItem(css::drawing::LineCap_ROUND));
+ break;
+ }
+ case mso_lineEndCapSquare:
+ {
+ rSet.Put(XLineCapItem(css::drawing::LineCap_SQUARE));
+ break;
+ }
+ }
+
+ auto eLineDashing = GetPropertyValue( DFF_Prop_lineDashing, mso_lineSolid);
+ if (eLineDashing == mso_lineSolid || nLineWidth < 0)
+ rSet.Put(XLineStyleItem( drawing::LineStyle_SOLID ) );
+ else
+ {
+ // Despite of naming "dot" and "dash", that are all dashes and a "dot" can be longer
+ // than a "dash". The naming indicates the order, "dot" is always the first dash and
+ // "dash" is always the second dash. MS Office always starts with the longer dash, so
+ // set it here accordingly.
+ // The preset from binary is essentially the same as from OOXML. So here the same
+ // setting is used as in oox import. The comment corresponds to
+ // "dots, dotLen, dashes, dashLen, distance" there.
+ // MS Office uses always relative length, so no need to consider nLineWidth
+ // here. Values are of kind 300 for 300% in css::drawing::DashStyle, for example.
+
+ sal_uInt16 nDots = 1; // in all cases, "solid" is treated above
+ // initialize, will be changed if necessary
+ sal_uInt32 nDotLen = 300;
+ sal_uInt16 nDashes = 0;
+ sal_uInt32 nDashLen = 0;
+ sal_uInt32 nDistance = 300;
+ switch ( eLineDashing )
+ {
+ default:
+ case mso_lineDotSys : // 1 1 0 0 1
+ {
+ nDotLen =100;
+ nDistance = 100;
+ }
+ break;
+
+ case mso_lineDashGEL : // 1 4 0 0 3
+ {
+ nDotLen = 400;
+ }
+ break;
+
+ case mso_lineDashDotGEL : // 1 4 1 1 3
+ {
+ nDotLen = 400;
+ nDashes = 1;
+ nDashLen = 100;
+ }
+ break;
+
+ case mso_lineLongDashGEL : // 1 8 0 0 3
+ {
+ nDotLen = 800;
+ }
+ break;
+
+ case mso_lineLongDashDotGEL : // 1 8 1 1 3
+ {
+ nDotLen = 800;
+ nDashes = 1;
+ nDashLen = 100;
+ }
+ break;
+
+ case mso_lineLongDashDotDotGEL: // 1 8 2 1 3
+ {
+ nDotLen = 800;
+ nDashes = 2;
+ nDashLen = 100;
+ }
+ break;
+
+ case mso_lineDotGEL: // 1 1 0 0 3
+ {
+ nDotLen = 100;
+ }
+ break;
+
+ case mso_lineDashSys: // 1 3 0 0 1
+ {
+ nDistance = 100;
+ }
+ break;
+
+ case mso_lineDashDotSys: // 1 3 1 1 1
+ {
+ nDashes = 1;
+ nDashLen = 100;
+ nDistance = 100;
+ }
+ break;
+
+ case mso_lineDashDotDotSys: // 1 3 2 1 1
+ {
+ nDashes = 2;
+ nDashLen = 100;
+ nDistance = 100;
+ }
+ break;
+ }
+ rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECTRELATIVE, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) );
+ rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) );
+ }
+ rSet.Put( XLineColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_lineColor, 0 ) ) ) );
+ if ( IsProperty( DFF_Prop_lineOpacity ) )
+ {
+ double nTrans = GetPropertyValue(DFF_Prop_lineOpacity, 0x10000);
+ nTrans = (nTrans * 100) / 65536;
+ rSet.Put(XLineTransparenceItem(
+ sal_uInt16(100 - ::rtl::math::round(nTrans))));
+ }
+
+ rManager.ScaleEmu( nLineWidth );
+ rSet.Put( XLineWidthItem( nLineWidth ) );
+
+ // SJ: LineJoint (setting each time a line is set, because our internal joint type has another default)
+ MSO_LineJoin eLineJointDefault = mso_lineJoinMiter;
+ if ( eShapeType == mso_sptMin )
+ eLineJointDefault = mso_lineJoinRound;
+ auto eLineJoint = GetPropertyValue(DFF_Prop_lineJoinStyle, eLineJointDefault);
+ css::drawing::LineJoint eXLineJoint( css::drawing::LineJoint_MITER );
+ if ( eLineJoint == mso_lineJoinBevel )
+ eXLineJoint = css::drawing::LineJoint_BEVEL;
+ else if ( eLineJoint == mso_lineJoinRound )
+ eXLineJoint = css::drawing::LineJoint_ROUND;
+ rSet.Put( XLineJointItem( eXLineJoint ) );
+
+ if ( nLineFlags & 0x10 )
+ {
+ bool bScaleArrows = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip;
+
+ // LineStart
+
+ if ( IsProperty( DFF_Prop_lineStartArrowhead ) )
+ {
+ auto eLineEnd = GetPropertyValue(DFF_Prop_lineStartArrowhead, 0);
+ auto eWidth = GetPropertyValue(DFF_Prop_lineStartArrowWidth, mso_lineMediumWidthArrow);
+ auto eLength = GetPropertyValue(DFF_Prop_lineStartArrowLength, mso_lineMediumLenArrow);
+
+ sal_Int32 nArrowWidth;
+ bool bArrowCenter;
+ OUString aArrowName;
+ basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
+
+ rSet.Put( XLineStartWidthItem( nArrowWidth ) );
+ rSet.Put( XLineStartItem( aArrowName, aPolyPoly) );
+ rSet.Put( XLineStartCenterItem( bArrowCenter ) );
+ }
+
+ // LineEnd
+
+ if ( IsProperty( DFF_Prop_lineEndArrowhead ) )
+ {
+ auto eLineEnd = GetPropertyValue(DFF_Prop_lineEndArrowhead, 0);
+ auto eWidth = GetPropertyValue(DFF_Prop_lineEndArrowWidth, mso_lineMediumWidthArrow);
+ auto eLength = GetPropertyValue(DFF_Prop_lineEndArrowLength, mso_lineMediumLenArrow);
+
+ sal_Int32 nArrowWidth;
+ bool bArrowCenter;
+ OUString aArrowName;
+ basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
+
+ rSet.Put( XLineEndWidthItem( nArrowWidth ) );
+ rSet.Put( XLineEndItem( aArrowName, aPolyPoly ) );
+ rSet.Put( XLineEndCenterItem( bArrowCenter ) );
+ }
+ }
+ }
+ else
+ rSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+}
+
+namespace {
+
+struct ShadeColor
+{
+ Color aColor;
+ double fDist;
+
+ ShadeColor( const Color& rC, double fR ) : aColor( rC ), fDist( fR ) {};
+};
+
+}
+
+static void GetShadeColors( const SvxMSDffManager& rManager, const DffPropertyReader& rProperties, SvStream& rIn, std::vector< ShadeColor >& rShadeColors )
+{
+ sal_uInt64 nPos = rIn.Tell();
+ if ( rProperties.IsProperty( DFF_Prop_fillShadeColors ) )
+ {
+ sal_uInt16 i = 0, nNumElem = 0;
+ bool bOk = false;
+ if (rProperties.SeekToContent(DFF_Prop_fillShadeColors, rIn))
+ {
+ sal_uInt16 nNumElemReserved = 0, nSize = 0;
+ rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemReserved ).ReadUInt16( nSize );
+ //sanity check that the stream is long enough to fulfill nNumElem * 2 sal_Int32s
+ bOk = rIn.remainingSize() / (2*sizeof(sal_Int32)) >= nNumElem;
+ }
+ if (bOk)
+ {
+ for ( ; i < nNumElem; i++ )
+ {
+ sal_Int32 nColor(0);
+ sal_Int32 nDist(0);
+
+ rIn.ReadInt32( nColor ).ReadInt32( nDist );
+ rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( nColor, DFF_Prop_fillColor ), 1.0 - ( nDist / 65536.0 ) );
+ }
+ }
+ }
+ if ( rShadeColors.empty() )
+ {
+ rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ), 0 );
+ rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ), 1 );
+ }
+ rIn.Seek( nPos );
+}
+
+static void ApplyRectangularGradientAsBitmap( const SvxMSDffManager& rManager, SvStream& rIn, SfxItemSet& rSet, const std::vector< ShadeColor >& rShadeColors, const DffObjData& rObjData, Degree100 nFix16Angle )
+{
+ Size aBitmapSizePixel( static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetWidth() / 2540.0 ) * 90.0 ), // we will create a bitmap with 90 dpi
+ static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetHeight() / 2540.0 ) * 90.0 ) );
+ if (aBitmapSizePixel.IsEmpty() || aBitmapSizePixel.Width() > 1024 || aBitmapSizePixel.Height() > 1024)
+ return;
+
+ double fFocusX = rManager.GetPropertyValue( DFF_Prop_fillToRight, 0 ) / 65536.0;
+ double fFocusY = rManager.GetPropertyValue( DFF_Prop_fillToBottom, 0 ) / 65536.0;
+
+ vcl::bitmap::RawBitmap aBitmap(aBitmapSizePixel, 24);
+
+ for ( tools::Long nY = 0; nY < aBitmapSizePixel.Height(); nY++ )
+ {
+ for ( tools::Long nX = 0; nX < aBitmapSizePixel.Width(); nX++ )
+ {
+ double fX = static_cast< double >( nX ) / aBitmapSizePixel.Width();
+ double fY = static_cast< double >( nY ) / aBitmapSizePixel.Height();
+
+ double fD, fDist;
+ if ( fX < fFocusX )
+ {
+ if ( fY < fFocusY )
+ {
+ if ( fX > fY )
+ {
+ fDist = fY;
+ fD = fFocusY;
+ }
+ else
+ {
+ fDist = fX;
+ fD = fFocusX;
+ }
+ }
+ else
+ {
+ if ( fX > ( 1 - fY ) )
+ {
+ fDist = 1 - fY;
+ fD = 1 - fFocusY;
+ }
+ else
+ {
+ fDist = fX;
+ fD = fFocusX;
+ }
+ }
+ }
+ else
+ {
+ if ( fY < fFocusY )
+ {
+ if ( ( 1 - fX ) > fY )
+ {
+ fDist = fY;
+ fD = fFocusY;
+ }
+ else
+ {
+ fDist = 1 - fX;
+ fD = 1 - fFocusX;
+ }
+ }
+ else
+ {
+ if ( ( 1 - fX ) > ( 1 - fY ) )
+ {
+ fDist = 1 - fY;
+ fD = 1 - fFocusY;
+ }
+ else
+ {
+ fDist = 1 - fX;
+ fD = 1 - fFocusX;
+ }
+ }
+ }
+ if ( fD != 0.0 )
+ fDist /= fD;
+
+ double fA = 0.0;
+ Color aColorA = rShadeColors.front().aColor;
+ double fB = 1.0;
+ Color aColorB( aColorA );
+ for ( const auto& rShadeColor : rShadeColors )
+ {
+ if ( fA <= rShadeColor.fDist && rShadeColor.fDist <= fDist )
+ {
+ fA = rShadeColor.fDist;
+ aColorA = rShadeColor.aColor;
+ }
+ if ( fDist < rShadeColor.fDist && rShadeColor.fDist <= fB )
+ {
+ fB = rShadeColor.fDist;
+ aColorB = rShadeColor.aColor;
+ }
+ }
+ double fRed = aColorA.GetRed(), fGreen = aColorA.GetGreen(), fBlue = aColorA.GetBlue();
+ double fD1 = fB - fA;
+ if ( fD1 != 0.0 )
+ {
+ fRed += ( ( ( fDist - fA ) * ( aColorB.GetRed() - aColorA.GetRed() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fRed;
+ fGreen += ( ( ( fDist - fA ) * ( aColorB.GetGreen() - aColorA.GetGreen() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fGreen;
+ fBlue += ( ( ( fDist - fA ) * ( aColorB.GetBlue() - aColorA.GetBlue() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fBlue;
+ }
+ sal_Int16 nRed = static_cast< sal_Int16 >( fRed + 0.5 );
+ sal_Int16 nGreen = static_cast< sal_Int16 >( fGreen + 0.5 );
+ sal_Int16 nBlue = static_cast< sal_Int16 >( fBlue + 0.5 );
+ if ( nRed < 0 )
+ nRed = 0;
+ if ( nRed > 255 )
+ nRed = 255;
+ if ( nGreen < 0 )
+ nGreen = 0;
+ if ( nGreen > 255 )
+ nGreen = 255;
+ if ( nBlue < 0 )
+ nBlue = 0;
+ if ( nBlue > 255 )
+ nBlue = 255;
+
+ aBitmap.SetPixel(nY, nX, Color(static_cast<sal_Int8>(nRed), static_cast<sal_Int8>(nGreen), static_cast<sal_Int8>(nBlue)));
+ }
+ }
+ BitmapEx aBitmapEx = vcl::bitmap::CreateFromData( std::move(aBitmap) );
+
+ if ( nFix16Angle )
+ {
+ bool bRotateWithShape = true; // sal_True seems to be default
+ sal_uInt64 nPos = rIn.Tell();
+ if ( const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.SeekToContent( rIn, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.Current()->SeekToBegOfRecord( rIn );
+ DffPropertyReader aSecPropSet( rManager );
+ aSecPropSet.ReadPropSet( rIn, nullptr );
+ sal_Int32 nSecFillProperties = aSecPropSet.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0x200020 );
+ bRotateWithShape = ( nSecFillProperties & 0x0020 );
+ }
+ rIn.Seek( nPos );
+ if ( bRotateWithShape )
+ {
+ // convert from 100th to 10th degrees
+ aBitmapEx.Rotate( to<Degree10>(nFix16Angle), rShadeColors[ 0 ].aColor );
+
+ BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
+ if ( rObjData.nSpFlags & ShapeFlag::FlipV )
+ nMirrorFlags |= BmpMirrorFlags::Vertical;
+ if ( rObjData.nSpFlags & ShapeFlag::FlipH )
+ nMirrorFlags |= BmpMirrorFlags::Horizontal;
+ if ( nMirrorFlags != BmpMirrorFlags::NONE )
+ aBitmapEx.Mirror( nMirrorFlags );
+ }
+ }
+
+ rSet.Put(XFillBmpTileItem(false));
+ rSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx)));
+}
+
+void DffPropertyReader::ApplyFillAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
+{
+ sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
+
+ std::vector< ShadeColor > aShadeColors;
+ GetShadeColors( rManager, *this, rIn, aShadeColors );
+
+ if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
+ {
+ nFillFlags &= ~0x10;
+ }
+
+ if ( nFillFlags & 0x10 )
+ {
+ auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
+ drawing::FillStyle eXFill = drawing::FillStyle_NONE;
+ switch( eMSO_FillType )
+ {
+ case mso_fillSolid : // Fill with a solid color
+ eXFill = drawing::FillStyle_SOLID;
+ break;
+ case mso_fillPattern : // Fill with a pattern (bitmap)
+ case mso_fillTexture : // A texture (pattern with its own color map)
+ case mso_fillPicture : // Center a picture in the shape
+ eXFill = drawing::FillStyle_BITMAP;
+ break;
+ case mso_fillShadeCenter : // Shade from bounding rectangle to end point
+ {
+ //If it is imported as a bitmap, it will not work well with transparency especially 100
+ //But the gradient look well comparing with imported as gradient. And rotate with shape
+ //also works better. So here just keep it.
+ if ( rObjData.aBoundRect.IsEmpty() )// size of object needed to be able
+ eXFill = drawing::FillStyle_GRADIENT; // to create a bitmap substitution
+ else
+ eXFill = drawing::FillStyle_BITMAP;
+ }
+ break;
+ case mso_fillShade : // Shade from start to end points
+ case mso_fillShadeShape : // Shade from shape outline to end point
+ case mso_fillShadeScale : // Similar to mso_fillShade, but the fillAngle
+ case mso_fillShadeTitle : // special type - shade to title --- for PP
+ eXFill = drawing::FillStyle_GRADIENT;
+ break;
+// case mso_fillBackground : // Use the background fill color/pattern
+ default: break;
+ }
+ rSet.Put( XFillStyleItem( eXFill ) );
+
+ double dTrans = 1.0;
+ double dBackTrans = 1.0;
+ if (IsProperty(DFF_Prop_fillOpacity))
+ {
+ dTrans = GetPropertyValue(DFF_Prop_fillOpacity, 0) / 65536.0;
+ if ( eXFill != drawing::FillStyle_GRADIENT )
+ {
+ dTrans = dTrans * 100;
+ rSet.Put(XFillTransparenceItem(
+ sal_uInt16(100 - ::rtl::math::round(dTrans))));
+ }
+ }
+
+ if ( IsProperty(DFF_Prop_fillBackOpacity) )
+ dBackTrans = GetPropertyValue(DFF_Prop_fillBackOpacity, 0) / 65536.0;
+
+ if ( ( eMSO_FillType == mso_fillShadeCenter ) && ( eXFill == drawing::FillStyle_BITMAP ) )
+ {
+ ApplyRectangularGradientAsBitmap( rManager, rIn, rSet, aShadeColors, rObjData, mnFix16Angle );
+ }
+ else if ( eXFill == drawing::FillStyle_GRADIENT )
+ {
+ ImportGradientColor ( rSet, eMSO_FillType, dTrans , dBackTrans );
+ }
+ else if ( eXFill == drawing::FillStyle_BITMAP )
+ {
+ if( IsProperty( DFF_Prop_fillBlip ) )
+ {
+ Graphic aGraf;
+ // first try to get BLIP from cache
+ bool bOK = const_cast<SvxMSDffManager&>(rManager).GetBLIP( GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf );
+ // then try directly from stream (i.e. Excel chart hatches/bitmaps)
+ if ( !bOK )
+ bOK = SeekToContent( DFF_Prop_fillBlip, rIn ) && SvxMSDffManager::GetBLIPDirect( rIn, aGraf );
+ if ( bOK )
+ {
+ if ( eMSO_FillType == mso_fillPattern )
+ {
+ Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() );
+ if (aBmp.GetSizePixel().Width() == 8 &&
+ aBmp.GetSizePixel().Height() == 8 &&
+ aBmp.getPixelFormat() == vcl::PixelFormat::N1_BPP)
+ {
+ Color aCol1( COL_WHITE ), aCol2( COL_WHITE );
+
+ if ( IsProperty( DFF_Prop_fillColor ) )
+ aCol1 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor );
+
+ if ( IsProperty( DFF_Prop_fillBackColor ) )
+ aCol2 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, 0 ), DFF_Prop_fillBackColor );
+
+ // Create a bitmap for the pattern with expected colors
+ vcl::bitmap::RawBitmap aResult(Size(8, 8), 24);
+ {
+ Bitmap::ScopedReadAccess pRead(aBmp);
+
+ for (tools::Long y = 0; y < aResult.Height(); ++y)
+ {
+ Scanline pScanlineRead = pRead->GetScanline( y );
+ for (tools::Long x = 0; x < aResult.Width(); ++x)
+ {
+ Color aReadColor;
+ if (pRead->HasPalette())
+ aReadColor = pRead->GetPaletteColor(pRead->GetIndexFromData(pScanlineRead, x));
+ else
+ aReadColor = pRead->GetPixelFromData(pScanlineRead, x);
+
+ if (aReadColor == Color(0))
+ aResult.SetPixel(y, x, aCol2);
+ else
+ aResult.SetPixel(y, x, aCol1);
+ }
+ }
+ }
+ aGraf = Graphic(vcl::bitmap::CreateFromData(std::move(aResult)));
+ }
+
+ rSet.Put(XFillBitmapItem(OUString(), aGraf));
+ }
+ else if ( eMSO_FillType == mso_fillTexture )
+ {
+ rSet.Put(XFillBmpTileItem(true));
+ rSet.Put(XFillBitmapItem(OUString(), aGraf));
+ rSet.Put(XFillBmpSizeXItem(GetPropertyValue(DFF_Prop_fillWidth, 0) / 360));
+ rSet.Put(XFillBmpSizeYItem(GetPropertyValue(DFF_Prop_fillHeight, 0) / 360));
+ rSet.Put(XFillBmpSizeLogItem(true));
+ }
+ else
+ {
+ rSet.Put(XFillBitmapItem(OUString(), aGraf));
+ rSet.Put(XFillBmpTileItem(false));
+ }
+ }
+ }
+ }
+ }
+ else
+ rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+}
+
+void DffPropertyReader::ApplyCustomShapeTextAttributes( SfxItemSet& rSet ) const
+{
+ bool bVerticalText = false;
+ sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ) / 360; // 0.25 cm (emu)
+ sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ) / 360; // 0.25 cm (emu)
+ sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ) / 360; // 0.13 cm (emu)
+ sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 ) /360; // 0.13 cm (emu)
+
+ SdrTextVertAdjust eTVA;
+ SdrTextHorzAdjust eTHA;
+
+ if ( IsProperty( DFF_Prop_txflTextFlow ) )
+ {
+ auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
+ switch( eTextFlow )
+ {
+ case mso_txflTtoBA : /* #68110# */ // Top to Bottom @-font, oben -> unten
+ case mso_txflTtoBN : // Top to Bottom non-@, oben -> unten
+ case mso_txflVertN : // Vertical, non-@, oben -> unten
+ bVerticalText = true; // nTextRotationAngle += 27000;
+ break;
+ default: break;
+ }
+ }
+ sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 );
+ if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) )
+ bVerticalText = !bVerticalText;
+
+ if ( bVerticalText )
+ {
+ eTHA = SDRTEXTHORZADJUST_CENTER;
+
+ // read text anchor
+ sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ case mso_anchorTopCentered:
+ case mso_anchorTopBaseline:
+ case mso_anchorTopCenteredBaseline:
+ eTHA = SDRTEXTHORZADJUST_RIGHT;
+ break;
+
+ case mso_anchorMiddle :
+ case mso_anchorMiddleCentered:
+ eTHA = SDRTEXTHORZADJUST_CENTER;
+ break;
+
+ case mso_anchorBottom:
+ case mso_anchorBottomCentered:
+ case mso_anchorBottomBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ eTHA = SDRTEXTHORZADJUST_LEFT;
+ break;
+ }
+ // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ case mso_anchorTopCenteredBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ break;
+
+ default :
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ break;
+ }
+ }
+ else
+ {
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+
+ // read text anchor
+ sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ case mso_anchorTopCentered:
+ case mso_anchorTopBaseline:
+ case mso_anchorTopCenteredBaseline:
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ break;
+
+ case mso_anchorMiddle :
+ case mso_anchorMiddleCentered:
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ break;
+
+ case mso_anchorBottom:
+ case mso_anchorBottomCentered:
+ case mso_anchorBottomBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ break;
+ }
+ // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ case mso_anchorTopCenteredBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ eTHA = SDRTEXTHORZADJUST_CENTER; // the text has to be displayed using the full width;
+ break;
+
+ default :
+ eTHA = SDRTEXTHORZADJUST_LEFT;
+ break;
+ }
+ }
+ rSet.Put( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
+
+ rSet.Put( SdrTextVertAdjustItem( eTVA ) );
+ rSet.Put( SdrTextHorzAdjustItem( eTHA ) );
+
+ rSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
+ rSet.Put( makeSdrTextRightDistItem( nTextRight ) );
+ rSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
+ rSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
+
+ rSet.Put( makeSdrTextWordWrapItem( GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone ) );
+ rSet.Put( makeSdrTextAutoGrowHeightItem( ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0 ) );
+}
+
+void DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
+{
+
+ sal_uInt32 nAdjustmentsWhichNeedsToBeConverted = 0;
+
+
+ // creating SdrCustomShapeGeometryItem
+
+ typedef std::vector< beans::PropertyValue > PropVec;
+
+ // aPropVec will be filled with all PropertyValues
+ PropVec aPropVec;
+ PropertyValue aProp;
+
+
+ // "Type" property, including the predefined CustomShape type name
+
+ aProp.Name = "Type";
+ aProp.Value <<= EnhancedCustomShapeTypeNames::Get( rObjData.eShapeType );
+ aPropVec.push_back( aProp );
+
+
+ // "ViewBox"
+
+
+ sal_Int32 nCoordWidth = 21600; // needed to replace handle type center with absolute value
+ sal_Int32 nCoordHeight= 21600;
+ if ( IsProperty( DFF_Prop_geoLeft ) || IsProperty( DFF_Prop_geoTop ) || IsProperty( DFF_Prop_geoRight ) || IsProperty( DFF_Prop_geoBottom ) )
+ {
+ css::awt::Rectangle aViewBox;
+ aViewBox.X = GetPropertyValue( DFF_Prop_geoLeft, 0 );
+ aViewBox.Y = GetPropertyValue( DFF_Prop_geoTop, 0 );
+ aViewBox.Width = nCoordWidth = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoRight, 21600), aViewBox.X);
+ aViewBox.Height = nCoordHeight = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoBottom, 21600), aViewBox.Y);
+ aProp.Name = "ViewBox";
+ aProp.Value <<= aViewBox;
+ aPropVec.push_back( aProp );
+ }
+
+ // TextRotateAngle
+
+ if ( IsProperty( DFF_Prop_txflTextFlow ) || IsProperty( DFF_Prop_cdirFont ) )
+ {
+ sal_Int32 nTextRotateAngle = 0;
+ auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
+
+ if ( eTextFlow == mso_txflBtoT ) // Bottom to Top non-@
+ nTextRotateAngle += 90;
+ switch( GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ) ) // SJ: mso_cdir90 and mso_cdir270 will be simulated by
+ { // activating vertical writing for the text objects
+ case mso_cdir90 :
+ {
+ if ( eTextFlow == mso_txflTtoBA )
+ nTextRotateAngle -= 180;
+ }
+ break;
+ case mso_cdir180: nTextRotateAngle -= 180; break;
+ case mso_cdir270:
+ {
+ if ( eTextFlow != mso_txflTtoBA )
+ nTextRotateAngle -= 180;
+ }
+ break;
+ default: break;
+ }
+ if ( nTextRotateAngle )
+ {
+ double fTextRotateAngle = nTextRotateAngle;
+ aProp.Name = "TextRotateAngle";
+ aProp.Value <<= fTextRotateAngle;
+ aPropVec.push_back( aProp );
+ }
+ }
+
+ // "Extrusion" PropertySequence element
+
+ bool bExtrusionOn = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) != 0;
+ if ( bExtrusionOn )
+ {
+ PropVec aExtrusionPropVec;
+
+ // "Extrusion"
+ aProp.Name = "Extrusion";
+ aProp.Value <<= bExtrusionOn;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "Brightness"
+ // MS Office default 0x00004E20 16.16 FixedPoint, 20000/65536=0.30517, ODF default 33%.
+ // Thus must set value even if default.
+ double fBrightness = 20000.0;
+ if ( IsProperty( DFF_Prop_c3DAmbientIntensity ) )
+ {
+ // Value must be in range 0.0 to 1.0 in MS Office binary specification, but larger
+ // values are in fact interpreted.
+ fBrightness = GetPropertyValue( DFF_Prop_c3DAmbientIntensity, 0 );
+ }
+ fBrightness /= 655.36;
+ aProp.Name = "Brightness";
+ aProp.Value <<= fBrightness;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "Depth" in 1/100mm
+ if ( IsProperty( DFF_Prop_c3DExtrudeBackward ) || IsProperty( DFF_Prop_c3DExtrudeForward ) )
+ {
+ double fBackDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeBackward, 1270 * 360 ))) / 360.0;
+ double fForeDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeForward, 0 ))) / 360.0;
+ double fDepth = fBackDepth + fForeDepth;
+ double fFraction = fDepth != 0.0 ? fForeDepth / fDepth : 0;
+ EnhancedCustomShapeParameterPair aDepthParaPair;
+ aDepthParaPair.First.Value <<= fDepth;
+ aDepthParaPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aDepthParaPair.Second.Value <<= fFraction;
+ aDepthParaPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aProp.Name = "Depth";
+ aProp.Value <<= aDepthParaPair;
+ aExtrusionPropVec.push_back( aProp );
+ }
+ // "Diffusion"
+ // ODF default is 0%, MS Office default is 100%. Thus must set value even if default.
+ double fDiffusion = 100;
+ if ( IsProperty( DFF_Prop_c3DDiffuseAmt ) )
+ {
+ fDiffusion = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DDiffuseAmt, 0 ));
+ fDiffusion /= 655.36;
+ }
+ aProp.Name = "Diffusion";
+ aProp.Value <<= fDiffusion;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "NumberOfLineSegments"
+ if ( IsProperty( DFF_Prop_c3DTolerance ) )
+ {
+ aProp.Name = "NumberOfLineSegments";
+ aProp.Value <<= static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DTolerance, 0 ));
+ aExtrusionPropVec.push_back( aProp );
+ }
+ // "LightFace"
+ bool bExtrusionLightFace = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 1 ) != 0;
+ aProp.Name = "LightFace";
+ aProp.Value <<= bExtrusionLightFace;
+ aExtrusionPropVec.push_back( aProp );
+ // "FirstLightHarsh"
+ bool bExtrusionFirstLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 2 ) != 0;
+ aProp.Name = "FirstLightHarsh";
+ aProp.Value <<= bExtrusionFirstLightHarsh;
+ aExtrusionPropVec.push_back( aProp );
+ // "SecondLightHarsh"
+ bool bExtrusionSecondLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 1 ) != 0;
+ aProp.Name = "SecondLightHarsh";
+ aProp.Value <<= bExtrusionSecondLightHarsh;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "FirstLightLevel"
+ // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%.
+ // Thus must set value even if default.
+ double fFirstLightLevel = 38000.0;
+ if ( IsProperty( DFF_Prop_c3DKeyIntensity ) )
+ {
+ // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here.
+ fFirstLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyIntensity, 0 ));
+ }
+ fFirstLightLevel /= 655.36;
+ aProp.Name = "FirstLightLevel";
+ aProp.Value <<= fFirstLightLevel;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "SecondLightLevel"
+ // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%.
+ // Thus must set value even if default.
+ double fSecondLightLevel = 38000.0;
+ if ( IsProperty( DFF_Prop_c3DFillIntensity ) )
+ {
+ // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here.
+ fSecondLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillIntensity, 0 ));
+ }
+ fSecondLightLevel /= 655.36;
+ aProp.Name = "SecondLightLevel";
+ aProp.Value <<= fSecondLightLevel;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "FirstLightDirection"
+ if ( IsProperty( DFF_Prop_c3DKeyX ) || IsProperty( DFF_Prop_c3DKeyY ) || IsProperty( DFF_Prop_c3DKeyZ ) )
+ {
+ double fLightX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyX, 50000 )));
+ double fLightY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyY, 0 )));
+ double fLightZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyZ, 10000 )));
+ css::drawing::Direction3D aExtrusionFirstLightDirection( fLightX, fLightY, fLightZ );
+ aProp.Name = "FirstLightDirection";
+ aProp.Value <<= aExtrusionFirstLightDirection;
+ aExtrusionPropVec.push_back( aProp );
+ }
+ // "SecondLightDirection"
+ if ( IsProperty( DFF_Prop_c3DFillX ) || IsProperty( DFF_Prop_c3DFillY ) || IsProperty( DFF_Prop_c3DFillZ ) )
+ {
+ double fLight2X = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillX, sal_uInt32(-50000) )));
+ double fLight2Y = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillY, 0 )));
+ double fLight2Z = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillZ, 10000 )));
+ css::drawing::Direction3D aExtrusionSecondLightDirection( fLight2X, fLight2Y, fLight2Z );
+ aProp.Name = "SecondLightDirection";
+ aProp.Value <<= aExtrusionSecondLightDirection;
+ aExtrusionPropVec.push_back( aProp );
+ }
+
+ // "Metal"
+ bool bExtrusionMetal = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 4 ) != 0;
+ aProp.Name = "Metal";
+ aProp.Value <<= bExtrusionMetal;
+ aExtrusionPropVec.push_back( aProp );
+ aProp.Name = "MetalType";
+ aProp.Value <<= css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
+ aExtrusionPropVec.push_back(aProp);
+
+ // "ShadeMode"
+ if ( IsProperty( DFF_Prop_c3DRenderMode ) )
+ {
+ sal_uInt32 nExtrusionRenderMode = GetPropertyValue( DFF_Prop_c3DRenderMode, 0 );
+ css::drawing::ShadeMode eExtrusionShadeMode( css::drawing::ShadeMode_FLAT );
+ if ( nExtrusionRenderMode == mso_Wireframe )
+ eExtrusionShadeMode = css::drawing::ShadeMode_DRAFT;
+
+ aProp.Name = "ShadeMode";
+ aProp.Value <<= eExtrusionShadeMode;
+ aExtrusionPropVec.push_back( aProp );
+ }
+ // "RotateAngle" in Degree
+ if ( IsProperty( DFF_Prop_c3DXRotationAngle ) || IsProperty( DFF_Prop_c3DYRotationAngle ) )
+ {
+ double fAngleX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXRotationAngle, 0 ))) / 65536.0;
+ double fAngleY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYRotationAngle, 0 ))) / 65536.0;
+ EnhancedCustomShapeParameterPair aRotateAnglePair;
+ aRotateAnglePair.First.Value <<= fAngleX;
+ aRotateAnglePair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aRotateAnglePair.Second.Value <<= fAngleY;
+ aRotateAnglePair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aProp.Name = "RotateAngle";
+ aProp.Value <<= aRotateAnglePair;
+ aExtrusionPropVec.push_back( aProp );
+ }
+
+ // "AutoRotationCenter"
+ if ( ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 8 ) == 0 )
+ {
+ // "RotationCenter"
+ if ( IsProperty( DFF_Prop_c3DRotationCenterX ) || IsProperty( DFF_Prop_c3DRotationCenterY ) || IsProperty( DFF_Prop_c3DRotationCenterZ ) )
+ {
+ // tdf#145904 X- and Y-component is fraction, Z-component in EMU
+ css::drawing::Direction3D aRotationCenter(
+ static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterX, 0 ))) / 65536.0,
+ static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterY, 0 ))) / 65536.0,
+ static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterZ, 0 ))) / 360.0 );
+
+ aProp.Name = "RotationCenter";
+ aProp.Value <<= aRotationCenter;
+ aExtrusionPropVec.push_back( aProp );
+ }
+ }
+ // "Shininess"
+ // MS Office default 5, ODF default 50%.
+ if ( IsProperty( DFF_Prop_c3DShininess ) )
+ {
+ double fShininess = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DShininess, 0 ));
+ fShininess *= 10.0; // error in [MS ODRAW] (2021), type is not FixedPoint but long.
+ aProp.Name = "Shininess";
+ aProp.Value <<= fShininess;
+ aExtrusionPropVec.push_back( aProp );
+ }
+
+ // "Skew"
+ // MS Office angle file value is 16.16 FixedPoint, default 0xFF790000,
+ // -8847360/65536=-135, ODF default 45. Thus must set value even if default.
+ double fSkewAngle = -135.0;
+ // MS Office amount file value is signed integer in range 0xFFFFFF9C to 0x00000064,
+ // default 0x00000032, ODF default 50.0
+ double fSkewAmount = 50.0;
+ if ( IsProperty( DFF_Prop_c3DSkewAmount ) || IsProperty( DFF_Prop_c3DSkewAngle ) )
+ {
+ fSkewAmount = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAmount, 50 ));
+ fSkewAngle = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) ));
+ fSkewAngle /= 65536.0;
+ }
+ EnhancedCustomShapeParameterPair aSkewPair;
+ aSkewPair.First.Value <<= fSkewAmount;
+ aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aSkewPair.Second.Value <<= fSkewAngle;
+ aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aProp.Name = "Skew";
+ aProp.Value <<= aSkewPair;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "Specularity"
+ // Type Fixed point 16.16, percent in API
+ if ( IsProperty( DFF_Prop_c3DSpecularAmt ) )
+ {
+ double fSpecularity = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSpecularAmt, 0 ));
+ fSpecularity /= 655.36;
+ aProp.Name = "Specularity";
+ aProp.Value <<= fSpecularity;
+ aExtrusionPropVec.push_back( aProp );
+ }
+ // "ProjectionMode"
+ ProjectionMode eProjectionMode = (GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 4) ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
+ aProp.Name = "ProjectionMode";
+ aProp.Value <<= eProjectionMode;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "ViewPoint" in 1/100mm
+ // MS Office default 1250000 EMU=3472.222 Hmm, ODF default 3.5cm
+ // Thus must set value even if default.
+ double fViewX = 1250000.0 / 360.0;
+ double fViewY = -1250000.0 / 360.0;;
+ double fViewZ = 9000000.0 / 360.0;
+ if ( IsProperty( DFF_Prop_c3DXViewpoint ) || IsProperty( DFF_Prop_c3DYViewpoint ) || IsProperty( DFF_Prop_c3DZViewpoint ) )
+ {
+ fViewX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0;
+ fViewY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0;
+ fViewZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0;
+ }
+ css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, fViewZ );
+ aProp.Name = "ViewPoint";
+ aProp.Value <<= aExtrusionViewPoint;
+ aExtrusionPropVec.push_back( aProp );
+
+ // "Origin"
+ if ( IsProperty( DFF_Prop_c3DOriginX ) || IsProperty( DFF_Prop_c3DOriginY ) )
+ {
+ double fOriginX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginX, 32768 )));
+ double fOriginY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginY, sal_uInt32(-32768) )));
+ fOriginX /= 65536;
+ fOriginY /= 65536;
+ EnhancedCustomShapeParameterPair aOriginPair;
+ aOriginPair.First.Value <<= fOriginX;
+ aOriginPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aOriginPair.Second.Value <<= fOriginY;
+ aOriginPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
+ aProp.Name = "Origin";
+ aProp.Value <<= aOriginPair;
+ aExtrusionPropVec.push_back( aProp );
+ }
+ // "ExtrusionColor"
+ bool bExtrusionColor = IsProperty( DFF_Prop_c3DExtrusionColor ); // ( GetPropertyValue( DFF_Prop_fc3DLightFace ) & 2 ) != 0;
+ aProp.Name = "Color";
+ aProp.Value <<= bExtrusionColor;
+ aExtrusionPropVec.push_back( aProp );
+ if ( IsProperty( DFF_Prop_c3DExtrusionColor ) )
+ rSet.Put( XSecondaryFillColorItem( OUString(), rManager.MSO_CLR_ToColor(
+ GetPropertyValue( DFF_Prop_c3DExtrusionColor, 0 ), DFF_Prop_c3DExtrusionColor ) ) );
+ // pushing the whole Extrusion element
+ aProp.Name = "Extrusion";
+ aProp.Value <<= comphelper::containerToSequence(aExtrusionPropVec);
+ aPropVec.push_back( aProp );
+ }
+
+
+ // "Equations" PropertySequence element
+
+ if ( IsProperty( DFF_Prop_pFormulas ) )
+ {
+ sal_uInt16 nNumElem = 0;
+
+ if ( SeekToContent( DFF_Prop_pFormulas, rIn ) )
+ {
+ sal_uInt16 nNumElemMem = 0;
+ sal_uInt16 nElemSize = 8;
+ rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
+ }
+ if ( nNumElem <= 128 )
+ {
+ uno::Sequence< OUString > aEquations( nNumElem );
+ for ( auto& rEquation : asNonConstRange(aEquations) )
+ {
+ sal_Int16 nP1(0), nP2(0), nP3(0);
+ sal_uInt16 nFlags(0);
+ rIn.ReadUInt16( nFlags ).ReadInt16( nP1 ).ReadInt16( nP2 ).ReadInt16( nP3 );
+ rEquation = EnhancedCustomShape2d::GetEquation( nFlags, nP1, nP2, nP3 );
+ }
+ // pushing the whole Equations element
+ aProp.Name = "Equations";
+ aProp.Value <<= aEquations;
+ aPropVec.push_back( aProp );
+ }
+ }
+
+
+ // "Handles" PropertySequence element
+
+ if ( IsProperty( DFF_Prop_Handles ) )
+ {
+ sal_uInt16 nNumElem = 0;
+ sal_uInt16 nElemSize = 36;
+
+ if ( SeekToContent( DFF_Prop_Handles, rIn ) )
+ {
+ sal_uInt16 nNumElemMem = 0;
+ rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
+ }
+ bool bImport = false;
+ if (nElemSize == 36)
+ {
+ //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
+ bImport = rIn.remainingSize() / nElemSize >= nNumElem;
+ }
+ if (bImport)
+ {
+ uno::Sequence< beans::PropertyValues > aHandles( nNumElem );
+ auto aHandlesRange = asNonConstRange(aHandles);
+ for (sal_uInt32 i = 0; i < nNumElem; ++i)
+ {
+ PropVec aHandlePropVec;
+ sal_uInt32 nFlagsTmp(0);
+ sal_Int32 nPositionX(0), nPositionY(0), nCenterX(0), nCenterY(0), nRangeXMin(0), nRangeXMax(0), nRangeYMin(0), nRangeYMax(0);
+ rIn.ReadUInt32( nFlagsTmp )
+ .ReadInt32( nPositionX )
+ .ReadInt32( nPositionY )
+ .ReadInt32( nCenterX )
+ .ReadInt32( nCenterY )
+ .ReadInt32( nRangeXMin )
+ .ReadInt32( nRangeXMax )
+ .ReadInt32( nRangeYMin )
+ .ReadInt32( nRangeYMax );
+ SvxMSDffHandleFlags nFlags = static_cast<SvxMSDffHandleFlags>(nFlagsTmp);
+ if ( nPositionX == 2 ) // replacing center position with absolute value
+ nPositionX = nCoordWidth / 2;
+ if ( nPositionY == 2 )
+ nPositionY = nCoordHeight / 2;
+ EnhancedCustomShapeParameterPair aPosition;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, nPositionX, true, true );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, nPositionY, true, false );
+ aProp.Name = "Position";
+ aProp.Value <<= aPosition;
+ aHandlePropVec.push_back( aProp );
+
+ if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
+ {
+ aProp.Name = "MirroredX";
+ aProp.Value <<= true;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
+ {
+ aProp.Name = "MirroredY";
+ aProp.Value <<= true;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
+ {
+ aProp.Name = "Switched";
+ aProp.Value <<= true;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( nFlags & SvxMSDffHandleFlags::POLAR )
+ {
+ if ( nCenterX == 2 )
+ nCenterX = nCoordWidth / 2;
+ if ( nCenterY == 2 )
+ nCenterY = nCoordHeight / 2;
+ if ((nPositionY >= 0x256 || nPositionY <= 0x107) && i < sizeof(sal_uInt32) * 8) // position y
+ nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
+ EnhancedCustomShapeParameterPair aPolar;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
+ aProp.Name = "Polar";
+ aProp.Value <<= aPolar;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( nFlags & SvxMSDffHandleFlags::MAP )
+ {
+ if ( nCenterX == 2 )
+ nCenterX = nCoordWidth / 2;
+ if ( nCenterY == 2 )
+ nCenterY = nCoordHeight / 2;
+ EnhancedCustomShapeParameterPair aMap;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
+ aProp.Name = "Map";
+ aProp.Value <<= aMap;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( nFlags & SvxMSDffHandleFlags::RANGE )
+ {
+ if ( static_cast<sal_uInt32>(nRangeXMin) != 0x80000000 )
+ {
+ if ( nRangeXMin == 2 )
+ nRangeXMin = nCoordWidth / 2;
+ EnhancedCustomShapeParameter aRangeXMinimum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, nRangeXMin,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
+ aProp.Name = "RangeXMinimum";
+ aProp.Value <<= aRangeXMinimum;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( static_cast<sal_uInt32>(nRangeXMax) != 0x7fffffff )
+ {
+ if ( nRangeXMax == 2 )
+ nRangeXMax = nCoordWidth / 2;
+ EnhancedCustomShapeParameter aRangeXMaximum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, nRangeXMax,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
+ aProp.Name = "RangeXMaximum";
+ aProp.Value <<= aRangeXMaximum;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( static_cast<sal_uInt32>(nRangeYMin) != 0x80000000 )
+ {
+ if ( nRangeYMin == 2 )
+ nRangeYMin = nCoordHeight / 2;
+ EnhancedCustomShapeParameter aRangeYMinimum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, nRangeYMin,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true );
+ aProp.Name = "RangeYMinimum";
+ aProp.Value <<= aRangeYMinimum;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( static_cast<sal_uInt32>(nRangeYMax) != 0x7fffffff )
+ {
+ if ( nRangeYMax == 2 )
+ nRangeYMax = nCoordHeight / 2;
+ EnhancedCustomShapeParameter aRangeYMaximum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, nRangeYMax,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false );
+ aProp.Name = "RangeYMaximum";
+ aProp.Value <<= aRangeYMaximum;
+ aHandlePropVec.push_back( aProp );
+ }
+ }
+ if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
+ {
+ if ( static_cast<sal_uInt32>(nRangeXMin) != 0x7fffffff )
+ {
+ if ( nRangeXMin == 2 )
+ nRangeXMin = nCoordWidth / 2;
+ EnhancedCustomShapeParameter aRadiusRangeMinimum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, nRangeXMin,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
+ aProp.Name = "RadiusRangeMinimum";
+ aProp.Value <<= aRadiusRangeMinimum;
+ aHandlePropVec.push_back( aProp );
+ }
+ if ( static_cast<sal_uInt32>(nRangeXMax) != 0x80000000 )
+ {
+ if ( nRangeXMax == 2 )
+ nRangeXMax = nCoordWidth / 2;
+ EnhancedCustomShapeParameter aRadiusRangeMaximum;
+ EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, nRangeXMax,
+ bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
+ aProp.Name = "RadiusRangeMaximum";
+ aProp.Value <<= aRadiusRangeMaximum;
+ aHandlePropVec.push_back( aProp );
+ }
+ }
+ if ( !aHandlePropVec.empty() )
+ {
+ aHandlesRange[ i ] = comphelper::containerToSequence(aHandlePropVec);
+ }
+ }
+ // pushing the whole Handles element
+ aProp.Name = "Handles";
+ aProp.Value <<= aHandles;
+ aPropVec.push_back( aProp );
+ }
+ }
+ else
+ {
+ const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( rObjData.eShapeType );
+ if ( pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles )
+ {
+ sal_uInt32 i, nCnt = pDefCustomShape->nHandles;
+ const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
+ for ( i = 0; i < nCnt; i++, pData++ )
+ {
+ if ( pData->nFlags & SvxMSDffHandleFlags::POLAR )
+ {
+ if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) )
+ nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
+ }
+ }
+ }
+ }
+
+ // "Path" PropertySequence element
+
+ {
+ PropVec aPathPropVec;
+
+ // "Path/ExtrusionAllowed"
+ if ( IsHardAttribute( DFF_Prop_f3DOK ) )
+ {
+ bool bExtrusionAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 16 ) != 0;
+ aProp.Name = "ExtrusionAllowed";
+ aProp.Value <<= bExtrusionAllowed;
+ aPathPropVec.push_back( aProp );
+ }
+ // "Path/ConcentricGradientFillAllowed"
+ if ( IsHardAttribute( DFF_Prop_fFillShadeShapeOK ) )
+ {
+ bool bConcentricGradientFillAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 2 ) != 0;
+ aProp.Name = "ConcentricGradientFillAllowed";
+ aProp.Value <<= bConcentricGradientFillAllowed;
+ aPathPropVec.push_back( aProp );
+ }
+ // "Path/TextPathAllowed"
+ if ( IsHardAttribute( DFF_Prop_fGtextOK ) || ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) )
+ {
+ bool bTextPathAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 4 ) != 0;
+ aProp.Name = "TextPathAllowed";
+ aProp.Value <<= bTextPathAllowed;
+ aPathPropVec.push_back( aProp );
+ }
+ // Path/Coordinates
+ if ( IsProperty( DFF_Prop_pVertices ) )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
+ sal_uInt16 nNumElemVert = 0;
+ sal_uInt16 nElemSizeVert = 8;
+
+ if ( SeekToContent( DFF_Prop_pVertices, rIn ) )
+ {
+ sal_uInt16 nNumElemMemVert = 0;
+ rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
+ // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
+ // low-order bytes are recorded
+ if (nElemSizeVert == 0xFFF0)
+ nElemSizeVert = 4;
+ }
+ //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
+ bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
+ if (bImport)
+ {
+ aCoordinates.realloc( nNumElemVert );
+ for (auto& rCoordinate : asNonConstRange(aCoordinates))
+ {
+ sal_Int32 nX(0), nY(0);
+
+ if ( nElemSizeVert == 8 )
+ {
+ rIn.ReadInt32( nX )
+ .ReadInt32( nY );
+ }
+ else
+ {
+ // The mso-spt19 (arc) uses this. But it needs unsigned integer. I don't
+ // know if other shape types also need it. They can be added as necessary.
+ bool bNeedsUnsigned = rObjData.eShapeType == mso_sptArc;
+ if (bNeedsUnsigned)
+ {
+ sal_uInt16 nTmpA(0), nTmpB(0);
+ rIn.ReadUInt16(nTmpA)
+ .ReadUInt16(nTmpB);
+ nX = nTmpA;
+ nY = nTmpB;
+ }
+ else
+ {
+ sal_Int16 nTmpA(0), nTmpB(0);
+ rIn.ReadInt16( nTmpA )
+ .ReadInt16( nTmpB );
+ nX = nTmpA;
+ nY = nTmpB;
+ }
+ }
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.First, nX );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.Second, nY );
+ }
+ }
+ aProp.Name = "Coordinates";
+ aProp.Value <<= aCoordinates;
+ aPathPropVec.push_back( aProp );
+ }
+ // Path/Segments
+ if ( IsProperty( DFF_Prop_pSegmentInfo ) )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
+
+ sal_uInt16 nNumElemSeg = 0;
+
+ if ( SeekToContent( DFF_Prop_pSegmentInfo, rIn ) )
+ {
+ sal_uInt16 nNumElemMemSeg = 0;
+ sal_uInt16 nElemSizeSeg = 2;
+ rIn.ReadUInt16( nNumElemSeg ).ReadUInt16( nNumElemMemSeg ).ReadUInt16( nElemSizeSeg );
+ }
+ sal_uInt64 nMaxEntriesPossible = rIn.remainingSize() / sizeof(sal_uInt16);
+ if (nNumElemSeg > nMaxEntriesPossible)
+ {
+ SAL_WARN("filter.ms", "NumElem list is longer than remaining bytes, ppt or parser is wrong");
+ nNumElemSeg = nMaxEntriesPossible;
+ }
+ if ( nNumElemSeg )
+ {
+ aSegments.realloc( nNumElemSeg );
+ for (auto& rSegment : asNonConstRange(aSegments))
+ {
+ sal_uInt16 nTmp(0);
+ rIn.ReadUInt16( nTmp );
+ sal_Int16 nCommand = EnhancedCustomShapeSegmentCommand::UNKNOWN;
+ sal_Int16 nCnt = static_cast<sal_Int16>( nTmp & 0x1fff );//Last 13 bits for segment points number
+ switch( nTmp >> 13 )//First 3 bits for command type
+ {
+ case 0x0:
+ nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
+ if ( !nCnt ) nCnt = 1;
+ break;
+ case 0x1:
+ nCommand = EnhancedCustomShapeSegmentCommand::CURVETO;
+ if ( !nCnt ) nCnt = 1;
+ break;
+ case 0x2:
+ nCommand = EnhancedCustomShapeSegmentCommand::MOVETO;
+ if ( !nCnt ) nCnt = 1;
+ break;
+ case 0x3:
+ nCommand = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
+ nCnt = 0;
+ break;
+ case 0x4:
+ nCommand = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
+ nCnt = 0;
+ break;
+ case 0x5:
+ case 0x6:
+ {
+ switch ( ( nTmp >> 8 ) & 0x1f )//5 bits next to command type is for path escape type
+ {
+ case 0x0:
+ {
+ //It is msopathEscapeExtension which is transformed into LINETO.
+ //If issue happens, I think this part can be comment so that it will be taken as unknown command.
+ //When export, origin data will be export without any change.
+ nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
+ if ( !nCnt )
+ nCnt = 1;
+ }
+ break;
+ case 0x1:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
+ nCnt = ( nTmp & 0xff ) / 3;
+ }
+ break;
+ case 0x2:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
+ nCnt = ( nTmp & 0xff ) / 3;
+ }
+ break;
+ case 0x3:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::ARCTO;
+ nCnt = ( nTmp & 0xff ) >> 2;
+ };
+ break;
+ case 0x4:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::ARC;
+ nCnt = ( nTmp & 0xff ) >> 2;
+ }
+ break;
+ case 0x5:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
+ nCnt = ( nTmp & 0xff ) >> 2;
+ }
+ break;
+ case 0x6:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
+ nCnt = ( nTmp & 0xff ) >> 2;
+ }
+ break;
+ case 0x7:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
+ nCnt = nTmp & 0xff;
+ }
+ break;
+ case 0x8:
+ {
+ nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
+ nCnt = nTmp & 0xff;
+ }
+ break;
+ case 0xa: nCommand = EnhancedCustomShapeSegmentCommand::NOFILL; nCnt = 0; break;
+ case 0xb: nCommand = EnhancedCustomShapeSegmentCommand::NOSTROKE; nCnt = 0; break;
+ }
+ }
+ break;
+ }
+ // if the command is unknown, we will store all the data in nCnt, so it will be possible to export without loss
+ if ( nCommand == EnhancedCustomShapeSegmentCommand::UNKNOWN )
+ nCnt = static_cast<sal_Int16>(nTmp);
+ rSegment.Command = nCommand;
+ rSegment.Count = nCnt;
+ }
+ }
+ aProp.Name = "Segments";
+ aProp.Value <<= aSegments;
+ aPathPropVec.push_back( aProp );
+ }
+ // Path/StretchX
+ if ( IsProperty( DFF_Prop_stretchPointX ) )
+ {
+ sal_Int32 nStretchX = GetPropertyValue( DFF_Prop_stretchPointX, 0 );
+ aProp.Name = "StretchX";
+ aProp.Value <<= nStretchX;
+ aPathPropVec.push_back( aProp );
+ }
+ // Path/StretchX
+ if ( IsProperty( DFF_Prop_stretchPointY ) )
+ {
+ sal_Int32 nStretchY = GetPropertyValue( DFF_Prop_stretchPointY, 0 );
+ aProp.Name = "StretchY";
+ aProp.Value <<= nStretchY;
+ aPathPropVec.push_back( aProp );
+ }
+ // Path/TextFrames
+ if ( IsProperty( DFF_Prop_textRectangles ) )
+ {
+ sal_uInt16 nNumElem = 0;
+ sal_uInt16 nElemSize = 16;
+
+ if ( SeekToContent( DFF_Prop_textRectangles, rIn ) )
+ {
+ sal_uInt16 nNumElemMem = 0;
+ rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
+ }
+ bool bImport = false;
+ if (nElemSize == 16)
+ {
+ //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
+ bImport = rIn.remainingSize() / nElemSize >= nNumElem;
+ }
+ if (bImport)
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrames( nNumElem );
+ for (auto& rTextFrame : asNonConstRange(aTextFrames))
+ {
+ sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0);
+
+ rIn.ReadInt32( nLeft )
+ .ReadInt32( nTop )
+ .ReadInt32( nRight )
+ .ReadInt32( nBottom );
+
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.First, nLeft );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.Second, nTop );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.First, nRight );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.Second, nBottom);
+ }
+ aProp.Name = "TextFrames";
+ aProp.Value <<= aTextFrames;
+ aPathPropVec.push_back( aProp );
+ }
+ }
+ //Path/GluePoints
+ if ( IsProperty( DFF_Prop_connectorPoints ) )
+ {
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
+ sal_uInt16 nNumElemVert = 0;
+ sal_uInt16 nElemSizeVert = 8;
+
+ if ( SeekToContent( DFF_Prop_connectorPoints, rIn ) )
+ {
+ sal_uInt16 nNumElemMemVert = 0;
+ rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
+ // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
+ // low-order bytes are recorded
+ if (nElemSizeVert == 0xFFF0)
+ nElemSizeVert = 4;
+ }
+
+ // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
+ bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
+ if (bImport)
+ {
+ aGluePoints.realloc( nNumElemVert );
+ for (auto& rGluePoint : asNonConstRange(aGluePoints))
+ {
+ sal_Int32 nX(0), nY(0);
+ if ( nElemSizeVert == 8 )
+ {
+ rIn.ReadInt32( nX )
+ .ReadInt32( nY );
+ }
+ else
+ {
+ sal_Int16 nTmpA(0), nTmpB(0);
+
+ rIn.ReadInt16( nTmpA )
+ .ReadInt16( nTmpB );
+
+ nX = nTmpA;
+ nY = nTmpB;
+ }
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.First, nX );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.Second, nY );
+ }
+ }
+ aProp.Name = "GluePoints";
+ aProp.Value <<= aGluePoints;
+ aPathPropVec.push_back( aProp );
+ }
+ if ( IsProperty( DFF_Prop_connectorType ) )
+ {
+ sal_Int16 nGluePointType = static_cast<sal_uInt16>(GetPropertyValue( DFF_Prop_connectorType, 0 ));
+ aProp.Name = "GluePointType";
+ aProp.Value <<= nGluePointType;
+ aPathPropVec.push_back( aProp );
+ }
+ // pushing the whole Path element
+ if ( !aPathPropVec.empty() )
+ {
+ aProp.Name = "Path";
+ aProp.Value <<= comphelper::containerToSequence(aPathPropVec);
+ aPropVec.push_back( aProp );
+ }
+ }
+
+ // "TextPath" PropertySequence element
+
+ bool bTextPathOn = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) != 0;
+ if ( bTextPathOn )
+ {
+ PropVec aTextPathPropVec;
+
+ // TextPath
+ aProp.Name = "TextPath";
+ aProp.Value <<= bTextPathOn;
+ aTextPathPropVec.push_back( aProp );
+
+ // TextPathMode
+ bool bTextPathFitPath = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x100 ) != 0;
+
+ bool bTextPathFitShape;
+ if ( IsHardAttribute( DFF_Prop_gtextFStretch ) )
+ bTextPathFitShape = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x400 ) != 0;
+ else
+ {
+ bTextPathFitShape = true;
+ switch( rObjData.eShapeType )
+ {
+ case mso_sptTextArchUpCurve :
+ case mso_sptTextArchDownCurve :
+ case mso_sptTextCircleCurve :
+ case mso_sptTextButtonCurve :
+ bTextPathFitShape = false;
+ break;
+ default : break;
+ }
+ }
+ EnhancedCustomShapeTextPathMode eTextPathMode( EnhancedCustomShapeTextPathMode_NORMAL );
+ if ( bTextPathFitShape )
+ eTextPathMode = EnhancedCustomShapeTextPathMode_SHAPE;
+ else if ( bTextPathFitPath )
+ eTextPathMode = EnhancedCustomShapeTextPathMode_PATH;
+ aProp.Name = "TextPathMode";
+ aProp.Value <<= eTextPathMode;
+ aTextPathPropVec.push_back( aProp );
+
+ // ScaleX
+ bool bTextPathScaleX = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x40 ) != 0;
+ aProp.Name = "ScaleX";
+ aProp.Value <<= bTextPathScaleX;
+ aTextPathPropVec.push_back( aProp );
+ // SameLetterHeights
+ bool bSameLetterHeight = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x80 ) != 0;
+ aProp.Name = "SameLetterHeights";
+ aProp.Value <<= bSameLetterHeight;
+ aTextPathPropVec.push_back( aProp );
+
+ // pushing the whole TextPath element
+ aProp.Name = "TextPath";
+ aProp.Value <<= comphelper::containerToSequence(aTextPathPropVec);
+ aPropVec.push_back( aProp );
+ }
+
+ // "AdjustmentValues" // The AdjustmentValues are imported at last, because depending to the type of the
+ //////////////////////// handle (POLAR) we will convert the adjustment value from a fixed float to double
+
+ // checking the last used adjustment handle, so we can determine how many handles are to allocate
+ sal_uInt32 i = DFF_Prop_adjust10Value;
+ while ( ( i >= DFF_Prop_adjustValue ) && !IsProperty( i ) )
+ i--;
+ sal_Int32 nAdjustmentValues = ( i - DFF_Prop_adjustValue ) + 1;
+ if ( nAdjustmentValues )
+ {
+ uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq( nAdjustmentValues );
+ auto pAdjustmentSeq = aAdjustmentSeq.getArray();
+ while( --nAdjustmentValues >= 0 )
+ {
+ sal_Int32 nValue = 0;
+ beans::PropertyState ePropertyState = beans::PropertyState_DEFAULT_VALUE;
+ if ( IsProperty( i ) )
+ {
+ nValue = GetPropertyValue( i, 0 );
+ ePropertyState = beans::PropertyState_DIRECT_VALUE;
+ }
+ if ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << ( i - DFF_Prop_adjustValue ) ) )
+ {
+ double fValue = nValue;
+ fValue /= 65536;
+ pAdjustmentSeq[ nAdjustmentValues ].Value <<= fValue;
+ }
+ else
+ pAdjustmentSeq[ nAdjustmentValues ].Value <<= nValue;
+ pAdjustmentSeq[ nAdjustmentValues ].State = ePropertyState;
+ i--;
+ }
+ aProp.Name = "AdjustmentValues";
+ aProp.Value <<= aAdjustmentSeq;
+ aPropVec.push_back( aProp );
+ }
+
+ // creating the whole property set
+ rSet.Put( SdrCustomShapeGeometryItem( comphelper::containerToSequence(aPropVec) ) );
+}
+
+void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet ) const
+{
+ DffRecordHeader aHdTemp;
+ DffObjData aDffObjTemp( aHdTemp, tools::Rectangle(), 0 );
+ ApplyAttributes( rIn, rSet, aDffObjTemp );
+}
+
+void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
+{
+ bool bHasShadow = false;
+ bool bNonZeroShadowOffset = false;
+
+ if ( IsProperty( DFF_Prop_gtextSize ) )
+ rSet.Put( SvxFontHeightItem( rManager.ScalePt( GetPropertyValue( DFF_Prop_gtextSize, 0 ) ), 100, EE_CHAR_FONTHEIGHT ) );
+ sal_uInt32 nFontAttributes = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
+ if ( nFontAttributes & 0x20 )
+ rSet.Put( SvxWeightItem( (nFontAttributes & 0x20) ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ if ( nFontAttributes & 0x10 )
+ rSet.Put( SvxPostureItem( (nFontAttributes & 0x10) ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
+ if ( nFontAttributes & 0x08 )
+ rSet.Put( SvxUnderlineItem( (nFontAttributes & 0x08) ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
+ if ( nFontAttributes & 0x40 )
+ rSet.Put( SvxShadowedItem( (nFontAttributes & 0x40) != 0, EE_CHAR_SHADOW ) );
+// if ( nFontAttributes & 0x02 )
+// rSet.Put( SvxCaseMapItem( nFontAttributes & 0x02 ? SvxCaseMap::SmallCaps : SvxCaseMap::NotMapped ) );
+ if ( nFontAttributes & 0x01 )
+ rSet.Put( SvxCrossedOutItem( (nFontAttributes & 0x01) ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
+ if ( IsProperty( DFF_Prop_fillColor ) )
+ rSet.Put( XFillColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor ) ) );
+ if ( IsProperty( DFF_Prop_shadowColor ) )
+ rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_shadowColor, 0 ), DFF_Prop_shadowColor ) ) );
+ else
+ {
+ //The default value for this property is 0x00808080
+ rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( 0x00808080, DFF_Prop_shadowColor ) ) );
+ }
+ if ( IsProperty( DFF_Prop_shadowOpacity ) )
+ rSet.Put( makeSdrShadowTransparenceItem( static_cast<sal_uInt16>( ( 0x10000 - GetPropertyValue( DFF_Prop_shadowOpacity, 0 ) ) / 655 ) ) );
+ if ( IsProperty( DFF_Prop_shadowOffsetX ) )
+ {
+ sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetX, 0 ) );
+ rManager.ScaleEmu( nVal );
+ rSet.Put( makeSdrShadowXDistItem( nVal ) );
+ bNonZeroShadowOffset = ( nVal > 0 );
+ }
+ if ( IsProperty( DFF_Prop_shadowOffsetY ) )
+ {
+ sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetY, 0 ) );
+ rManager.ScaleEmu( nVal );
+ rSet.Put( makeSdrShadowYDistItem( nVal ) );
+ bNonZeroShadowOffset = ( nVal > 0 );
+ }
+ if ( IsProperty( DFF_Prop_fshadowObscured ) )
+ {
+ bHasShadow = ( GetPropertyValue( DFF_Prop_fshadowObscured, 0 ) & 2 ) != 0;
+ if ( bHasShadow )
+ {
+ if ( !IsProperty( DFF_Prop_shadowOffsetX ) )
+ rSet.Put( makeSdrShadowXDistItem( 35 ) );
+ if ( !IsProperty( DFF_Prop_shadowOffsetY ) )
+ rSet.Put( makeSdrShadowYDistItem( 35 ) );
+ }
+ }
+ if ( IsProperty( DFF_Prop_shadowType ) )
+ {
+ auto eShadowType = GetPropertyValue(DFF_Prop_shadowType, 0);
+ if( eShadowType != mso_shadowOffset && !bNonZeroShadowOffset )
+ {
+ //0.12" == 173 twip == 302 100mm
+ sal_uInt32 nDist = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip ? 173: 302;
+ rSet.Put( makeSdrShadowXDistItem( nDist ) );
+ rSet.Put( makeSdrShadowYDistItem( nDist ) );
+ }
+ }
+ if ( bHasShadow )
+ {
+ static bool bCheckShadow(false); // loplugin:constvars:ignore
+
+ // #i124477# Found no reason not to set shadow, esp. since it is applied to evtl. existing text
+ // and will lead to an error if in PPT someone used text and added the object shadow to the
+ // object carrying that text. I found no cases where this leads to problems (the old bugtracker
+ // task #160376# from sj is unfortunately no longer available). Keeping the code for now
+ // to allow easy fallback when this shows problems in the future
+ if(bCheckShadow)
+ {
+ // #160376# sj: activating shadow only if fill and or linestyle is used
+ // this is required because of the latest drawing layer core changes.
+ // #i104085# is related to this.
+ sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
+ if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( rObjData.eShapeType ))
+ nLineFlags &= ~0x08;
+ sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
+ if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
+ nFillFlags &= ~0x10;
+ if ( nFillFlags & 0x10 )
+ {
+ auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
+ switch( eMSO_FillType )
+ {
+ case mso_fillSolid :
+ case mso_fillPattern :
+ case mso_fillTexture :
+ case mso_fillPicture :
+ case mso_fillShade :
+ case mso_fillShadeCenter :
+ case mso_fillShadeShape :
+ case mso_fillShadeScale :
+ case mso_fillShadeTitle :
+ break;
+ default:
+ nFillFlags &=~0x10; // no fillstyle used
+ break;
+ }
+ }
+ if ( ( ( nLineFlags & 0x08 ) == 0 ) && ( ( nFillFlags & 0x10 ) == 0 ) && ( rObjData.eShapeType != mso_sptPictureFrame )) // if there is no fillstyle and linestyle
+ bHasShadow = false; // we are turning shadow off.
+ }
+
+ if ( bHasShadow )
+ rSet.Put( makeSdrShadowItem( bHasShadow ) );
+ }
+ ApplyLineAttributes( rSet, rObjData.eShapeType ); // #i28269#
+ ApplyFillAttributes( rIn, rSet, rObjData );
+ if ( rObjData.eShapeType != mso_sptNil || IsProperty( DFF_Prop_pVertices ) )
+ {
+ ApplyCustomShapeGeometryAttributes( rIn, rSet, rObjData );
+ ApplyCustomShapeTextAttributes( rSet );
+ if ( rManager.GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL )
+ {
+ if ( mnFix16Angle || ( rObjData.nSpFlags & ShapeFlag::FlipV ) )
+ CheckAndCorrectExcelTextRotation( rIn, rSet, rObjData );
+ }
+ }
+}
+
+void DffPropertyReader::CheckAndCorrectExcelTextRotation( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
+{
+ bool bRotateTextWithShape = rObjData.bRotateTextWithShape;
+ if ( rObjData.bOpt2 ) // sj: #158494# is the second property set available ? if then we have to check the xml data of
+ { // the shape, because the textrotation of Excel 2003 and greater versions is stored there
+ // (upright property of the textbox)
+ if ( rManager.pSecPropSet->SeekToContent( DFF_Prop_metroBlob, rIn ) )
+ {
+ sal_uInt32 nLen = rManager.pSecPropSet->GetPropertyValue( DFF_Prop_metroBlob, 0 );
+ if ( nLen )
+ {
+ css::uno::Sequence< sal_Int8 > aXMLDataSeq( nLen );
+ rIn.ReadBytes(aXMLDataSeq.getArray(), nLen);
+ css::uno::Reference< css::io::XInputStream > xInputStream
+ ( new ::comphelper::SequenceInputStream( aXMLDataSeq ) );
+ try
+ {
+ css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ css::uno::Reference< css::embed::XStorage > xStorage
+ ( ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
+ OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, true ) );
+ if ( xStorage.is() )
+ {
+ css::uno::Reference< css::embed::XStorage >
+ xStorageDRS( xStorage->openStorageElement( "drs", css::embed::ElementModes::SEEKABLEREAD ) );
+ if ( xStorageDRS.is() )
+ {
+ css::uno::Reference< css::io::XStream > xShapeXMLStream( xStorageDRS->openStreamElement( "shapexml.xml", css::embed::ElementModes::SEEKABLEREAD ) );
+ if ( xShapeXMLStream.is() )
+ {
+ css::uno::Reference< css::io::XInputStream > xShapeXMLInputStream( xShapeXMLStream->getInputStream() );
+ if ( xShapeXMLInputStream.is() )
+ {
+ css::uno::Sequence< sal_Int8 > aSeq;
+ sal_Int32 nBytesRead = xShapeXMLInputStream->readBytes( aSeq, 0x7fffffff );
+ if ( nBytesRead )
+ { // for only one property I spare to use a XML parser at this point, this
+ // should be enhanced if needed
+
+ bRotateTextWithShape = true; // using the correct xml default
+ const char* pArry = reinterpret_cast< char* >( aSeq.getArray() );
+ const char* const pUpright = "upright=";
+ const char* pEnd = pArry + nBytesRead;
+ const char* pPtr = pArry;
+ while( ( pPtr + 12 ) < pEnd )
+ {
+ if ( !memcmp( pUpright, pPtr, 8 ) )
+ {
+ bRotateTextWithShape = ( pPtr[ 9 ] != '1' ) && ( pPtr[ 9 ] != 't' );
+ break;
+ }
+ else
+ pPtr++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+ if ( bRotateTextWithShape )
+ return;
+
+ const css::uno::Any* pAny;
+ SdrCustomShapeGeometryItem aGeometryItem(rSet.Get( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
+ static const OUStringLiteral sTextRotateAngle( u"TextRotateAngle" );
+ pAny = aGeometryItem.GetPropertyValueByName( sTextRotateAngle );
+ double fExtraTextRotateAngle = 0.0;
+ if ( pAny )
+ *pAny >>= fExtraTextRotateAngle;
+
+ if ( rManager.mnFix16Angle )
+ fExtraTextRotateAngle += toDegrees(mnFix16Angle);
+ if ( rObjData.nSpFlags & ShapeFlag::FlipV )
+ fExtraTextRotateAngle -= 180.0;
+
+ css::beans::PropertyValue aTextRotateAngle;
+ aTextRotateAngle.Name = sTextRotateAngle;
+ aTextRotateAngle.Value <<= fExtraTextRotateAngle;
+ aGeometryItem.SetPropertyValue( aTextRotateAngle );
+ rSet.Put( aGeometryItem );
+}
+
+
+void DffPropertyReader::ImportGradientColor( SfxItemSet& aSet, sal_uInt32 eMSO_FillType, double dTrans , double dBackTrans) const
+{
+ //MS Focus prop will impact the start and end color position. And AOO does not
+ //support this prop. So need some swap for the two color to keep fidelity with AOO and MS shape.
+ //So below var is defined.
+ sal_Int32 nChgColors = 0;
+ sal_Int32 nAngleFix16 = GetPropertyValue( DFF_Prop_fillAngle, 0 );
+ if(nAngleFix16 >= 0)
+ nChgColors ^= 1;
+
+ //Translate a MS clockwise(+) or count clockwise angle(-) into an AOO count clock wise angle
+ Degree10 nAngle( 3600_deg10 - to<Degree10>( Fix16ToAngle(nAngleFix16) ) );
+ //Make sure this angle belongs to 0~3600
+ while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10;
+ while ( nAngle < 0_deg10 ) nAngle += 3600_deg10;
+
+ //Rotate angle
+ if ( mbRotateGranientFillWithAngle )
+ {
+ sal_Int32 nRotateAngle = GetPropertyValue( DFF_Prop_Rotation, 0 );
+ //nAngle is a clockwise angle. If nRotateAngle is a clockwise angle, then gradient needs to be rotated a little less
+ //or it needs to be rotated a little more
+ nAngle -= to<Degree10>(Fix16ToAngle(nRotateAngle));
+ }
+ while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10;
+ while ( nAngle < 0_deg10 ) nAngle += 3600_deg10;
+
+ css::awt::GradientStyle eGrad = css::awt::GradientStyle_LINEAR;
+
+ sal_Int32 nFocus = GetPropertyValue( DFF_Prop_fillFocus, 0 );
+ if ( !nFocus )
+ nChgColors ^= 1;
+ else if ( nFocus < 0 )//If it is a negative focus, the color will be swapped
+ {
+ nFocus = o3tl::saturating_toggle_sign(nFocus);
+ nChgColors ^= 1;
+ }
+
+ if( nFocus > 40 && nFocus < 60 )
+ {
+ eGrad = css::awt::GradientStyle_AXIAL;//A axial gradient other than linear
+ nChgColors ^= 1;
+ }
+ //if the type is linear or axial, just save focus to nFocusX and nFocusY for export
+ //Core function does no need them. They serve for rect gradient(CenterXY).
+ sal_uInt16 nFocusX = static_cast<sal_uInt16>(nFocus);
+ sal_uInt16 nFocusY = static_cast<sal_uInt16>(nFocus);
+
+ switch( eMSO_FillType )
+ {
+ case mso_fillShadeShape :
+ {
+ eGrad = css::awt::GradientStyle_RECT;
+ nFocusY = nFocusX = 50;
+ nChgColors ^= 1;
+ }
+ break;
+ case mso_fillShadeCenter :
+ {
+ eGrad = css::awt::GradientStyle_RECT;
+ //A MS fillTo prop specifies the relative position of the left boundary
+ //of the center rectangle in a concentric shaded fill. Use 100 or 0 to keep fidelity
+ nFocusX=(GetPropertyValue( DFF_Prop_fillToRight, 0 )==0x10000) ? 100 : 0;
+ nFocusY=(GetPropertyValue( DFF_Prop_fillToBottom,0 )==0x10000) ? 100 : 0;
+ nChgColors ^= 1;
+ }
+ break;
+ default: break;
+ }
+
+ Color aCol1( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ) );
+ Color aCol2( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ) );
+ if ( nChgColors )
+ {
+ //Swap start and end color
+ Color aZwi( aCol1 );
+ aCol1 = aCol2;
+ aCol2 = aZwi;
+ //Swap two colors' transparency
+ double dTemp = dTrans;
+ dTrans = dBackTrans;
+ dBackTrans = dTemp;
+ }
+
+ //Construct gradient item
+ XGradient aGrad( aCol2, aCol1, eGrad, nAngle, nFocusX, nFocusY );
+ //Intensity has been merged into color. So here just set is as 100
+ aGrad.SetStartIntens( 100 );
+ aGrad.SetEndIntens( 100 );
+ aSet.Put( XFillGradientItem( OUString(), aGrad ) );
+ //Construct transparency item. This item can coordinate with both solid and gradient.
+ if ( dTrans < 1.0 || dBackTrans < 1.0 )
+ {
+ sal_uInt8 nStartCol = static_cast<sal_uInt8>( (1 - dTrans )* 255 );
+ sal_uInt8 nEndCol = static_cast<sal_uInt8>( ( 1- dBackTrans ) * 255 );
+ aCol1 = Color(nStartCol, nStartCol, nStartCol);
+ aCol2 = Color(nEndCol, nEndCol, nEndCol);
+
+ XGradient aGrad2( aCol2 , aCol1 , eGrad, nAngle, nFocusX, nFocusY );
+ aSet.Put( XFillFloatTransparenceItem( OUString(), aGrad2 ) );
+ }
+}
+
+
+//- Record Manager ----------------------------------------------------------
+
+
+DffRecordList::DffRecordList( DffRecordList* pList ) :
+ nCount ( 0 ),
+ nCurrent ( 0 ),
+ pPrev ( pList )
+{
+ if ( pList )
+ pList->pNext.reset( this );
+}
+
+DffRecordList::~DffRecordList()
+{
+}
+
+DffRecordManager::DffRecordManager() :
+ DffRecordList ( nullptr ),
+ pCList ( static_cast<DffRecordList*>(this) )
+{
+}
+
+DffRecordManager::DffRecordManager( SvStream& rIn ) :
+ DffRecordList ( nullptr ),
+ pCList ( static_cast<DffRecordList*>(this) )
+{
+ Consume( rIn );
+}
+
+void DffRecordManager::Consume( SvStream& rIn, sal_uInt32 nStOfs )
+{
+ Clear();
+ sal_uInt64 nOldPos = rIn.Tell();
+ if ( !nStOfs )
+ {
+ DffRecordHeader aHd;
+ bool bOk = ReadDffRecordHeader( rIn, aHd );
+ if (bOk && aHd.nRecVer == DFF_PSFLAG_CONTAINER)
+ nStOfs = aHd.GetRecEndFilePos();
+ }
+ if ( !nStOfs )
+ return;
+
+ pCList = this;
+ while ( pCList->pNext )
+ pCList = pCList->pNext.get();
+ while (rIn.good() && ( ( rIn.Tell() + 8 ) <= nStOfs ))
+ {
+ if ( pCList->nCount == DFF_RECORD_MANAGER_BUF_SIZE )
+ pCList = new DffRecordList( pCList );
+ if (!ReadDffRecordHeader(rIn, pCList->mHd[ pCList->nCount ]))
+ break;
+ bool bSeekSucceeded = pCList->mHd[ pCList->nCount++ ].SeekToEndOfRecord(rIn);
+ if (!bSeekSucceeded)
+ break;
+ }
+ rIn.Seek( nOldPos );
+}
+
+void DffRecordManager::Clear()
+{
+ pCList = this;
+ pNext.reset();
+ nCurrent = 0;
+ nCount = 0;
+}
+
+DffRecordHeader* DffRecordManager::Current()
+{
+ DffRecordHeader* pRet = nullptr;
+ if ( pCList->nCurrent < pCList->nCount )
+ pRet = &pCList->mHd[ pCList->nCurrent ];
+ return pRet;
+}
+
+DffRecordHeader* DffRecordManager::First()
+{
+ DffRecordHeader* pRet = nullptr;
+ pCList = this;
+ if ( pCList->nCount )
+ {
+ pCList->nCurrent = 0;
+ pRet = &pCList->mHd[ 0 ];
+ }
+ return pRet;
+}
+
+DffRecordHeader* DffRecordManager::Next()
+{
+ DffRecordHeader* pRet = nullptr;
+ sal_uInt32 nC = pCList->nCurrent + 1;
+ if ( nC < pCList->nCount )
+ {
+ pCList->nCurrent++;
+ pRet = &pCList->mHd[ nC ];
+ }
+ else if ( pCList->pNext )
+ {
+ pCList = pCList->pNext.get();
+ pCList->nCurrent = 0;
+ pRet = &pCList->mHd[ 0 ];
+ }
+ return pRet;
+}
+
+DffRecordHeader* DffRecordManager::Prev()
+{
+ DffRecordHeader* pRet = nullptr;
+ sal_uInt32 nCur = pCList->nCurrent;
+ if ( !nCur && pCList->pPrev )
+ {
+ pCList = pCList->pPrev;
+ nCur = pCList->nCount;
+ }
+ if ( nCur-- )
+ {
+ pCList->nCurrent = nCur;
+ pRet = &pCList->mHd[ nCur ];
+ }
+ return pRet;
+}
+
+DffRecordHeader* DffRecordManager::Last()
+{
+ DffRecordHeader* pRet = nullptr;
+ while ( pCList->pNext )
+ pCList = pCList->pNext.get();
+ sal_uInt32 nCnt = pCList->nCount;
+ if ( nCnt-- )
+ {
+ pCList->nCurrent = nCnt;
+ pRet = &pCList->mHd[ nCnt ];
+ }
+ return pRet;
+}
+
+bool DffRecordManager::SeekToContent( SvStream& rIn, sal_uInt16 nRecId, DffSeekToContentMode eMode )
+{
+ DffRecordHeader* pHd = GetRecordHeader( nRecId, eMode );
+ if ( pHd )
+ {
+ pHd->SeekToContent( rIn );
+ return true;
+ }
+ else
+ return false;
+}
+
+DffRecordHeader* DffRecordManager::GetRecordHeader( sal_uInt16 nRecId, DffSeekToContentMode eMode )
+{
+ sal_uInt32 nOldCurrent = pCList->nCurrent;
+ DffRecordList* pOldList = pCList;
+ DffRecordHeader* pHd;
+
+ if ( eMode == SEEK_FROM_BEGINNING )
+ pHd = First();
+ else
+ pHd = Next();
+
+ while ( pHd )
+ {
+ if ( pHd->nRecType == nRecId )
+ break;
+ pHd = Next();
+ }
+ if ( !pHd && eMode == SEEK_FROM_CURRENT_AND_RESTART )
+ {
+ DffRecordHeader* pBreak = &pOldList->mHd[ nOldCurrent ];
+ pHd = First();
+ if ( pHd )
+ {
+ while ( pHd != pBreak )
+ {
+ if ( pHd->nRecType == nRecId )
+ break;
+ pHd = Next();
+ }
+ if ( pHd->nRecType != nRecId )
+ pHd = nullptr;
+ }
+ }
+ if ( !pHd )
+ {
+ pCList = pOldList;
+ pOldList->nCurrent = nOldCurrent;
+ }
+ return pHd;
+}
+
+
+// private methods
+
+
+bool CompareSvxMSDffShapeInfoById::operator() (
+ std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
+ std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
+{
+ return lhs->nShapeId < rhs->nShapeId;
+}
+
+bool CompareSvxMSDffShapeInfoByTxBxComp::operator() (
+ std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
+ std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
+{
+ return lhs->nTxBxComp < rhs->nTxBxComp;
+}
+
+void SvxMSDffManager::Scale( sal_Int32& rVal ) const
+{
+ if ( bNeedMap )
+ rVal = BigMulDiv( rVal, nMapMul, nMapDiv );
+}
+
+void SvxMSDffManager::Scale( Point& rPos ) const
+{
+ rPos.AdjustX(nMapXOfs );
+ rPos.AdjustY(nMapYOfs );
+ if ( bNeedMap )
+ {
+ rPos.setX( BigMulDiv( rPos.X(), nMapMul, nMapDiv ) );
+ rPos.setY( BigMulDiv( rPos.Y(), nMapMul, nMapDiv ) );
+ }
+}
+
+void SvxMSDffManager::Scale( Size& rSiz ) const
+{
+ if ( bNeedMap )
+ {
+ rSiz.setWidth( BigMulDiv( rSiz.Width(), nMapMul, nMapDiv ) );
+ rSiz.setHeight( BigMulDiv( rSiz.Height(), nMapMul, nMapDiv ) );
+ }
+}
+
+void SvxMSDffManager::ScaleEmu( sal_Int32& rVal ) const
+{
+ rVal = BigMulDiv( rVal, nEmuMul, nEmuDiv );
+}
+
+sal_uInt32 SvxMSDffManager::ScalePt( sal_uInt32 nVal ) const
+{
+ MapUnit eMap = pSdrModel->GetScaleUnit();
+ Fraction aFact( GetMapFactor( MapUnit::MapPoint, eMap ).X() );
+ tools::Long aMul = aFact.GetNumerator();
+ tools::Long aDiv = aFact.GetDenominator() * 65536;
+ aFact = Fraction( aMul, aDiv ); // try again to shorten it
+ return BigMulDiv( nVal, aFact.GetNumerator(), aFact.GetDenominator() );
+}
+
+sal_Int32 SvxMSDffManager::ScalePoint( sal_Int32 nVal ) const
+{
+ return BigMulDiv( nVal, nPntMul, nPntDiv );
+};
+
+void SvxMSDffManager::SetModel(SdrModel* pModel, tools::Long nApplicationScale)
+{
+ pSdrModel = pModel;
+ if( pModel && (0 < nApplicationScale) )
+ {
+ // PPT works in units of 576DPI
+ // WW on the other side uses twips, i.e. 1440DPI.
+ MapUnit eMap = pSdrModel->GetScaleUnit();
+ Fraction aFact( GetMapFactor(MapUnit::MapInch, eMap).X() );
+ tools::Long nMul=aFact.GetNumerator();
+ tools::Long nDiv=aFact.GetDenominator()*nApplicationScale;
+ aFact=Fraction(nMul,nDiv); // try again to shorten it
+ // For 100TH_MM -> 2540/576=635/144
+ // For Twip -> 1440/576=5/2
+ nMapMul = aFact.GetNumerator();
+ nMapDiv = aFact.GetDenominator();
+ bNeedMap = nMapMul!=nMapDiv;
+
+ // MS-DFF-Properties are mostly given in EMU (English Metric Units)
+ // 1mm=36000emu, 1twip=635emu
+ aFact=GetMapFactor(MapUnit::Map100thMM,eMap).X();
+ nMul=aFact.GetNumerator();
+ nDiv=aFact.GetDenominator()*360;
+ aFact=Fraction(nMul,nDiv); // try again to shorten it
+ // For 100TH_MM -> 1/360
+ // For Twip -> 14,40/(25,4*360)=144/91440=1/635
+ nEmuMul=aFact.GetNumerator();
+ nEmuDiv=aFact.GetDenominator();
+
+ // And something for typographic Points
+ aFact=GetMapFactor(MapUnit::MapPoint,eMap).X();
+ nPntMul=aFact.GetNumerator();
+ nPntDiv=aFact.GetDenominator();
+ }
+ else
+ {
+ pModel = nullptr;
+ nMapMul = nMapDiv = nMapXOfs = nMapYOfs = nEmuMul = nEmuDiv = nPntMul = nPntDiv = 0;
+ bNeedMap = false;
+ }
+}
+
+bool SvxMSDffManager::SeekToShape( SvStream& rSt, SvxMSDffClientData* /* pClientData */, sal_uInt32 nId ) const
+{
+ bool bRet = false;
+ if ( !maFidcls.empty() )
+ {
+ sal_uInt64 nOldPos = rSt.Tell();
+ sal_uInt32 nSec = ( nId >> 10 ) - 1;
+ if ( nSec < mnIdClusters )
+ {
+ OffsetMap::const_iterator it = maDgOffsetTable.find( maFidcls[ nSec ].dgid );
+ if ( it != maDgOffsetTable.end() )
+ {
+ sal_uInt64 nOfs = it->second;
+ rSt.Seek( nOfs );
+ DffRecordHeader aEscherF002Hd;
+ bool bOk = ReadDffRecordHeader( rSt, aEscherF002Hd );
+ sal_uLong nEscherF002End = bOk ? aEscherF002Hd.GetRecEndFilePos() : 0;
+ while (rSt.good() && rSt.Tell() < nEscherF002End)
+ {
+ DffRecordHeader aEscherObjListHd;
+ if (!ReadDffRecordHeader(rSt, aEscherObjListHd))
+ break;
+ if ( aEscherObjListHd.nRecVer != 0xf )
+ {
+ bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
+ if (!bSeekSuccess)
+ break;
+ }
+ else if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer )
+ {
+ DffRecordHeader aShapeHd;
+ if ( SeekToRec( rSt, DFF_msofbtSp, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) )
+ {
+ sal_uInt32 nShapeId(0);
+ rSt.ReadUInt32( nShapeId );
+ if ( nId == nShapeId )
+ {
+ aEscherObjListHd.SeekToBegOfRecord( rSt );
+ bRet = true;
+ break;
+ }
+ }
+ bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
+ if (!bSeekSuccess)
+ break;
+ }
+ }
+ }
+ }
+ if ( !bRet )
+ rSt.Seek( nOldPos );
+ }
+ return bRet;
+}
+
+bool SvxMSDffManager::SeekToRec( SvStream& rSt, sal_uInt16 nRecId, sal_uLong nMaxFilePos, DffRecordHeader* pRecHd, sal_uLong nSkipCount )
+{
+ bool bRet = false;
+ sal_uInt64 nOldFPos = rSt.Tell(); // store FilePos to restore it later if necessary
+ do
+ {
+ DffRecordHeader aHd;
+ if (!ReadDffRecordHeader(rSt, aHd))
+ break;
+ if (aHd.nRecLen > nMaxLegalDffRecordLength)
+ break;
+ if ( aHd.nRecType == nRecId )
+ {
+ if ( nSkipCount )
+ nSkipCount--;
+ else
+ {
+ bRet = true;
+ if ( pRecHd != nullptr )
+ *pRecHd = aHd;
+ else
+ {
+ bool bSeekSuccess = aHd.SeekToBegOfRecord(rSt);
+ if (!bSeekSuccess)
+ {
+ bRet = false;
+ break;
+ }
+ }
+ }
+ }
+ if ( !bRet )
+ {
+ bool bSeekSuccess = aHd.SeekToEndOfRecord(rSt);
+ if (!bSeekSuccess)
+ break;
+ }
+ }
+ while ( rSt.good() && rSt.Tell() < nMaxFilePos && !bRet );
+ if ( !bRet )
+ rSt.Seek( nOldFPos ); // restore original FilePos
+ return bRet;
+}
+
+bool SvxMSDffManager::SeekToRec2( sal_uInt16 nRecId1, sal_uInt16 nRecId2, sal_uLong nMaxFilePos ) const
+{
+ bool bRet = false;
+ sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for conditionally later restoration
+ do
+ {
+ DffRecordHeader aHd;
+ if (!ReadDffRecordHeader(rStCtrl, aHd))
+ break;
+ if ( aHd.nRecType == nRecId1 || aHd.nRecType == nRecId2 )
+ {
+ bRet = true;
+ bool bSeekSuccess = aHd.SeekToBegOfRecord(rStCtrl);
+ if (!bSeekSuccess)
+ {
+ bRet = false;
+ break;
+ }
+ }
+ if ( !bRet )
+ {
+ bool bSeekSuccess = aHd.SeekToEndOfRecord(rStCtrl);
+ if (!bSeekSuccess)
+ break;
+ }
+ }
+ while ( rStCtrl.good() && rStCtrl.Tell() < nMaxFilePos && !bRet );
+ if ( !bRet )
+ rStCtrl.Seek( nOldFPos ); // restore FilePos
+ return bRet;
+}
+
+
+bool SvxMSDffManager::GetColorFromPalette( sal_uInt16 /* nNum */, Color& rColor ) const
+{
+ // This method has to be overwritten in the class
+ // derived for the excel export
+ rColor = COL_WHITE;
+ return true;
+}
+
+// sj: the documentation is not complete, especially in ppt the normal rgb for text
+// color is written as 0xfeRRGGBB, this can't be explained by the documentation, nearly
+// every bit in the upper code is set -> so there seems to be a special handling for
+// ppt text colors, i decided not to fix this in MSO_CLR_ToColor because of possible
+// side effects, instead MSO_TEXT_CLR_ToColor is called for PPT text colors, to map
+// the color code to something that behaves like the other standard color codes used by
+// fill and line color
+Color SvxMSDffManager::MSO_TEXT_CLR_ToColor( sal_uInt32 nColorCode ) const
+{
+ // for text colors: Header is 0xfeRRGGBB
+ if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 )
+ nColorCode &= 0x00ffffff;
+ else
+ {
+ // for colorscheme colors the color index are the lower three bits of the upper byte
+ if ( ( nColorCode & 0xf8000000 ) == 0 ) // this must be a colorscheme index
+ {
+ nColorCode >>= 24;
+ nColorCode |= 0x8000000;
+ }
+ }
+ return MSO_CLR_ToColor( nColorCode );
+}
+
+Color SvxMSDffManager::MSO_CLR_ToColor( sal_uInt32 nColorCode, sal_uInt16 nContentProperty ) const
+{
+ Color aColor( mnDefaultColor );
+
+ // for text colors: Header is 0xfeRRGGBB
+ if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 ) // sj: it needs to be checked if 0xfe is used in
+ nColorCode &= 0x00ffffff; // other cases than ppt text -> if not this code can be removed
+
+ sal_uInt8 nUpper = static_cast<sal_uInt8>( nColorCode >> 24 );
+
+ // sj: below change from 0x1b to 0x19 was done because of i84812 (0x02 -> rgb color),
+ // now I have some problems to fix i104685 (there the color value is 0x02000000 which requires
+ // a 0x2 scheme color to be displayed properly), the color docu seems to be incomplete
+ if( nUpper & 0x19 ) // if( nUpper & 0x1f )
+ {
+ if( ( nUpper & 0x08 ) || ( ( nUpper & 0x10 ) == 0 ) )
+ {
+ // SCHEMECOLOR
+ if ( !GetColorFromPalette( ( nUpper & 8 ) ? static_cast<sal_uInt16>(nColorCode) : nUpper, aColor ) )
+ {
+ switch( nContentProperty )
+ {
+ case DFF_Prop_pictureTransparent :
+ case DFF_Prop_shadowColor :
+ case DFF_Prop_fillBackColor :
+ case DFF_Prop_fillColor :
+ aColor = COL_WHITE;
+ break;
+ case DFF_Prop_lineColor :
+ {
+ aColor = COL_BLACK;
+ }
+ break;
+ }
+ }
+ }
+ else // SYSCOLOR
+ {
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ sal_uInt16 nParameter = sal_uInt16(( nColorCode >> 16 ) & 0x00ff); // the HiByte of nParameter is not zero, an exclusive AND is helping :o
+ sal_uInt16 nFunctionBits = static_cast<sal_uInt16>( ( nColorCode & 0x00000f00 ) >> 8 );
+ sal_uInt16 nAdditionalFlags = static_cast<sal_uInt16>( ( nColorCode & 0x0000f000) >> 8 );
+ sal_uInt16 nColorIndex = sal_uInt16(nColorCode & 0x00ff);
+ sal_uInt32 nPropColor = 0;
+
+ sal_uInt16 nCProp = 0;
+
+ switch ( nColorIndex )
+ {
+ case mso_syscolorButtonFace : aColor = rStyleSettings.GetFaceColor(); break;
+ case mso_syscolorWindowText : aColor = rStyleSettings.GetWindowTextColor(); break;
+ case mso_syscolorMenu : aColor = rStyleSettings.GetMenuColor(); break;
+ case mso_syscolor3DLight :
+ case mso_syscolorButtonHighlight :
+ case mso_syscolorHighlight : aColor = rStyleSettings.GetHighlightColor(); break;
+ case mso_syscolorHighlightText : aColor = rStyleSettings.GetHighlightTextColor(); break;
+ case mso_syscolorCaptionText : aColor = rStyleSettings.GetMenuTextColor(); break;
+ case mso_syscolorActiveCaption : aColor = rStyleSettings.GetHighlightColor(); break;
+ case mso_syscolorButtonShadow : aColor = rStyleSettings.GetShadowColor(); break;
+ case mso_syscolorButtonText : aColor = rStyleSettings.GetButtonTextColor(); break;
+ case mso_syscolorGrayText : aColor = rStyleSettings.GetDeactiveColor(); break;
+ case mso_syscolorInactiveCaption : aColor = rStyleSettings.GetDeactiveColor(); break;
+ case mso_syscolorInactiveCaptionText : aColor = rStyleSettings.GetDeactiveColor(); break;
+ case mso_syscolorInfoBackground : aColor = rStyleSettings.GetFaceColor(); break;
+ case mso_syscolorInfoText : aColor = rStyleSettings.GetLabelTextColor(); break;
+ case mso_syscolorMenuText : aColor = rStyleSettings.GetMenuTextColor(); break;
+ case mso_syscolorScrollbar : aColor = rStyleSettings.GetFaceColor(); break;
+ case mso_syscolorWindow : aColor = rStyleSettings.GetWindowColor(); break;
+ case mso_syscolorWindowFrame : aColor = rStyleSettings.GetWindowColor(); break;
+
+ case mso_colorFillColor :
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
+ nCProp = DFF_Prop_fillColor;
+ }
+ break;
+ case mso_colorLineOrFillColor : // ( use the line color only if there is a line )
+ {
+ if ( GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ) & 8 )
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
+ nCProp = DFF_Prop_lineColor;
+ }
+ else
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
+ nCProp = DFF_Prop_fillColor;
+ }
+ }
+ break;
+ case mso_colorLineColor :
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
+ nCProp = DFF_Prop_lineColor;
+ }
+ break;
+ case mso_colorShadowColor :
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_shadowColor, 0x808080 );
+ nCProp = DFF_Prop_shadowColor;
+ }
+ break;
+ case mso_colorThis : // ( use this color ... )
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
+ nCProp = DFF_Prop_fillColor;
+ }
+ break;
+ case mso_colorFillBackColor :
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_fillBackColor, 0xffffff );
+ nCProp = DFF_Prop_fillBackColor;
+ }
+ break;
+ case mso_colorLineBackColor :
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_lineBackColor, 0xffffff );
+ nCProp = DFF_Prop_lineBackColor;
+ }
+ break;
+ case mso_colorFillThenLine : // ( use the fillcolor unless no fill and line )
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
+ nCProp = DFF_Prop_fillColor;
+ }
+ break;
+ case mso_colorIndexMask : // ( extract the color index ) ?
+ {
+ nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
+ nCProp = DFF_Prop_fillColor;
+ }
+ break;
+ }
+ if ( nCProp && ( nPropColor & 0x10000000 ) == 0 ) // beware of looping recursive
+ aColor = MSO_CLR_ToColor( nPropColor, nCProp );
+
+ if( nAdditionalFlags & 0x80 ) // make color gray
+ {
+ sal_uInt8 nZwi = aColor.GetLuminance();
+ aColor = Color( nZwi, nZwi, nZwi );
+ }
+ switch( nFunctionBits )
+ {
+ case 0x01 : // darken color by parameter
+ {
+ aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetRed() ) >> 8 ) );
+ aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetGreen() ) >> 8 ) );
+ aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetBlue() ) >> 8 ) );
+ }
+ break;
+ case 0x02 : // lighten color by parameter
+ {
+ sal_uInt16 nInvParameter = ( 0x00ff - nParameter ) * 0xff;
+ aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetRed() ) ) >> 8 ) );
+ aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetGreen() ) ) >> 8 ) );
+ aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetBlue() ) ) >> 8 ) );
+ }
+ break;
+ case 0x03 : // add grey level RGB(p,p,p)
+ {
+ sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) + static_cast<sal_Int16>(nParameter);
+ sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) + static_cast<sal_Int16>(nParameter);
+ sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) + static_cast<sal_Int16>(nParameter);
+ if ( nR > 0x00ff )
+ nR = 0x00ff;
+ if ( nG > 0x00ff )
+ nG = 0x00ff;
+ if ( nB > 0x00ff )
+ nB = 0x00ff;
+ aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
+ }
+ break;
+ case 0x04 : // subtract grey level RGB(p,p,p)
+ {
+ sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) - static_cast<sal_Int16>(nParameter);
+ sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) - static_cast<sal_Int16>(nParameter);
+ sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) - static_cast<sal_Int16>(nParameter);
+ if ( nR < 0 )
+ nR = 0;
+ if ( nG < 0 )
+ nG = 0;
+ if ( nB < 0 )
+ nB = 0;
+ aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
+ }
+ break;
+ case 0x05 : // subtract from gray level RGB(p,p,p)
+ {
+ sal_Int16 nR = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetRed());
+ sal_Int16 nG = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetGreen());
+ sal_Int16 nB = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetBlue());
+ if ( nR < 0 )
+ nR = 0;
+ if ( nG < 0 )
+ nG = 0;
+ if ( nB < 0 )
+ nB = 0;
+ aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
+ }
+ break;
+ case 0x06 : // per component: black if < p, white if >= p
+ {
+ aColor.SetRed( aColor.GetRed() < nParameter ? 0x00 : 0xff );
+ aColor.SetGreen( aColor.GetGreen() < nParameter ? 0x00 : 0xff );
+ aColor.SetBlue( aColor.GetBlue() < nParameter ? 0x00 : 0xff );
+ }
+ break;
+ }
+ if ( nAdditionalFlags & 0x40 ) // top-bit invert
+ aColor = Color( aColor.GetRed() ^ 0x80, aColor.GetGreen() ^ 0x80, aColor.GetBlue() ^ 0x80 );
+
+ if ( nAdditionalFlags & 0x20 ) // invert color
+ aColor = Color(0xff - aColor.GetRed(), 0xff - aColor.GetGreen(), 0xff - aColor.GetBlue());
+ }
+ }
+ else if ( ( nUpper & 4 ) && ( ( nColorCode & 0xfffff8 ) == 0 ) )
+ { // case of nUpper == 4 powerpoint takes this as argument for a colorschemecolor
+ GetColorFromPalette( nUpper, aColor );
+ }
+ else // attributed hard, maybe with hint to SYSTEMRGB
+ aColor = Color( static_cast<sal_uInt8>(nColorCode), static_cast<sal_uInt8>( nColorCode >> 8 ), static_cast<sal_uInt8>( nColorCode >> 16 ) );
+ return aColor;
+}
+
+void SvxMSDffManager::ReadObjText( SvStream& rStream, SdrObject* pObj )
+{
+ DffRecordHeader aRecHd;
+ if (!ReadDffRecordHeader(rStream, aRecHd))
+ return;
+ if( aRecHd.nRecType != DFF_msofbtClientTextbox && aRecHd.nRecType != 0x1022 )
+ return;
+
+ while (rStream.good() && rStream.Tell() < aRecHd.GetRecEndFilePos())
+ {
+ DffRecordHeader aHd;
+ if (!ReadDffRecordHeader(rStream, aHd))
+ break;
+ switch( aHd.nRecType )
+ {
+ case DFF_PST_TextBytesAtom:
+ case DFF_PST_TextCharsAtom:
+ {
+ bool bUniCode = ( aHd.nRecType == DFF_PST_TextCharsAtom );
+ sal_uInt32 nBytes = aHd.nRecLen;
+ OUString aStr = MSDFFReadZString( rStream, nBytes, bUniCode );
+ ReadObjText( aStr, pObj );
+ }
+ break;
+ default:
+ break;
+ }
+ bool bSeekSuccess = aHd.SeekToEndOfRecord(rStream);
+ if (!bSeekSuccess)
+ break;
+ }
+}
+
+// sj: I just want to set a string for a text object that may contain multiple
+// paragraphs. If I now take a look at the following code I get the impression that
+// our outliner is too complicate to be used properly,
+void SvxMSDffManager::ReadObjText( const OUString& rText, SdrObject* pObj )
+{
+ SdrTextObj* pText = dynamic_cast<SdrTextObj*>( pObj );
+ if ( !pText )
+ return;
+
+ SdrOutliner& rOutliner = pText->ImpGetDrawOutliner();
+ rOutliner.Init( OutlinerMode::TextObject );
+
+ bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
+ rOutliner.SetVertical( pText->IsVerticalWriting() );
+
+ sal_Int32 nParaIndex = 0;
+ sal_Int32 nParaSize;
+ const sal_Unicode* pBuf = rText.getStr();
+ const sal_Unicode* pEnd = rText.getStr() + rText.getLength();
+
+ while( pBuf < pEnd )
+ {
+ const sal_Unicode* pCurrent = pBuf;
+
+ for ( nParaSize = 0; pBuf < pEnd; )
+ {
+ sal_Unicode nChar = *pBuf++;
+ if ( nChar == 0xa )
+ {
+ if ( ( pBuf < pEnd ) && ( *pBuf == 0xd ) )
+ pBuf++;
+ break;
+ }
+ else if ( nChar == 0xd )
+ {
+ if ( ( pBuf < pEnd ) && ( *pBuf == 0xa ) )
+ pBuf++;
+ break;
+ }
+ else
+ ++nParaSize;
+ }
+ ESelection aSelection( nParaIndex, 0, nParaIndex, 0 );
+ OUString aParagraph( pCurrent, nParaSize );
+ if ( !nParaIndex && aParagraph.isEmpty() ) // SJ: we are crashing if the first paragraph is empty ?
+ aParagraph += " "; // otherwise these two lines can be removed.
+ rOutliner.Insert( aParagraph, nParaIndex );
+ rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() );
+
+ SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
+ if ( !aSelection.nStartPos )
+ aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
+ aSelection.nStartPos = 0;
+ rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
+ nParaIndex++;
+ }
+ std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
+ rOutliner.Clear();
+ rOutliner.SetUpdateLayout( bOldUpdateMode );
+ pText->SetOutlinerParaObject( std::move(pNewText) );
+ // tdf#143315: restore stylesheet applied to Outliner's nodes when SdrTextObj initializes
+ // its attributes, but removed by Outliner::Init, which calls Outliner::Clear.
+ pText->SetStyleSheet(pText->GetStyleSheet(), true);
+}
+
+//static
+OUString SvxMSDffManager::MSDFFReadZString(SvStream& rIn,
+ sal_uInt32 nLen, bool bUniCode)
+{
+ if (!nLen)
+ return OUString();
+
+ OUString sBuf;
+
+ if( bUniCode )
+ sBuf = read_uInt16s_ToOUString(rIn, nLen/2);
+ else
+ sBuf = read_uInt8s_ToOUString(rIn, nLen, RTL_TEXTENCODING_MS_1252);
+
+ return comphelper::string::stripEnd(sBuf, 0);
+}
+
+static Size lcl_GetPrefSize(const Graphic& rGraf, const MapMode& aWanted)
+{
+ MapMode aPrefMapMode(rGraf.GetPrefMapMode());
+ if (aPrefMapMode == aWanted)
+ return rGraf.GetPrefSize();
+ Size aRetSize;
+ if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
+ {
+ aRetSize = Application::GetDefaultDevice()->PixelToLogic(
+ rGraf.GetPrefSize(), aWanted);
+ }
+ else
+ {
+ aRetSize = OutputDevice::LogicToLogic(
+ rGraf.GetPrefSize(), rGraf.GetPrefMapMode(), aWanted);
+ }
+ return aRetSize;
+}
+
+// sj: if the parameter pSet is null, then the resulting crop bitmap will be stored in rGraf,
+// otherwise rGraf is untouched and pSet is used to store the corresponding SdrGrafCropItem
+static void lcl_ApplyCropping( const DffPropSet& rPropSet, SfxItemSet* pSet, Graphic& rGraf )
+{
+ sal_Int32 nCropTop = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromTop, 0 ));
+ sal_Int32 nCropBottom = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromBottom, 0 ));
+ sal_Int32 nCropLeft = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromLeft, 0 ));
+ sal_Int32 nCropRight = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromRight, 0 ));
+
+ if( !(nCropTop || nCropBottom || nCropLeft || nCropRight) )
+ return;
+
+ double fFactor;
+ Size aCropSize;
+ BitmapEx aCropBitmap;
+ sal_uInt32 nTop( 0 ), nBottom( 0 ), nLeft( 0 ), nRight( 0 );
+
+ // Cropping has to be applied on a loaded graphic.
+ rGraf.makeAvailable();
+
+ if ( pSet ) // use crop attributes ?
+ aCropSize = lcl_GetPrefSize(rGraf, MapMode(MapUnit::Map100thMM));
+ else
+ {
+ aCropBitmap = rGraf.GetBitmapEx();
+ aCropSize = aCropBitmap.GetSizePixel();
+ }
+ if ( nCropTop )
+ {
+ fFactor = static_cast<double>(nCropTop) / 65536.0;
+ nTop = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
+ }
+ if ( nCropBottom )
+ {
+ fFactor = static_cast<double>(nCropBottom) / 65536.0;
+ nBottom = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
+ }
+ if ( nCropLeft )
+ {
+ fFactor = static_cast<double>(nCropLeft) / 65536.0;
+ nLeft = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
+ }
+ if ( nCropRight )
+ {
+ fFactor = static_cast<double>(nCropRight) / 65536.0;
+ nRight = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
+ }
+ if ( pSet ) // use crop attributes ?
+ pSet->Put( SdrGrafCropItem( nLeft, nTop, nRight, nBottom ) );
+ else
+ {
+ tools::Rectangle aCropRect( nLeft, nTop, aCropSize.Width() - nRight, aCropSize.Height() - nBottom );
+ aCropBitmap.Crop( aCropRect );
+ rGraf = aCropBitmap;
+ }
+}
+
+SdrObject* SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, const DffObjData& rObjData )
+{
+ SdrObject* pRet = nullptr;
+ OUString aLinkFileName;
+ tools::Rectangle aVisArea;
+
+ auto eFlags = GetPropertyValue(DFF_Prop_pibFlags, mso_blipflagDefault);
+ sal_uInt32 nBlipId = GetPropertyValue( DFF_Prop_pib, 0 );
+ bool bGrfRead = false,
+
+ // Graphic linked
+ bLinkGrf = 0 != ( eFlags & mso_blipflagLinkToFile );
+ {
+ OUString aFileName;
+ Graphic aGraf; // be sure this graphic is deleted before swapping out
+ if( SeekToContent( DFF_Prop_pibName, rSt ) )
+ aFileName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_pibName, 0 ), true );
+
+ // AND, OR the following:
+ if( !( eFlags & mso_blipflagDoNotSave ) ) // Graphic embedded
+ {
+ bGrfRead = GetBLIP( nBlipId, aGraf, &aVisArea );
+ if ( !bGrfRead )
+ {
+ /*
+ Still no luck, lets look at the end of this record for a FBSE pool,
+ this fallback is a specific case for how word does it sometimes
+ */
+ bool bOk = rObjData.rSpHd.SeekToEndOfRecord( rSt );
+ DffRecordHeader aHd;
+ if (bOk)
+ {
+ bOk = ReadDffRecordHeader(rSt, aHd);
+ }
+ if (bOk && DFF_msofbtBSE == aHd.nRecType)
+ {
+ const sal_uLong nSkipBLIPLen = 20;
+ const sal_uLong nSkipShapePos = 4;
+ const sal_uLong nSkipBLIP = 4;
+ const sal_uLong nSkip =
+ nSkipBLIPLen + 4 + nSkipShapePos + 4 + nSkipBLIP;
+
+ if (nSkip <= aHd.nRecLen)
+ {
+ rSt.SeekRel(nSkip);
+ if (ERRCODE_NONE == rSt.GetError())
+ bGrfRead = GetBLIPDirect( rSt, aGraf, &aVisArea );
+ }
+ }
+ }
+ }
+ if ( bGrfRead )
+ {
+ // the writer is doing its own cropping, so this part affects only impress and calc,
+ // unless we're inside a group, in which case writer doesn't crop either
+ if (( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_CROP_BITMAPS ) || rObjData.nCalledByGroup != 0 )
+ lcl_ApplyCropping( *this, !bool( rObjData.nSpFlags & ShapeFlag::OLEShape ) ? &rSet : nullptr, aGraf );
+
+ if ( IsProperty( DFF_Prop_pictureTransparent ) )
+ {
+ sal_uInt32 nTransColor = GetPropertyValue( DFF_Prop_pictureTransparent, 0 );
+
+ if ( aGraf.GetType() == GraphicType::Bitmap )
+ {
+ BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
+ aBitmapEx.CombineMaskOr( MSO_CLR_ToColor( nTransColor, DFF_Prop_pictureTransparent ), 9 );
+ aGraf = aBitmapEx;
+ }
+ }
+
+ sal_Int32 nContrast = GetPropertyValue( DFF_Prop_pictureContrast, 0x10000 );
+ /*
+ 0x10000 is msoffice 50%
+ < 0x10000 is in units of 1/50th of 0x10000 per 1%
+ > 0x10000 is in units where
+ a msoffice x% is stored as 50/(100-x) * 0x10000
+
+ plus, a (ui) microsoft % ranges from 0 to 100, OOO
+ from -100 to 100, so also normalize into that range
+ */
+ if ( nContrast > 0x10000 )
+ {
+ double fX = nContrast;
+ fX /= 0x10000;
+ fX /= 51; // 50 + 1 to round
+ fX = 1/fX;
+ nContrast = static_cast<sal_Int32>(fX);
+ nContrast -= 100;
+ nContrast = -nContrast;
+ nContrast = (nContrast-50)*2;
+ }
+ else if ( nContrast == 0x10000 )
+ nContrast = 0;
+ else
+ {
+ if (o3tl::checked_multiply<sal_Int32>(nContrast, 101, nContrast)) //100 + 1 to round
+ {
+ SAL_WARN("filter.ms", "bad Contrast value:" << nContrast);
+ nContrast = 0;
+ }
+ else
+ {
+ nContrast /= 0x10000;
+ nContrast -= 100;
+ }
+ }
+ sal_Int16 nBrightness = static_cast<sal_Int16>( static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_pictureBrightness, 0 )) / 327 );
+ sal_Int32 nGamma = GetPropertyValue( DFF_Prop_pictureGamma, 0x10000 );
+ GraphicDrawMode eDrawMode = GraphicDrawMode::Standard;
+ switch ( GetPropertyValue( DFF_Prop_pictureActive, 0 ) & 6 )
+ {
+ case 4 : eDrawMode = GraphicDrawMode::Greys; break;
+ case 6 : eDrawMode = GraphicDrawMode::Mono; break;
+ case 0 :
+ {
+ //office considers the converted values of (in OOo) 70 to be the
+ //"watermark" values, which can vary slightly due to rounding from the
+ //above values
+ if (( nContrast == -70 ) && ( nBrightness == 70 ))
+ {
+ nContrast = 0;
+ nBrightness = 0;
+ eDrawMode = GraphicDrawMode::Watermark;
+ };
+ }
+ break;
+ }
+
+ if ( nContrast || nBrightness || ( nGamma != 0x10000 ) || ( eDrawMode != GraphicDrawMode::Standard ) )
+ {
+ // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
+ // while MSO apparently applies half of brightness before contrast and half after. So if only
+ // contrast or brightness need to be altered, the result is the same, but if both are involved,
+ // there's no way to map that, so just force a conversion of the image.
+ bool needsConversion = nContrast != 0 && nBrightness != 0;
+ if ( !bool(rObjData.nSpFlags & ShapeFlag::OLEShape) && !needsConversion )
+ {
+ if ( nBrightness )
+ rSet.Put( SdrGrafLuminanceItem( nBrightness ) );
+ if ( nContrast )
+ rSet.Put( SdrGrafContrastItem( static_cast<sal_Int16>(nContrast) ) );
+ if ( nGamma != 0x10000 )
+ rSet.Put( SdrGrafGamma100Item( nGamma / 655 ) );
+ if ( eDrawMode != GraphicDrawMode::Standard )
+ rSet.Put( SdrGrafModeItem( eDrawMode ) );
+ }
+ else
+ {
+ if ( eDrawMode == GraphicDrawMode::Watermark )
+ {
+ nContrast = 60;
+ nBrightness = 70;
+ eDrawMode = GraphicDrawMode::Standard;
+ }
+ switch ( aGraf.GetType() )
+ {
+ case GraphicType::Bitmap :
+ {
+ BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
+ if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
+ aBitmapEx.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
+ if ( eDrawMode == GraphicDrawMode::Greys )
+ aBitmapEx.Convert( BmpConversion::N8BitGreys );
+ else if ( eDrawMode == GraphicDrawMode::Mono )
+ aBitmapEx.Convert( BmpConversion::N1BitThreshold );
+ aGraf = aBitmapEx;
+
+ }
+ break;
+
+ case GraphicType::GdiMetafile :
+ {
+ GDIMetaFile aGdiMetaFile( aGraf.GetGDIMetaFile() );
+ if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
+ aGdiMetaFile.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
+ if ( eDrawMode == GraphicDrawMode::Greys )
+ aGdiMetaFile.Convert( MtfConversion::N8BitGreys );
+ else if ( eDrawMode == GraphicDrawMode::Mono )
+ aGdiMetaFile.Convert( MtfConversion::N1BitThreshold );
+ aGraf = aGdiMetaFile;
+ }
+ break;
+ default: break;
+ }
+ }
+ }
+ }
+
+ // should it be an OLE object?
+ if( bGrfRead && !bLinkGrf && IsProperty( DFF_Prop_pictureId ) )
+ {
+ // TODO/LATER: in future probably the correct aspect should be provided here
+ // #i32596# - pass <nCalledByGroup> to method
+ pRet = ImportOLE( GetPropertyValue( DFF_Prop_pictureId, 0 ), aGraf, rObjData.aBoundRect, aVisArea, rObjData.nCalledByGroup );
+ }
+ if( !pRet )
+ {
+ pRet = new SdrGrafObj(*pSdrModel);
+ if( bGrfRead )
+ static_cast<SdrGrafObj*>(pRet)->SetGraphic( aGraf );
+
+ if( bLinkGrf && !bGrfRead ) // sj: #i55484# if the graphic was embedded ( bGrfRead == true ) then
+ { // we do not need to set a link. TODO: not to lose the information where the graphic is linked from
+ INetURLObject aAbsURL;
+ if ( !INetURLObject( maBaseURL ).GetNewAbsURL( aFileName, &aAbsURL ) )
+ {
+ OUString aValidURL;
+ if( osl::FileBase::getFileURLFromSystemPath( aFileName, aValidURL ) == osl::FileBase::E_None )
+ aAbsURL = INetURLObject( aValidURL );
+ }
+ if( aAbsURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ aLinkFileName = aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
+ }
+ else
+ aLinkFileName = aFileName;
+ }
+ }
+
+ // set the size from BLIP if there is one
+ if ( bGrfRead && !aVisArea.IsEmpty() )
+ pRet->SetBLIPSizeRectangle( aVisArea );
+
+ if (pRet->GetName().isEmpty()) // SJ 22.02.00 : PPT OLE IMPORT:
+ { // name is already set in ImportOLE !!
+ // JP 01.12.99: SetName before SetModel - because in the other order the Bug 70098 is active
+ if ( ( eFlags & mso_blipflagType ) != mso_blipflagComment )
+ {
+ INetURLObject aURL;
+ aURL.SetSmartURL( aFileName );
+ pRet->SetName( aURL.getBase() );
+ }
+ else
+ pRet->SetName( aFileName );
+ }
+ }
+ pRet->NbcSetLogicRect( rObjData.aBoundRect );
+
+ if (SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>(pRet))
+ {
+ if( aLinkFileName.getLength() )
+ {
+ pGrafObj->SetGraphicLink( aLinkFileName );
+ Graphic aGraphic(pGrafObj->GetGraphic());
+ aGraphic.setOriginURL(aLinkFileName);
+ }
+
+ if ( bLinkGrf && !bGrfRead )
+ {
+ Graphic aGraf(pGrafObj->GetGraphic());
+ lcl_ApplyCropping( *this, &rSet, aGraf );
+ }
+ }
+
+ return pRet;
+}
+
+// PptSlidePersistEntry& rPersistEntry, SdPage* pPage
+SdrObject* SvxMSDffManager::ImportObj( SvStream& rSt, SvxMSDffClientData& rClientData,
+ tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, int nCalledByGroup, sal_Int32* pShapeId )
+{
+ SdrObject* pRet = nullptr;
+ DffRecordHeader aObjHd;
+ bool bOk = ReadDffRecordHeader(rSt, aObjHd);
+ if (bOk && aObjHd.nRecType == DFF_msofbtSpgrContainer)
+ {
+ pRet = ImportGroup( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
+ }
+ else if (bOk && aObjHd.nRecType == DFF_msofbtSpContainer)
+ {
+ pRet = ImportShape( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
+ }
+ aObjHd.SeekToBegOfRecord( rSt ); // restore FilePos
+ return pRet;
+}
+
+SdrObject* SvxMSDffManager::ImportGroup( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
+ tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
+ int nCalledByGroup, sal_Int32* pShapeId )
+{
+ SdrObject* pRet = nullptr;
+
+ if( pShapeId )
+ *pShapeId = 0;
+
+ if (!rHd.SeekToContent(rSt))
+ return pRet;
+
+ DffRecordHeader aRecHd; // the first atom has to be the SpContainer for the GroupObject
+ bool bOk = ReadDffRecordHeader(rSt, aRecHd);
+ if (bOk && aRecHd.nRecType == DFF_msofbtSpContainer)
+ {
+ mnFix16Angle = 0_deg100;
+ if (!aRecHd.SeekToBegOfRecord(rSt))
+ return pRet;
+ pRet = ImportObj( rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup + 1, pShapeId );
+ if ( pRet )
+ {
+ Degree100 nGroupRotateAngle(0);
+ ShapeFlag nSpFlags = nGroupShapeFlags;
+ nGroupRotateAngle = mnFix16Angle;
+
+ tools::Rectangle aClientRect( rClientRect );
+
+ tools::Rectangle aGlobalChildRect;
+ if ( !nCalledByGroup || rGlobalChildRect.IsEmpty() )
+ aGlobalChildRect = GetGlobalChildAnchor( rHd, rSt, aClientRect );
+ else
+ aGlobalChildRect = rGlobalChildRect;
+
+ if ( ( nGroupRotateAngle > 4500_deg100 && nGroupRotateAngle <= 13500_deg100 )
+ || ( nGroupRotateAngle > 22500_deg100 && nGroupRotateAngle <= 31500_deg100 ) )
+ {
+ sal_Int32 nHalfWidth = ( aClientRect.GetWidth() + 1 ) >> 1;
+ sal_Int32 nHalfHeight = ( aClientRect.GetHeight() + 1 ) >> 1;
+ Point aTopLeft( aClientRect.Left() + nHalfWidth - nHalfHeight,
+ aClientRect.Top() + nHalfHeight - nHalfWidth );
+ const tools::Long nRotatedWidth = aClientRect.GetHeight();
+ const tools::Long nRotatedHeight = aClientRect.GetWidth();
+ Size aNewSize(nRotatedWidth, nRotatedHeight);
+ tools::Rectangle aNewRect( aTopLeft, aNewSize );
+ aClientRect = aNewRect;
+ }
+
+ // now importing the inner objects of the group
+ if (!aRecHd.SeekToEndOfRecord(rSt))
+ return pRet;
+
+ while (rSt.good() && ( rSt.Tell() < rHd.GetRecEndFilePos()))
+ {
+ DffRecordHeader aRecHd2;
+ if (!ReadDffRecordHeader(rSt, aRecHd2))
+ break;
+ if ( aRecHd2.nRecType == DFF_msofbtSpgrContainer )
+ {
+ tools::Rectangle aGroupClientAnchor, aGroupChildAnchor;
+ GetGroupAnchors( aRecHd2, rSt, aGroupClientAnchor, aGroupChildAnchor, aClientRect, aGlobalChildRect );
+ if (!aRecHd2.SeekToBegOfRecord(rSt))
+ return pRet;
+ sal_Int32 nShapeId;
+ SdrObject* pTmp = ImportGroup( aRecHd2, rSt, rClientData, aGroupClientAnchor, aGroupChildAnchor, nCalledByGroup + 1, &nShapeId );
+ if (pTmp)
+ {
+ SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pRet);
+ if (pGroup && pGroup->GetSubList())
+ {
+ pGroup->GetSubList()->NbcInsertObject(pTmp);
+ if (nShapeId)
+ insertShapeId(nShapeId, pTmp);
+ }
+ else
+ FreeObj(rClientData, pTmp);
+ }
+ }
+ else if ( aRecHd2.nRecType == DFF_msofbtSpContainer )
+ {
+ if (!aRecHd2.SeekToBegOfRecord(rSt))
+ return pRet;
+ sal_Int32 nShapeId;
+ SdrObject* pTmp = ImportShape( aRecHd2, rSt, rClientData, aClientRect, aGlobalChildRect, nCalledByGroup + 1, &nShapeId );
+ if (pTmp)
+ {
+ SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pRet);
+ if (pGroup && pGroup->GetSubList())
+ {
+ pGroup->GetSubList()->NbcInsertObject(pTmp);
+ if (nShapeId)
+ insertShapeId(nShapeId, pTmp);
+ }
+ else
+ FreeObj(rClientData, pTmp);
+ }
+ }
+ if (!aRecHd2.SeekToEndOfRecord(rSt))
+ return pRet;
+ }
+
+ if ( nGroupRotateAngle )
+ pRet->NbcRotate( aClientRect.Center(), nGroupRotateAngle );
+ if ( nSpFlags & ShapeFlag::FlipV )
+ { // BoundRect in aBoundRect
+ Point aLeft( aClientRect.Left(), ( aClientRect.Top() + aClientRect.Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ pRet->NbcMirror( aLeft, aRight );
+ }
+ if ( nSpFlags & ShapeFlag::FlipH )
+ { // BoundRect in aBoundRect
+ Point aTop( ( aClientRect.Left() + aClientRect.Right() ) >> 1, aClientRect.Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ pRet->NbcMirror( aTop, aBottom );
+ }
+ }
+ }
+ if (o3tl::make_unsigned(nCalledByGroup) < maPendingGroupData.size())
+ {
+ // finalization for this group is pending, do it now
+ pRet = FinalizeObj(maPendingGroupData.back().first, pRet);
+ maPendingGroupData.pop_back();
+ }
+ return pRet;
+}
+
+SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
+ tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
+ int nCalledByGroup, sal_Int32* pShapeId )
+{
+ if( pShapeId )
+ *pShapeId = 0;
+
+ if (!rHd.SeekToBegOfRecord(rSt))
+ return nullptr;
+
+ DffObjData aObjData( rHd, rClientRect, nCalledByGroup );
+
+ aObjData.bRotateTextWithShape = ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL ) == 0;
+ maShapeRecords.Consume( rSt );
+ if( maShapeRecords.SeekToContent( rSt,
+ DFF_msofbtUDefProp ) )
+ {
+ sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
+ while( 5 < nBytesLeft )
+ {
+ sal_uInt16 nPID(0);
+ rSt.ReadUInt16(nPID);
+ if (!rSt.good())
+ break;
+ sal_uInt32 nUDData(0);
+ rSt.ReadUInt32(nUDData);
+ if (!rSt.good())
+ break;
+ if (nPID == 447)
+ {
+ mbRotateGranientFillWithAngle = nUDData & 0x20;
+ break;
+ }
+ nBytesLeft -= 6;
+ }
+ }
+ aObjData.bShapeType = maShapeRecords.SeekToContent( rSt, DFF_msofbtSp );
+ if ( aObjData.bShapeType )
+ {
+ sal_uInt32 temp(0);
+ rSt.ReadUInt32( aObjData.nShapeId )
+ .ReadUInt32( temp );
+ aObjData.nSpFlags = ShapeFlag(temp);
+ aObjData.eShapeType = static_cast<MSO_SPT>(maShapeRecords.Current()->nRecInstance);
+ }
+ else
+ {
+ aObjData.nShapeId = 0;
+ aObjData.nSpFlags = ShapeFlag::NONE;
+ aObjData.eShapeType = mso_sptNil;
+ }
+
+ if( pShapeId )
+ *pShapeId = aObjData.nShapeId;
+
+ aObjData.bOpt = maShapeRecords.SeekToContent( rSt, DFF_msofbtOPT, SEEK_FROM_CURRENT_AND_RESTART );
+ if ( aObjData.bOpt )
+ {
+ if (!maShapeRecords.Current()->SeekToBegOfRecord(rSt))
+ return nullptr;
+#ifdef DBG_AUTOSHAPE
+ ReadPropSet( rSt, &rClientData, (sal_uInt32)aObjData.eShapeType );
+#else
+ ReadPropSet( rSt, &rClientData );
+#endif
+ }
+ else
+ {
+ InitializePropSet( DFF_msofbtOPT ); // get the default PropSet
+ static_cast<DffPropertyReader*>(this)->mnFix16Angle = 0_deg100;
+ }
+
+ aObjData.bOpt2 = maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART );
+ if ( aObjData.bOpt2 )
+ {
+ maShapeRecords.Current()->SeekToBegOfRecord( rSt );
+ pSecPropSet.reset( new DffPropertyReader( *this ) );
+ pSecPropSet->ReadPropSet( rSt, nullptr );
+ }
+
+ aObjData.bChildAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtChildAnchor, SEEK_FROM_CURRENT_AND_RESTART );
+ if ( aObjData.bChildAnchor )
+ {
+ sal_Int32 l(0), o(0), r(0), u(0);
+ rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
+ Scale( l );
+ Scale( o );
+ Scale( r );
+ Scale( u );
+ aObjData.aChildAnchor = tools::Rectangle( l, o, r, u );
+ sal_Int32 nWidth, nHeight;
+ if (!rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() &&
+ !o3tl::checked_sub(r, l, nWidth) && !o3tl::checked_sub(u, o, nHeight))
+ {
+ double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
+ double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
+ double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
+ double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top();
+ double fWidth = nWidth * fXScale;
+ double fHeight = nHeight * fYScale;
+ aObjData.aChildAnchor = tools::Rectangle( Point( fl, fo ), Size( fWidth + 1, fHeight + 1 ) );
+ }
+ }
+
+ aObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtClientAnchor, SEEK_FROM_CURRENT_AND_RESTART );
+ if ( aObjData.bClientAnchor )
+ ProcessClientAnchor2( rSt, *maShapeRecords.Current(), aObjData );
+
+ if ( aObjData.bChildAnchor )
+ aObjData.aBoundRect = aObjData.aChildAnchor;
+
+ if ( aObjData.nSpFlags & ShapeFlag::Background )
+ aObjData.aBoundRect = tools::Rectangle( Point(), Size( 1, 1 ) );
+
+ SdrObjectUniquePtr xRet;
+
+ tools::Rectangle aTextRect;
+ if ( !aObjData.aBoundRect.IsEmpty() )
+ { // apply rotation to the BoundingBox BEFORE an object has been generated
+ if( mnFix16Angle )
+ {
+ Degree100 nAngle = mnFix16Angle;
+ if ( ( nAngle > 4500_deg100 && nAngle <= 13500_deg100 ) || ( nAngle > 22500_deg100 && nAngle <= 31500_deg100 ) )
+ {
+ sal_Int32 nHalfWidth = ( aObjData.aBoundRect.GetWidth() + 1 ) >> 1;
+ sal_Int32 nHalfHeight = ( aObjData.aBoundRect.GetHeight() + 1 ) >> 1;
+ Point aTopLeft( aObjData.aBoundRect.Left() + nHalfWidth - nHalfHeight,
+ aObjData.aBoundRect.Top() + nHalfHeight - nHalfWidth );
+ Size aNewSize( aObjData.aBoundRect.GetHeight(), aObjData.aBoundRect.GetWidth() );
+ tools::Rectangle aNewRect( aTopLeft, aNewSize );
+ aObjData.aBoundRect = aNewRect;
+ }
+ }
+ aTextRect = aObjData.aBoundRect;
+ bool bGraphic = IsProperty( DFF_Prop_pib ) ||
+ IsProperty( DFF_Prop_pibName ) ||
+ IsProperty( DFF_Prop_pibFlags );
+
+ if ( aObjData.nSpFlags & ShapeFlag::Group )
+ {
+ xRet.reset(new SdrObjGroup(*pSdrModel));
+ /* After CWS aw033 has been integrated, an empty group object
+ cannot store its resulting bounding rectangle anymore. We have
+ to return this rectangle via rClientRect now, but only, if
+ caller has not passed an own bounding ractangle. */
+ if ( rClientRect.IsEmpty() )
+ rClientRect = aObjData.aBoundRect;
+ nGroupShapeFlags = aObjData.nSpFlags;
+ }
+ else if ( ( aObjData.eShapeType != mso_sptNil ) || IsProperty( DFF_Prop_pVertices ) || bGraphic )
+ {
+ SfxItemSet aSet( pSdrModel->GetItemPool() );
+
+ bool bIsConnector = ( ( aObjData.eShapeType >= mso_sptStraightConnector1 ) && ( aObjData.eShapeType <= mso_sptCurvedConnector5 ) );
+ Degree100 nObjectRotation = mnFix16Angle;
+ ShapeFlag nSpFlags = aObjData.nSpFlags;
+
+ if ( bGraphic )
+ {
+ if (!mbSkipImages) {
+ xRet.reset(ImportGraphic(rSt, aSet, aObjData)); // SJ: #68396# is no longer true (fixed in ppt2000)
+ ApplyAttributes( rSt, aSet, aObjData );
+ xRet->SetMergedItemSet(aSet);
+ }
+ }
+ else if ( aObjData.eShapeType == mso_sptLine && !( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) )
+ {
+ basegfx::B2DPolygon aPoly;
+ aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Left(), aObjData.aBoundRect.Top()));
+ aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Right(), aObjData.aBoundRect.Bottom()));
+ xRet.reset(new SdrPathObj(
+ *pSdrModel,
+ SdrObjKind::Line,
+ basegfx::B2DPolyPolygon(aPoly)));
+ ApplyAttributes( rSt, aSet, aObjData );
+ xRet->SetMergedItemSet(aSet);
+ }
+ else
+ {
+ if ( GetCustomShapeContent( aObjData.eShapeType ) || IsProperty( DFF_Prop_pVertices ) )
+ {
+
+ ApplyAttributes( rSt, aSet, aObjData );
+
+ xRet.reset(new SdrObjCustomShape(*pSdrModel));
+
+ sal_uInt32 ngtextFStrikethrough = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
+ bool bIsFontwork = ( ngtextFStrikethrough & 0x4000 ) != 0;
+
+ // in case of a FontWork, the text is set by the escher import
+ if ( bIsFontwork )
+ {
+ OUString aObjectText;
+ OUString aFontName;
+
+ if ( SeekToContent( DFF_Prop_gtextFont, rSt ) )
+ {
+ SvxFontItem aLatin(EE_CHAR_FONTINFO), aAsian(EE_CHAR_FONTINFO_CJK), aComplex(EE_CHAR_FONTINFO_CTL);
+ GetDefaultFonts( aLatin, aAsian, aComplex );
+
+ aFontName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextFont, 0 ), true );
+ aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
+ PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO ));
+ aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
+ PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CJK ) );
+ aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
+ PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CTL ) );
+ }
+
+ // SJ: applying fontattributes for Fontwork :
+ if ( IsHardAttribute( DFF_Prop_gtextFItalic ) )
+ aSet.Put( SvxPostureItem( ( ngtextFStrikethrough & 0x0010 ) != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
+
+ if ( IsHardAttribute( DFF_Prop_gtextFBold ) )
+ aSet.Put( SvxWeightItem( ( ngtextFStrikethrough & 0x0020 ) != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+
+ // SJ TODO: Vertical Writing is not correct, instead
+ // this should be replaced through "CharacterRotation"
+ // by 90 degrees, therefore a new Item has to be
+ // supported by svx core, api and xml file format
+ static_cast<SdrObjCustomShape*>(xRet.get())->SetVerticalWriting( ( ngtextFStrikethrough & 0x2000 ) != 0 );
+
+ if ( SeekToContent( DFF_Prop_gtextUNICODE, rSt ) )
+ {
+ aObjectText = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextUNICODE, 0 ), true );
+ ReadObjText(aObjectText, xRet.get());
+ }
+
+ auto eGeoTextAlign = GetPropertyValue(DFF_Prop_gtextAlign, mso_alignTextCenter);
+ {
+ SdrTextHorzAdjust eHorzAdjust;
+ switch( eGeoTextAlign )
+ {
+ case mso_alignTextLetterJust :
+ case mso_alignTextWordJust :
+ case mso_alignTextStretch : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break;
+ default:
+ case mso_alignTextInvalid :
+ case mso_alignTextCenter : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break;
+ case mso_alignTextLeft : eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break;
+ case mso_alignTextRight : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break;
+ }
+ aSet.Put( SdrTextHorzAdjustItem( eHorzAdjust ) );
+
+ drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE;
+ if ( eGeoTextAlign == mso_alignTextStretch )
+ eFTS = drawing::TextFitToSizeType_ALLLINES;
+ aSet.Put( SdrTextFitToSizeTypeItem( eFTS ) );
+ }
+ if ( IsProperty( DFF_Prop_gtextSpacing ) )
+ {
+ sal_Int32 nTextWidth = GetPropertyValue( DFF_Prop_gtextSpacing, 1 << 16 ) / 655;
+ if ( nTextWidth != 100 )
+ aSet.Put( SvxCharScaleWidthItem( static_cast<sal_uInt16>(nTextWidth), EE_CHAR_FONTWIDTH ) );
+ }
+ if ( ngtextFStrikethrough & 0x1000 ) // SJ: Font Kerning On ?
+ aSet.Put( SvxKerningItem( 1, EE_CHAR_KERNING ) );
+
+ // #i119496# the resize autoshape to fit text attr of word art in MS PPT is always false
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ aSet.Put(makeSdrTextAutoGrowWidthItem(false));
+
+ bool bWithPadding = !( ngtextFStrikethrough & use_gtextFBestFit
+ && ngtextFStrikethrough & use_gtextFShrinkFit
+ && ngtextFStrikethrough & use_gtextFStretch
+ && ngtextFStrikethrough & gtextFBestFit
+ && ngtextFStrikethrough & gtextFShrinkFit
+ && ngtextFStrikethrough & gtextFStretch );
+
+ if ( bWithPadding )
+ {
+ // trim, remove additional space
+ VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
+ vcl::Font aFont = pDevice->GetFont();
+ aFont.SetFamilyName( aFontName );
+ aFont.SetFontSize( Size( 0, 96 ) );
+ pDevice->SetFont( aFont );
+
+ auto nTextWidth = pDevice->GetTextWidth( aObjectText );
+ OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
+ if ( nTextWidth && aObjData.eShapeType == mso_sptTextPlainText
+ && aObjName.match( "PowerPlusWaterMarkObject" ) )
+ {
+ double fRatio = static_cast<double>(pDevice->GetTextHeight()) / nTextWidth;
+ sal_Int32 nNewHeight = fRatio * aObjData.aBoundRect.getWidth();
+ sal_Int32 nPaddingY = aObjData.aBoundRect.getHeight() - nNewHeight;
+
+ if ( nPaddingY > 0 )
+ aObjData.aBoundRect.setHeight( nNewHeight );
+ }
+ }
+ }
+ xRet->SetMergedItemSet( aSet );
+
+ // sj: taking care of rtl, ltr. In case of fontwork mso. seems not to be able to set
+ // proper text directions, instead the text default is depending to the string.
+ // so we have to calculate the a text direction from string:
+ if ( bIsFontwork )
+ {
+ OutlinerParaObject* pParaObj = static_cast<SdrObjCustomShape*>(xRet.get())->GetOutlinerParaObject();
+ if ( pParaObj )
+ {
+ SdrOutliner& rOutliner = static_cast<SdrObjCustomShape*>(xRet.get())->ImpGetDrawOutliner();
+ rOutliner.SetStyleSheetPool(static_cast< SfxStyleSheetPool* >(xRet->getSdrModelFromSdrObject().GetStyleSheetPool()));
+ bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
+ rOutliner.SetText( *pParaObj );
+ ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::DEFAULT);
+ pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM));
+ sal_Int32 i, nParagraphs = rOutliner.GetParagraphCount();
+ if ( nParagraphs )
+ {
+ bool bCreateNewParaObject = false;
+ for ( i = 0; i < nParagraphs; i++ )
+ {
+ OUString aString(rOutliner.GetText(rOutliner.GetParagraph(i)));
+ bool bIsRTL = pVirDev->GetTextIsRTL(aString, 0, aString.getLength());
+ if ( bIsRTL )
+ {
+ SfxItemSet aSet2( rOutliner.GetParaAttribs( i ) );
+ aSet2.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
+ rOutliner.SetParaAttribs( i, aSet2 );
+ bCreateNewParaObject = true;
+ }
+ }
+ if ( bCreateNewParaObject )
+ {
+ std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
+ rOutliner.Init( OutlinerMode::TextObject );
+ static_cast<SdrObjCustomShape*>(xRet.get())->NbcSetOutlinerParaObject( std::move(pNewText) );
+ }
+ }
+ rOutliner.Clear();
+ rOutliner.SetUpdateLayout( bOldUpdateMode );
+ }
+ }
+
+ // mso_sptArc special treating
+ // tdf#124029: A new custom shape is generated from prototype 'msoArc'. Values, which are
+ // read here, are adapted and merged. The shape type is changed, so this code
+ // applies only if importing arcs from MS Office.
+ if ( aObjData.eShapeType == mso_sptArc )
+ {
+ static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
+ static const OUStringLiteral sViewBox( u"ViewBox" );
+ static const OUStringLiteral sPath( u"Path" );
+ SdrCustomShapeGeometryItem aGeometryItem( static_cast<SdrObjCustomShape*>(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ PropertyValue aPropVal;
+
+ // The default arc goes form -90deg to 0deg. Replace general defaults used
+ // when read from stream with this specific values.
+ double fStartAngle(-90.0);
+ double fEndAngle(0.0);
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
+ const uno::Any* pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues);
+ if (pAny && (*pAny >>= seqAdjustmentValues) && seqAdjustmentValues.getLength() > 1)
+ {
+ auto pseqAdjustmentValues = seqAdjustmentValues.getArray();
+ if (seqAdjustmentValues[0].State == css::beans::PropertyState_DEFAULT_VALUE)
+ {
+ pseqAdjustmentValues[0].Value <<= -90.0;
+ pseqAdjustmentValues[0].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
+ }
+ if (seqAdjustmentValues[1].State == css::beans::PropertyState_DEFAULT_VALUE)
+ {
+ pseqAdjustmentValues[1].Value <<= 0.0;
+ pseqAdjustmentValues[1].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
+ }
+ seqAdjustmentValues[0].Value >>= fStartAngle;
+ seqAdjustmentValues[1].Value >>= fEndAngle;
+ aPropVal.Name = sAdjustmentValues;
+ aPropVal.Value <<= seqAdjustmentValues;
+ aGeometryItem.SetPropertyValue(aPropVal);
+ }
+
+ // arc first command is always wr -- clockwise arc
+ // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y)
+ // The left/top vertex of the frame rectangle of the sector is the origin
+ // of the shape internal coordinate system in MS Office. The default arc
+ // has an ellipse frame rectangle with LT(-21600,0) and
+ // RB(21600,43200) in this coordinate system.
+ basegfx::B2DRectangle aEllipseRect_MS(-21600.0, 0.0, 21600.0, 43200.0);
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;
+ pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
+ if (pAny && (*pAny >>= seqCoordinates) && (seqCoordinates.getLength() >= 2))
+ {
+ auto const nL
+ = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].First.Value);
+ auto const nT
+ = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].Second.Value);
+ auto const nR
+ = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].First.Value);
+ auto const nB
+ = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].Second.Value);
+ aEllipseRect_MS = basegfx::B2DRectangle(nL, nT, nR, nB);
+ }
+
+ // MS Office uses the pie frame rectangle as reference for outer position
+ // and size of the shape and for text in the shape. We can get this rectangle
+ // from imported viewBox or from the arc geometry.
+ basegfx::B2DRectangle aPieRect_MS(0.0 , 0.0, 21600.0, 21600.0);
+ pAny = aGeometryItem.GetPropertyValueByName(sPath,sViewBox);
+ css::awt::Rectangle aImportedViewBox;
+ if (pAny && (*pAny >>= aImportedViewBox))
+ {
+ aPieRect_MS = basegfx::B2DRectangle( aImportedViewBox.X,
+ aImportedViewBox.Y,
+ aImportedViewBox.X + aImportedViewBox.Width,
+ aImportedViewBox.Y + aImportedViewBox.Height);
+ }
+ else
+ {
+ double fRadStartAngle(basegfx::deg2rad(NormAngle360(fStartAngle)));
+ double fRadEndAngle(basegfx::deg2rad(NormAngle360(fEndAngle)));
+ basegfx::B2DPoint aCenter(aEllipseRect_MS.getCenter());
+ basegfx::B2DPolygon aTempPie(
+ basegfx::utils::createPolygonFromEllipseSegment(
+ aCenter,
+ aEllipseRect_MS.getWidth() * 0.5,
+ aEllipseRect_MS.getHeight() * 0.5,
+ fRadStartAngle,
+ fRadEndAngle));
+ aTempPie.append(aCenter);
+ aPieRect_MS = aTempPie.getB2DRange();
+ }
+
+ // MS Office uses for mso_sptArc a frame rectangle (=resize handles)
+ // which encloses only the sector, LibreOffice uses for custom shapes as
+ // default a frame rectangle, which encloses the entire ellipse. That would
+ // result in wrong positions in Writer and Calc, see tdf#124029.
+ // We workaround this problem, by setting a suitable viewBox.
+ bool bIsImportPPT(GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT);
+ if (bIsImportPPT || aPieRect_MS.getWidth() == 0 || aPieRect_MS.getHeight() == 0)
+ { // clear item, so that default from EnhancedCustomShapeGeometry is used
+ aGeometryItem.ClearPropertyValue(sViewBox);
+ }
+ else
+ {
+ double fX((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) / 2.0);
+ double fY((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) / 2.0);
+ css::awt::Rectangle aViewBox_LO; // in LO coordinate system
+ aViewBox_LO.X = static_cast<sal_Int32>(fX);
+ aViewBox_LO.Y = static_cast<sal_Int32>(fY);
+ aViewBox_LO.Width = static_cast<sal_Int32>(aPieRect_MS.getWidth() / 2.0);
+ aViewBox_LO.Height = static_cast<sal_Int32>(aPieRect_MS.getHeight() / 2.0);
+ aPropVal.Name = sViewBox;
+ aPropVal.Value <<= aViewBox_LO;
+ aGeometryItem.SetPropertyValue(aPropVal);
+ }
+
+ // aObjData.aBoundRect contains position and size of the sector in (outer)
+ // logic coordinates, e.g. for PPT in 1/100 mm, for Word in twips.
+ // For Impress the default viewBox is used, so adapt aObjData.aBoundRect.
+ tools::Rectangle aOldBoundRect(aObjData.aBoundRect); // backup, needed later on
+ if (bIsImportPPT)
+ {
+ double fLogicXOfs(0.0); // LogicLeft_LO = LogicLeft_MS + fXLogicOfs
+ double fLogicYOfs(0.0);
+ double fLogicPieWidth(aObjData.aBoundRect.getWidth());
+ double fLogicPieHeight(aObjData.aBoundRect.getHeight());
+ double fLogicEllipseWidth(0.0); // to be LogicWidth_LO
+ double fLogicEllipseHeight(0.0);
+ if (aPieRect_MS.getWidth())
+ {
+ // fXScale = ratio 'logic length' : 'shape internal length'
+ double fXScale = fLogicPieWidth / aPieRect_MS.getWidth();
+ if (nSpFlags & ShapeFlag::FlipH)
+ fLogicXOfs = (aPieRect_MS.getMaxX() - aEllipseRect_MS.getMaxX()) * fXScale;
+ else
+ fLogicXOfs = (aEllipseRect_MS.getMinX() - aPieRect_MS.getMinX()) * fXScale;
+ fLogicEllipseWidth = aEllipseRect_MS.getWidth() * fXScale;
+ }
+ if (aPieRect_MS.getHeight())
+ {
+ double fYScale = fLogicPieHeight / aPieRect_MS.getHeight();
+ if (nSpFlags & ShapeFlag::FlipV)
+ fLogicYOfs = (aPieRect_MS.getMaxY() - aEllipseRect_MS.getMaxY()) * fYScale;
+ else
+ fLogicYOfs = (aEllipseRect_MS.getMinY() - aPieRect_MS.getMinY()) * fYScale;
+ fLogicEllipseHeight = aEllipseRect_MS.getHeight() * fYScale;
+ }
+ aObjData.aBoundRect = tools::Rectangle(
+ Point(aOldBoundRect.Left() + static_cast<sal_Int32>(fLogicXOfs),
+ aOldBoundRect.Top() + static_cast<sal_Int32>(fLogicYOfs)),
+ Size(static_cast<sal_Int32>(fLogicEllipseWidth),
+ static_cast<sal_Int32>(fLogicEllipseHeight)));
+ }
+ // else nothing to do. aObjData.aBoundRect corresponds to changed viewBox.
+
+ // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system
+ double fTextFrameScaleX = 0.0;
+ double fTextFrameScaleY = 0.0;
+ if (aEllipseRect_MS.getWidth())
+ fTextFrameScaleX = 21600.0 / aEllipseRect_MS.getWidth();
+ if (aEllipseRect_MS.getHeight())
+ fTextFrameScaleY = 21600.0 / aEllipseRect_MS.getHeight();
+
+ sal_Int32 nLeft = static_cast<sal_Int32>((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
+ sal_Int32 nTop = static_cast<sal_Int32>((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
+ sal_Int32 nRight = static_cast<sal_Int32>((aPieRect_MS.getMaxX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
+ sal_Int32 nBottom= static_cast<sal_Int32>((aPieRect_MS.getMaxY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
+ css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 );
+ auto pTextFrame = aTextFrame.getArray();
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.First, nLeft );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.Second, nTop );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.First, nRight );
+ EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.Second,nBottom );
+ PropertyValue aProp;
+ aProp.Name = "TextFrames";
+ aProp.Value <<= aTextFrame;
+ aGeometryItem.SetPropertyValue( sPath, aProp );
+
+ // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect
+ if ( mnFix16Angle )
+ {
+ Degree100 nAngle = mnFix16Angle;
+ if ( nSpFlags & ShapeFlag::FlipH )
+ nAngle = 36000_deg100 - nAngle;
+ if ( nSpFlags & ShapeFlag::FlipV )
+ nAngle = -nAngle;
+ double a = toRadians(nAngle);
+ double ss = sin( a );
+ double cc = cos( a );
+ Point aP1( aOldBoundRect.TopLeft() );
+ Point aC1( aObjData.aBoundRect.Center() );
+ Point aP2( aOldBoundRect.TopLeft() );
+ Point aC2( aOldBoundRect.Center() );
+ RotatePoint( aP1, aC1, ss, cc );
+ RotatePoint( aP2, aC2, ss, cc );
+ aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() );
+ }
+
+ // clearing items, so MergeDefaultAttributes will set the corresponding
+ // defaults from EnhancedCustomShapeGeometry
+ aGeometryItem.ClearPropertyValue( "Handles" );
+ aGeometryItem.ClearPropertyValue( "Equations" );
+ aGeometryItem.ClearPropertyValue( sPath );
+
+ static_cast<SdrObjCustomShape*>(xRet.get())->SetMergedItem( aGeometryItem );
+ static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
+
+ // now setting a new name, so the above correction is only done once when importing from ms
+ SdrCustomShapeGeometryItem aGeoName( static_cast<SdrObjCustomShape*>(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
+ aPropVal.Name = "Type";
+ aPropVal.Value <<= OUString( "mso-spt100" );
+ aGeoName.SetPropertyValue( aPropVal );
+ static_cast<SdrObjCustomShape*>(xRet.get())->SetMergedItem( aGeoName );
+ }
+ else
+ static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
+
+ xRet->SetSnapRect( aObjData.aBoundRect );
+ EnhancedCustomShape2d aCustomShape2d(static_cast<SdrObjCustomShape&>(*xRet));
+ aTextRect = aCustomShape2d.GetTextRect();
+
+ if( bIsConnector )
+ {
+ if( nObjectRotation )
+ xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
+ // mirrored horizontally?
+ if ( nSpFlags & ShapeFlag::FlipH )
+ {
+ tools::Rectangle aBndRect(xRet->GetSnapRect());
+ Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ xRet->NbcMirror( aTop, aBottom );
+ }
+ // mirrored vertically?
+ if ( nSpFlags & ShapeFlag::FlipV )
+ {
+ tools::Rectangle aBndRect(xRet->GetSnapRect());
+ Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ xRet->NbcMirror( aLeft, aRight );
+ }
+ basegfx::B2DPolyPolygon aPoly( static_cast<SdrObjCustomShape*>(xRet.get())->GetLineGeometry( true ) );
+
+ xRet.reset(new SdrEdgeObj(*pSdrModel));
+ ApplyAttributes( rSt, aSet, aObjData );
+ xRet->SetLogicRect( aObjData.aBoundRect );
+ xRet->SetMergedItemSet(aSet);
+
+ // connectors
+ auto eConnectorStyle = GetPropertyValue(DFF_Prop_cxstyle, mso_cxstyleStraight);
+
+ static_cast<SdrEdgeObj*>(xRet.get())->ConnectToNode(true, nullptr);
+ static_cast<SdrEdgeObj*>(xRet.get())->ConnectToNode(false, nullptr);
+
+ Point aPoint1( aObjData.aBoundRect.TopLeft() );
+ Point aPoint2( aObjData.aBoundRect.BottomRight() );
+
+ // pay attention to the rotations
+ if ( nObjectRotation )
+ {
+ double a = toRadians(nObjectRotation);
+ Point aCenter( aObjData.aBoundRect.Center() );
+ double ss = sin(a);
+ double cc = cos(a);
+
+ RotatePoint(aPoint1, aCenter, ss, cc);
+ RotatePoint(aPoint2, aCenter, ss, cc);
+
+ // #i120437# reset rotation, it is part of the path and shall not be applied again
+ nObjectRotation = 0_deg100;
+ }
+
+ // rotate/mirror line within the area as we need it
+ if ( nSpFlags & ShapeFlag::FlipH )
+ {
+ sal_Int32 n = aPoint1.X();
+ aPoint1.setX( aPoint2.X() );
+ aPoint2.setX( n );
+
+ // #i120437# reset hor flip
+ nSpFlags &= ~ShapeFlag::FlipH;
+ }
+ if ( nSpFlags & ShapeFlag::FlipV )
+ {
+ sal_Int32 n = aPoint1.Y();
+ aPoint1.setY( aPoint2.Y() );
+ aPoint2.setY( n );
+
+ // #i120437# reset ver flip
+ nSpFlags &= ~ShapeFlag::FlipV;
+ }
+
+ xRet->NbcSetPoint(aPoint1, 0); // start point
+ xRet->NbcSetPoint(aPoint2, 1); // endpoint
+
+ sal_Int32 n1HorzDist, n1VertDist, n2HorzDist, n2VertDist;
+ n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 0;
+ switch( eConnectorStyle )
+ {
+ case mso_cxstyleBent:
+ {
+ aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OrthoLines ) );
+ n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 630;
+ }
+ break;
+ case mso_cxstyleCurved:
+ aSet.Put( SdrEdgeKindItem( SdrEdgeKind::Bezier ) );
+ break;
+ default: // mso_cxstyleStraight || mso_cxstyleNone
+ aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OneLine ) );
+ break;
+ }
+ aSet.Put( SdrEdgeNode1HorzDistItem( n1HorzDist ) );
+ aSet.Put( SdrEdgeNode1VertDistItem( n1VertDist ) );
+ aSet.Put( SdrEdgeNode2HorzDistItem( n2HorzDist ) );
+ aSet.Put( SdrEdgeNode2VertDistItem( n2VertDist ) );
+
+ static_cast<SdrEdgeObj*>(xRet.get())->SetEdgeTrackPath( aPoly );
+ xRet->SetMergedItemSet(aSet);
+ }
+ if ( aObjData.eShapeType == mso_sptLine )
+ {
+ xRet->SetMergedItemSet(aSet);
+ static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
+ }
+ }
+ }
+
+ if (xRet)
+ {
+ if( nObjectRotation )
+ xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
+ // mirrored horizontally?
+ if ( nSpFlags & ShapeFlag::FlipH )
+ {
+ tools::Rectangle aBndRect(xRet->GetSnapRect());
+ Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
+ Point aBottom( aTop.X(), aTop.Y() + 1000 );
+ xRet->NbcMirror(aTop, aBottom);
+ }
+ // mirrored vertically?
+ if ( nSpFlags & ShapeFlag::FlipV )
+ {
+ tools::Rectangle aBndRect(xRet->GetSnapRect());
+ Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
+ Point aRight( aLeft.X() + 1000, aLeft.Y() );
+ xRet->NbcMirror(aLeft, aRight);
+ }
+ }
+ }
+ }
+
+ // #i51348# #118052# name of the shape
+ if (xRet)
+ {
+ OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
+ if( !aObjName.isEmpty() )
+ xRet->SetName(aObjName);
+ }
+
+ xRet.reset(ProcessObj(rSt, aObjData, rClientData, aTextRect, xRet.release()));
+
+ if (xRet)
+ {
+ sal_Int32 nGroupProperties( GetPropertyValue( DFF_Prop_fPrint, 0 ) );
+ const bool bVisible = ( ( nGroupProperties & 2 ) == 0 );
+ xRet->SetVisible( bVisible );
+ // In Excel hidden means not printed
+ if ( !bVisible )
+ {
+ xRet->SetPrintable(false);
+ }
+ else
+ {
+ // This property isn't used in Excel anymore, leaving it for legacy reasons
+ xRet->SetPrintable( ( nGroupProperties & 1 ) != 0 );
+ }
+ }
+
+ //Import alt text as description
+ if (xRet && SeekToContent(DFF_Prop_wzDescription, rSt))
+ {
+ OUString aAltText = MSDFFReadZString(rSt, GetPropertyValue(DFF_Prop_wzDescription, 0), true);
+ xRet->SetDescription(aAltText);
+ }
+
+ // If this shape opens a new group, push back its object data because
+ // finalization will be called when nested objects have been imported;
+ // otherwise, just finalize here
+ if (o3tl::make_unsigned(nCalledByGroup) > maPendingGroupData.size())
+ {
+ auto xHdClone = std::make_shared<DffRecordHeader>(aObjData.rSpHd);
+ maPendingGroupData.emplace_back(DffObjData(xHdClone, aObjData), xHdClone );
+ }
+ else
+ {
+ xRet.reset(FinalizeObj(aObjData, xRet.release()));
+ }
+ return xRet.release();
+}
+
+tools::Rectangle SvxMSDffManager::GetGlobalChildAnchor( const DffRecordHeader& rHd, SvStream& rSt, tools::Rectangle& aClientRect )
+{
+ tools::Rectangle aChildAnchor;
+ if (!rHd.SeekToContent(rSt))
+ return aChildAnchor;
+
+ bool bIsClientRectRead = false;
+ while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < rHd.GetRecEndFilePos() ) )
+ {
+ DffRecordHeader aShapeHd;
+ if (!ReadDffRecordHeader(rSt, aShapeHd))
+ break;
+ if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
+ ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
+ {
+ DffRecordHeader aShapeHd2( aShapeHd );
+ if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
+ ReadDffRecordHeader( rSt, aShapeHd2 );
+ while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
+ {
+ DffRecordHeader aShapeAtom;
+ if (!ReadDffRecordHeader(rSt, aShapeAtom))
+ break;
+
+ if ( aShapeAtom.nRecType == DFF_msofbtClientAnchor )
+ {
+ if ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT )
+ {
+ sal_Int32 l(0), t(0), r(0), b(0);
+ if ( aShapeAtom.nRecLen == 16 )
+ {
+ rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b );
+ }
+ else
+ {
+ sal_Int16 ls(0), ts(0), rs(0), bs(0);
+ rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange...
+ l = ls;
+ t = ts;
+ r = rs;
+ b = bs;
+ }
+ Scale( l );
+ Scale( t );
+ Scale( r );
+ Scale( b );
+ if ( bIsClientRectRead )
+ {
+ tools::Rectangle aChild( l, t, r, b );
+ aChildAnchor.Union( aChild );
+ }
+ else
+ {
+ aClientRect = tools::Rectangle( l, t, r, b );
+ bIsClientRectRead = true;
+ }
+ }
+ break;
+ }
+ else if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
+ {
+ sal_Int32 l(0), o(0), r(0), u(0);
+ rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
+ Scale( l );
+ Scale( o );
+ Scale( r );
+ Scale( u );
+ tools::Rectangle aChild( l, o, r, u );
+ aChildAnchor.Union( aChild );
+ break;
+ }
+ if (!aShapeAtom.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+ if (!aShapeHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ return aChildAnchor;
+}
+
+void SvxMSDffManager::GetGroupAnchors( const DffRecordHeader& rHd, SvStream& rSt,
+ tools::Rectangle& rGroupClientAnchor, tools::Rectangle& rGroupChildAnchor,
+ const tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect )
+{
+ if (!rHd.SeekToContent(rSt))
+ return;
+
+ bool bFirst = true;
+ DffRecordHeader aShapeHd;
+ while (rSt.good() && rSt.Tell() < rHd.GetRecEndFilePos())
+ {
+ if (!ReadDffRecordHeader(rSt, aShapeHd))
+ break;
+ if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
+ ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
+ {
+ DffRecordHeader aShapeHd2( aShapeHd );
+ if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
+ ReadDffRecordHeader( rSt, aShapeHd2 );
+ while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
+ {
+ DffRecordHeader aShapeAtom;
+ if (!ReadDffRecordHeader(rSt, aShapeAtom))
+ break;
+ if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
+ {
+ sal_Int32 l(0), o(0), r(0), u(0);
+ rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
+ Scale( l );
+ Scale( o );
+ Scale( r );
+ Scale( u );
+ tools::Rectangle aChild( l, o, r, u );
+
+ if ( bFirst )
+ {
+ if ( !rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() )
+ {
+ double fWidth = o3tl::saturating_sub(r, l);
+ double fHeight= o3tl::saturating_sub(u, o);
+ double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
+ double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
+ double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
+ double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top();
+ fWidth *= fXScale;
+ fHeight *= fYScale;
+ rGroupClientAnchor = tools::Rectangle( Point( static_cast<sal_Int32>(fl), static_cast<sal_Int32>(fo) ), Size( static_cast<sal_Int32>( fWidth + 1 ), static_cast<sal_Int32>( fHeight + 1 ) ) );
+ }
+ bFirst = false;
+ }
+ else
+ rGroupChildAnchor.Union( aChild );
+ break;
+ }
+ if (!aShapeAtom.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+ if (!aShapeHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+}
+
+SvxMSDffImportRec* SvxMSDffImportData::find(const SdrObject* pObj)
+{
+ auto it = m_ObjToRecMap.find(pObj);
+ if (it != m_ObjToRecMap.end())
+ return it->second;
+ return nullptr;
+}
+
+void SvxMSDffImportData::insert(std::unique_ptr<SvxMSDffImportRec> pImpRec)
+{
+ auto aRet = m_Records.insert(std::move(pImpRec));
+ bool bSuccess = aRet.second;
+ if (bSuccess)
+ {
+ SvxMSDffImportRec* pRec = aRet.first->get();
+ m_ObjToRecMap[pRec->pObj] = pRec;
+ }
+}
+
+void SvxMSDffImportData::NotifyFreeObj(SdrObject* pObj)
+{
+ if (SvxMSDffImportRec* pRecord = find(pObj))
+ {
+ m_ObjToRecMap.erase(pObj);
+ pRecord->pObj = nullptr;
+ }
+}
+
+void SvxMSDffManager::NotifyFreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
+{
+ if (SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pObj))
+ {
+ SdrObjList* pSubList = pGroup->GetSubList();
+ size_t nObjCount = pSubList->GetObjCount();
+ for (size_t i = 0; i < nObjCount; ++i)
+ NotifyFreeObj(rData, pSubList->GetObj(i));
+ }
+
+ rData.NotifyFreeObj(pObj);
+}
+
+void SvxMSDffManager::FreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
+{
+ NotifyFreeObj(rData, pObj);
+ SdrObject::Free(pObj);
+}
+
+SdrObject* SvxMSDffManager::ProcessObj(SvStream& rSt,
+ DffObjData& rObjData,
+ SvxMSDffClientData& rData,
+ tools::Rectangle& rTextRect,
+ SdrObject* pObj
+ )
+{
+ if( !rTextRect.IsEmpty() )
+ {
+ SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
+ SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec;
+ bool bDeleteImpRec = true;
+ SvxMSDffImportRec* pTextImpRec = pImpRec;
+ bool bDeleteTextImpRec = false;
+
+ // fill Import Record with data
+ pImpRec->nShapeId = rObjData.nShapeId;
+ pImpRec->eShapeType = rObjData.eShapeType;
+
+ auto eWrapMode = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare);
+ rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
+ DFF_msofbtClientAnchor,
+ SEEK_FROM_CURRENT_AND_RESTART );
+ if( rObjData.bClientAnchor )
+ ProcessClientAnchor( rSt,
+ maShapeRecords.Current()->nRecLen,
+ pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
+
+ rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
+ DFF_msofbtClientData,
+ SEEK_FROM_CURRENT_AND_RESTART );
+ if( rObjData.bClientData )
+ ProcessClientData( rSt,
+ maShapeRecords.Current()->nRecLen,
+ pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
+
+
+ // process user (== Winword) defined parameters in 0xF122 record
+ if( maShapeRecords.SeekToContent( rSt,
+ DFF_msofbtUDefProp,
+ SEEK_FROM_CURRENT_AND_RESTART )
+ && maShapeRecords.Current()->nRecLen )
+ {
+ sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
+ while( 5 < nBytesLeft )
+ {
+ sal_uInt16 nPID(0);
+ rSt.ReadUInt16(nPID);
+ if (!rSt.good())
+ break;
+ sal_uInt32 nUDData(0);
+ rSt.ReadUInt32(nUDData);
+ switch (nPID)
+ {
+ case 0x038F: pImpRec->nXAlign = nUDData; break;
+ case 0x0390:
+ pImpRec->nXRelTo = nUDData;
+ break;
+ case 0x0391: pImpRec->nYAlign = nUDData; break;
+ case 0x0392:
+ pImpRec->nYRelTo = nUDData;
+ break;
+ case 0x03BF: pImpRec->nGroupShapeBooleanProperties = nUDData; break;
+ case 0x0393:
+ // This seems to correspond to o:hrpct from .docx (even including
+ // the difference that it's in 0.1% even though the .docx spec
+ // says it's in 1%).
+ pImpRec->relativeHorizontalWidth = nUDData;
+ break;
+ case 0x0394:
+ // And this is really just a guess, but a mere presence of this
+ // flag makes a horizontal rule be as wide as the page (unless
+ // overridden by something), so it probably matches o:hr from .docx.
+ pImpRec->isHorizontalRule = true;
+ break;
+ }
+ if (!rSt.good())
+ break;
+ nBytesLeft -= 6;
+ }
+ }
+
+ // text frame, also Title or Outline
+ SdrObject* pOrgObj = pObj;
+ SdrRectObj* pTextObj = nullptr;
+ sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
+ if( nTextId )
+ {
+ SfxItemSet aSet( pSdrModel->GetItemPool() );
+
+ //Originally anything that as a mso_sptTextBox was created as a
+ //textbox, this was changed for #88277# to be created as a simple
+ //rect to keep impress happy. For the rest of us we'd like to turn
+ //it back into a textbox again.
+ bool bTextFrame = (pImpRec->eShapeType == mso_sptTextBox);
+ if (!bTextFrame)
+ {
+ //Either
+ //a) it's a simple text object or
+ //b) it's a rectangle with text and square wrapping.
+ bTextFrame =
+ (
+ (pImpRec->eShapeType == mso_sptTextSimple) ||
+ (
+ (pImpRec->eShapeType == mso_sptRectangle)
+ && (eWrapMode == mso_wrapSquare)
+ && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
+ )
+ );
+ }
+
+ if (bTextFrame)
+ {
+ SdrObject::Free( pObj );
+ pObj = pOrgObj = nullptr;
+ }
+
+ // Distance of Textbox to its surrounding Customshape
+ sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L);
+ sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L );
+ sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L );
+ sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L );
+
+ ScaleEmu( nTextLeft );
+ ScaleEmu( nTextRight );
+ ScaleEmu( nTextTop );
+ ScaleEmu( nTextBottom );
+
+ Degree100 nTextRotationAngle(0);
+ bool bVerticalText = false;
+ if ( IsProperty( DFF_Prop_txflTextFlow ) )
+ {
+ auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
+ switch( eTextFlow )
+ {
+ case mso_txflBtoT:
+ nTextRotationAngle = 9000_deg100;
+ break;
+ case mso_txflVertN:
+ case mso_txflTtoBN:
+ nTextRotationAngle = 27000_deg100;
+ break;
+ case mso_txflTtoBA:
+ bVerticalText = true;
+ break;
+ case mso_txflHorzA:
+ bVerticalText = true;
+ nTextRotationAngle = 9000_deg100;
+ break;
+ case mso_txflHorzN:
+ default :
+ break;
+ }
+ }
+
+ if (nTextRotationAngle)
+ {
+ switch (nTextRotationAngle.get())
+ {
+ case 9000:
+ {
+ tools::Long nWidth = rTextRect.GetWidth();
+ rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
+ rTextRect.SetBottom( rTextRect.Top() + nWidth );
+
+ sal_Int32 nOldTextLeft = nTextLeft;
+ sal_Int32 nOldTextRight = nTextRight;
+ sal_Int32 nOldTextTop = nTextTop;
+ sal_Int32 nOldTextBottom = nTextBottom;
+
+ nTextLeft = nOldTextBottom;
+ nTextRight = nOldTextTop;
+ nTextTop = nOldTextLeft;
+ nTextBottom = nOldTextRight;
+ }
+ break;
+ case 27000:
+ {
+ tools::Long nWidth = rTextRect.GetWidth();
+ rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
+ rTextRect.SetBottom( rTextRect.Top() + nWidth );
+
+ sal_Int32 nOldTextLeft = nTextLeft;
+ sal_Int32 nOldTextRight = nTextRight;
+ sal_Int32 nOldTextTop = nTextTop;
+ sal_Int32 nOldTextBottom = nTextBottom;
+
+ nTextLeft = nOldTextTop;
+ nTextRight = nOldTextBottom;
+ nTextTop = nOldTextRight;
+ nTextBottom = nOldTextLeft;
+ }
+ break;
+ }
+ }
+
+ pTextObj = new SdrRectObj(
+ *pSdrModel,
+ SdrObjKind::Text,
+ rTextRect);
+ pTextImpRec = new SvxMSDffImportRec(*pImpRec);
+ bDeleteTextImpRec = true;
+
+ // the vertical paragraph indents are part of the BoundRect,
+ // here we 'remove' them by calculating
+ tools::Rectangle aNewRect(rTextRect);
+ aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
+ aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
+
+ // Only if it's a simple textbox may Writer replace
+ // the object with a frame, otherwise
+ if( bTextFrame )
+ {
+ auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
+
+ SvxMSDffShapeInfos_ById::const_iterator const it =
+ m_xShapeInfosById->find(pTmpRec);
+ if (it != m_xShapeInfosById->end())
+ {
+ SvxMSDffShapeInfo& rInfo = **it;
+ pTextImpRec->bReplaceByFly = rInfo.bReplaceByFly;
+ }
+ }
+
+ if( !pObj )
+ ApplyAttributes( rSt, aSet, rObjData );
+
+ bool bFitText = false;
+ if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
+ {
+ aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
+ aSet.Put( makeSdrTextMinFrameHeightItem(
+ aNewRect.Bottom() - aNewRect.Top() ) );
+ aSet.Put( makeSdrTextMinFrameWidthItem(
+ aNewRect.Right() - aNewRect.Left() ) );
+ bFitText = true;
+ }
+ else
+ {
+ aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
+ aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
+ }
+
+ switch (GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare))
+ {
+ case mso_wrapNone :
+ aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
+ if (bFitText)
+ {
+ //can't do autowidth in flys #i107184#
+ pTextImpRec->bReplaceByFly = false;
+ }
+ break;
+ case mso_wrapByPoints :
+ aSet.Put( makeSdrTextContourFrameItem( true ) );
+ break;
+ default: break;
+ }
+
+ // set margins at the border of the textbox
+ aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
+ aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
+ aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
+ aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
+ pTextImpRec->nDxTextLeft = nTextLeft;
+ pTextImpRec->nDyTextTop = nTextTop;
+ pTextImpRec->nDxTextRight = nTextRight;
+ pTextImpRec->nDyTextBottom = nTextBottom;
+
+ // read text anchor
+ if ( IsProperty( DFF_Prop_anchorText ) )
+ {
+ auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, 0);
+
+ SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_CENTER;
+ bool bTVASet(false);
+ bool bTHASet(false);
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ {
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ bTVASet = true;
+ }
+ break;
+ case mso_anchorTopCentered:
+ {
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ bTVASet = true;
+ bTHASet = true;
+ }
+ break;
+
+ case mso_anchorMiddle:
+ bTVASet = true;
+ break;
+ case mso_anchorMiddleCentered:
+ {
+ bTVASet = true;
+ bTHASet = true;
+ }
+ break;
+ case mso_anchorBottom:
+ {
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ bTVASet = true;
+ }
+ break;
+ case mso_anchorBottomCentered:
+ {
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ bTVASet = true;
+ bTHASet = true;
+ }
+ break;
+ default : break;
+ }
+ // insert
+ if ( bTVASet )
+ aSet.Put( SdrTextVertAdjustItem( eTVA ) );
+ if ( bTHASet )
+ aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) );
+ }
+
+ pTextObj->SetMergedItemSet(aSet);
+
+ if (bVerticalText)
+ pTextObj->SetVerticalWriting(true);
+
+ if (nTextRotationAngle)
+ {
+ tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
+ rTextRect.GetWidth() : rTextRect.GetHeight();
+ nMinWH /= 2;
+ Point aPivot(rTextRect.TopLeft());
+ aPivot.AdjustX(nMinWH );
+ aPivot.AdjustY(nMinWH );
+ pTextObj->SdrAttrObj::NbcRotate(aPivot, nTextRotationAngle);
+ }
+
+ // rotate text with shape?
+ if ( mnFix16Angle )
+ {
+ double a = toRadians(mnFix16Angle);
+ pTextObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
+ sin( a ), cos( a ) );
+ }
+
+ if( !pObj )
+ {
+ pObj = pTextObj;
+ }
+ else
+ {
+ if( pTextObj != pObj )
+ {
+ SdrObject* pGroup = new SdrObjGroup(*pSdrModel);
+ pGroup->GetSubList()->NbcInsertObject( pObj );
+ pGroup->GetSubList()->NbcInsertObject( pTextObj );
+ if (pOrgObj == pObj)
+ pOrgObj = pGroup;
+ else
+ pOrgObj = pObj;
+ pObj = pGroup;
+ }
+ }
+ }
+ else if( !pObj )
+ {
+ // simple rectangular objects are ignored by ImportObj() :-(
+ // this is OK for Draw but not for Calc and Writer
+ // cause here these objects have a default border
+ pObj = new SdrRectObj(
+ *pSdrModel,
+ rTextRect);
+
+ pOrgObj = pObj;
+ SfxItemSet aSet( pSdrModel->GetItemPool() );
+ ApplyAttributes( rSt, aSet, rObjData );
+
+ SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR );
+ if( SfxItemState::DEFAULT == eState )
+ aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
+ pObj->SetMergedItemSet(aSet);
+ }
+
+ //Means that fBehindDocument is set
+ if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
+ pImpRec->bDrawHell = true;
+ else
+ pImpRec->bDrawHell = false;
+ if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
+ pImpRec->bHidden = true;
+ pTextImpRec->bDrawHell = pImpRec->bDrawHell;
+ pTextImpRec->bHidden = pImpRec->bHidden;
+ pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 );
+ pTextImpRec->nNextShapeId=pImpRec->nNextShapeId;
+
+ if ( nTextId )
+ {
+ pTextImpRec->aTextId.nTxBxS = static_cast<sal_uInt16>( nTextId >> 16 );
+ pTextImpRec->aTextId.nSequence = static_cast<sal_uInt16>(nTextId);
+ }
+
+ pTextImpRec->nDxWrapDistLeft = GetPropertyValue(
+ DFF_Prop_dxWrapDistLeft, 114935L ) / 635L;
+ pTextImpRec->nDyWrapDistTop = GetPropertyValue(
+ DFF_Prop_dyWrapDistTop, 0 ) / 635L;
+ pTextImpRec->nDxWrapDistRight = GetPropertyValue(
+ DFF_Prop_dxWrapDistRight, 114935L ) / 635L;
+ pTextImpRec->nDyWrapDistBottom = GetPropertyValue(
+ DFF_Prop_dyWrapDistBottom, 0 ) / 635L;
+ // 16.16 fraction times total image width or height, as appropriate.
+
+ if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
+ {
+ pTextImpRec->pWrapPolygon.reset();
+ sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(8);
+ rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
+ // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
+ // low-order bytes are recorded
+ if (nElemSizeVert == 0xFFF0)
+ nElemSizeVert = 4;
+
+ // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
+ bool bOk = nElemSizeVert && (rSt.remainingSize() / nElemSizeVert >= nNumElemVert);
+ if (bOk)
+ {
+ pTextImpRec->pWrapPolygon = tools::Polygon(nNumElemVert);
+ for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
+ {
+ sal_Int32 nX(0), nY(0);
+ if (nElemSizeVert == 8)
+ rSt.ReadInt32( nX ).ReadInt32( nY );
+ else
+ {
+ sal_Int16 nSmallX(0), nSmallY(0);
+ rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
+ nX = nSmallX;
+ nY = nSmallY;
+ }
+ (*(pTextImpRec->pWrapPolygon))[i].setX( nX );
+ (*(pTextImpRec->pWrapPolygon))[i].setY( nY );
+ }
+ }
+ }
+
+ pImpRec->nCropFromTop = GetPropertyValue(
+ DFF_Prop_cropFromTop, 0 );
+ pImpRec->nCropFromBottom = GetPropertyValue(
+ DFF_Prop_cropFromBottom, 0 );
+ pImpRec->nCropFromLeft = GetPropertyValue(
+ DFF_Prop_cropFromLeft, 0 );
+ pImpRec->nCropFromRight = GetPropertyValue(
+ DFF_Prop_cropFromRight, 0 );
+
+ pImpRec->bVFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipV);
+ pImpRec->bHFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipH);
+
+ sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
+ pImpRec->eLineStyle = (nLineFlags & 8)
+ ? static_cast<MSO_LineStyle>(GetPropertyValue(
+ DFF_Prop_lineStyle,
+ mso_lineSimple ))
+ : MSO_LineStyle_NONE;
+ pTextImpRec->eLineStyle = pImpRec->eLineStyle;
+
+ pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
+ DFF_Prop_lineDashing, mso_lineSolid ));
+ pTextImpRec->eLineDashing = pImpRec->eLineDashing;
+
+ if( pImpRec->nShapeId )
+ {
+ // amend the import record list
+ if( pOrgObj )
+ {
+ pImpRec->pObj = pOrgObj;
+ rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pImpRec));
+ bDeleteImpRec = false;
+ if (pImpRec == pTextImpRec)
+ bDeleteTextImpRec = false;
+ }
+
+ if( pTextObj && (pOrgObj != pTextObj) )
+ {
+ // Modify ShapeId (must be unique)
+ pImpRec->nShapeId |= 0x8000000;
+ pTextImpRec->pObj = pTextObj;
+ rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pTextImpRec));
+ bDeleteTextImpRec = false;
+ if (pTextImpRec == pImpRec)
+ bDeleteImpRec = false;
+ }
+
+ // entry in the z-order-list in order to complement the pointer to this object
+ /*Only store objects which are not deep inside the tree*/
+ if( ( rObjData.nCalledByGroup == 0 )
+ ||
+ ( (rObjData.nSpFlags & ShapeFlag::Group)
+ && (rObjData.nCalledByGroup < 2) )
+ )
+ StoreShapeOrder( pImpRec->nShapeId,
+ ( static_cast<sal_uLong>(pImpRec->aTextId.nTxBxS) << 16 )
+ + pImpRec->aTextId.nSequence, pObj );
+ }
+
+ if (bDeleteImpRec)
+ delete pImpRec;
+
+ if (bDeleteTextImpRec)
+ delete pTextImpRec;
+ }
+
+ return pObj;
+};
+
+SdrObject* SvxMSDffManager::FinalizeObj(DffObjData& /* rObjData */, SdrObject* pObj)
+{
+ return pObj;
+}
+
+
+void SvxMSDffManager::StoreShapeOrder(sal_uLong nId,
+ sal_uLong nTxBx,
+ SdrObject* pObject,
+ SwFlyFrameFormat* pFly) const
+{
+ for (const auto& pOrder : m_aShapeOrders)
+ {
+ if (pOrder->nShapeId == nId)
+ {
+ pOrder->nTxBxComp = nTxBx;
+ pOrder->pObj = pObject;
+ pOrder->pFly = pFly;
+ }
+ }
+}
+
+
+void SvxMSDffManager::ExchangeInShapeOrder( SdrObject const * pOldObject,
+ sal_uLong nTxBx,
+ SdrObject* pObject) const
+{
+ for (const auto& pOrder : m_aShapeOrders)
+ {
+ if (pOrder->pObj == pOldObject)
+ {
+ pOrder->pFly = nullptr;
+ pOrder->pObj = pObject;
+ pOrder->nTxBxComp = nTxBx;
+ }
+ }
+}
+
+
+void SvxMSDffManager::RemoveFromShapeOrder( SdrObject const * pObject ) const
+{
+ for (const auto& pOrder : m_aShapeOrders)
+ {
+ if (pOrder->pObj == pObject)
+ {
+ pOrder->pObj = nullptr;
+ pOrder->pFly = nullptr;
+ pOrder->nTxBxComp = 0;
+ }
+ }
+}
+
+
+// exported class: Public Methods
+
+SvxMSDffManager::SvxMSDffManager(SvStream& rStCtrl_,
+ OUString aBaseURL,
+ sal_uInt32 nOffsDgg_,
+ SvStream* pStData_,
+ SdrModel* pSdrModel_,// see SetModel() below
+ tools::Long nApplicationScale,
+ Color mnDefaultColor_,
+ SvStream* pStData2_,
+ bool bSkipImages )
+ :DffPropertyReader( *this ),
+ m_pBLIPInfos( new SvxMSDffBLIPInfos ),
+ m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
+ nOffsDgg( nOffsDgg_ ),
+ nBLIPCount( USHRT_MAX ), // initialize with error, since we first check if the
+ nGroupShapeFlags(ShapeFlag::NONE), // ensure initialization here, as some corrupted
+ // files may yield to this being uninitialized
+ maBaseURL(std::move( aBaseURL )),
+ mnIdClusters(0),
+ rStCtrl( rStCtrl_ ),
+ pStData( pStData_ ),
+ pStData2( pStData2_ ),
+ nSvxMSDffSettings( 0 ),
+ nSvxMSDffOLEConvFlags( 0 ),
+ mnDefaultColor( mnDefaultColor_),
+ mbSkipImages (bSkipImages)
+{
+ SetModel( pSdrModel_, nApplicationScale );
+
+ // remember FilePos of the stream(s)
+ sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
+ sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
+
+ // if no data stream is given we assume that the BLIPs
+ // are in the control stream
+ if( !pStData )
+ pStData = &rStCtrl;
+
+ SetDefaultPropSet( rStCtrl, nOffsDgg );
+
+ // read control stream, if successful set nBLIPCount
+ GetCtrlData( nOffsDgg );
+
+ // check Text-Box-Story-Chain-Infos
+ CheckTxBxStoryChain();
+
+ // restore old FilePos of the stream(s)
+ rStCtrl.Seek( nOldPosCtrl );
+ if( &rStCtrl != pStData )
+ pStData->Seek( nOldPosData );
+}
+
+SvxMSDffManager::SvxMSDffManager( SvStream& rStCtrl_, OUString aBaseURL )
+ :DffPropertyReader( *this ),
+ m_pBLIPInfos( new SvxMSDffBLIPInfos ),
+ m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
+ nOffsDgg( 0 ),
+ nBLIPCount( USHRT_MAX ), // initialize with error, since we first have to check
+ nGroupShapeFlags(ShapeFlag::NONE),
+ maBaseURL(std::move( aBaseURL )),
+ mnIdClusters(0),
+ rStCtrl( rStCtrl_ ),
+ pStData( nullptr ),
+ pStData2( nullptr ),
+ nSvxMSDffSettings( 0 ),
+ nSvxMSDffOLEConvFlags( 0 ),
+ mnDefaultColor( COL_DEFAULT ),
+ mbSkipImages(false)
+{
+ SetModel( nullptr, 0 );
+}
+
+SvxMSDffManager::~SvxMSDffManager()
+{
+}
+
+void SvxMSDffManager::InitSvxMSDffManager( sal_uInt32 nOffsDgg_, SvStream* pStData_, sal_uInt32 nOleConvFlags )
+{
+ nOffsDgg = nOffsDgg_;
+ pStData = pStData_;
+ nSvxMSDffOLEConvFlags = nOleConvFlags;
+
+ // remember FilePos of the stream(s)
+ sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
+
+ SetDefaultPropSet( rStCtrl, nOffsDgg );
+
+ // insert fidcl cluster table
+ GetFidclData( nOffsDgg );
+
+ // read control stream, if successful, set nBLIPCount
+ GetCtrlData( nOffsDgg );
+
+ // check Text-Box-Story-Chain-Infos
+ CheckTxBxStoryChain();
+
+ // restore old FilePos of the stream(s)
+ rStCtrl.Seek( nOldPosCtrl );
+}
+
+void SvxMSDffManager::SetDgContainer( SvStream& rSt )
+{
+ sal_uInt64 nFilePos = rSt.Tell();
+ DffRecordHeader aDgContHd;
+ bool bOk = ReadDffRecordHeader(rSt, aDgContHd);
+ // insert this container only if there is also a DggAtom
+ if (bOk && SeekToRec(rSt, DFF_msofbtDg, aDgContHd.GetRecEndFilePos()))
+ {
+ DffRecordHeader aRecHd;
+ if (ReadDffRecordHeader(rSt, aRecHd))
+ {
+ sal_uInt32 nDrawingId = aRecHd.nRecInstance;
+ maDgOffsetTable[nDrawingId] = nFilePos;
+ }
+ }
+ rSt.Seek(nFilePos);
+}
+
+void SvxMSDffManager::GetFidclData( sal_uInt32 nOffsDggL )
+{
+ if (!nOffsDggL)
+ return;
+
+ sal_uInt64 nOldPos = rStCtrl.Tell();
+
+ if (nOffsDggL == rStCtrl.Seek(nOffsDggL))
+ {
+ DffRecordHeader aRecHd;
+ bool bOk = ReadDffRecordHeader(rStCtrl, aRecHd);
+
+ DffRecordHeader aDggAtomHd;
+ if (bOk && SeekToRec(rStCtrl, DFF_msofbtDgg, aRecHd.GetRecEndFilePos(), &aDggAtomHd))
+ {
+ aDggAtomHd.SeekToContent( rStCtrl );
+ sal_uInt32 nCurMaxShapeId;
+ sal_uInt32 nDummy;
+ rStCtrl.ReadUInt32( nCurMaxShapeId )
+ .ReadUInt32( mnIdClusters )
+ .ReadUInt32( nDummy )
+ .ReadUInt32( nDummy ); // nDrawingsSaved
+
+ if ( mnIdClusters-- > 2 )
+ {
+ const std::size_t nFIDCLsize = sizeof(sal_uInt32) * 2;
+ if ( aDggAtomHd.nRecLen == ( mnIdClusters * nFIDCLsize + 16 ) )
+ {
+ sal_uInt64 nMaxEntriesPossible = rStCtrl.remainingSize() / nFIDCLsize;
+ SAL_WARN_IF(nMaxEntriesPossible < mnIdClusters,
+ "filter.ms", "FIDCL list longer than remaining bytes, ppt or parser is wrong");
+ mnIdClusters = std::min(nMaxEntriesPossible, static_cast<sal_uInt64>(mnIdClusters));
+
+ maFidcls.resize(mnIdClusters);
+ for (sal_uInt32 i = 0; i < mnIdClusters; ++i)
+ {
+ sal_uInt32 cspidCur; ///< number of SPIDs used so far
+ rStCtrl.ReadUInt32( maFidcls[ i ].dgid )
+ .ReadUInt32( cspidCur );
+ }
+ }
+ }
+ }
+ }
+ rStCtrl.Seek( nOldPos );
+}
+
+void SvxMSDffManager::CheckTxBxStoryChain()
+{
+ m_xShapeInfosById.reset(new SvxMSDffShapeInfos_ById);
+ // mangle old Info array, sorted by nTxBxComp
+ sal_uInt32 nChain = std::numeric_limits<sal_uInt32>::max();
+ bool bSetReplaceFALSE = false;
+ for (SvxMSDffShapeInfos_ByTxBxComp::iterator iter =
+ m_xShapeInfosByTxBxComp->begin(),
+ mark = m_xShapeInfosByTxBxComp->begin();
+ iter != m_xShapeInfosByTxBxComp->end(); ++iter)
+ {
+ std::shared_ptr<SvxMSDffShapeInfo> const pObj = *iter;
+ if( pObj->nTxBxComp )
+ {
+ // group change?
+ // the text id also contains an internal drawing container id
+ // to distinguish between text id of drawing objects in different
+ // drawing containers.
+ if( nChain != pObj->nTxBxComp )
+ {
+ // reset mark and helper flag
+ mark = iter;
+ nChain = pObj->nTxBxComp;
+ bSetReplaceFALSE = !pObj->bReplaceByFly;
+ }
+ else if( !pObj->bReplaceByFly )
+ {
+ // object that must NOT be replaced by frame?
+ bSetReplaceFALSE = true;
+ // maybe reset flags in start of group
+ for (SvxMSDffShapeInfos_ByTxBxComp::iterator itemp = mark;
+ itemp != iter; ++itemp)
+ {
+ (*itemp)->bReplaceByFly = false;
+ }
+ }
+
+ if( bSetReplaceFALSE )
+ {
+ pObj->bReplaceByFly = false;
+ }
+ }
+ // copy all Shape Info objects to m_xShapeInfosById, sorted by nShapeId
+ pObj->nTxBxComp = pObj->nTxBxComp & 0xFFFF0000;
+ m_xShapeInfosById->insert( pObj );
+ }
+ // free original array but don't free its elements
+ m_xShapeInfosByTxBxComp.reset();
+}
+
+
+/*****************************************************************************
+
+ Reading the Shape-Infos in the Ctor:
+ ---------------------------------
+ remembering the Shape-Ids and the associated Blip-Numbers and TextBox-Infos
+ ========= ============ =============
+ and remembering the File-Offsets for each Blip
+ ============
+******************************************************************************/
+void SvxMSDffManager::GetCtrlData(sal_uInt32 nOffsDggL)
+{
+ // position control stream
+ if (!checkSeek(rStCtrl, nOffsDggL))
+ return;
+
+ sal_uInt8 nVer;
+ sal_uInt16 nInst;
+ sal_uInt16 nFbt;
+ sal_uInt32 nLength;
+ if( !ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) ) return;
+
+ sal_uInt64 nPos = nOffsDggL + DFF_COMMON_RECORD_HEADER_SIZE;
+
+ // case A: first Drawing Group Container, then n times Drawing Container
+ if( DFF_msofbtDggContainer != nFbt )
+ return;
+
+ bool bOk;
+ GetDrawingGroupContainerData( rStCtrl, nLength );
+
+ sal_uInt64 nMaxStrPos = rStCtrl.TellEnd();
+
+ nPos += nLength;
+ sal_uInt16 nDrawingContainerId = 1;
+ do
+ {
+ if (!checkSeek(rStCtrl, nPos))
+ break;
+
+ bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) && ( DFF_msofbtDgContainer == nFbt );
+
+ if( !bOk )
+ {
+ nPos++; // ????????? TODO: trying to get a one-hit wonder, this code should be rewritten...
+ if (nPos != rStCtrl.Seek(nPos))
+ break;
+ bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength )
+ && ( DFF_msofbtDgContainer == nFbt );
+ }
+ if( bOk )
+ {
+ GetDrawingContainerData( rStCtrl, nLength, nDrawingContainerId );
+ }
+ nPos += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
+ ++nDrawingContainerId;
+ }
+ while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( nPos < nMaxStrPos ) && bOk );
+}
+
+
+// from here on: Drawing Group Container i.e. document-wide valid data
+
+void SvxMSDffManager::GetDrawingGroupContainerData( SvStream& rSt, sal_uInt32 nLenDgg )
+{
+ sal_uInt8 nVer;
+ sal_uInt16 nInst;
+ sal_uInt16 nFbt;
+ sal_uInt32 nLength;
+
+ sal_uInt32 nLenBStoreCont = 0, nLenFBSE = 0;
+ sal_uLong nRead = 0;
+
+ // search for a BStore Container
+ bool bOk = true;
+ do
+ {
+ if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
+ return;
+ nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
+ if (DFF_msofbtBstoreContainer == nFbt)
+ {
+ nLenBStoreCont = nLength;
+ break;
+ }
+ bOk = checkSeek(rSt, rSt.Tell() + nLength);
+ }
+ while (bOk && nRead < nLenDgg);
+
+ if (!bOk || !nLenBStoreCont)
+ return;
+
+ // Read all atoms of the containers from the BStore container and store all
+ // relevant data of all contained FBSEs in out pointer array.
+ // We also count all found FBSEs in member nBLIPCount.
+
+ const sal_uLong nSkipBLIPLen = 20; // skip to get to the nBLIPLen
+ const sal_uLong nSkipBLIPPos = 4; // thereafter skip up to nBLIPPos
+
+ sal_uInt32 nBLIPLen = 0, nBLIPPos = 0;
+
+ nRead = 0;
+ do
+ {
+ if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return;
+ nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
+ if( DFF_msofbtBSE == nFbt && /* magic value from spec */ 0x2 == nVer )
+ {
+ nLenFBSE = nLength;
+ // is FBSE big enough for our data
+ bOk = ( nSkipBLIPLen + 4 + nSkipBLIPPos + 4 <= nLenFBSE );
+
+ if (bOk)
+ {
+ rSt.SeekRel( nSkipBLIPLen );
+ rSt.ReadUInt32( nBLIPLen );
+ rSt.SeekRel( nSkipBLIPPos );
+ rSt.ReadUInt32( nBLIPPos );
+ bOk = rSt.GetError() == ERRCODE_NONE;
+
+ nLength -= nSkipBLIPLen+ 4 + nSkipBLIPPos + 4;
+ }
+
+ if (bOk)
+ {
+ // specialty:
+ // If nBLIPLen is less than nLenFBSE AND nBLIPPos is NULL,
+ // then we assume, that the image is in FBSE!
+ if( (!nBLIPPos) && (nBLIPLen < nLenFBSE) )
+ nBLIPPos = rSt.Tell() + 4;
+
+ if( USHRT_MAX == nBLIPCount )
+ nBLIPCount = 1;
+ else
+ nBLIPCount++;
+
+ // now save the info for later access
+ m_pBLIPInfos->push_back(SvxMSDffBLIPInfo(nBLIPPos));
+ }
+ if (!checkSeek(rSt, rSt.Tell() + nLength))
+ return; // invalid offset
+ }
+ else return; // invalid input
+ }
+ while( nRead < nLenBStoreCont );
+}
+
+
+// from now on: Drawing Container which means Pages (Sheet, Slide) - wide valid data
+// ================= ======
+
+void SvxMSDffManager::GetDrawingContainerData( SvStream& rSt, sal_uInt32 nLenDg,
+ sal_uInt16 nDrawingContainerId )
+{
+ sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
+
+ sal_uLong nReadDg = 0;
+
+ // We are now in a drawing container (one per each page) and
+ // we now have to iterate through all contained shape group containers
+ do
+ {
+ if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
+ return;
+ nReadDg += DFF_COMMON_RECORD_HEADER_SIZE;
+ // Patriarch found (the upmost shape group container) ?
+ if (DFF_msofbtSpgrContainer == nFbt)
+ {
+ if (!GetShapeGroupContainerData(rSt, nLength, true, nDrawingContainerId))
+ return;
+ }
+ // empty Shape Container ? (outside of shape group container)
+ else if (DFF_msofbtSpContainer == nFbt)
+ {
+ if (!GetShapeContainerData(
+ rSt, nLength, std::numeric_limits<sal_uInt64>::max(), nDrawingContainerId))
+ return;
+ }
+ else
+ {
+ if (!checkSeek(rSt, rSt.Tell() + nLength))
+ return;
+ }
+ nReadDg += nLength;
+ }
+ while( nReadDg < nLenDg );
+}
+
+bool SvxMSDffManager::GetShapeGroupContainerData( SvStream& rSt,
+ sal_uInt32 nLenShapeGroupCont,
+ bool bPatriarch,
+ sal_uInt16 nDrawingContainerId )
+{
+ sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
+ sal_uInt64 nStartShapeGroupCont = rSt.Tell();
+ // We are now in a shape group container (conditionally multiple per page)
+ // and we now have to iterate through all contained shape containers
+ bool bFirst = !bPatriarch;
+ sal_uLong nReadSpGrCont = 0;
+ do
+ {
+ if( !ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength ) )
+ return false;
+ nReadSpGrCont += DFF_COMMON_RECORD_HEADER_SIZE;
+ // Shape Container?
+ if( DFF_msofbtSpContainer == nFbt )
+ {
+ sal_uInt64 nGroupOffs = bFirst ? nStartShapeGroupCont - DFF_COMMON_RECORD_HEADER_SIZE : std::numeric_limits<sal_uInt64>::max();
+ if ( !GetShapeContainerData( rSt, nLength, nGroupOffs, nDrawingContainerId ) )
+ return false;
+ bFirst = false;
+ }
+ // nested shape group container ?
+ else if( DFF_msofbtSpgrContainer == nFbt )
+ {
+ if ( !GetShapeGroupContainerData( rSt, nLength, false, nDrawingContainerId ) )
+ return false;
+ }
+ else
+ {
+ if (!checkSeek(rSt, rSt.Tell() + nLength))
+ return false;
+ }
+ nReadSpGrCont += nLength;
+ }
+ while( nReadSpGrCont < nLenShapeGroupCont );
+ // position the stream correctly
+ rSt.Seek( nStartShapeGroupCont + nLenShapeGroupCont );
+ return true;
+}
+
+bool SvxMSDffManager::GetShapeContainerData( SvStream& rSt,
+ sal_uInt32 nLenShapeCont,
+ sal_uInt64 nPosGroup,
+ sal_uInt16 nDrawingContainerId )
+{
+ sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
+ sal_uInt64 nStartShapeCont = rSt.Tell();
+
+ // We are in a shape container (possibly more than one per shape group) and we now
+ // have to fetch the shape id and file position (to be able to access them again later)
+ // and the first BStore reference (if present).
+ sal_uInt32 nLenShapePropTbl = 0;
+ sal_uLong nReadSpCont = 0;
+
+ // Store file offset of the shape containers or respectively the group(!).
+ sal_uInt64 nStartOffs = (std::numeric_limits<sal_uInt64>::max() > nPosGroup) ?
+ nPosGroup : nStartShapeCont - DFF_COMMON_RECORD_HEADER_SIZE;
+ SvxMSDffShapeInfo aInfo( nStartOffs );
+
+ // Can the shape be replaced with a frame?
+ // (provided that it is a TextBox and the text is not rotated)
+ bool bCanBeReplaced = nPosGroup >= std::numeric_limits<sal_uInt64>::max();
+
+ // we don't know yet whether it's a TextBox
+ MSO_SPT eShapeType = mso_sptNil;
+
+ // analyze Shape
+
+ do
+ {
+ if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return false;
+ nReadSpCont += DFF_COMMON_RECORD_HEADER_SIZE;
+ // FSP ?
+ if( ( DFF_msofbtSp == nFbt ) && ( 4 <= nLength ) )
+ {
+ // we've found the FSP: note Shape Type and Id!
+ eShapeType = static_cast<MSO_SPT>(nInst);
+ rSt.ReadUInt32( aInfo.nShapeId );
+ rSt.SeekRel( nLength - 4 );
+ nReadSpCont += nLength;
+ }
+ else if( DFF_msofbtOPT == nFbt ) // Shape Property Table ?
+ {
+ // We've found the Property Table:
+ // search for the Blip Property!
+ sal_uLong nPropRead = 0;
+ nLenShapePropTbl = nLength;
+ auto nStartShapePropTbl = rSt.Tell();
+ do
+ {
+ sal_uInt16 nPropId(0);
+ sal_uInt32 nPropVal(0);
+
+ rSt.ReadUInt16( nPropId )
+ .ReadUInt32( nPropVal );
+ nPropRead += 6;
+
+ switch( nPropId )
+ {
+ case DFF_Prop_txflTextFlow :
+ //Writer can now handle vertical textflows in its
+ //native frames, to only need to do this for the
+ //other two formats
+
+ //Writer will handle all textflow except BtoT
+ if (GetSvxMSDffSettings() &
+ (SVXMSDFF_SETTINGS_IMPORT_PPT |
+ SVXMSDFF_SETTINGS_IMPORT_EXCEL))
+ {
+ if( 0 != nPropVal )
+ bCanBeReplaced = false;
+ }
+ else if (
+ (nPropVal != mso_txflHorzN) &&
+ (nPropVal != mso_txflTtoBA)
+ )
+ {
+ bCanBeReplaced = false;
+ }
+ break;
+ case DFF_Prop_cdirFont :
+ //Writer can now handle right to left and left
+ //to right in its native frames, so only do
+ //this for the other two formats.
+ if (GetSvxMSDffSettings() &
+ (SVXMSDFF_SETTINGS_IMPORT_PPT |
+ SVXMSDFF_SETTINGS_IMPORT_EXCEL))
+ {
+ if( 0 != nPropVal )
+ bCanBeReplaced = false;
+ }
+ break;
+ case DFF_Prop_Rotation :
+ if( 0 != nPropVal )
+ bCanBeReplaced = false;
+ break;
+
+ case DFF_Prop_gtextFStrikethrough :
+ if( ( 0x20002000 & nPropVal ) == 0x20002000 )
+ bCanBeReplaced = false;
+ break;
+
+ case DFF_Prop_fc3DLightFace :
+ if( ( 0x00080008 & nPropVal ) == 0x00080008 )
+ bCanBeReplaced = false;
+ break;
+
+ case DFF_Prop_WrapText :
+ //TODO: eWrapMode = (MSO_WrapMode)nPropVal;
+ break;
+
+ default:
+ {
+ // is the Bit set and valid?
+ if( 0x4000 == ( nPropId & 0xC000 ) )
+ {
+ // Blip Property found: remember BStore Idx!
+ nPropRead = nLenShapePropTbl;
+ }
+ else if( 0x8000 & nPropId )
+ {
+ // complex Prop found:
+ // Length is always 6. The length of the appended extra data
+ // after the actual prop table is of different size.
+ nPropVal = 6;
+ }
+ }
+ break;
+ }
+ }
+ while (rSt.good() && nPropRead < nLenShapePropTbl);
+ rSt.Seek( nStartShapePropTbl + nLenShapePropTbl );
+ nReadSpCont += nLenShapePropTbl;
+ }
+ else if( ( DFF_msofbtClientTextbox == nFbt ) && ( 4 == nLength ) ) // Text-Box-Story-Entry found
+ {
+ rSt.ReadUInt32( aInfo.nTxBxComp );
+ // Add internal drawing container id to text id.
+ // Note: The text id uses the first two bytes, while the internal
+ // drawing container id used the second two bytes.
+ aInfo.nTxBxComp = ( aInfo.nTxBxComp & 0xFFFF0000 ) +
+ nDrawingContainerId;
+ DBG_ASSERT( (aInfo.nTxBxComp & 0x0000FFFF) == nDrawingContainerId,
+ "<SvxMSDffManager::GetShapeContainerData(..)> - internal drawing container Id could not be correctly merged into DFF_msofbtClientTextbox value." );
+ }
+ else
+ {
+ if (!checkSeek(rSt, rSt.Tell() + nLength))
+ {
+ SAL_WARN("filter.ms", "remaining record longer than available data, ppt or parser is wrong");
+ break;
+ }
+ nReadSpCont += nLength;
+ }
+ }
+ while( nReadSpCont < nLenShapeCont );
+
+
+ // Now possibly store the information for subsequent accesses to the shape
+
+ if( aInfo.nShapeId )
+ {
+ // Possibly allow replacement of textboxes with frames
+ if( bCanBeReplaced
+ && aInfo.nTxBxComp
+ && (
+ ( eShapeType == mso_sptTextSimple )
+ || ( eShapeType == mso_sptTextBox )
+ || ( eShapeType == mso_sptRectangle )
+ || ( eShapeType == mso_sptRoundRectangle )
+ ) )
+ {
+ aInfo.bReplaceByFly = true;
+ }
+ m_xShapeInfosByTxBxComp->insert(std::make_shared<SvxMSDffShapeInfo>(
+ aInfo));
+ m_aShapeOrders.push_back(std::make_unique<SvxMSDffShapeOrder>(
+ aInfo.nShapeId ));
+ }
+
+ // and position the Stream correctly again
+ rSt.Seek( nStartShapeCont + nLenShapeCont );
+ return true;
+}
+
+
+/*****************************************************************************
+
+ Access to a shape at runtime (via the Shape-Id)
+ ----------------------------
+******************************************************************************/
+bool SvxMSDffManager::GetShape(sal_uLong nId, SdrObject*& rpShape,
+ SvxMSDffImportData& rData)
+{
+ auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, nId);
+
+ SvxMSDffShapeInfos_ById::const_iterator const it =
+ m_xShapeInfosById->find(pTmpRec);
+ if (it == m_xShapeInfosById->end())
+ return false;
+
+ // Possibly delete old error flag.
+ if( rStCtrl.GetError() )
+ rStCtrl.ResetError();
+ // store FilePos of the stream(s)
+ sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
+ sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
+ // jump to the shape in the control stream
+ sal_uInt64 const nFilePos((*it)->nFilePos);
+ bool bSeeked = (nFilePos == rStCtrl.Seek(nFilePos));
+
+ // if it failed, reset error statusF
+ if (!bSeeked || rStCtrl.GetError())
+ rStCtrl.ResetError();
+ else
+ rpShape = ImportObj( rStCtrl, rData, rData.aParentRect, rData.aParentRect, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
+
+ // restore old FilePos of the stream(s)
+ rStCtrl.Seek( nOldPosCtrl );
+ if( &rStCtrl != pStData && pStData )
+ pStData->Seek( nOldPosData );
+ return ( nullptr != rpShape );
+}
+
+
+/** Access to a BLIP at runtime (if the Blip-Number is already known)
+ */
+bool SvxMSDffManager::GetBLIP( sal_uLong nIdx_, Graphic& rGraphic, tools::Rectangle* pVisArea )
+{
+ if (!pStData)
+ return false;
+
+ bool bOk = false; // initialize result variable
+
+ // check if a graphic for this blipId is already imported
+ if (nIdx_)
+ {
+ auto iter = aEscherBlipCache.find(nIdx_);
+
+ if (iter != aEscherBlipCache.end())
+ {
+ /* if this entry is available */
+ rGraphic = iter->second;
+ if (rGraphic.GetType() != GraphicType::NONE)
+ bOk = true;
+ else
+ aEscherBlipCache.erase(iter);
+ }
+ }
+
+ if (!bOk)
+ {
+ sal_uInt16 nIdx = sal_uInt16( nIdx_ );
+ if (!nIdx || (m_pBLIPInfos->size() < nIdx))
+ return false;
+
+ // possibly delete old error flag(s)
+ if( rStCtrl.GetError() )
+ rStCtrl.ResetError();
+ if( ( &rStCtrl != pStData )
+ && pStData->GetError() )
+ pStData->ResetError();
+
+ // remember FilePos of the stream(s)
+ sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
+ sal_uInt64 nOldPosData = pStData->Tell();
+
+ // fetch matching info struct out of the pointer array
+ SvxMSDffBLIPInfo& rInfo = (*m_pBLIPInfos)[ nIdx-1 ];
+ // jump to the BLIP atom in the data stream
+ bOk = checkSeek(*pStData, rInfo.nFilePos);
+ // possibly reset error status
+ if (!bOk || pStData->GetError())
+ pStData->ResetError();
+ else
+ bOk = GetBLIPDirect( *pStData, rGraphic, pVisArea );
+ if( pStData2 && !bOk )
+ {
+ // Error, but the is a second chance: There is a second
+ // data stream in which the graphic could be stored!
+ if( pStData2->GetError() )
+ pStData2->ResetError();
+ sal_uInt64 nOldPosData2 = pStData2->Tell();
+ // jump to the BLIP atom in the second data stream
+ bOk = checkSeek(*pStData2, rInfo.nFilePos);
+ // reset error status if necessary
+ if (!bOk || pStData2->GetError())
+ pStData2->ResetError();
+ else
+ bOk = GetBLIPDirect( *pStData2, rGraphic, pVisArea );
+ // restore of FilePos of the second data stream
+ pStData2->Seek( nOldPosData2 );
+ }
+ // restore old FilePos of the stream(s)
+ rStCtrl.Seek( nOldPosCtrl );
+ if( &rStCtrl != pStData )
+ pStData->Seek( nOldPosData );
+
+ if (bOk)
+ {
+ // create new BlipCacheEntry for this graphic
+ aEscherBlipCache.insert(std::make_pair(nIdx_, rGraphic));
+ }
+ }
+
+ return bOk;
+}
+
+/* access to a BLIP at runtime (with correctly positioned stream)
+ ---------------------------------
+******************************************************************************/
+bool SvxMSDffManager::GetBLIPDirect( SvStream& rBLIPStream, Graphic& rData, tools::Rectangle* pVisArea )
+{
+ sal_uInt64 nOldPos = rBLIPStream.Tell();
+
+ ErrCode nRes = ERRCODE_GRFILTER_OPENERROR; // initialize error variable
+
+ // check whether it's really a BLIP
+ sal_uInt32 nLength;
+ sal_uInt16 nInst, nFbt( 0 );
+ sal_uInt8 nVer;
+ if( ReadCommonRecordHeader( rBLIPStream, nVer, nInst, nFbt, nLength) && ( 0xF018 <= nFbt ) && ( 0xF117 >= nFbt ) )
+ {
+ Size aMtfSize100;
+ bool bMtfBLIP = false;
+ bool bZCodecCompression = false;
+ // now position it exactly at the beginning of the embedded graphic
+ sal_uLong nSkip = (nInst & 0x0001) ? 32 : 16;
+ const OfficeArtBlipRecInstance aRecInstanse = OfficeArtBlipRecInstance(nInst & 0xFFFE);
+ switch (aRecInstanse)
+ {
+ case OfficeArtBlipRecInstance::EMF:
+ case OfficeArtBlipRecInstance::WMF:
+ case OfficeArtBlipRecInstance::PICT:
+ {
+ rBLIPStream.SeekRel(nSkip + 20);
+
+ // read in size of metafile in English Metric Units (EMUs)
+ sal_Int32 width(0), height(0);
+ rBLIPStream.ReadInt32(width).ReadInt32(height);
+ aMtfSize100.setWidth(width);
+ aMtfSize100.setHeight(height);
+
+ // 1 EMU = 1/360,000 of a centimeter
+ // scale to 1/100mm
+ aMtfSize100.setWidth(aMtfSize100.Width() / 360);
+ aMtfSize100.setHeight(aMtfSize100.Height() / 360);
+
+ if (pVisArea) // seem that we currently are skipping the visarea position
+ *pVisArea = tools::Rectangle(Point(), aMtfSize100);
+
+ // skip rest of header
+ nSkip = 6;
+ bMtfBLIP = bZCodecCompression = true;
+ }
+ break;
+ case OfficeArtBlipRecInstance::JPEG_RGB:
+ case OfficeArtBlipRecInstance::JPEG_CMYK:
+ case OfficeArtBlipRecInstance::PNG:
+ case OfficeArtBlipRecInstance::DIB:
+ case OfficeArtBlipRecInstance::TIFF:
+ nSkip += 1; // Skip one byte tag
+ break;
+ }
+ rBLIPStream.SeekRel( nSkip );
+
+ SvStream* pGrStream = &rBLIPStream;
+ std::unique_ptr<SvMemoryStream> xOut;
+ if( bZCodecCompression )
+ {
+ xOut.reset(new SvMemoryStream( 0x8000, 0x4000 ));
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression();
+ aZCodec.Decompress( rBLIPStream, *xOut );
+ aZCodec.EndCompression();
+ xOut->Seek( STREAM_SEEK_TO_BEGIN );
+ xOut->SetResizeOffset( 0 ); // sj: #i102257# setting ResizeOffset of 0 prevents from seeking
+ // behind the stream end (allocating too much memory)
+ pGrStream = xOut.get();
+ }
+
+#ifdef DEBUG_FILTER_MSDFFIMP
+ // extract graphics from ole storage into "dbggfxNNN.*"
+ static sal_Int32 nGrfCount;
+
+ OUString aFileName = "dbggfx" + OUString::number(nGrfCount++);
+ switch (aRecInstanse)
+ {
+ case OfficeArtBlipRecInstance::WMF:
+ aFileName += ".wmf";
+ break;
+ case OfficeArtBlipRecInstance::EMF:
+ aFileName += ".emf";
+ break;
+ case OfficeArtBlipRecInstance::PICT:
+ aFileName += ".pct";
+ break;
+ case OfficeArtBlipRecInstance::JPEG_RGB:
+ case OfficeArtBlipRecInstance::JPEG_CMYK:
+ aFileName += ".jpg";
+ break;
+ case OfficeArtBlipRecInstance::PNG:
+ aFileName += ".png";
+ break;
+ case OfficeArtBlipRecInstance::DIB:
+ aFileName += ".bmp";
+ break;
+ case OfficeArtBlipRecInstance::TIFF:
+ aFileName += ".tif";
+ break;
+ }
+
+
+ OUString aURLStr;
+ if( osl::FileBase::getFileURLFromSystemPath( Application::GetAppFileName(), aURLStr ) == osl::FileBase::E_None )
+ {
+ INetURLObject aURL( aURLStr );
+
+ aURL.removeSegment();
+ aURL.removeFinalSlash();
+ aURL.Append( aFileName );
+
+ aURLStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ SAL_INFO("filter.ms", "dumping " << aURLStr);
+
+ std::unique_ptr<SvStream> pDbgOut(::utl::UcbStreamHelper::CreateStream(aURLStr, StreamMode::TRUNC | StreamMode::WRITE));
+
+ if( pDbgOut )
+ {
+ if ( bZCodecCompression )
+ {
+ pDbgOut->WriteBytes(xOut->GetData(), xOut->TellEnd());
+ xOut->Seek(STREAM_SEEK_TO_BEGIN);
+ }
+ else
+ {
+ sal_Int32 nDbgLen = nLength - nSkip;
+ if ( nDbgLen )
+ {
+ std::vector<char> aData(nDbgLen);
+ pGrStream->ReadBytes(aData.data(), nDbgLen);
+ pDbgOut->WriteBytes(aData.data(), nDbgLen);
+ pGrStream->SeekRel(-nDbgLen);
+ }
+ }
+ }
+ }
+#endif
+ if (aRecInstanse == OfficeArtBlipRecInstance::DIB)
+ { // getting the DIBs immediately
+ Bitmap aNew;
+ if( ReadDIB(aNew, *pGrStream, false) )
+ {
+ rData = Graphic(BitmapEx(aNew));
+ nRes = ERRCODE_NONE;
+ }
+ }
+ else
+ { // and unleash our filter
+ GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
+ // ImportUnloadedGraphic() may simply read the entire rest of the stream,
+ // which may be very large if the whole document is large. Limit the read
+ // size to the size of this record.
+ sal_uInt64 maxSize = pGrStream == &rBLIPStream ? nLength : 0;
+ Graphic aGraphic;
+
+ // Size available in metafile header.
+ if (aMtfSize100.getWidth() && aMtfSize100.getHeight())
+ aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize, &aMtfSize100);
+ else
+ aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize);
+
+ if (!aGraphic.IsNone())
+ {
+ rData = aGraphic;
+ nRes = ERRCODE_NONE;
+ }
+ else
+ nRes = rGF.ImportGraphic( rData, u"", *pGrStream );
+
+ // SJ: I40472, sometimes the aspect ratio (aMtfSize100) does not match and we get scaling problems,
+ // then it is better to use the prefsize that is stored within the metafile. Bug #72846# for what the
+ // scaling has been implemented does not happen anymore.
+ //
+ // For pict graphics we will furthermore scale the metafile, because font scaling leads to error if the
+ // dxarray is empty (this has been solved in wmf/emf but not for pict)
+ if (bMtfBLIP && (ERRCODE_NONE == nRes) && (rData.GetType() == GraphicType::GdiMetafile)
+ && (aRecInstanse == OfficeArtBlipRecInstance::PICT))
+ {
+ if ( ( aMtfSize100.Width() >= 1000 ) && ( aMtfSize100.Height() >= 1000 ) )
+ { // #75956#, scaling does not work properly, if the graphic is less than 1cm
+ GDIMetaFile aMtf( rData.GetGDIMetaFile() );
+ const Size aOldSize( aMtf.GetPrefSize() );
+
+ if( aOldSize.Width() && ( aOldSize.Width() != aMtfSize100.Width() ) &&
+ aOldSize.Height() && ( aOldSize.Height() != aMtfSize100.Height() ) )
+ {
+ aMtf.Scale( static_cast<double>(aMtfSize100.Width()) / aOldSize.Width(),
+ static_cast<double>(aMtfSize100.Height()) / aOldSize.Height() );
+ aMtf.SetPrefSize( aMtfSize100 );
+ aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
+ rData = aMtf;
+ }
+ }
+ }
+ }
+ // reset error status if necessary
+ if ( ERRCODE_IO_PENDING == pGrStream->GetError() )
+ pGrStream->ResetError();
+ }
+ rBLIPStream.Seek( nOldPos ); // restore old FilePos of the stream
+
+ return ( ERRCODE_NONE == nRes ); // return result
+}
+
+/* also static */
+bool SvxMSDffManager::ReadCommonRecordHeader(SvStream& rSt,
+ sal_uInt8& rVer, sal_uInt16& rInst, sal_uInt16& rFbt, sal_uInt32& rLength)
+{
+ sal_uInt16 nTmp(0);
+ rSt.ReadUInt16( nTmp ).ReadUInt16( rFbt ).ReadUInt32( rLength );
+ rVer = sal::static_int_cast< sal_uInt8 >(nTmp & 15);
+ rInst = nTmp >> 4;
+ if (!rSt.good())
+ return false;
+ if (rLength > nMaxLegalDffRecordLength)
+ return false;
+ return true;
+}
+
+void SvxMSDffManager::ProcessClientAnchor(SvStream& rStData, sal_uInt32 nDatLen,
+ std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
+{
+ if( nDatLen )
+ {
+ rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
+ rpBuff.reset( new char[rBuffLen] );
+ rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
+ }
+}
+
+void SvxMSDffManager::ProcessClientData(SvStream& rStData, sal_uInt32 nDatLen,
+ std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
+{
+ if( nDatLen )
+ {
+ rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
+ rpBuff.reset( new char[rBuffLen] );
+ rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
+ }
+}
+
+
+void SvxMSDffManager::ProcessClientAnchor2( SvStream& /* rSt */, DffRecordHeader& /* rHd */ , DffObjData& /* rObj */ )
+{
+ // will be overridden by SJ in Draw
+}
+
+bool SvxMSDffManager::GetOLEStorageName( sal_uInt32, OUString&, tools::SvRef<SotStorage>&, uno::Reference < embed::XStorage >& ) const
+{
+ return false;
+}
+
+bool SvxMSDffManager::ShapeHasText( sal_uLong /* nShapeId */, sal_uLong /* nFilePos */ ) const
+{
+ return true;
+}
+
+// #i32596# - add new parameter <_nCalledByGroup>
+SdrObject* SvxMSDffManager::ImportOLE( sal_uInt32 nOLEId,
+ const Graphic& rGrf,
+ const tools::Rectangle& rBoundRect,
+ const tools::Rectangle& rVisArea,
+ const int /* _nCalledByGroup */ ) const
+{
+ SdrObject* pRet = nullptr;
+ OUString sStorageName;
+ tools::SvRef<SotStorage> xSrcStg;
+ ErrCode nError = ERRCODE_NONE;
+ uno::Reference < embed::XStorage > xDstStg;
+ if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
+ pRet = CreateSdrOLEFromStorage(
+ *GetModel(),
+ sStorageName,
+ xSrcStg,
+ xDstStg,
+ rGrf,
+ rBoundRect,
+ rVisArea,
+ pStData,
+ nError,
+ nSvxMSDffOLEConvFlags,
+ embed::Aspects::MSOLE_CONTENT,
+ maBaseURL);
+ return pRet;
+}
+
+bool SvxMSDffManager::MakeContentStream( SotStorage * pStor, const GDIMetaFile & rMtf )
+{
+ tools::SvRef<SotStorageStream> xStm = pStor->OpenSotStream(SVEXT_PERSIST_STREAM);
+ xStm->SetVersion( pStor->GetVersion() );
+ xStm->SetBufferSize( 8192 );
+
+ Impl_OlePres aEle;
+ // Convert the size in 1/100 mm
+ // If a not applicable MapUnit (device dependent) is used,
+ // SV tries to guess a best match for the right value
+ Size aSize = rMtf.GetPrefSize();
+ const MapMode& aMMSrc = rMtf.GetPrefMapMode();
+ MapMode aMMDst( MapUnit::Map100thMM );
+ aSize = OutputDevice::LogicToLogic( aSize, aMMSrc, aMMDst );
+ aEle.SetSize( aSize );
+ aEle.SetAspect( ASPECT_CONTENT );
+ aEle.SetAdviseFlags( 2 );
+ aEle.SetMtf( rMtf );
+ aEle.Write( *xStm );
+
+ xStm->SetBufferSize( 0 );
+ return xStm->GetError() == ERRCODE_NONE;
+}
+
+namespace {
+
+struct ClsIDs {
+ sal_uInt32 nId;
+ const char* pSvrName;
+ const char* pDspName;
+};
+
+}
+
+const ClsIDs aClsIDs[] = {
+
+ { 0x000212F0, "MSWordArt", "Microsoft Word Art" },
+ { 0x000212F0, "MSWordArt.2", "Microsoft Word Art 2.0" },
+
+ // MS Apps
+ { 0x00030000, "ExcelWorksheet", "Microsoft Excel Worksheet" },
+ { 0x00030001, "ExcelChart", "Microsoft Excel Chart" },
+ { 0x00030002, "ExcelMacrosheet", "Microsoft Excel Macro" },
+ { 0x00030003, "WordDocument", "Microsoft Word Document" },
+ { 0x00030004, "MSPowerPoint", "Microsoft PowerPoint" },
+ { 0x00030005, "MSPowerPointSho", "Microsoft PowerPoint Slide Show"},
+ { 0x00030006, "MSGraph", "Microsoft Graph" },
+ { 0x00030007, "MSDraw", "Microsoft Draw" },
+ { 0x00030008, "Note-It", "Microsoft Note-It" },
+ { 0x00030009, "WordArt", "Microsoft Word Art" },
+ { 0x0003000a, "PBrush", "Microsoft PaintBrush Picture" },
+ { 0x0003000b, "Equation", "Microsoft Equation Editor" },
+ { 0x0003000c, "Package", "Package" },
+ { 0x0003000d, "SoundRec", "Sound" },
+ { 0x0003000e, "MPlayer", "Media Player" },
+ // MS Demos
+ { 0x0003000f, "ServerDemo", "OLE 1.0 Server Demo" },
+ { 0x00030010, "Srtest", "OLE 1.0 Test Demo" },
+ { 0x00030011, "SrtInv", "OLE 1.0 Inv Demo" },
+ { 0x00030012, "OleDemo", "OLE 1.0 Demo" },
+
+ // Coromandel / Dorai Swamy / 718-793-7963
+ { 0x00030013, "CoromandelIntegra", "Coromandel Integra" },
+ { 0x00030014, "CoromandelObjServer","Coromandel Object Server" },
+
+ // 3-d Visions Corp / Peter Hirsch / 310-325-1339
+ { 0x00030015, "StanfordGraphics", "Stanford Graphics" },
+
+ // Deltapoint / Nigel Hearne / 408-648-4000
+ { 0x00030016, "DGraphCHART", "DeltaPoint Graph Chart" },
+ { 0x00030017, "DGraphDATA", "DeltaPoint Graph Data" },
+
+ // Corel / Richard V. Woodend / 613-728-8200 x1153
+ { 0x00030018, "PhotoPaint", "Corel PhotoPaint" },
+ { 0x00030019, "CShow", "Corel Show" },
+ { 0x0003001a, "CorelChart", "Corel Chart" },
+ { 0x0003001b, "CDraw", "Corel Draw" },
+
+ // Inset Systems / Mark Skiba / 203-740-2400
+ { 0x0003001c, "HJWIN1.0", "Inset Systems" },
+
+ // Mark V Systems / Mark McGraw / 818-995-7671
+ { 0x0003001d, "ObjMakerOLE", "MarkV Systems Object Maker" },
+
+ // IdentiTech / Mike Gilger / 407-951-9503
+ { 0x0003001e, "FYI", "IdentiTech FYI" },
+ { 0x0003001f, "FYIView", "IdentiTech FYI Viewer" },
+
+ // Inventa Corporation / Balaji Varadarajan / 408-987-0220
+ { 0x00030020, "Stickynote", "Inventa Sticky Note" },
+
+ // ShapeWare Corp. / Lori Pearce / 206-467-6723
+ { 0x00030021, "ShapewareVISIO10", "Shapeware Visio 1.0" },
+ { 0x00030022, "ImportServer", "Spaheware Import Server" },
+
+ // test app SrTest
+ { 0x00030023, "SrvrTest", "OLE 1.0 Server Test" },
+
+ // test app ClTest. Doesn't really work as a server but is in reg db
+ { 0x00030025, "Cltest", "OLE 1.0 Client Test" },
+
+ // Microsoft ClipArt Gallery Sherry Larsen-Holmes
+ { 0x00030026, "MS_ClipArt_Gallery", "Microsoft ClipArt Gallery" },
+ // Microsoft Project Cory Reina
+ { 0x00030027, "MSProject", "Microsoft Project" },
+
+ // Microsoft Works Chart
+ { 0x00030028, "MSWorksChart", "Microsoft Works Chart" },
+
+ // Microsoft Works Spreadsheet
+ { 0x00030029, "MSWorksSpreadsheet", "Microsoft Works Spreadsheet" },
+
+ // AFX apps - Dean McCrory
+ { 0x0003002A, "MinSvr", "AFX Mini Server" },
+ { 0x0003002B, "HierarchyList", "AFX Hierarchy List" },
+ { 0x0003002C, "BibRef", "AFX BibRef" },
+ { 0x0003002D, "MinSvrMI", "AFX Mini Server MI" },
+ { 0x0003002E, "TestServ", "AFX Test Server" },
+
+ // Ami Pro
+ { 0x0003002F, "AmiProDocument", "Ami Pro Document" },
+
+ // WordPerfect Presentations For Windows
+ { 0x00030030, "WPGraphics", "WordPerfect Presentation" },
+ { 0x00030031, "WPCharts", "WordPerfect Chart" },
+
+ // MicroGrafx Charisma
+ { 0x00030032, "Charisma", "MicroGrafx Charisma" },
+ { 0x00030033, "Charisma_30", "MicroGrafx Charisma 3.0" },
+ { 0x00030034, "CharPres_30", "MicroGrafx Charisma 3.0 Pres" },
+ // MicroGrafx Draw
+ { 0x00030035, "Draw", "MicroGrafx Draw" },
+ // MicroGrafx Designer
+ { 0x00030036, "Designer_40", "MicroGrafx Designer 4.0" },
+
+ // STAR DIVISION
+ { 0x00043AD2, "FontWork", "Star FontWork" },
+
+ { 0, "", "" } };
+
+
+bool SvxMSDffManager::ConvertToOle2( SvStream& rStm, sal_uInt32 nReadLen,
+ const GDIMetaFile * pMtf, const tools::SvRef<SotStorage>& rDest )
+{
+ bool bMtfRead = false;
+ tools::SvRef<SotStorageStream> xOle10Stm = rDest->OpenSotStream( "\1Ole10Native",
+ StreamMode::WRITE| StreamMode::SHARE_DENYALL );
+ if( xOle10Stm->GetError() )
+ return false;
+
+ OUString aSvrName;
+ sal_uInt32 nDummy0;
+ sal_uInt32 nDummy1;
+ sal_uInt32 nBytesRead = 0;
+ do
+ {
+ sal_uInt32 nType(0);
+ sal_uInt32 nRecType(0);
+ sal_uInt32 nStrLen(0);
+
+ rStm.ReadUInt32( nType );
+ rStm.ReadUInt32( nRecType );
+ rStm.ReadUInt32( nStrLen );
+ if( nStrLen )
+ {
+ if( 0x10000L > nStrLen )
+ {
+ std::unique_ptr<char[]> pBuf(new char[ nStrLen ]);
+ rStm.ReadBytes(pBuf.get(), nStrLen);
+ aSvrName = OUString( pBuf.get(), static_cast<sal_uInt16>(nStrLen)-1, osl_getThreadTextEncoding() );
+ }
+ else
+ break;
+ }
+ rStm.ReadUInt32( nDummy0 );
+ rStm.ReadUInt32( nDummy1 );
+ sal_uInt32 nDataLen(0);
+ rStm.ReadUInt32( nDataLen );
+
+ nBytesRead += 6 * sizeof( sal_uInt32 ) + nStrLen + nDataLen;
+
+ if (rStm.good() && nReadLen > nBytesRead && nDataLen)
+ {
+ if( xOle10Stm.is() )
+ {
+ std::unique_ptr<sal_uInt8[]> pData(new sal_uInt8[ nDataLen ]);
+ rStm.ReadBytes(pData.get(), nDataLen);
+
+ // write to ole10 stream
+ xOle10Stm->WriteUInt32( nDataLen );
+ xOle10Stm->WriteBytes(pData.get(), nDataLen);
+ xOle10Stm = tools::SvRef<SotStorageStream>();
+
+ // set the compobj stream
+ const ClsIDs* pIds;
+ for( pIds = aClsIDs; pIds->nId; pIds++ )
+ {
+ if( aSvrName == OUString::createFromAscii(pIds->pSvrName) )
+ break;
+ }
+
+ if( pIds->nId )
+ {
+ // found!
+ SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
+ rDest->SetClass( SvGlobalName( pIds->nId, 0, 0, 0xc0,0,0,0,0,0,0,0x46 ), nCbFmt,
+ OUString::createFromAscii( pIds->pDspName ) );
+ }
+ else
+ {
+ SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
+ rDest->SetClass( SvGlobalName(), nCbFmt, aSvrName );
+ }
+ }
+ else if( nRecType == 5 && !pMtf )
+ {
+ sal_uInt64 nPos = rStm.Tell();
+ sal_uInt16 sz[4];
+ rStm.ReadBytes( sz, 8 );
+ Graphic aGraphic;
+ if( ERRCODE_NONE == GraphicConverter::Import( rStm, aGraphic ) && aGraphic.GetType() != GraphicType::NONE )
+ {
+ const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile();
+ MakeContentStream( rDest.get(), rMtf );
+ bMtfRead = true;
+ }
+ // set behind the data
+ rStm.Seek( nPos + nDataLen );
+ }
+ else
+ rStm.SeekRel( nDataLen );
+ }
+ } while (rStm.good() && nReadLen >= nBytesRead);
+
+ if( !bMtfRead && pMtf )
+ {
+ MakeContentStream( rDest.get(), *pMtf );
+ return true;
+ }
+
+ return false;
+}
+
+static const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName )
+{
+ if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 )
+ || aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
+ return "swriter";
+ else if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 )
+ || aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
+ return "scalc";
+ else if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 )
+ || aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
+ return "simpress";
+ else if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 )
+ || aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
+ return "sdraw";
+ else if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 )
+ || aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
+ return "smath";
+ else if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 )
+ || aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
+ return "schart";
+ return nullptr;
+}
+
+OUString SvxMSDffManager::GetFilterNameFromClassID( const SvGlobalName& aGlobName )
+{
+ if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) )
+ return "StarOffice XML (Writer)";
+
+ if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
+ return "writer8";
+
+ if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 ) )
+ return "StarOffice XML (Calc)";
+
+ if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
+ return "calc8";
+
+ if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) )
+ return "StarOffice XML (Impress)";
+
+ if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
+ return "impress8";
+
+ if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) )
+ return "StarOffice XML (Draw)";
+
+ if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
+ return "draw8";
+
+ if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 ) )
+ return "StarOffice XML (Math)";
+
+ if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
+ return "math8";
+
+ if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 ) )
+ return "StarOffice XML (Chart)";
+
+ if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
+ return "chart8";
+
+ return OUString();
+}
+
+void SvxMSDffManager::ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream)
+{
+ tools::SvRef<SotStorageStream> xStr
+ = rSrcStg.OpenSotStream("package_stream", StreamMode::STD_READ);
+ xStr->ReadStream(rMemStream);
+}
+
+css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags,
+ SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage,
+ const Graphic& rGrf,
+ const tools::Rectangle& rVisArea, OUString const& rBaseURL)
+{
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ SvGlobalName aStgNm = rSrcStg.GetClassName();
+ const char* pName = GetInternalServerName_Impl( aStgNm );
+ OUString sStarName;
+ if ( pName )
+ sStarName = OUString::createFromAscii( pName );
+ else if ( nConvertFlags )
+ {
+ static struct ObjImpType
+ {
+ sal_uInt32 nFlag;
+ const char* pFactoryNm;
+ // GlobalNameId
+ sal_uInt32 n1;
+ sal_uInt16 n2, n3;
+ sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
+ } const aArr[] = {
+ { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION3_CLASSID },
+ { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION2_CLASSID },
+ { OLE_WINWORD_2_STARWRITER, "swriter", MSO_WW8_CLASSID },
+ // Excel table
+ { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL5_CLASSID },
+ { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CLASSID },
+ // 114465: additional Excel OLE chart classId to above.
+ { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CHART_CLASSID },
+ // PowerPoint presentation
+ { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_CLASSID },
+ // PowerPoint slide
+ { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_SLIDE_CLASSID },
+ { 0, nullptr,
+ 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+ for( const ObjImpType* pArr = aArr; pArr->nFlag; ++pArr )
+ {
+ if( nConvertFlags & pArr->nFlag )
+ {
+ SvGlobalName aTypeName( pArr->n1, pArr->n2, pArr->n3,
+ pArr->b8, pArr->b9, pArr->b10, pArr->b11,
+ pArr->b12, pArr->b13, pArr->b14, pArr->b15 );
+
+ if ( aStgNm == aTypeName )
+ {
+ sStarName = OUString::createFromAscii( pArr->pFactoryNm );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( sStarName.getLength() )
+ {
+ //TODO/MBA: check if (and when) storage and stream will be destroyed!
+ std::shared_ptr<const SfxFilter> pFilter;
+ SvMemoryStream aMemStream;
+ if ( pName )
+ {
+ // TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also
+ SvxMSDffManager::ExtractOwnStream(rSrcStg, aMemStream);
+ }
+ else
+ {
+ tools::SvRef<SotStorage> xStorage = new SotStorage( false, aMemStream );
+ rSrcStg.CopyTo( xStorage.get() );
+ xStorage->Commit();
+ xStorage.clear();
+ OUString aType = SfxFilter::GetTypeFromStorage( rSrcStg );
+ if (aType.getLength() && !utl::ConfigManager::IsFuzzing())
+ {
+ SfxFilterMatcher aMatch( sStarName );
+ pFilter = aMatch.GetFilter4EA( aType );
+ }
+ }
+
+#ifdef DEBUG_FILTER_MSFILTER
+ // extract embedded ole streams into "/tmp/embedded_stream_NNN"
+ static sal_Int32 nOleCount(0);
+ OUString aTmpName("/tmp/embedded_stream_");
+ aTmpName += OUString::number(nOleCount++);
+ aTmpName += ".bin";
+ SvFileStream aTmpStream(aTmpName,StreamMode::READ|StreamMode::WRITE|StreamMode::TRUNC);
+ xMemStream->Seek(0);
+ aTmpStream.WriteStream(*xMemStream);
+ aTmpStream.Close();
+#endif
+ if ( pName || pFilter )
+ {
+ //Reuse current ole name
+ OUString aDstStgName = MSO_OLE_Obj + OUString::number(nMSOleObjCntr);
+
+ OUString aFilterName;
+ if ( pFilter )
+ aFilterName = pFilter->GetName();
+ else
+ aFilterName = SvxMSDffManager::GetFilterNameFromClassID( aStgNm );
+
+ uno::Sequence<beans::PropertyValue> aMedium(aFilterName.isEmpty() ? 3 : 4);
+ auto pMedium = aMedium.getArray();
+ pMedium[0].Name = "InputStream";
+ uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( aMemStream );
+ pMedium[0].Value <<= xStream;
+ pMedium[1].Name = "URL";
+ pMedium[1].Value <<= OUString( "private:stream" );
+ pMedium[2].Name = "DocumentBaseURL";
+ pMedium[2].Value <<= rBaseURL;
+
+ if ( !aFilterName.isEmpty() )
+ {
+ pMedium[3].Name = "FilterName";
+ pMedium[3].Value <<= aFilterName;
+ }
+
+ OUString aName( aDstStgName );
+ comphelper::EmbeddedObjectContainer aCnt( rDestStorage );
+ xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
+
+ if ( !xObj.is() )
+ {
+ if( !aFilterName.isEmpty() )
+ {
+ // throw the filter parameter away as workaround
+ aMedium.realloc( 2 );
+ xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
+ }
+
+ if ( !xObj.is() )
+ return xObj;
+ }
+
+ // JP 26.10.2001: Bug 93374 / 91928 the writer
+ // objects need the correct visarea needs the
+ // correct visarea, but this is not true for
+ // PowerPoint (see bugdoc 94908b)
+ // SJ: 19.11.2001 bug 94908, also chart objects
+ // needs the correct visarea
+
+ // If pName is set this is an own embedded object, it should have the correct size internally
+ // TODO/LATER: it might make sense in future to set the size stored in internal object
+ if( !pName && ( sStarName == "swriter" || sStarName == "scalc" ) )
+ {
+ // TODO/LATER: ViewAspect must be passed from outside!
+ sal_Int64 nViewAspect = embed::Aspects::MSOLE_CONTENT;
+ MapMode aMapMode( VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nViewAspect ) ) );
+ Size aSz;
+ if ( rVisArea.IsEmpty() )
+ aSz = lcl_GetPrefSize(rGrf, aMapMode );
+ else
+ {
+ aSz = rVisArea.GetSize();
+ aSz = OutputDevice::LogicToLogic( aSz, MapMode( MapUnit::Map100thMM ), aMapMode );
+ }
+
+ // don't modify the object
+ //TODO/LATER: remove those hacks, that needs to be done differently!
+ //xIPObj->EnableSetModified( sal_False );
+ awt::Size aSize;
+ aSize.Width = aSz.Width();
+ aSize.Height = aSz.Height();
+ xObj->setVisualAreaSize( nViewAspect, aSize );
+ //xIPObj->EnableSetModified( sal_True );
+ }
+ else if ( sStarName == "smath" )
+ { // SJ: force the object to recalc its visarea
+ //TODO/LATER: wait for PrinterChangeNotification
+ //xIPObj->OnDocumentPrinterChanged( NULL );
+ }
+ }
+ }
+
+ return xObj;
+}
+
+// TODO/MBA: code review and testing!
+SdrOle2Obj* SvxMSDffManager::CreateSdrOLEFromStorage(
+ SdrModel& rSdrModel,
+ const OUString& rStorageName,
+ tools::SvRef<SotStorage> const & rSrcStorage,
+ const uno::Reference < embed::XStorage >& xDestStorage,
+ const Graphic& rGrf,
+ const tools::Rectangle& rBoundRect,
+ const tools::Rectangle& rVisArea,
+ SvStream* pDataStrm,
+ ErrCode& rError,
+ sal_uInt32 nConvertFlags,
+ sal_Int64 nRecommendedAspect,
+ OUString const& rBaseURL)
+{
+ sal_Int64 nAspect = nRecommendedAspect;
+ SdrOle2Obj* pRet = nullptr;
+ if( rSrcStorage.is() && xDestStorage.is() && rStorageName.getLength() )
+ {
+ comphelper::EmbeddedObjectContainer aCnt( xDestStorage );
+ // does the 01Ole-Stream exist at all?
+ // (that's not the case for e.g. Fontwork )
+ // If that's not the case -> include it as graphic
+ bool bValidStorage = false;
+ OUString aDstStgName = MSO_OLE_Obj + OUString::number( ++nMSOleObjCntr );
+
+ {
+ tools::SvRef<SotStorage> xObjStg = rSrcStorage->OpenSotStorage( rStorageName );
+ if( xObjStg.is() )
+ {
+ {
+ sal_uInt8 aTestA[10]; // exist the \1CompObj-Stream ?
+ tools::SvRef<SotStorageStream> xSrcTst = xObjStg->OpenSotStream( "\1CompObj" );
+ bValidStorage = xSrcTst.is() && sizeof( aTestA ) ==
+ xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
+ if( !bValidStorage )
+ {
+ // or the \1Ole-Stream ?
+ xSrcTst = xObjStg->OpenSotStream( "\1Ole" );
+ bValidStorage = xSrcTst.is() && sizeof(aTestA) ==
+ xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
+ }
+ }
+
+ if( bValidStorage )
+ {
+ if ( nAspect != embed::Aspects::MSOLE_ICON )
+ {
+ // check whether the object is iconified one
+ // usually this information is already known, the only exception
+ // is a kind of embedded objects in Word documents
+ // TODO/LATER: should the caller be notified if the aspect changes in future?
+
+ tools::SvRef<SotStorageStream> xObjInfoSrc = xObjStg->OpenSotStream(
+ "\3ObjInfo", StreamMode::STD_READ );
+ if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
+ {
+ sal_uInt8 nByte = 0;
+ xObjInfoSrc->ReadUChar( nByte );
+ if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
+ nAspect = embed::Aspects::MSOLE_ICON;
+ }
+ }
+
+ uno::Reference < embed::XEmbeddedObject > xObj( CheckForConvertToSOObj(
+ nConvertFlags, *xObjStg, xDestStorage, rGrf,
+ rVisArea, rBaseURL));
+ if ( xObj.is() )
+ {
+ // remember file name to use in the title bar
+ INetURLObject aURL(rBaseURL);
+ xObj->setContainerName(aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset));
+
+ svt::EmbeddedObjectRef aObj( xObj, nAspect );
+
+ // TODO/LATER: need MediaType
+ aObj.SetGraphic( rGrf, OUString() );
+
+ // TODO/MBA: check setting of PersistName
+ pRet = new SdrOle2Obj(
+ rSdrModel,
+ aObj,
+ OUString(),
+ rBoundRect);
+
+ // we have the Object, don't create another
+ bValidStorage = false;
+ }
+ }
+ }
+ }
+
+ if( bValidStorage )
+ {
+ // object is not an own object
+ tools::SvRef<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName, StreamMode::READWRITE );
+
+ if ( xObjStor.is() )
+ {
+ tools::SvRef<SotStorage> xSrcStor = rSrcStorage->OpenSotStorage( rStorageName, StreamMode::READ );
+ xSrcStor->CopyTo( xObjStor.get() );
+
+ if( !xObjStor->GetError() )
+ xObjStor->Commit();
+
+ if( xObjStor->GetError() )
+ {
+ rError = xObjStor->GetError();
+ bValidStorage = false;
+ }
+ else if( !xObjStor.is() )
+ bValidStorage = false;
+ }
+ }
+ else if( pDataStrm )
+ {
+ sal_uInt32 nLen(0), nDummy(0);
+ pDataStrm->ReadUInt32( nLen ).ReadUInt32( nDummy );
+ if( ERRCODE_NONE != pDataStrm->GetError() ||
+ // Id in BugDoc - exist there other Ids?
+ // The ConvertToOle2 - does not check for consistent
+ 0x30008 != nDummy )
+ bValidStorage = false;
+ else
+ {
+ // or is it an OLE-1 Stream in the DataStream?
+ tools::SvRef<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName );
+ //TODO/MBA: remove metafile conversion from ConvertToOle2
+ //when is this code used?!
+ GDIMetaFile aMtf;
+ bValidStorage = ConvertToOle2( *pDataStrm, nLen, &aMtf, xObjStor );
+ xObjStor->Commit();
+ }
+ }
+
+ if( bValidStorage )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj = aCnt.GetEmbeddedObject( aDstStgName );
+ if( xObj.is() )
+ {
+ // remember file name to use in the title bar
+ INetURLObject aURL( rBaseURL );
+ xObj->setContainerName( aURL.GetLastName( INetURLObject::DecodeMechanism::WithCharset ) );
+
+ // the visual area must be retrieved from the metafile (object doesn't know it so far)
+
+ if ( nAspect != embed::Aspects::MSOLE_ICON )
+ {
+ // working with visual area can switch the object to running state
+ try
+ {
+ awt::Size aAwtSz;
+ // the provided visual area should be used, if there is any
+ if ( rVisArea.IsEmpty() )
+ {
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+ Size aSz(lcl_GetPrefSize(rGrf, MapMode(aMapUnit)));
+ aAwtSz.Width = aSz.Width();
+ aAwtSz.Height = aSz.Height();
+ }
+ else
+ {
+ aAwtSz.Width = rVisArea.GetWidth();
+ aAwtSz.Height = rVisArea.GetHeight();
+ }
+ //xInplaceObj->EnableSetModified( sal_False );
+ xObj->setVisualAreaSize( nAspect, aAwtSz );
+ //xInplaceObj->EnableSetModified( sal_True );
+ }
+ catch( const uno::Exception& )
+ {
+ OSL_FAIL( "Could not set visual area of the object!" );
+ }
+ }
+
+ svt::EmbeddedObjectRef aObj( xObj, nAspect );
+
+ // TODO/LATER: need MediaType
+ aObj.SetGraphic( rGrf, OUString() );
+
+ pRet = new SdrOle2Obj(
+ rSdrModel,
+ aObj,
+ aDstStgName,
+ rBoundRect);
+ }
+ }
+ }
+
+ return pRet;
+}
+
+bool SvxMSDffManager::SetPropValue( const uno::Any& rAny, const uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ const OUString& rPropName )
+{
+ bool bRetValue = false;
+ try
+ {
+ uno::Reference< beans::XPropertySetInfo >
+ aXPropSetInfo( rXPropSet->getPropertySetInfo() );
+ if ( aXPropSetInfo.is() )
+ bRetValue = aXPropSetInfo->hasPropertyByName( rPropName );
+ }
+ catch( const uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ if ( bRetValue )
+ {
+ try
+ {
+ rXPropSet->setPropertyValue( rPropName, rAny );
+ bRetValue = true;
+ }
+ catch( const uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ return bRetValue;
+}
+
+SvxMSDffImportRec::SvxMSDffImportRec()
+ : pObj( nullptr ),
+ nClientAnchorLen( 0 ),
+ nClientDataLen( 0 ),
+ nXAlign( 0 ), // position n cm from left
+ nYAlign( 0 ), // position n cm below
+ nGroupShapeBooleanProperties(0), // 16 settings: LayoutInCell/AllowOverlap/BehindDocument...
+ nFlags( ShapeFlag::NONE ),
+ nDxTextLeft( 144 ),
+ nDyTextTop( 72 ),
+ nDxTextRight( 144 ),
+ nDyTextBottom( 72 ),
+ nDxWrapDistLeft( 0 ),
+ nDyWrapDistTop( 0 ),
+ nDxWrapDistRight( 0 ),
+ nDyWrapDistBottom(0 ),
+ nCropFromTop( 0 ),
+ nCropFromBottom( 0 ),
+ nCropFromLeft( 0 ),
+ nCropFromRight( 0 ),
+ nNextShapeId( 0 ),
+ nShapeId( 0 ),
+ eShapeType( mso_sptNil ),
+ relativeHorizontalWidth( -1 ),
+ isHorizontalRule( false )
+{
+ eLineStyle = mso_lineSimple; // GPF-Bug #66227#
+ eLineDashing = mso_lineSolid;
+ bDrawHell = false;
+ bHidden = false;
+
+ bReplaceByFly = false;
+ bVFlip = false;
+ bHFlip = false;
+ bAutoWidth = false;
+}
+
+SvxMSDffImportRec::SvxMSDffImportRec(const SvxMSDffImportRec& rCopy)
+ : pObj( rCopy.pObj ),
+ nXAlign( rCopy.nXAlign ),
+ nXRelTo( rCopy.nXRelTo ),
+ nYAlign( rCopy.nYAlign ),
+ nYRelTo( rCopy.nYRelTo ),
+ nGroupShapeBooleanProperties(rCopy.nGroupShapeBooleanProperties),
+ nFlags( rCopy.nFlags ),
+ nDxTextLeft( rCopy.nDxTextLeft ),
+ nDyTextTop( rCopy.nDyTextTop ),
+ nDxTextRight( rCopy.nDxTextRight ),
+ nDyTextBottom( rCopy.nDyTextBottom ),
+ nDxWrapDistLeft( rCopy.nDxWrapDistLeft ),
+ nDyWrapDistTop( rCopy.nDyWrapDistTop ),
+ nDxWrapDistRight( rCopy.nDxWrapDistRight ),
+ nDyWrapDistBottom(rCopy.nDyWrapDistBottom ),
+ nCropFromTop( rCopy.nCropFromTop ),
+ nCropFromBottom( rCopy.nCropFromBottom ),
+ nCropFromLeft( rCopy.nCropFromLeft ),
+ nCropFromRight( rCopy.nCropFromRight ),
+ aTextId( rCopy.aTextId ),
+ nNextShapeId( rCopy.nNextShapeId ),
+ nShapeId( rCopy.nShapeId ),
+ eShapeType( rCopy.eShapeType ),
+ relativeHorizontalWidth( rCopy.relativeHorizontalWidth ),
+ isHorizontalRule( rCopy.isHorizontalRule )
+{
+ eLineStyle = rCopy.eLineStyle; // GPF-Bug #66227#
+ eLineDashing = rCopy.eLineDashing;
+ bDrawHell = rCopy.bDrawHell;
+ bHidden = rCopy.bHidden;
+ bReplaceByFly = rCopy.bReplaceByFly;
+ bAutoWidth = rCopy.bAutoWidth;
+ bVFlip = rCopy.bVFlip;
+ bHFlip = rCopy.bHFlip;
+ nClientAnchorLen = rCopy.nClientAnchorLen;
+ if( rCopy.nClientAnchorLen )
+ {
+ pClientAnchorBuffer.reset( new char[ nClientAnchorLen ] );
+ memcpy( pClientAnchorBuffer.get(),
+ rCopy.pClientAnchorBuffer.get(),
+ nClientAnchorLen );
+ }
+ else
+ pClientAnchorBuffer = nullptr;
+
+ nClientDataLen = rCopy.nClientDataLen;
+ if( rCopy.nClientDataLen )
+ {
+ pClientDataBuffer.reset( new char[ nClientDataLen ] );
+ memcpy( pClientDataBuffer.get(),
+ rCopy.pClientDataBuffer.get(),
+ nClientDataLen );
+ }
+ else
+ pClientDataBuffer = nullptr;
+
+ if (rCopy.pWrapPolygon)
+ pWrapPolygon = rCopy.pWrapPolygon;
+}
+
+SvxMSDffImportRec::~SvxMSDffImportRec()
+{
+}
+
+void SvxMSDffManager::insertShapeId( sal_Int32 nShapeId, SdrObject* pShape )
+{
+ maShapeIdContainer[nShapeId] = pShape;
+}
+
+void SvxMSDffManager::removeShapeId( SdrObject const * pShape )
+{
+ SvxMSDffShapeIdContainer::iterator aIter = std::find_if(maShapeIdContainer.begin(), maShapeIdContainer.end(),
+ [&pShape](const SvxMSDffShapeIdContainer::value_type& rEntry) { return rEntry.second == pShape; });
+ if (aIter != maShapeIdContainer.end())
+ maShapeIdContainer.erase( aIter );
+}
+
+SdrObject* SvxMSDffManager::getShapeForId( sal_Int32 nShapeId )
+{
+ SvxMSDffShapeIdContainer::iterator aIter( maShapeIdContainer.find(nShapeId) );
+ return aIter != maShapeIdContainer.end() ? (*aIter).second : nullptr;
+}
+
+SvxMSDffImportData::SvxMSDffImportData(const tools::Rectangle& rParentRect)
+ : aParentRect(rParentRect)
+{
+}
+
+SvxMSDffImportData::~SvxMSDffImportData()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/msfilter.component b/filter/source/msfilter/msfilter.component
new file mode 100644
index 000000000..0e1a35ee4
--- /dev/null
+++ b/filter/source/msfilter/msfilter.component
@@ -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 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.vba.VBAMacroResolver"
+ constructor="filter_VBAMacroResolver_get_implementation">
+ <service name="com.sun.star.script.vba.VBAMacroResolver"/>
+ </implementation>
+</component>
diff --git a/filter/source/msfilter/msocximex.cxx b/filter/source/msfilter/msocximex.cxx
new file mode 100644
index 000000000..e3ccf6524
--- /dev/null
+++ b/filter/source/msfilter/msocximex.cxx
@@ -0,0 +1,146 @@
+/* -*- 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/.
+ *
+ * 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 <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <osl/diagnose.h>
+#include <filter/msfilter/msocximex.hxx>
+#include <utility>
+
+using namespace ::com::sun::star;
+
+constexpr OUStringLiteral sWW8_form( u"WW-Standard" );
+
+SvxMSConvertOCXControls::SvxMSConvertOCXControls( uno::Reference< frame::XModel > xModel) : mxModel(std::move(xModel))
+{
+}
+
+SvxMSConvertOCXControls::~SvxMSConvertOCXControls()
+{
+}
+
+void SvxMSConvertOCXControls::GetDrawPage()
+{
+ if( !xDrawPage.is() && mxModel.is() )
+ {
+ uno::Reference< drawing::XDrawPageSupplier > xTxtDoc(mxModel,
+ uno::UNO_QUERY);
+ OSL_ENSURE(xTxtDoc.is(),"no XDrawPageSupplier from XModel");
+ xDrawPage = xTxtDoc->getDrawPage();
+ OSL_ENSURE( xDrawPage.is(), "no XDrawPage" );
+ }
+}
+
+
+const uno::Reference< lang::XMultiServiceFactory >&
+ SvxMSConvertOCXControls::GetServiceFactory()
+{
+ if( !xServiceFactory.is() && mxModel.is() )
+ {
+ xServiceFactory = uno::Reference< lang::XMultiServiceFactory >
+ (mxModel, uno::UNO_QUERY);
+ OSL_ENSURE( xServiceFactory.is(),
+ "no XMultiServiceFactory from doc Model" );
+ }
+
+ return xServiceFactory;
+}
+
+const uno::Reference< drawing::XShapes >& SvxMSConvertOCXControls::GetShapes()
+{
+ if( !xShapes.is() )
+ {
+ GetDrawPage();
+ if( xDrawPage.is() )
+ {
+ xShapes = xDrawPage;
+ }
+ }
+ return xShapes;
+}
+
+const uno::Reference< container::XIndexContainer >&
+ SvxMSConvertOCXControls::GetFormComps()
+{
+ if( !xFormComps.is() )
+ {
+ GetDrawPage();
+ if( xDrawPage.is() )
+ {
+ uno::Reference< form::XFormsSupplier > xFormsSupplier( xDrawPage,
+ uno::UNO_QUERY );
+ OSL_ENSURE( xFormsSupplier.is(),
+ "UNO_QUERY failed for XFormsSupplier from XDrawPage" );
+
+ uno::Reference< container::XNameContainer > xNameCont =
+ xFormsSupplier->getForms();
+
+ // The form gets a new name like "WW-Standard[n]" and will
+ // created new in any case.
+ OUString sName( sWW8_form );
+ sal_uInt16 n = 0;
+
+ while( xNameCont->hasByName( sName ) )
+ {
+ sName = sWW8_form + OUString::number( ++n );
+ }
+
+ const uno::Reference< lang::XMultiServiceFactory > &rServiceFactory
+ = GetServiceFactory();
+ if( !rServiceFactory.is() )
+ return xFormComps;
+
+ uno::Reference< uno::XInterface > xCreate =
+ rServiceFactory->createInstance(
+ "com.sun.star.form.component.Form" );
+ if( xCreate.is() )
+ {
+ uno::Reference< beans::XPropertySet > xFormPropSet( xCreate,
+ uno::UNO_QUERY );
+
+ uno::Any aTmp(&sName,cppu::UnoType<OUString>::get());
+ xFormPropSet->setPropertyValue( "Name", aTmp );
+
+ uno::Reference< form::XForm > xForm( xCreate, uno::UNO_QUERY );
+ OSL_ENSURE(xForm.is(), "no Form?");
+
+ uno::Reference< container::XIndexContainer > xForms( xNameCont,
+ uno::UNO_QUERY );
+ OSL_ENSURE( xForms.is(), "XForms not available" );
+
+ aTmp <<= xForm;
+ xForms->insertByIndex( xForms->getCount(), aTmp );
+
+ xFormComps = uno::Reference< container::XIndexContainer >
+ (xCreate, uno::UNO_QUERY);
+ }
+ }
+ }
+
+ return xFormComps;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/msoleexp.cxx b/filter/source/msfilter/msoleexp.cxx
new file mode 100644
index 000000000..9e68e5cb0
--- /dev/null
+++ b/filter/source/msfilter/msoleexp.cxx
@@ -0,0 +1,340 @@
+/* -*- 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/.
+ *
+ * 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 <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <comphelper/classids.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sot/formats.hxx>
+#include <sot/storage.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/fileformat.h>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <svtools/embedhlp.hxx>
+#include <filter/msfilter/msdffimp.hxx>
+
+#include <filter/msfilter/msoleexp.hxx>
+
+using namespace ::com::sun::star;
+
+static SvGlobalName GetEmbeddedVersion( const SvGlobalName& aAppName )
+{
+ if ( aAppName == SvGlobalName( SO3_SM_CLASSID_60 ) )
+ return SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 );
+ else if ( aAppName == SvGlobalName( SO3_SW_CLASSID_60 ) )
+ return SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 );
+ else if ( aAppName == SvGlobalName( SO3_SC_CLASSID_60 ) )
+ return SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 );
+ else if ( aAppName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) )
+ return SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 );
+ else if ( aAppName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) )
+ return SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 );
+ else if ( aAppName == SvGlobalName( SO3_SCH_CLASSID_60 ) )
+ return SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 );
+
+ return SvGlobalName();
+}
+
+static OUString GetStorageType( const SvGlobalName& aEmbName )
+{
+ if ( aEmbName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
+ return "LibreOffice.MathDocument.1";
+ else if ( aEmbName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
+ return "LibreOffice.WriterDocument.1";
+ else if ( aEmbName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
+ return "LibreOffice.CalcDocument.1";
+ else if ( aEmbName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
+ return "LibreOffice.DrawDocument.1";
+ else if ( aEmbName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
+ return "LibreOffice.ImpressDocument.1";
+ else if ( aEmbName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
+ return "LibreOffice.ChartDocument.1";
+ return OUString();
+}
+
+static bool UseOldMSExport()
+{
+ uno::Reference< lang::XMultiServiceFactory > xProvider(
+ configuration::theDefaultProvider::get(
+ comphelper::getProcessComponentContext()));
+ try {
+ uno::Sequence< uno::Any > aArg{ uno::Any(
+ OUString( "/org.openoffice.Office.Common/InternalMSExport" )) };
+ uno::Reference< container::XNameAccess > xNameAccess(
+ xProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationUpdateAccess",
+ aArg ),
+ uno::UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ uno::Any aResult = xNameAccess->getByName( "UseOldExport" );
+
+ bool bResult;
+ if ( aResult >>= bResult )
+ return bResult;
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ OSL_FAIL( "Could not get access to configuration entry!" );
+ return false;
+}
+
+void SvxMSExportOLEObjects::ExportOLEObject( const css::uno::Reference < css::embed::XEmbeddedObject>& rObj, SotStorage& rDestStg )
+{
+ svt::EmbeddedObjectRef aObj( rObj, embed::Aspects::MSOLE_CONTENT );
+ ExportOLEObject( aObj, rDestStg );
+}
+
+void SvxMSExportOLEObjects::ExportOLEObject( svt::EmbeddedObjectRef const & rObj, SotStorage& rDestStg )
+{
+ SvGlobalName aOwnGlobalName;
+ SvGlobalName aObjName( rObj->getClassID() );
+ std::shared_ptr<const SfxFilter> pExpFilter;
+ {
+ static struct ObjExpType {
+ sal_uInt32 nFlag;
+ const char* pFilterNm;
+ // GlobalNameId
+ struct GlobalNameIds {
+ sal_uInt32 n1;
+ sal_uInt16 n2, n3;
+ sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
+ }
+ aGlNmIds[4];
+ } const aArr[] = {
+ { OLE_STARMATH_2_MATHTYPE, "MathType 3.x",
+ {{SO3_SM_CLASSID_60}, {SO3_SM_CLASSID_50},
+ {SO3_SM_CLASSID_40}, {SO3_SM_CLASSID_30 }}},
+ { OLE_STARWRITER_2_WINWORD, "MS Word 97",
+ {{SO3_SW_CLASSID_60}, {SO3_SW_CLASSID_50},
+ {SO3_SW_CLASSID_40}, {SO3_SW_CLASSID_30 }}},
+ { OLE_STARCALC_2_EXCEL, "MS Excel 97",
+ {{SO3_SC_CLASSID_60}, {SO3_SC_CLASSID_50},
+ {SO3_SC_CLASSID_40}, {SO3_SC_CLASSID_30 }}},
+ { OLE_STARIMPRESS_2_POWERPOINT, "MS PowerPoint 97",
+ {{SO3_SIMPRESS_CLASSID_60}, {SO3_SIMPRESS_CLASSID_50},
+ {SO3_SIMPRESS_CLASSID_40}, {SO3_SIMPRESS_CLASSID_30 }}},
+ { 0, "",
+ {{SO3_SCH_CLASSID_60}, {SO3_SCH_CLASSID_50},
+ {SO3_SCH_CLASSID_40}, {SO3_SCH_CLASSID_30 }}},
+ { 0, "",
+ {{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}, // SJ: !!!! SO3_SDRAW_CLASSID is only available up from
+ {SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50 }}}, // ver 5.0, it is purpose to have double entries here.
+
+ { 0xffff,nullptr,
+ {{SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50},
+ {SO3_SDRAW_CLASSID_60}, {SO3_SDRAW_CLASSID_50}}}
+ };
+
+ for( const ObjExpType* pArr = aArr; !pExpFilter && ( pArr->nFlag != 0xffff ); ++pArr )
+ {
+ for (const ObjExpType::GlobalNameIds& rId : pArr->aGlNmIds)
+ {
+ SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3,
+ rId.b8, rId.b9, rId.b10, rId.b11,
+ rId.b12, rId.b13, rId.b14, rId.b15 );
+ if( aObjName == aGlbNm )
+ {
+ aOwnGlobalName = aGlbNm;
+
+ // flags for checking if conversion is wanted at all (SaveOptions?!)
+ if( nConvertFlags & pArr->nFlag )
+ {
+ pExpFilter = SfxFilterMatcher().GetFilter4FilterName(OUString::createFromAscii(pArr->pFilterNm));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if( pExpFilter ) // use this filter for the export
+ {
+ try
+ {
+ if ( rObj->getCurrentState() == embed::EmbedStates::LOADED )
+ rObj->changeState( embed::EmbedStates::RUNNING );
+ //TODO/LATER: is stream instead of outputstream a better choice?!
+ //TODO/LATER: a "StoreTo" method at embedded object would be nice
+ SvStream* pStream = new SvMemoryStream;
+ ::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *pStream );
+ uno::Sequence < beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue("OutputStream", xOut),
+ comphelper::makePropertyValue("FilterName", pExpFilter->GetName())
+ };
+ uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY );
+ try
+ {
+ xStor->storeToURL( "private:stream", aSeq );
+ }
+ catch( const uno::Exception& ) {} // #TODO really handle exceptions - interactionalhandler etc. ?
+
+ tools::SvRef<SotStorage> xOLEStor = new SotStorage( pStream, true );
+ xOLEStor->CopyTo( &rDestStg );
+ rDestStg.Commit();
+ }
+ catch( const uno::Exception& )
+ {
+ // TODO/LATER: Error handling
+ OSL_FAIL( "The object could not be exported!" );
+ }
+ }
+ else if( aOwnGlobalName != SvGlobalName() )
+ {
+ // own format, maybe SO6 format or lower
+ SvGlobalName aEmbName = GetEmbeddedVersion( aOwnGlobalName );
+ if ( aEmbName != SvGlobalName() && !UseOldMSExport() )
+ {
+ // this is a SO6 embedded object, save in old binary format
+ rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 );
+ rDestStg.SetClass( aEmbName,
+ SotClipboardFormatId::EMBEDDED_OBJ_OLE,
+ GetStorageType( aEmbName ) );
+ tools::SvRef<SotStorageStream> xExtStm = rDestStg.OpenSotStream(
+ "properties_stream");
+
+ bool bExtentSuccess = false;
+ if( !xExtStm->GetError() )
+ {
+ // write extent
+ //TODO/MBA: check if writing a size is enough
+ if( rObj.GetObject().is() )
+ {
+ // MSOLE objects don't need to be in running state for VisualArea access
+ awt::Size aSize;
+ try
+ {
+ // this is an own object, the content size must be stored in the
+ // extension stream
+ aSize = rObj->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT );
+ }
+ catch( const embed::NoVisualAreaSizeException& )
+ {
+ OSL_FAIL( "Could not get visual area size!" );
+ aSize.Width = 5000;
+ aSize.Height = 5000;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION(
+ "filter.ms", "Unexpected exception while getting visual area size!");
+ aSize.Width = 5000;
+ aSize.Height = 5000;
+ }
+
+ sal_Int32 pRect[4];
+ pRect[0] = 0;
+ pRect[1] = aSize.Width;
+ pRect[2] = 0;
+ pRect[3] = aSize.Height;
+
+ sal_Int8 aWriteSet[16];
+ for ( int ind = 0; ind < 4; ind++ )
+ {
+ sal_Int32 nVal = pRect[ind];
+ for ( int nByte = 0; nByte < 4; nByte++ )
+ {
+ aWriteSet[ind*4+nByte] = static_cast<sal_Int8>(nVal) % 0x100;
+ nVal /= 0x100;
+ }
+ }
+
+ bExtentSuccess = (xExtStm->WriteBytes(aWriteSet, 16) == 16);
+ }
+ }
+
+ if ( bExtentSuccess )
+ {
+ tools::SvRef<SotStorageStream> xEmbStm = rDestStg.OpenSotStream(
+ "package_stream");
+ if( !xEmbStm->GetError() )
+ {
+ try
+ {
+ if ( rObj->getCurrentState() == embed::EmbedStates::LOADED )
+ rObj->changeState( embed::EmbedStates::RUNNING );
+ //TODO/LATER: is stream instead of outputstream a better choice?!
+ //TODO/LATER: a "StoreTo" method at embedded object would be nice
+ ::uno::Reference < io::XOutputStream > xOut = new ::utl::OOutputStreamWrapper( *xEmbStm );
+ uno::Sequence < beans::PropertyValue > aSeq{ comphelper::makePropertyValue(
+ "OutputStream", xOut) };
+ uno::Reference < frame::XStorable > xStor( rObj->getComponent(), uno::UNO_QUERY );
+ xStor->storeToURL( "private:stream", aSeq );
+ }
+ catch( const uno::Exception& )
+ {
+ // TODO/LATER: Error handling
+ OSL_FAIL( "The object could not be exported!" );
+ }
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("Own binary format inside own container document!");
+ }
+ }
+ else
+ {
+ // alien objects
+ //TODO/LATER: a "StoreTo" method at embedded object would be nice
+ rDestStg.SetVersion( SOFFICE_FILEFORMAT_31 );
+ uno::Reference < embed::XStorage > xStor = ::comphelper::OStorageHelper::GetTemporaryStorage();
+ uno::Reference < embed::XEmbedPersist > xPers( rObj.GetObject(), uno::UNO_QUERY );
+ if ( xPers.is() )
+ {
+ uno::Sequence < beans::PropertyValue > aEmptySeq;
+ OUString aTempName( "bla" );
+ try
+ {
+ xPers->storeToEntry( xStor, aTempName, aEmptySeq, aEmptySeq );
+ }
+ catch ( const uno::Exception& )
+ {}
+
+ tools::SvRef<SotStorage> xOLEStor = SotStorage::OpenOLEStorage( xStor, aTempName, StreamMode::STD_READ );
+ xOLEStor->CopyTo( &rDestStg );
+ rDestStg.Commit();
+ }
+ }
+
+ //We never need this stream: See #99809# and #i2179#
+ rDestStg.Remove( SVEXT_PERSIST_STREAM );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/mstoolbar.cxx b/filter/source/msfilter/mstoolbar.cxx
new file mode 100644
index 000000000..aa781c471
--- /dev/null
+++ b/filter/source/msfilter/mstoolbar.cxx
@@ -0,0 +1,824 @@
+/* -*- 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 <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <filter/msfilter/mstoolbar.hxx>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XUIConfigurationPersistence.hpp>
+#include <com/sun/star/ui/XImageManager.hpp>
+#include <com/sun/star/ui/ImageType.hpp>
+#include <com/sun/star/ui/ItemType.hpp>
+#include <com/sun/star/ui/ItemStyle.hpp>
+#include <utility>
+#include <vcl/dibtools.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/bitmapex.hxx>
+#include <sfx2/objsh.hxx>
+#include <filter/msfilter/msvbahelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+
+using namespace com::sun::star;
+
+int TBBase::nIndent = 0;
+
+void CustomToolBarImportHelper::ScaleImage( uno::Reference< graphic::XGraphic >& xGraphic, tools::Long nNewSize )
+{
+ Graphic aGraphic( xGraphic );
+ Size aSize = aGraphic.GetSizePixel();
+ if ( aSize.Height() && ( aSize.Height() == aSize.Width() ) )
+ {
+ Graphic aImage(xGraphic);
+ if ( aSize.Height() != nNewSize )
+ {
+ BitmapEx aBitmap = aImage.GetBitmapEx();
+ BitmapEx aBitmapex = BitmapEx::AutoScaleBitmap(aBitmap, nNewSize );
+ aImage = Graphic(aBitmapex);
+ xGraphic = aImage.GetXGraphic();
+ }
+ }
+}
+
+void CustomToolBarImportHelper::applyIcons()
+{
+ for (auto const& concommand : iconcommands)
+ {
+ uno::Sequence<OUString> commands { concommand.sCommand };
+ uno::Sequence< uno::Reference< graphic::XGraphic > > images { concommand.image };
+ auto pimages = images.getArray();
+
+ uno::Reference< ui::XImageManager > xImageManager( getCfgManager()->getImageManager(), uno::UNO_QUERY_THROW );
+ sal_uInt16 nColor = ui::ImageType::COLOR_NORMAL;
+
+ vcl::Window* topwin = Application::GetActiveTopWindow();
+ if ( topwin != nullptr && topwin->GetBackgroundColor().IsDark() )
+ nColor = css::ui::ImageType::COLOR_HIGHCONTRAST;
+
+ ScaleImage( pimages[ 0 ], 16 );
+ xImageManager->replaceImages( ui::ImageType::SIZE_DEFAULT | nColor, commands, images );
+ ScaleImage( pimages[ 0 ], 26 );
+ xImageManager->replaceImages( ui::ImageType::SIZE_LARGE | nColor, commands, images );
+ }
+}
+
+void CustomToolBarImportHelper::addIcon( const uno::Reference< graphic::XGraphic >& xImage, const OUString& sString )
+{
+ iconcontrolitem item;
+ item.sCommand = sString;
+ item.image = xImage;
+ iconcommands.push_back( item );
+}
+
+CustomToolBarImportHelper::CustomToolBarImportHelper( SfxObjectShell& rDocShell, const css::uno::Reference< css::ui::XUIConfigurationManager>& rxAppCfgMgr ) : mrDocSh( rDocShell )
+{
+ m_xCfgSupp.set( mrDocSh.GetModel(), uno::UNO_QUERY_THROW );
+ m_xAppCfgMgr.set( rxAppCfgMgr, uno::UNO_SET_THROW );
+}
+
+uno::Reference< ui::XUIConfigurationManager >
+CustomToolBarImportHelper::getCfgManager()
+{
+ return m_xCfgSupp->getUIConfigurationManager();
+}
+
+
+uno::Any
+CustomToolBarImportHelper::createCommandFromMacro( std::u16string_view sCmd )
+{
+ //"vnd.sun.star.script:Standard.Module1.Main?language=Basic&location=document"
+ // create script url
+ OUString scriptURL
+ = OUString::Concat("vnd.sun.star.script:") + sCmd + "?language=Basic&location=document";
+ return uno::Any( scriptURL );
+}
+
+OUString CustomToolBarImportHelper::MSOCommandToOOCommand( sal_Int16 msoCmd )
+{
+ OUString result;
+ if (pMSOCmdConvertor)
+ result = pMSOCmdConvertor->MSOCommandToOOCommand( msoCmd );
+ return result;
+}
+
+OUString CustomToolBarImportHelper::MSOTCIDToOOCommand( sal_Int16 msoTCID )
+{
+ OUString result;
+ if (pMSOCmdConvertor)
+ result = pMSOCmdConvertor->MSOTCIDToOOCommand( msoTCID );
+ return result;
+}
+
+bool
+CustomToolBarImportHelper::createMenu( const OUString& rName, const uno::Reference< container::XIndexAccess >& xMenuDesc )
+{
+ bool bRes = true;
+ try
+ {
+ uno::Reference< ui::XUIConfigurationManager > xCfgManager( getCfgManager() );
+ OUString sMenuBar = "private:resource/menubar/" + rName;
+ uno::Reference< container::XIndexContainer > xPopup( xCfgManager->createSettings(), uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xProps( xPopup, uno::UNO_QUERY_THROW );
+ // set name for menubar
+ xProps->setPropertyValue("UIName", uno::Any( rName ) );
+ if ( xPopup.is() )
+ {
+ uno::Sequence< beans::PropertyValue > aPopupMenu{
+ comphelper::makePropertyValue("CommandURL", "vnd.openoffice.org:" + rName),
+ comphelper::makePropertyValue("Label", rName),
+ comphelper::makePropertyValue("ItemDescriptorContainer", xMenuDesc),
+ comphelper::makePropertyValue("Type", sal_Int32( 0 ))
+ };
+
+ xPopup->insertByIndex( xPopup->getCount(), uno::Any( aPopupMenu ) );
+ xCfgManager->insertSettings( sMenuBar, xPopup );
+ uno::Reference< ui::XUIConfigurationPersistence > xPersistence( xCfgManager, uno::UNO_QUERY_THROW );
+ xPersistence->store();
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ bRes = false;
+ }
+ return bRes;
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void TBBase::indent_printf( FILE* fp, const char* format, ... )
+{
+ va_list ap;
+ va_start ( ap, format );
+
+ // indent nIndent spaces
+ for ( int i=0; i<nIndent; ++i)
+ fprintf(fp," ");
+ // append the rest of the message
+ vfprintf( fp, format, ap );
+ va_end( ap );
+}
+#endif
+
+TBCHeader::TBCHeader()
+ : bSignature(0x3)
+ , bVersion(0x01)
+ , bFlagsTCR(0)
+ , tct(0x1) // default to Button
+ , tcid(0)
+ , tbct(0)
+ , bPriority(0)
+{
+}
+
+TBCHeader::~TBCHeader()
+{
+}
+
+bool TBCHeader::Read( SvStream &rS )
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadSChar( bSignature ).ReadSChar( bVersion ).ReadUChar( bFlagsTCR ).ReadUChar( tct ).ReadUInt16( tcid ).ReadUInt32( tbct ).ReadUChar( bPriority );
+ // bit 4 ( from lsb )
+ if ( bFlagsTCR & 0x10 )
+ {
+ width = std::make_shared<sal_uInt16>();
+ height = std::make_shared<sal_uInt16>();
+ rS.ReadUInt16( *width ).ReadUInt16( *height );
+ }
+ return true;
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void TBCHeader::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf(fp,"[ 0x%x ] TBCHeader -- dump\n", nOffSet );
+ indent_printf(fp," bSignature 0x%x\n", bSignature );
+ indent_printf(fp," bVersion 0x%x\n", bVersion );
+ indent_printf(fp," bFlagsTCR 0x%x\n", bFlagsTCR );
+ indent_printf(fp," tct 0x%x\n", tct );
+ indent_printf(fp," tcid 0x%x\n", tcid );
+ indent_printf(fp," tbct 0x%x\n", static_cast< unsigned int >( tbct ));
+ indent_printf(fp," bPriority 0x%x\n", bPriority );
+ if ( width.get() )
+ indent_printf(fp," width %d(0x%x)\n", *width, *width);
+ if ( height.get() )
+ indent_printf(fp," height %d(0x%x)\n", *height, *height);
+}
+#endif
+
+TBCData::TBCData( TBCHeader Header ) : rHeader(std::move( Header ))
+{
+}
+
+bool TBCData::Read(SvStream &rS)
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ if ( !controlGeneralInfo.Read(rS) /*|| !controlSpecificInfo.Read(rS)*/ )
+ return false;
+ switch ( rHeader.getTct() )
+ {
+ case 0x01: // (Button control)
+ case 0x10: // (ExpandingGrid control)
+ controlSpecificInfo = std::make_shared<TBCBSpecific>();
+ break;
+ case 0x0A: // (Popup control)
+ case 0x0C: // (ButtonPopup control)
+ case 0x0D: // (SplitButtonPopup control)
+ case 0x0E: // (SplitButtonMRUPopup control)
+ controlSpecificInfo = std::make_shared<TBCMenuSpecific>();
+ break;
+ case 0x02: // (Edit control)
+ case 0x04: // (ComboBox control)
+ case 0x14: // (GraphicCombo control)
+ case 0x03: // (DropDown control)
+ case 0x06: // (SplitDropDown control)
+ case 0x09: // (GraphicDropDown control)
+ controlSpecificInfo = std::make_shared<TBCComboDropdownSpecific>( rHeader );
+ break;
+ default:
+ break;
+ }
+ if ( controlSpecificInfo )
+ return controlSpecificInfo->Read( rS );
+ //#FIXME I need to be able to handle different controlSpecificInfo types.
+ return true;
+}
+
+TBCMenuSpecific* TBCData::getMenuSpecific()
+{
+ TBCMenuSpecific* pMenu = dynamic_cast< TBCMenuSpecific* >( controlSpecificInfo.get() );
+ return pMenu;
+}
+void TBCData::ImportToolBarControl( CustomToolBarImportHelper& helper, std::vector< css::beans::PropertyValue >& props, bool& bBeginGroup, bool bIsMenuBar )
+{
+ sal_uInt16 nStyle = 0;
+ bBeginGroup = rHeader.isBeginGroup();
+ controlGeneralInfo.ImportToolBarControlData( helper, props );
+ beans::PropertyValue aProp;
+ aProp.Name = "Visible";
+ aProp.Value <<= rHeader.isVisible(); // where is the visible attribute stored
+ props.push_back( aProp );
+ if ( rHeader.getTct() == 0x01
+ || rHeader.getTct() == 0x10 )
+ {
+ TBCBSpecific* pSpecificInfo = dynamic_cast< TBCBSpecific* >( controlSpecificInfo.get() );
+ if ( pSpecificInfo )
+ {
+ // if we have an icon then lets set it for the command
+ OUString sCommand;
+ for (auto const& property : props)
+ {
+ // TODO JNA : couldn't we break if we find CommandURL to avoid keeping on the loop?
+ if ( property.Name == "CommandURL" )
+ property.Value >>= sCommand;
+ }
+ if ( TBCBitMap* pIcon = pSpecificInfo->getIcon() )
+ {
+ // Without a command openoffice won't display the icon
+ if ( !sCommand.isEmpty() )
+ {
+ BitmapEx aBitEx( pIcon->getBitMap() );
+ TBCBitMap* pIconMask = pSpecificInfo->getIconMask();
+ if (pIconMask)
+ {
+ const Bitmap& rMaskBase(pIconMask->getBitMap().GetBitmap());
+ Size aMaskSize = rMaskBase.GetSizePixel();
+ if (aMaskSize.Width() && aMaskSize.Height())
+ {
+ // according to the spec:
+ // "the iconMask is white in all the areas in which the icon is
+ // displayed as transparent and is black in all other areas."
+ aBitEx = BitmapEx(aBitEx.GetBitmap(), rMaskBase.CreateMask(COL_WHITE));
+ }
+ }
+
+ Graphic aGraphic( aBitEx );
+ helper.addIcon( aGraphic.GetXGraphic(), sCommand );
+ }
+ }
+ else if ( pSpecificInfo->getBtnFace() )
+ {
+
+ OUString sBuiltInCmd = helper.MSOTCIDToOOCommand( *pSpecificInfo->getBtnFace() );
+ if ( !sBuiltInCmd.isEmpty() )
+ {
+ uno::Sequence<OUString> sCmds { sBuiltInCmd };
+ uno::Reference< ui::XImageManager > xImageManager( helper.getAppCfgManager()->getImageManager(), uno::UNO_QUERY_THROW );
+ // 0 = default image size
+ uno::Sequence< uno::Reference< graphic::XGraphic > > sImages = xImageManager->getImages( 0, sCmds );
+ if ( sImages.hasElements() && sImages[0].is() )
+ helper.addIcon( sImages[0], sCommand );
+ }
+ }
+ }
+ }
+ else if ( rHeader.getTct() == 0x0a )
+ {
+ aProp.Name = "CommandURL";
+
+ TBCMenuSpecific* pMenu = getMenuSpecific();
+ if ( pMenu )
+ {
+ OUString sMenuBar = "private:resource/menubar/" + pMenu->Name();
+ aProp.Value <<= sMenuBar; // name of popup
+ }
+ nStyle |= ui::ItemStyle::DROP_DOWN;
+ props.push_back( aProp );
+ }
+
+ short icontext = ( rHeader.getTbct() & 0x03 );
+ aProp.Name = "Style";
+ if ( bIsMenuBar )
+ {
+ nStyle |= ui::ItemStyle::TEXT;
+ if ( !icontext || icontext == 0x3 )
+ // Text And image
+ nStyle |= ui::ItemStyle::ICON;
+ }
+ else
+ {
+ if ( ( icontext & 0x02 ) == 0x02 )
+ nStyle |= ui::ItemStyle::TEXT;
+ if ( !icontext || ( icontext & 0x03 ) == 0x03 )
+ nStyle |= ui::ItemStyle::ICON;
+ }
+ aProp.Value <<= nStyle;
+ props.push_back( aProp );
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void TBCData::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf(fp,"[ 0x%x ] TBCData -- dump\n", nOffSet );
+ indent_printf(fp," dumping controlGeneralInfo( TBCGeneralInfo )\n");
+ controlGeneralInfo.Print( fp );
+ //if ( rHeader.getTct() == 1 )
+ if ( controlSpecificInfo.get() )
+ {
+ indent_printf(fp," dumping controlSpecificInfo( TBCBSpecificInfo )\n");
+ controlSpecificInfo->Print( fp );
+ }
+}
+#endif
+
+bool
+WString::Read( SvStream &rS )
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ sal_uInt8 nChars = 0;
+ rS.ReadUChar( nChars );
+ sString = read_uInt16s_ToOUString(rS, nChars);
+ return true;
+}
+
+TBCExtraInfo::TBCExtraInfo()
+ : idHelpContext(0)
+ , tbcu(0)
+ , tbmg(0)
+{
+}
+
+bool
+TBCExtraInfo::Read( SvStream &rS )
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ if( !wstrHelpFile.Read( rS ) )
+ return false;
+
+ rS.ReadInt32( idHelpContext );
+
+ if ( !wstrTag.Read( rS ) || !wstrOnAction.Read( rS ) || !wstrParam.Read( rS ) )
+ return false;
+
+ rS.ReadSChar( tbcu ).ReadSChar( tbmg );
+ return true;
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void
+TBCExtraInfo::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] TBCExtraInfo -- dump\n", nOffSet );
+ indent_printf( fp, " wstrHelpFile %s\n",
+ OUStringToOString( wstrHelpFile.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ indent_printf( fp, " idHelpContext 0x%x\n", static_cast< unsigned int >( idHelpContext ) );
+ indent_printf( fp, " wstrTag %s\n",
+ OUStringToOString( wstrTag.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ indent_printf( fp, " wstrOnAction %s\n",
+ OUStringToOString( wstrOnAction.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ indent_printf( fp, " wstrParam %s\n",
+ OUStringToOString( wstrParam.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ indent_printf( fp, " tbcu 0x%x\n", tbcu );
+ indent_printf( fp, " tbmg 0x%x\n", tbmg );
+}
+#endif
+
+OUString const &
+TBCExtraInfo::getOnAction() const
+{
+ return wstrOnAction.getString();
+}
+
+TBCGeneralInfo::TBCGeneralInfo() : bFlags( 0 )
+{
+}
+
+bool TBCGeneralInfo::Read( SvStream &rS )
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadUChar( bFlags );
+
+ if ( ( bFlags & 0x1 ) && !customText.Read( rS ) )
+ return false;
+ if ( ( bFlags & 0x2 ) && ( !descriptionText.Read( rS ) || !tooltip.Read( rS ) ) )
+ return false;
+ if ( ( bFlags & 0x4 ) && !extraInfo.Read( rS ) )
+ return false;
+ return true;
+}
+
+#ifdef DEBUG_FILTER_MSFILTER
+void
+TBCGeneralInfo::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] TBCGeneralInfo -- dump\n", nOffSet );
+ indent_printf( fp, " bFlags 0x%x\n", bFlags );
+ indent_printf( fp, " customText %s\n",
+ OUStringToOString( customText.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ indent_printf( fp, " description %s\n",
+ OUStringToOString( descriptionText.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ indent_printf( fp, " tooltip %s\n",
+ OUStringToOString( tooltip.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ if ( bFlags & 0x4 )
+ extraInfo.Print( fp );
+}
+#endif
+
+void
+TBCGeneralInfo::ImportToolBarControlData( CustomToolBarImportHelper& helper, std::vector< beans::PropertyValue >& sControlData )
+{
+ if ( !(bFlags & 0x5) )
+ return;
+
+ beans::PropertyValue aProp;
+ // probably access to the header would be a better test than seeing if there is an action, e.g.
+ // if ( rHeader.getTct() == 0x01 && rHeader.getTcID() == 0x01 ) // not defined, probably this is a command
+ if ( !extraInfo.getOnAction().isEmpty() )
+ {
+ aProp.Name = "CommandURL";
+ ooo::vba::MacroResolvedInfo aMacroInf = ooo::vba::resolveVBAMacro( &helper.GetDocShell(), extraInfo.getOnAction(), true );
+ if ( aMacroInf.mbFound )
+ aProp.Value = CustomToolBarImportHelper::createCommandFromMacro( aMacroInf.msResolvedMacro );
+ else
+ aProp.Value <<= "UnResolvedMacro[" + extraInfo.getOnAction() + "]";
+ sControlData.push_back( aProp );
+ }
+
+ aProp.Name = "Label";
+ aProp.Value <<= customText.getString().replace('&','~');
+ sControlData.push_back( aProp );
+
+ aProp.Name = "Type";
+ aProp.Value <<= ui::ItemType::DEFAULT;
+ sControlData.push_back( aProp );
+
+ aProp.Name = "Tooltip";
+ aProp.Value <<= tooltip.getString();
+ sControlData.push_back( aProp );
+/*
+aToolbarItem(0).Name = "CommandURL" wstrOnAction
+aToolbarItem(0).Value = Command
+aToolbarItem(1).Name = "Label" customText
+aToolbarItem(1).Value = Label
+aToolbarItem(2).Name = "Type"
+aToolbarItem(2).Value = 0
+aToolbarItem(3).Name = "Visible"
+aToolbarItem(3).Value = true
+*/
+}
+
+TBCMenuSpecific::TBCMenuSpecific() : tbid( 0 )
+{
+}
+
+bool
+TBCMenuSpecific::Read( SvStream &rS)
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadInt32( tbid );
+ if ( tbid == 1 )
+ {
+ name = std::make_shared<WString>();
+ return name->Read( rS );
+ }
+ return true;
+}
+
+#ifdef DEBUG_FILTER_MSFILTER
+void
+TBCMenuSpecific::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] TBCMenuSpecific -- dump\n", nOffSet );
+ indent_printf( fp, " tbid 0x%x\n", static_cast< unsigned int >( tbid ) );
+ if ( tbid == 1 )
+ indent_printf( fp, " name %s\n", OUStringToOString( name->getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+}
+#endif
+
+OUString TBCMenuSpecific::Name()
+{
+ OUString aName;
+ if ( name )
+ aName = name->getString();
+ return aName;
+}
+TBCBSpecific::TBCBSpecific() : bFlags( 0 )
+{
+}
+
+bool TBCBSpecific::Read( SvStream &rS)
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadUChar( bFlags );
+
+ // bFlags determines what we read next
+
+ // bFlags.fCustomBitmap = 1 ( 0x8 ) set
+ if ( bFlags & 0x8 )
+ {
+ icon = std::make_shared<TBCBitMap>();
+ iconMask = std::make_shared<TBCBitMap>();
+ if ( !icon->Read( rS ) || !iconMask->Read( rS ) )
+ return false;
+ }
+ // if bFlags.fCustomBtnFace = 1 ( 0x10 )
+ if ( bFlags & 0x10 )
+ {
+ iBtnFace = std::make_shared<sal_uInt16>();
+ rS.ReadUInt16( *iBtnFace );
+ }
+ // if bFlags.fAccelerator equals 1 ( 0x04 )
+ if ( bFlags & 0x04 )
+ {
+ wstrAcc = std::make_shared<WString>();
+ return wstrAcc->Read( rS );
+ }
+ return true;
+}
+
+
+#ifdef DEBUG_FILTER_MSFILTER
+void TBCBSpecific::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] TBCBSpecific -- dump\n", nOffSet );
+ indent_printf( fp, " bFlags 0x%x\n", bFlags );
+ bool bResult = ( icon.get() != NULL );
+ indent_printf( fp, " icon present? %s\n", bResult ? "true" : "false" );
+ if ( bResult )
+ {
+ Indent b;
+ indent_printf( fp, " icon: \n");
+ icon->Print( fp ); // will dump size
+ }
+ bResult = ( iconMask.get() != NULL );
+ indent_printf( fp, " icon mask present? %s\n", bResult ? "true" : "false" );
+ if ( bResult )
+ {
+ Indent c;
+ indent_printf( fp, " icon mask: \n");
+ iconMask->Print( fp ); // will dump size
+ }
+ if ( iBtnFace.get() )
+ {
+ indent_printf( fp, " iBtnFace 0x%x\n", *iBtnFace );
+ }
+ bResult = ( wstrAcc.get() != NULL );
+ indent_printf( fp, " option string present? %s ->%s<-\n", bResult ? "true" : "false", bResult ? OUStringToOString( wstrAcc->getString(), RTL_TEXTENCODING_UTF8 ).getStr() : "N/A" );
+}
+#endif
+
+TBCBitMap*
+TBCBSpecific::getIcon()
+{
+ return icon.get();
+}
+
+TBCBitMap*
+TBCBSpecific::getIconMask()
+{
+ return iconMask.get();
+}
+
+TBCComboDropdownSpecific::TBCComboDropdownSpecific(const TBCHeader& header )
+{
+ if ( header.getTcID() == 0x01 )
+ data = std::make_shared<TBCCDData>();
+}
+
+bool TBCComboDropdownSpecific::Read( SvStream &rS)
+{
+ nOffSet = rS.Tell();
+ if ( data )
+ return data->Read( rS );
+ return true;
+}
+
+#ifdef DEBUG_FILTER_MSFILTER
+void TBCComboDropdownSpecific::Print( FILE* fp)
+{
+ Indent a;
+ indent_printf(fp,"[ 0x%x ] TBCComboDropdownSpecific -- dump\n", nOffSet );
+ if ( data.get() )
+ data->Print( fp );
+ else
+ indent_printf(fp," no data " );
+}
+#endif
+
+TBCCDData::TBCCDData()
+ : cwstrItems(0)
+ , cwstrMRU(0)
+ , iSel(0)
+ , cLines(0)
+ , dxWidth(0)
+{
+}
+
+TBCCDData::~TBCCDData()
+{
+}
+
+bool TBCCDData::Read( SvStream &rS)
+{
+ nOffSet = rS.Tell();
+ rS.ReadInt16( cwstrItems );
+ if (cwstrItems > 0)
+ {
+ auto nItems = o3tl::make_unsigned(cwstrItems);
+ //each WString is at least one byte
+ if (rS.remainingSize() < nItems)
+ return false;
+ for (decltype(nItems) index = 0; index < nItems; ++index)
+ {
+ WString aString;
+ if ( !aString.Read( rS ) )
+ return false;
+ wstrList.push_back( aString );
+ }
+ }
+ rS.ReadInt16( cwstrMRU ).ReadInt16( iSel ).ReadInt16( cLines ).ReadInt16( dxWidth );
+
+ return wstrEdit.Read( rS );
+}
+
+#ifdef DEBUG_FILTER_MSFILTER
+void TBCCDData::Print( FILE* fp)
+{
+ Indent a;
+ indent_printf(fp,"[ 0x%x ] TBCCDData -- dump\n", nOffSet );
+ indent_printf(fp," cwstrItems items in wstrList %d\n", cwstrItems);
+ for ( sal_Int32 index=0; index < cwstrItems; ++index )
+ {
+ Indent b;
+ indent_printf(fp, " wstrList[%d] %s", static_cast< int >( index ), OUStringToOString( wstrList[index].getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ indent_printf(fp," cwstrMRU num most recently used string %d item\n", cwstrMRU);
+ indent_printf(fp," iSel index of selected item %d item\n", iSel);
+ indent_printf(fp," cLines num of suggested lines to display %d", cLines);
+ indent_printf(fp," dxWidth width in pixels %d", dxWidth);
+ indent_printf(fp," wstrEdit %s", OUStringToOString( wstrEdit.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+}
+#endif
+
+TBCBitMap::TBCBitMap() : cbDIB( 0 )
+{
+}
+
+TBCBitMap::~TBCBitMap()
+{
+}
+
+bool TBCBitMap::Read( SvStream& rS)
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadInt32( cbDIB );
+ // cbDIB = sizeOf(biHeader) + sizeOf(colors) + sizeOf(bitmapData) + 10
+ return ReadDIBBitmapEx(mBitMap, rS, false, true);
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void TBCBitMap::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf(fp, "[ 0x%x ] TBCBitMap -- dump\n", nOffSet );
+ indent_printf(fp, " TBCBitMap size of bitmap data 0x%x\n", static_cast< unsigned int > ( cbDIB ) );
+}
+#endif
+
+TB::TB() : bSignature(0x2),
+bVersion(0x1),
+cCL(0),
+ltbid( 0x1 ),
+ltbtr(0),
+cRowsDefault( 0 ),
+bFlags( 0 )
+{
+}
+
+bool TB::Read(SvStream &rS)
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadUChar( bSignature ).ReadUChar( bVersion ).ReadInt16( cCL ).ReadInt32( ltbid ).ReadUInt32( ltbtr ).ReadUInt16( cRowsDefault ).ReadUInt16( bFlags );
+ name.Read( rS );
+ return true;
+
+}
+
+bool TB::IsEnabled() const
+{
+ return ( bFlags & 0x01 ) != 0x01;
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void TB::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf(fp,"[ 0x%x ] TB -- dump\n", nOffSet );
+ indent_printf(fp," bSignature 0x%x\n", bSignature );
+ indent_printf(fp," bVersion 0x%x\n", bVersion );
+ indent_printf(fp," cCL 0x%x\n", cCL );
+ indent_printf(fp," ltbid 0x%x\n", ltbid );
+ indent_printf(fp," ltbtr 0x%x\n", ltbtr );
+ indent_printf(fp," cRowsDefault 0x%x\n", cRowsDefault );
+ indent_printf(fp," bFlags 0x%x\n", bFlags );
+ indent_printf(fp, " name %s\n", OUStringToOString( name.getString(), RTL_TEXTENCODING_UTF8 ).getStr() );
+}
+#endif
+
+TBVisualData::TBVisualData() : tbds(0), tbv(0), tbdsDock(0), iRow(0)
+{
+}
+
+bool TBVisualData::Read( SvStream& rS )
+{
+ SAL_INFO("filter.ms", "stream pos " << rS.Tell());
+ nOffSet = rS.Tell();
+ rS.ReadSChar( tbds ).ReadSChar( tbv ).ReadSChar( tbdsDock ).ReadSChar( iRow );
+ rcDock.Read( rS );
+ rcFloat.Read( rS );
+ return true;
+}
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void SRECT::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, " left 0x%x\n", left);
+ indent_printf( fp, " top 0x%x\n", top);
+ indent_printf( fp, " right 0x%x\n", right);
+ indent_printf( fp, " bottom 0x%x\n", bottom);
+}
+#endif
+
+#ifdef DEBUG_FILTER_MSTOOLBAR
+void TBVisualData::Print( FILE* fp )
+{
+ Indent a;
+ indent_printf( fp, "[ 0x%x ] TBVisualData -- dump\n", nOffSet );
+ indent_printf( fp, " tbds 0x%x\n", tbds);
+ indent_printf( fp, " tbv 0x%x\n", tbv);
+ indent_printf( fp, " tbdsDoc 0x%x\n", tbdsDock);
+ indent_printf( fp, " iRow 0x%x\n", iRow);
+ rcDock.Print( fp );
+ rcFloat.Print( fp );
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/msvbahelper.cxx b/filter/source/msfilter/msvbahelper.cxx
new file mode 100644
index 000000000..d55a636fc
--- /dev/null
+++ b/filter/source/msfilter/msvbahelper.cxx
@@ -0,0 +1,768 @@
+/* -*- 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/.
+ *
+ * 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 <config_features.h>
+
+#include <filter/msfilter/msvbahelper.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/basmgr.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbmeth.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+#include <unotools/pathoptions.hxx>
+#include <rtl/character.hxx>
+#include <sfx2/objsh.hxx>
+#include <o3tl/string_view.hxx>
+#include <svtools/acceleratorexecute.hxx>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager.hpp>
+#include <map>
+
+using namespace ::com::sun::star;
+
+namespace ooo::vba {
+
+constexpr OUStringLiteral sUrlPart0( u"vnd.sun.star.script:" );
+constexpr OUStringLiteral sUrlPart1( u"?language=Basic&location=document" );
+
+OUString makeMacroURL( std::u16string_view sMacroName )
+{
+ return sUrlPart0 + sMacroName + sUrlPart1;
+}
+
+OUString extractMacroName( const OUString& rMacroUrl )
+{
+ if( rMacroUrl.startsWith( sUrlPart0 ) && rMacroUrl.endsWith( sUrlPart1 ) )
+ {
+ return rMacroUrl.copy( sUrlPart0.getLength(),
+ rMacroUrl.getLength() - sUrlPart0.getLength() - sUrlPart1.getLength() );
+ }
+ return OUString();
+}
+
+static std::u16string_view trimMacroName( std::u16string_view rMacroName )
+{
+ // the name may contain whitespaces and may be enclosed in apostrophs
+ std::u16string_view aMacroName = o3tl::trim(rMacroName);
+ size_t nMacroLen = aMacroName.size();
+ if( (nMacroLen >= 2) && (aMacroName[ 0 ] == '\'') && (aMacroName[ nMacroLen - 1 ] == '\'') )
+ aMacroName = o3tl::trim(aMacroName.substr( 1, nMacroLen - 2 ));
+ return aMacroName;
+}
+
+#if HAVE_FEATURE_SCRIPTING
+
+static SfxObjectShell* findShellForUrl( const OUString& sMacroURLOrPath )
+{
+ SfxObjectShell* pFoundShell=nullptr;
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ INetURLObject aObj;
+ aObj.SetURL( sMacroURLOrPath );
+ bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
+ OUString aURL;
+ if ( bIsURL )
+ aURL = sMacroURLOrPath;
+ else
+ {
+ osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL );
+ aObj.SetURL( aURL );
+ }
+ while ( pShell )
+ {
+
+ uno::Reference< frame::XModel > xModel = pShell->GetModel();
+ // are we searching for a template? if so we have to cater for the
+ // fact that in openoffice a document opened from a template is always
+ // a new document :/
+ if ( xModel.is() )
+ {
+ SAL_INFO(
+ "filter.ms",
+ "shell " << pShell << " has model with url " << xModel->getURL()
+ << " and we look for " << aURL);
+ OUString aName = xModel->getURL() ;
+ if (aName.isEmpty())
+ {
+ uno::Reference< frame::XFrame > xFrame( xModel->getCurrentController()->getFrame(), uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xProps( xFrame, uno::UNO_QUERY_THROW );
+ xProps->getPropertyValue("Title") >>= aName;
+ aName = o3tl::trim(o3tl::getToken(aName, 0, '-'));
+ if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 )
+ {
+ pFoundShell = pShell;
+ break;
+ }
+ }
+
+ if ( sMacroURLOrPath.endsWithIgnoreAsciiCase( ".dot" ) )
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> const
+ xDocPropSupp(xModel, uno::UNO_QUERY);
+ if (xDocPropSupp.is())
+ {
+ uno::Reference< document::XDocumentProperties > const
+ xDocProps(xDocPropSupp->getDocumentProperties(),
+ uno::UNO_SET_THROW);
+ OUString sCurrName = xDocProps->getTemplateName();
+ if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 )
+ {
+ pFoundShell = pShell;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // sometimes just the name of the document ( without the path
+ // is used
+ bool bDocNameNoPathMatch = false;
+ if ( !aURL.isEmpty() && aURL.indexOf( '/' ) == -1 )
+ {
+ sal_Int32 lastSlashIndex = xModel->getURL().lastIndexOf( '/' );
+ if ( lastSlashIndex > -1 )
+ {
+ bDocNameNoPathMatch = xModel->getURL().subView( lastSlashIndex + 1 ) == aURL;
+ if ( !bDocNameNoPathMatch )
+ {
+ OUString aTmpName = OUString::Concat("'") + xModel->getURL().subView( lastSlashIndex + 1 ) + "'";
+ bDocNameNoPathMatch = aTmpName == aURL;
+ }
+ }
+ }
+
+ if ( aURL == xModel->getURL() || bDocNameNoPathMatch )
+ {
+ pFoundShell = pShell;
+ break;
+ }
+ }
+ }
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+ return pFoundShell;
+}
+
+// sMod can be empty ( but we really need the library to search in )
+// if sMod is empty and a macro is found then sMod is updated
+// if sMod is empty, only standard modules will be searched (no class, document, form modules)
+static bool hasMacro( SfxObjectShell const * pShell, const OUString& sLibrary, OUString& sMod, const OUString& sMacro )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) pShell;
+ (void) sLibrary;
+ (void) sMod;
+ (void) sMacro;
+#else
+ if ( !sLibrary.isEmpty() && !sMacro.isEmpty() )
+ {
+ BasicManager* pBasicMgr = pShell-> GetBasicManager();
+ if ( pBasicMgr )
+ {
+ StarBASIC* pBasic = pBasicMgr->GetLib( sLibrary );
+ if ( !pBasic )
+ {
+ sal_uInt16 nId = pBasicMgr->GetLibId( sLibrary );
+ pBasicMgr->LoadLib( nId );
+ pBasic = pBasicMgr->GetLib( sLibrary );
+ }
+ if ( pBasic )
+ {
+ if ( !sMod.isEmpty() ) // we wish to find the macro is a specific module
+ {
+ SbModule* pModule = pBasic->FindModule( sMod );
+ if ( pModule && pModule->FindMethod( sMacro, SbxClassType::Method ))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ for (auto const& rModuleRef : pBasic->GetModules())
+ {
+ if (rModuleRef && rModuleRef->FindMethod(sMacro, SbxClassType::Method))
+ {
+ sMod = rModuleRef->GetName();
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+ return false;
+}
+
+#endif
+
+#if HAVE_FEATURE_SCRIPTING
+
+OUString getDefaultProjectName( SfxObjectShell const * pShell )
+{
+ OUString aPrjName;
+ if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : nullptr )
+ {
+ aPrjName = pBasicMgr->GetName();
+ if( aPrjName.isEmpty() )
+ aPrjName = "Standard";
+ }
+ return aPrjName;
+}
+
+static void parseMacro( const OUString& sMacro, OUString& sContainer, OUString& sModule, OUString& sProcedure )
+{
+ sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' );
+
+ if ( nMacroDot != -1 )
+ {
+ sProcedure = sMacro.copy( nMacroDot + 1 );
+
+ sal_Int32 nContainerDot = sMacro.lastIndexOf( '.', nMacroDot - 1 );
+ if ( nContainerDot != -1 )
+ {
+ sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 );
+ sContainer = sMacro.copy( 0, nContainerDot );
+ }
+ else
+ sModule = sMacro.copy( 0, nMacroDot );
+ }
+ else
+ sProcedure = sMacro;
+}
+
+#endif
+
+OUString resolveVBAMacro( SfxObjectShell const * pShell, const OUString& rLibName, const OUString& rModuleName, const OUString& rMacroName )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) pShell;
+ (void) rLibName;
+ (void) rModuleName;
+ (void) rMacroName;
+#else
+ if( pShell )
+ {
+ OUString aLibName = rLibName.isEmpty() ? getDefaultProjectName( pShell ) : rLibName ;
+ OUString aModuleName = rModuleName;
+ if( hasMacro( pShell, aLibName, aModuleName, rMacroName ) )
+ return aLibName + "." + aModuleName + "." + rMacroName;
+ }
+#endif
+ return OUString();
+}
+
+MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const OUString& MacroName, bool bSearchGlobalTemplates )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) pShell;
+ (void) MacroName;
+ (void) bSearchGlobalTemplates;
+
+ return MacroResolvedInfo();
+#else
+ if( !pShell )
+ return MacroResolvedInfo();
+
+ // the name may be enclosed in apostrophs
+ std::u16string_view aMacroName = trimMacroName( MacroName );
+
+ // parse the macro name
+ size_t nDocSepIndex = aMacroName.find( '!' );
+ if( nDocSepIndex > 0 && nDocSepIndex != std::u16string_view::npos )
+ {
+ // macro specified by document name
+ // find document shell for document name and call ourselves
+ // recursively
+
+ // assume for now that the document name is *this* document
+ std::u16string_view sDocUrlOrPath = aMacroName.substr( 0, nDocSepIndex );
+ aMacroName = aMacroName.substr( nDocSepIndex + 1 );
+ SAL_INFO("filter.ms", "doc search, current shell is " << pShell);
+ SfxObjectShell* pFoundShell = nullptr;
+ if( bSearchGlobalTemplates )
+ {
+ SvtPathOptions aPathOpt;
+ const OUString& aAddinPath = aPathOpt.GetAddinPath();
+ if( o3tl::starts_with(sDocUrlOrPath, aAddinPath) )
+ pFoundShell = pShell;
+ }
+ if( !pFoundShell )
+ pFoundShell = findShellForUrl( OUString(sDocUrlOrPath) );
+ SAL_INFO(
+ "filter.ms",
+ "doc search, after find, found shell is " << pFoundShell);
+ return resolveVBAMacro( pFoundShell, OUString(aMacroName) );
+ }
+
+ // macro is contained in 'this' document ( or code imported from a template
+ // where that template is a global template or perhaps the template this
+ // document is created from )
+
+ MacroResolvedInfo aRes( pShell );
+
+ // macro format = Container.Module.Procedure
+ OUString sContainer, sModule, sProcedure;
+ parseMacro( OUString(aMacroName), sContainer, sModule, sProcedure );
+
+#if 0
+ // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call
+ // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance)
+ uno::Reference< container::XNameContainer > xPrjNameCache;
+ uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY);
+ if ( xSF.is() ) try
+ {
+ xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
+ }
+ catch( const uno::Exception& ) // createInstance may throw
+ {
+ }
+#endif
+
+ std::vector< OUString > sSearchList;
+
+ if ( !sContainer.isEmpty() )
+ {
+// service VBAProjectNameProvider not implemented
+#if 0
+ // get the Project associated with the Container
+ if ( xPrjNameCache.is() )
+ {
+ if ( xPrjNameCache->hasByName( sContainer ) )
+ {
+ OUString sProject;
+ xPrjNameCache->getByName( sContainer ) >>= sProject;
+ sContainer = sProject;
+ }
+ }
+#endif
+ sSearchList.push_back( sContainer ); // First Lib to search
+ }
+ else
+ {
+ // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates,
+ // get the name of Project/Library for 'this' document
+ OUString sThisProject( "Standard" );
+ try
+ {
+ uno::Reference< beans::XPropertySet > xProps( pShell->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
+ sThisProject = xVBAMode->getProjectName();
+ }
+ catch( const uno::Exception& /*e*/) {}
+
+ sSearchList.push_back( sThisProject ); // First Lib to search
+
+// service VBAProjectNameProvider not implemented
+#if 0
+ if ( xPrjNameCache.is() )
+ {
+ // is this document created from a template?
+ uno::Reference< document::XDocumentPropertiesSupplier > const
+ xDocPropSupp(pShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
+
+ OUString sCreatedFrom = xDocProps->getTemplateURL();
+ if ( !sCreatedFrom.isEmpty() )
+ {
+ INetURLObject aObj;
+ aObj.SetURL( sCreatedFrom );
+ bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
+ OUString aURL;
+ if ( bIsURL )
+ aURL = sCreatedFrom;
+ else
+ {
+ osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL );
+ aObj.SetURL( aURL );
+ }
+ sCreatedFrom = aObj.GetLastName();
+ }
+
+ sal_Int32 nIndex = sCreatedFrom.lastIndexOf( '.' );
+ if ( nIndex != -1 )
+ sCreatedFrom = sCreatedFrom.copy( 0, nIndex );
+
+ OUString sPrj;
+ if ( !sCreatedFrom.isEmpty() && xPrjNameCache->hasByName( sCreatedFrom ) )
+ {
+ xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj;
+ // Make sure we don't double up with this project
+ if ( !sPrj.equals( sThisProject ) )
+ sSearchList.push_back( sPrj );
+ }
+
+ // get list of global template Names
+ uno::Sequence< OUString > sTemplateNames = xPrjNameCache->getElementNames();
+ sal_Int32 nLen = sTemplateNames.getLength();
+ for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index )
+ {
+
+ if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) )
+ {
+ if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) )
+ {
+ xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj;
+ // Make sure we don't double up with this project
+ if ( !sPrj.equals( sThisProject ) )
+ sSearchList.push_back( sPrj );
+ }
+ }
+
+ }
+ }
+#endif
+ }
+
+ for (auto const& search : sSearchList)
+ {
+ aRes.mbFound = hasMacro( pShell, search, sModule, sProcedure );
+ if ( aRes.mbFound )
+ {
+ sContainer = search;
+ break;
+ }
+ }
+ //aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 );
+ aRes.msResolvedMacro = sContainer + "." + sModule + "." + sProcedure;
+
+ return aRes;
+#endif
+}
+
+// Treat the args as possible inputs (conversion at bottom of method)
+bool executeMacro( SfxObjectShell* pShell, const OUString& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& aRet, const uno::Any& /*aCaller*/)
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) pShell;
+ (void) sMacroName;
+ (void) aArgs;
+ (void) aRet;
+
+ return false;
+#else
+ bool bRes = false;
+ if ( !pShell )
+ return bRes;
+ OUString sUrl = makeMacroURL( sMacroName );
+
+ uno::Sequence< sal_Int16 > aOutArgsIndex;
+ uno::Sequence< uno::Any > aOutArgs;
+
+ try
+ {
+ ErrCode nErr = pShell->CallXScript(sUrl, aArgs, aRet, aOutArgsIndex, aOutArgs, false);
+ sal_Int32 nLen = aOutArgs.getLength();
+ // convert any out params to seem like they were inputs
+ if (nLen)
+ {
+ auto pArgs = aArgs.getArray();
+ for (sal_Int32 index = 0; index < nLen; ++index)
+ {
+ sal_Int32 nOutIndex = aOutArgsIndex[index];
+ pArgs[nOutIndex] = aOutArgs[index];
+ }
+ }
+ bRes = ( nErr == ERRCODE_NONE );
+ }
+ catch ( const uno::Exception& )
+ {
+ bRes = false;
+ }
+ return bRes;
+#endif
+}
+
+
+
+VBAMacroResolver::VBAMacroResolver() :
+ mpObjShell( nullptr )
+{
+}
+
+VBAMacroResolver::~VBAMacroResolver()
+{
+}
+
+// com.sun.star.lang.XServiceInfo interface -----------------------------------
+
+OUString SAL_CALL VBAMacroResolver::getImplementationName()
+{
+ return "com.sun.star.comp.vba.VBAMacroResolver";
+}
+
+sal_Bool SAL_CALL VBAMacroResolver::supportsService( const OUString& rService )
+{
+ return cppu::supportsService(this, rService);
+}
+
+uno::Sequence< OUString > SAL_CALL VBAMacroResolver::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.vba.VBAMacroResolver" };
+}
+
+// com.sun.star.lang.XInitialization interface --------------------------------
+
+void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rArgs )
+{
+ OSL_ENSURE( rArgs.getLength() > 1, "VBAMacroResolver::initialize - missing arguments" );
+ if( rArgs.getLength() < 2 )
+ throw uno::RuntimeException();
+
+ // first argument: document model
+ mxModel.set( rArgs[ 0 ], uno::UNO_QUERY_THROW );
+ mpObjShell = comphelper::getFromUnoTunnel<SfxObjectShell>(mxModel);
+ if( !mpObjShell )
+ throw uno::RuntimeException();
+
+ // second argument: VBA project name
+ if( !(rArgs[ 1 ] >>= maProjectName) || (maProjectName.isEmpty()) )
+ throw uno::RuntimeException();
+}
+
+// com.sun.star.script.vba.XVBAMacroResolver interface ------------------------
+
+OUString SAL_CALL VBAMacroResolver::resolveVBAMacroToScriptURL( const OUString& rVBAMacroName )
+{
+ if( !mpObjShell )
+ throw uno::RuntimeException();
+
+ // the name may be enclosed in apostrophs
+ OUString aMacroName( trimMacroName( rVBAMacroName ) );
+ if( aMacroName.isEmpty() )
+ throw lang::IllegalArgumentException();
+
+ // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname")
+ if( (aMacroName[ 0 ] == '[') || (aMacroName.indexOf( '!' ) >= 0) )
+ throw lang::IllegalArgumentException();
+
+ // check if macro name starts with project name, replace with "Standard"
+ // TODO: adjust this when custom VBA project name is supported
+ sal_Int32 nDotPos = aMacroName.indexOf( '.' );
+ if( (nDotPos == 0) || (nDotPos + 1 == aMacroName.getLength()) )
+ throw lang::IllegalArgumentException();
+ if( (nDotPos > 0) && aMacroName.matchIgnoreAsciiCase( maProjectName ) )
+ aMacroName = aMacroName.copy( nDotPos + 1 );
+
+ // try to find the macro
+ MacroResolvedInfo aInfo = resolveVBAMacro( mpObjShell, aMacroName );
+ if( !aInfo.mbFound )
+ throw lang::IllegalArgumentException();
+
+ // build and return the script URL
+ return makeMacroURL( aInfo.msResolvedMacro );
+}
+
+OUString SAL_CALL VBAMacroResolver::resolveScriptURLtoVBAMacro( const OUString& /*rScriptURL*/ )
+{
+ OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" );
+ throw uno::RuntimeException();
+}
+
+static bool getModifier( sal_Unicode c, sal_uInt16& mod )
+{
+ if ( c == '+' ) {
+ mod |= KEY_SHIFT;
+ return true;
+ } else if ( c == '^' ) {
+ mod |= KEY_MOD1;
+ return true;
+ } else if ( c == '%' ) {
+ mod |= KEY_MOD2;
+ return true;
+ }
+ return false;
+}
+
+/// @throws uno::RuntimeException
+static sal_uInt16 parseChar( sal_Unicode c )
+{
+ sal_uInt16 nVclKey = 0;
+ // do we care about locale here for letters/digits? probably not
+ if ( rtl::isAsciiAlpha( c ) )
+ {
+ nVclKey |= ( rtl::toAsciiUpperCase( c ) - 'A' ) + KEY_A;
+ if ( rtl::isAsciiUpperCase( c ) )
+ nVclKey |= KEY_SHIFT;
+ }
+ else if ( rtl::isAsciiDigit( c ) )
+ nVclKey |= ( c - '0' ) + KEY_0;
+ else if ( c == '~' ) // special case
+ nVclKey = KEY_RETURN;
+ else if ( c == ' ' ) // special case
+ nVclKey = KEY_SPACE;
+ else // I guess we have a problem ( but not sure if locale specific keys might come into play here )
+ throw uno::RuntimeException();
+ return nVclKey;
+}
+
+namespace {
+
+struct KeyCodeEntry
+{
+ const char* sName;
+ sal_uInt16 nCode;
+};
+
+}
+
+KeyCodeEntry const aMSKeyCodesData[] = {
+ { "BACKSPACE", KEY_BACKSPACE },
+ { "BS", KEY_BACKSPACE },
+ { "DELETE", KEY_DELETE },
+ { "DEL", KEY_DELETE },
+ { "DOWN", KEY_DOWN },
+ { "UP", KEY_UP },
+ { "LEFT", KEY_LEFT },
+ { "RIGHT", KEY_RIGHT },
+ { "END", KEY_END },
+ { "ESCAPE", KEY_ESCAPE },
+ { "ESC", KEY_ESCAPE },
+ { "HELP", KEY_HELP },
+ { "HOME", KEY_HOME },
+ { "PGDN", KEY_PAGEDOWN },
+ { "PGUP", KEY_PAGEUP },
+ { "INSERT", KEY_INSERT },
+ { "SCROLLLOCK", KEY_SCROLLLOCK },
+ { "NUMLOCK", KEY_NUMLOCK },
+ { "TAB", KEY_TAB },
+ { "F1", KEY_F1 },
+ { "F2", KEY_F2 },
+ { "F3", KEY_F3 },
+ { "F4", KEY_F4 },
+ { "F5", KEY_F5 },
+ { "F6", KEY_F6 },
+ { "F7", KEY_F7 },
+ { "F8", KEY_F8 },
+ { "F9", KEY_F9 },
+ { "F10", KEY_F10 },
+ { "F11", KEY_F11 },
+ { "F12", KEY_F12 },
+ { "F13", KEY_F13 },
+ { "F14", KEY_F14 },
+ { "F15", KEY_F15 },
+};
+
+awt::KeyEvent parseKeyEvent( const OUString& Key )
+{
+ static std::map< OUString, sal_uInt16 > s_KeyCodes = []()
+ {
+ std::map< OUString, sal_uInt16 > tmp;
+ for (KeyCodeEntry const & i : aMSKeyCodesData)
+ {
+ tmp[ OUString::createFromAscii( i.sName ) ] = i.nCode;
+ }
+ return tmp;
+ }();
+ OUString sKeyCode;
+ sal_uInt16 nVclKey = 0;
+
+ // parse the modifier if any
+ for ( int i=0; i<Key.getLength(); ++i )
+ {
+ if ( ! getModifier( Key[ i ], nVclKey ) )
+ {
+ sKeyCode = Key.copy( i );
+ break;
+ }
+ }
+
+ // check if keycode is surrounded by '{}', if so scoop out the contents
+ // else it should be just one char of ( 'a-z,A-Z,0-9' )
+ if ( sKeyCode.getLength() == 1 ) // ( a single char )
+ {
+ nVclKey |= parseChar( sKeyCode[ 0 ] );
+ }
+ else // key should be enclosed in '{}'
+ {
+ if ( sKeyCode.getLength() < 3 || sKeyCode[0] != '{' || sKeyCode[sKeyCode.getLength() - 1 ] != '}' )
+ throw uno::RuntimeException();
+
+ sKeyCode = sKeyCode.copy(1, sKeyCode.getLength() - 2 );
+
+ if ( sKeyCode.getLength() == 1 )
+ nVclKey |= parseChar( sKeyCode[ 0 ] );
+ else
+ {
+ auto it = s_KeyCodes.find( sKeyCode );
+ if ( it == s_KeyCodes.end() ) // unknown or unsupported
+ throw uno::RuntimeException();
+ nVclKey |= it->second;
+ }
+ }
+
+ awt::KeyEvent aKeyEvent = svt::AcceleratorExecute::st_VCLKey2AWTKey( vcl::KeyCode( nVclKey ) );
+ return aKeyEvent;
+}
+
+void applyShortCutKeyBinding ( const uno::Reference< frame::XModel >& rxModel, const awt::KeyEvent& rKeyEvent, const OUString& rMacroName )
+{
+ OUString MacroName( rMacroName );
+ if ( !MacroName.isEmpty() )
+ {
+ OUString aMacroName = MacroName.trim();
+ if( aMacroName.startsWith("!") )
+ aMacroName = o3tl::trim(aMacroName.subView(1));
+ SfxObjectShell* pShell = nullptr;
+ if ( rxModel.is() )
+ {
+ pShell = comphelper::getFromUnoTunnel<SfxObjectShell>(rxModel);
+ if ( !pShell )
+ throw uno::RuntimeException();
+ }
+ MacroResolvedInfo aMacroInfo = resolveVBAMacro( pShell, aMacroName );
+ if( !aMacroInfo.mbFound )
+ throw uno::RuntimeException( "The procedure doesn't exist" );
+ MacroName = aMacroInfo.msResolvedMacro;
+ }
+ uno::Reference< ui::XUIConfigurationManagerSupplier > xCfgSupplier(rxModel, uno::UNO_QUERY_THROW);
+ uno::Reference< ui::XUIConfigurationManager > xCfgMgr = xCfgSupplier->getUIConfigurationManager();
+
+ uno::Reference< ui::XAcceleratorConfiguration > xAcc( xCfgMgr->getShortCutManager(), uno::UNO_SET_THROW );
+ if ( MacroName.isEmpty() )
+ // I believe this should really restore the [application] default. Since
+ // afaik we don't actually setup application default bindings on import
+ // we don't even know what the 'default' would be for this key
+ xAcc->removeKeyEvent( rKeyEvent );
+ else
+ xAcc->setKeyEvent( rKeyEvent, ooo::vba::makeMacroURL( MacroName ) );
+
+}
+
+
+} // namespace ooo
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+filter_VBAMacroResolver_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new ooo::vba::VBAMacroResolver());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/filter/source/msfilter/rtfutil.cxx b/filter/source/msfilter/rtfutil.cxx
new file mode 100644
index 000000000..e20a146c4
--- /dev/null
+++ b/filter/source/msfilter/rtfutil.cxx
@@ -0,0 +1,401 @@
+/* -*- 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 <filter/msfilter/rtfutil.hxx>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <svtools/rtfkeywd.hxx>
+#include <rtl/character.hxx>
+#include <tools/stream.hxx>
+#include <sot/storage.hxx>
+
+namespace
+{
+/**
+ * If rOle1 is native OLE1 data of size nOle1Size, wraps it in an OLE2 container.
+ *
+ * The OLE2 root's CLSID is set based on rClassName.
+ */
+void WrapOle1InOle2(SvStream& rOle1, sal_uInt32 nOle1Size, SvStream& rOle2,
+ const OString& rClassName)
+{
+ tools::SvRef<SotStorage> pStorage = new SotStorage(rOle2);
+ OString aAnsiUserType;
+ SvGlobalName aName;
+ if (rClassName == "PBrush")
+ {
+ aAnsiUserType = "Bitmap Image";
+ aName = SvGlobalName(0x0003000A, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
+ }
+ else
+ {
+ if (!rClassName.isEmpty() && rClassName != "Package")
+ {
+ SAL_WARN("filter.ms", "WrapOle1InOle2: unexpected class name: '" << rClassName << "'");
+ }
+ aAnsiUserType = "OLE Package";
+ aName = SvGlobalName(0x0003000C, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
+ }
+ pStorage->SetClass(aName, SotClipboardFormatId::NONE, "");
+
+ // [MS-OLEDS] 2.3.7 CompObjHeader
+ tools::SvRef<SotStorageStream> pCompObj = pStorage->OpenSotStream("\1CompObj");
+ // Reserved1
+ pCompObj->WriteUInt32(0xfffe0001);
+ // Version
+ pCompObj->WriteUInt32(0x00000a03);
+ // Reserved2
+ pCompObj->WriteUInt32(0xffffffff);
+ pCompObj->WriteUInt32(0x0003000c);
+ pCompObj->WriteUInt32(0x00000000);
+ pCompObj->WriteUInt32(0x000000c0);
+ pCompObj->WriteUInt32(0x46000000);
+ // Rest of CompObjStream
+ // AnsiUserType
+ pCompObj->WriteUInt32(aAnsiUserType.getLength() + 1);
+ pCompObj->WriteOString(aAnsiUserType);
+ pCompObj->WriteChar(0);
+ // AnsiClipboardFormat
+ pCompObj->WriteUInt32(0x00000000);
+ // Reserved1
+ pCompObj->WriteUInt32(rClassName.getLength() + 1);
+ pCompObj->WriteOString(rClassName);
+ pCompObj->WriteChar(0);
+ // UnicodeMarker
+ pCompObj->WriteUInt32(0x71B239F4);
+ // UnicodeUserType
+ pCompObj->WriteUInt32(0x00000000);
+ // UnicodeClipboardFormat
+ pCompObj->WriteUInt32(0x00000000);
+ // Reserved2
+ pCompObj->WriteUInt32(0x00000000);
+ pCompObj->Commit();
+ pCompObj.clear();
+
+ // [MS-OLEDS] 2.3.6 OLENativeStream
+ tools::SvRef<SotStorageStream> pOleNative = pStorage->OpenSotStream("\1Ole10Native");
+ // NativeDataSize
+ pOleNative->WriteUInt32(nOle1Size);
+ pOleNative->WriteStream(rOle1, nOle1Size);
+ pOleNative->Commit();
+ pOleNative.clear();
+
+ pStorage->Commit();
+ pStorage.clear();
+ rOle2.Seek(0);
+}
+}
+
+namespace msfilter::rtfutil
+{
+OString OutHex(sal_uLong nHex, sal_uInt8 nLen)
+{
+ char aNToABuf[] = "0000000000000000";
+
+ OSL_ENSURE(nLen < sizeof(aNToABuf), "nLen is too big");
+ if (nLen >= sizeof(aNToABuf))
+ nLen = (sizeof(aNToABuf) - 1);
+
+ // Set pointer to the buffer end
+ char* pStr = aNToABuf + (sizeof(aNToABuf) - 1);
+ for (sal_uInt8 n = 0; n < nLen; ++n)
+ {
+ *(--pStr) = static_cast<char>(nHex & 0xf) + 48;
+ if (*pStr > '9')
+ *pStr += 39;
+ nHex >>= 4;
+ }
+ return pStr;
+}
+
+// Ideally, this function should work on (sal_uInt32) Unicode scalar values
+// instead of (sal_Unicode) UTF-16 code units. However, at least "Rich Text
+// Format (RTF) Specification Version 1.9.1" available at
+// <https://www.microsoft.com/en-us/download/details.aspx?id=10725> does not
+// look like it allows non-BMP Unicode characters >= 0x10000 in the \uN notation
+// (it only talks about "Unicode character", but then explains how values of N
+// greater than 32767 will be expressed as negative signed 16-bit numbers, so
+// that smells like \uN is limited to BMP).
+// However the "Mathematics" section has an example that shows the code point
+// U+1D44E being encoded as UTF-16 surrogate pair "\u-10187?\u-9138?", so
+// sal_Unicode actually works fine here.
+OString OutChar(sal_Unicode c, int* pUCMode, rtl_TextEncoding eDestEnc, bool* pSuccess,
+ bool bUnicode)
+{
+ if (pSuccess)
+ *pSuccess = true;
+ OStringBuffer aBuf;
+ const char* pStr = nullptr;
+ // 0x0b instead of \n, etc because of the replacements in SwWW8AttrIter::GetSnippet()
+ switch (c)
+ {
+ case 0x0b:
+ // hard line break
+ pStr = OOO_STRING_SVTOOLS_RTF_LINE;
+ break;
+ case '\t':
+ pStr = OOO_STRING_SVTOOLS_RTF_TAB;
+ break;
+ case '\\':
+ case '}':
+ case '{':
+ aBuf.append('\\');
+ aBuf.append(static_cast<char>(c));
+ break;
+ case 0xa0:
+ // non-breaking space
+ pStr = "\\~";
+ break;
+ case 0x1e:
+ // non-breaking hyphen
+ pStr = "\\_";
+ break;
+ case 0x1f:
+ // optional hyphen
+ pStr = "\\-";
+ break;
+ default:
+ if (c >= ' ' && c <= '~')
+ aBuf.append(static_cast<char>(c));
+ else
+ {
+ OUString sBuf(&c, 1);
+ OString sConverted;
+ if (pSuccess)
+ *pSuccess &= sBuf.convertToString(&sConverted, eDestEnc,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
+ else
+ sBuf.convertToString(&sConverted, eDestEnc, OUSTRING_TO_OSTRING_CVTFLAGS);
+ const sal_Int32 nLen = sConverted.getLength();
+
+ if (pUCMode && bUnicode)
+ {
+ if (*pUCMode != nLen)
+ {
+ aBuf.append("\\uc");
+ aBuf.append(nLen);
+ // #i47831# add an additional whitespace, so that "document whitespaces" are not ignored.
+ aBuf.append(' ');
+ *pUCMode = nLen;
+ }
+ aBuf.append("\\u");
+ aBuf.append(static_cast<sal_Int32>(c));
+ }
+
+ for (sal_Int32 nI = 0; nI < nLen; ++nI)
+ {
+ aBuf.append("\\'");
+ aBuf.append(OutHex(sConverted[nI], 2));
+ }
+ }
+ }
+ if (pStr)
+ {
+ aBuf.append(pStr);
+ switch (c)
+ {
+ case 0xa0:
+ case 0x1e:
+ case 0x1f:
+ break;
+ default:
+ aBuf.append(' ');
+ }
+ }
+ return aBuf.makeStringAndClear();
+}
+
+OString OutString(const OUString& rStr, rtl_TextEncoding eDestEnc, bool bUnicode)
+{
+ SAL_INFO("filter.ms", __func__ << ", rStr = '" << rStr << "'");
+ OStringBuffer aBuf;
+ int nUCMode = 1;
+ for (sal_Int32 n = 0; n < rStr.getLength(); ++n)
+ aBuf.append(OutChar(rStr[n], &nUCMode, eDestEnc, nullptr, bUnicode));
+ if (nUCMode != 1)
+ {
+ aBuf.append(OOO_STRING_SVTOOLS_RTF_UC);
+ aBuf.append(sal_Int32(1));
+ aBuf.append(
+ " "); // #i47831# add an additional whitespace, so that "document whitespaces" are not ignored.;
+ }
+ return aBuf.makeStringAndClear();
+}
+
+/// Checks if lossless conversion of the string to eDestEnc is possible or not.
+static bool TryOutString(const OUString& rStr, rtl_TextEncoding eDestEnc)
+{
+ int nUCMode = 1;
+ for (sal_Int32 n = 0; n < rStr.getLength(); ++n)
+ {
+ bool bRet;
+ OutChar(rStr[n], &nUCMode, eDestEnc, &bRet);
+ if (!bRet)
+ return false;
+ }
+ return true;
+}
+
+OString OutStringUpr(const char* pToken, const OUString& rStr, rtl_TextEncoding eDestEnc)
+{
+ if (TryOutString(rStr, eDestEnc))
+ return OString::Concat("{") + pToken + " " + OutString(rStr, eDestEnc) + "}";
+
+ return OString::Concat("{" OOO_STRING_SVTOOLS_RTF_UPR "{") + pToken + " "
+ + OutString(rStr, eDestEnc, /*bUnicode =*/false)
+ + "}{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_UD "{" + pToken + " "
+ + OutString(rStr, eDestEnc) + "}}}";
+}
+
+int AsHex(char ch)
+{
+ int ret = 0;
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ ret = ch - '0';
+ else
+ {
+ if (ch >= 'a' && ch <= 'f')
+ ret = ch - 'a';
+ else if (ch >= 'A' && ch <= 'F')
+ ret = ch - 'A';
+ else
+ return -1;
+ ret += 10;
+ }
+ return ret;
+}
+
+OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, SvStream* pStream, sal_uInt32 nLimit)
+{
+ OStringBuffer aRet;
+
+ sal_uInt32 nBreak = 0;
+ for (sal_uInt32 i = 0; i < nSize; i++)
+ {
+ OString sNo = OString::number(pData[i], 16);
+ if (sNo.getLength() < 2)
+ {
+ if (pStream)
+ pStream->WriteChar('0');
+ else
+ aRet.append('0');
+ }
+ if (pStream)
+ pStream->WriteOString(sNo);
+ else
+ aRet.append(sNo);
+ if (++nBreak == nLimit)
+ {
+ if (pStream)
+ pStream->WriteCharPtr(SAL_NEWLINE_STRING);
+ else
+ aRet.append(SAL_NEWLINE_STRING);
+ nBreak = 0;
+ }
+ }
+
+ return aRet.makeStringAndClear();
+}
+
+bool ExtractOLE2FromObjdata(const OString& rObjdata, SvStream& rOle2)
+{
+ SvMemoryStream aStream;
+ int b = 0;
+ int count = 2;
+
+ // Feed the destination text to a stream.
+ for (int i = 0; i < rObjdata.getLength(); ++i)
+ {
+ char ch = rObjdata[i];
+ if (ch != 0x0d && ch != 0x0a)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return false;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aStream.WriteChar(b);
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+
+ // Skip ObjectHeader, see [MS-OLEDS] 2.2.4.
+ if (!aStream.Tell())
+ return true;
+
+ aStream.Seek(0);
+ sal_uInt32 nData;
+ aStream.ReadUInt32(nData); // OLEVersion
+ aStream.ReadUInt32(nData); // FormatID
+ aStream.ReadUInt32(nData); // ClassName
+ OString aClassName;
+ if (nData)
+ {
+ // -1 because it is null-terminated.
+ aClassName = read_uInt8s_ToOString(aStream, nData - 1);
+ // Skip null-termination.
+ aStream.SeekRel(1);
+ }
+ aStream.ReadUInt32(nData); // TopicName
+ aStream.SeekRel(nData);
+ aStream.ReadUInt32(nData); // ItemName
+ aStream.SeekRel(nData);
+ aStream.ReadUInt32(nData); // NativeDataSize
+
+ if (!nData)
+ return true;
+
+ sal_uInt64 nPos = aStream.Tell();
+ sal_uInt8 aSignature[8];
+ aStream.ReadBytes(aSignature, SAL_N_ELEMENTS(aSignature));
+ aStream.Seek(nPos);
+ const sal_uInt8 aOle2Signature[8] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+ // Don't use Storage::IsStorageFile() here, that would seek to the start of the stream,
+ // where the magic will always mismatch.
+ if (std::memcmp(aSignature, aOle2Signature, SAL_N_ELEMENTS(aSignature)) == 0)
+ {
+ // NativeData
+ rOle2.WriteStream(aStream, nData);
+ }
+ else
+ {
+ SvMemoryStream aStorage;
+ WrapOle1InOle2(aStream, nData, aStorage, aClassName);
+ rOle2.WriteStream(aStorage);
+ }
+ rOle2.Seek(0);
+
+ return true;
+}
+
+bool StripMetafileHeader(const sal_uInt8*& rpGraphicAry, sal_uInt64& rSize)
+{
+ if (rpGraphicAry && (rSize > 0x22))
+ {
+ if ((rpGraphicAry[0] == 0xd7) && (rpGraphicAry[1] == 0xcd) && (rpGraphicAry[2] == 0xc6)
+ && (rpGraphicAry[3] == 0x9a))
+ {
+ // we have to get rid of the metafileheader
+ rpGraphicAry += 22;
+ rSize -= 22;
+ return true;
+ }
+ }
+ return false;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/svdfppt.cxx b/filter/source/msfilter/svdfppt.cxx
new file mode 100644
index 000000000..74f8da16f
--- /dev/null
+++ b/filter/source/msfilter/svdfppt.cxx
@@ -0,0 +1,7832 @@
+/* -*- 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/.
+ *
+ * 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 <osl/endian.h>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <unotools/tempfile.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editdata.hxx>
+#include <sot/storage.hxx>
+#include <sot/storinfo.hxx>
+#include <sot/stg.hxx>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/office/XAnnotation.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <filter/msfilter/svdfppt.hxx>
+#include <svx/xflgrit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdotable.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xfltrit.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/numdef.hxx>
+#include <svx/sdasitm.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/sdtagitm.hxx>
+#include <svx/sdtditm.hxx>
+#include <svx/sdtfsitm.hxx>
+#include <svx/sdtmfitm.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <editeng/hngpnctitem.hxx>
+#include <editeng/forbiddenruleitem.hxx>
+#include <svx/svdoashp.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/editids.hrc>
+
+#include <editeng/adjustitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/numitem.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/BitmapReadAccess.hxx>
+#include <svx/svditer.hxx>
+#include <editeng/flditem.hxx>
+#include <tools/zcodec.hxx>
+#include <filter/msfilter/svxmsbas.hxx>
+#include <sfx2/objsh.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/langitem.hxx>
+#include <svx/svdoole2.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <editeng/frmdiritem.hxx>
+#include <svx/sdtfchim.hxx>
+#include <com/sun/star/awt/Gradient.hpp>
+#include <com/sun/star/table/XMergeableCellRange.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/table/BorderLineStyle.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <svtools/embedhlp.hxx>
+#include <o3tl/enumrange.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <cassert>
+#include <rtl/strbuf.hxx>
+#include <tools/time.hxx>
+#include <memory>
+
+// PPT ColorScheme Slots
+#define PPT_COLSCHEME (0x08000000)
+#define PPT_COLSCHEME_HINTERGRUND (0x08000000)
+#define PPT_COLSCHEME_TEXT_UND_ZEILEN (0x08000001)
+#define PPT_COLSCHEME_TITELTEXT (0x08000003)
+#define PPT_COLSCHEME_A_UND_HYPERLINK (0x08000006)
+
+#define ANSI_CHARSET 0
+#define SYMBOL_CHARSET 2
+
+/* Font Families */
+#define FF_ROMAN 0x10
+#define FF_SWISS 0x20
+#define FF_MODERN 0x30
+#define FF_SCRIPT 0x40
+#define FF_DECORATIVE 0x50
+
+#define DEFAULT_PITCH 0x00
+#define FIXED_PITCH 0x01
+#define VARIABLE_PITCH 0x02
+
+using namespace ::com::sun::star ;
+using namespace uno ;
+using namespace beans ;
+using namespace drawing ;
+using namespace container ;
+using namespace table ;
+
+PowerPointImportParam::PowerPointImportParam( SvStream& rDocStrm ) :
+ rDocStream ( rDocStrm ),
+ nImportFlags ( 0 )
+{
+}
+
+SvStream& ReadPptCurrentUserAtom( SvStream& rIn, PptCurrentUserAtom& rAtom )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+ if ( aHd.nRecType == PPT_PST_CurrentUserAtom )
+ {
+ sal_uInt32 nLen;
+ sal_uInt16 nUserNameLen(0), nPad;
+ rIn.ReadUInt32( nLen )
+ .ReadUInt32( rAtom.nMagic )
+ .ReadUInt32( rAtom.nCurrentUserEdit )
+ .ReadUInt16( nUserNameLen )
+ .ReadUInt16( rAtom.nDocFileVersion )
+ .ReadUChar( rAtom.nMajorVersion )
+ .ReadUChar( rAtom.nMinorVersion )
+ .ReadUInt16( nPad );
+ rAtom.aCurrentUser = SvxMSDffManager::MSDFFReadZString( rIn, nUserNameLen, true );
+ }
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+void PptSlidePersistAtom::Clear()
+{
+ nReserved = nPsrReference = nFlags = nNumberTexts = nSlideId = 0;
+}
+
+SvStream& ReadPptSlidePersistAtom( SvStream& rIn, PptSlidePersistAtom& rAtom )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+ rIn
+ .ReadUInt32( rAtom.nPsrReference )
+ .ReadUInt32( rAtom.nFlags )
+ .ReadUInt32( rAtom.nNumberTexts )
+ .ReadUInt32( rAtom.nSlideId );
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+PptSlidePersistList::PptSlidePersistList() {}
+
+PptSlidePersistList::~PptSlidePersistList() {}
+
+sal_uInt16 PptSlidePersistList::FindPage(sal_uInt32 nId) const
+{
+ for ( size_t i=0; i < mvEntries.size(); i++ )
+ {
+ if (mvEntries[ i ]->GetSlideId() == nId) return i;
+ }
+ return PPTSLIDEPERSIST_ENTRY_NOTFOUND;
+}
+
+SvStream& ReadPptInteractiveInfoAtom( SvStream& rIn, PptInteractiveInfoAtom& rAtom )
+{
+ rIn.ReadUInt32( rAtom.nSoundRef )
+ .ReadUInt32( rAtom.nExHyperlinkId )
+ .ReadUChar( rAtom.nAction )
+ .ReadUChar( rAtom.nOleVerb )
+ .ReadUChar( rAtom.nJump )
+ .ReadUChar( rAtom.nFlags )
+ .ReadUChar( rAtom.nHyperlinkType )
+ .ReadUChar( rAtom.nUnknown1 )
+ .ReadUChar( rAtom.nUnknown2 )
+ .ReadUChar( rAtom.nUnknown3 );
+ return rIn;
+}
+
+SvStream& ReadPptExOleObjAtom( SvStream& rIn, PptExOleObjAtom& rAtom )
+{
+ sal_uInt32 nDummy1;
+ sal_uInt32 nDummy2;
+ sal_uInt32 nDummy4;
+
+ rIn.ReadUInt32( rAtom.nAspect )
+ .ReadUInt32( nDummy1 )
+ .ReadUInt32( rAtom.nId )
+ .ReadUInt32( nDummy2 )
+ .ReadUInt32( rAtom.nPersistPtr )
+ .ReadUInt32( nDummy4 );
+ return rIn;
+}
+
+SvStream& ReadPptDocumentAtom(SvStream& rIn, PptDocumentAtom& rAtom)
+{
+// Actual format:
+// 00 aSlidePageSizeXY 8
+// 08 aNotesPageSizeXY 8
+// 16 aZoomRatio (OLE) 8
+// 24 nNotesMasterPersist 4
+// 28 nHandoutMasterPersist 4
+// 32 n1stPageNumber 2
+// 34 ePageFormat 2
+// 36 bEmbeddedTrueType 1
+// 37 bOmitTitlePlace 1
+// 38 bRightToLeft 1
+// 39 bShowComments 1
+
+ DffRecordHeader aHd;
+ sal_Int32 nSlideX(0), nSlideY(0), nNoticeX(0), nNoticeY(0), nDummy;
+ sal_uInt16 nSlidePageFormat(0);
+ sal_Int8 nEmbeddedTrueType(0), nTitlePlaceHoldersOmitted(0), nRightToLeft(0), nShowComments(0);
+
+ ReadDffRecordHeader( rIn, aHd );
+ rIn
+ .ReadInt32( nSlideX ).ReadInt32( nSlideY )
+ .ReadInt32( nNoticeX ).ReadInt32( nNoticeY )
+ .ReadInt32( nDummy ).ReadInt32( nDummy ) // skip ZoomRatio
+ .ReadUInt32( rAtom.nNotesMasterPersist )
+ .ReadUInt32( rAtom.nHandoutMasterPersist )
+ .ReadUInt16( rAtom.n1stPageNumber )
+ .ReadUInt16( nSlidePageFormat )
+ .ReadSChar( nEmbeddedTrueType )
+ .ReadSChar( nTitlePlaceHoldersOmitted )
+ .ReadSChar( nRightToLeft )
+ .ReadSChar( nShowComments );
+ // clamp dodgy data to avoid overflow in later calculations
+ const sal_Int32 nPageClamp = SAL_MAX_INT32/5;
+ rAtom.aSlidesPageSize.setWidth( std::clamp<sal_Int32>(nSlideX, -nPageClamp, nPageClamp) );
+ rAtom.aSlidesPageSize.setHeight( std::clamp<sal_Int32>(nSlideY, -nPageClamp, nPageClamp) );
+ const sal_Int32 nNoteClamp = 65536;
+ rAtom.aNotesPageSize.setWidth( std::clamp<sal_Int32>(nNoticeX, -nNoteClamp, nNoteClamp) );
+ rAtom.aNotesPageSize.setHeight( std::clamp<sal_Int32>(nNoticeY, -nNoteClamp, nNoteClamp) );
+ rAtom.eSlidesPageFormat = static_cast<PptPageFormat>(nSlidePageFormat);
+ rAtom.bEmbeddedTrueType = nEmbeddedTrueType;
+ rAtom.bTitlePlaceholdersOmitted = nTitlePlaceHoldersOmitted;
+ rAtom.bRightToLeft = nRightToLeft;
+ rAtom.bShowComments = nShowComments;
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+void PptSlideLayoutAtom::Clear()
+{
+ eLayout = PptSlideLayout::TITLESLIDE;
+ for (PptPlaceholder & i : aPlaceholderId)
+ i = PptPlaceholder::NONE;
+}
+
+SvStream& ReadPptSlideLayoutAtom( SvStream& rIn, PptSlideLayoutAtom& rAtom )
+{
+ sal_Int32 nTmp;
+ rIn.ReadInt32(nTmp);
+ rAtom.eLayout = static_cast<PptSlideLayout>(nTmp);
+ static_assert(sizeof(rAtom.aPlaceholderId) == 8, "wrong size of serialized array");
+ rIn.ReadBytes(rAtom.aPlaceholderId, 8);
+ return rIn;
+}
+
+SvStream& ReadPptSlideAtom( SvStream& rIn, PptSlideAtom& rAtom )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+ ReadPptSlideLayoutAtom( rIn, rAtom.aLayout );
+ rIn.ReadUInt32( rAtom.nMasterId )
+ .ReadUInt32( rAtom.nNotesId )
+ .ReadUInt16( rAtom.nFlags );
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+void PptSlideAtom::Clear()
+{
+ nMasterId = nNotesId = 0;
+ nFlags = 0;
+}
+
+SvStream& ReadPptNotesAtom( SvStream& rIn, PptNotesAtom& rAtom )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+ rIn
+ .ReadUInt32( rAtom.nSlideId )
+ .ReadUInt16( rAtom.nFlags );
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+void PptNotesAtom::Clear()
+{
+ nSlideId = 0;
+ nFlags = 0;
+}
+
+PptColorSchemeAtom::PptColorSchemeAtom()
+{
+}
+
+Color PptColorSchemeAtom::GetColor( sal_uInt16 nNum ) const
+{
+ Color aRetval;
+ if ( nNum < 8 )
+ {
+ nNum <<= 2;
+ aRetval.SetRed( aData[ nNum++ ] );
+ aRetval.SetGreen( aData[ nNum++ ] );
+ aRetval.SetBlue( aData[ nNum++ ] );
+ }
+ return aRetval;
+}
+
+SvStream& ReadPptColorSchemeAtom( SvStream& rIn, PptColorSchemeAtom& rAtom )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+ rIn.ReadBytes(rAtom.aData, 32);
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+SvStream& ReadPptFontEntityAtom( SvStream& rIn, PptFontEntityAtom& rAtom )
+{
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rIn, aHd );
+ sal_Unicode nTemp, cData[ 32 ];
+ rIn.ReadBytes(cData, 64);
+
+ sal_uInt8 lfCharset, lfPitchAndFamily;
+
+ rIn.ReadUChar( lfCharset )
+ .ReadUChar( rAtom.lfClipPrecision )
+ .ReadUChar( rAtom.lfQuality )
+ .ReadUChar( lfPitchAndFamily );
+
+ switch( lfCharset )
+ {
+ case SYMBOL_CHARSET :
+ rAtom.eCharSet = RTL_TEXTENCODING_SYMBOL;
+ break;
+ case ANSI_CHARSET :
+ rAtom.eCharSet = RTL_TEXTENCODING_MS_1252;
+ break;
+
+ default :
+ rAtom.eCharSet = osl_getThreadTextEncoding();
+ }
+ switch ( lfPitchAndFamily & 0xf0 )
+ {
+ case FF_ROMAN:
+ rAtom.eFamily = FAMILY_ROMAN;
+ break;
+
+ case FF_SWISS:
+ rAtom.eFamily = FAMILY_SWISS;
+ break;
+
+ case FF_MODERN:
+ rAtom.eFamily = FAMILY_MODERN;
+ break;
+
+ case FF_SCRIPT:
+ rAtom.eFamily = FAMILY_SCRIPT;
+ break;
+
+ case FF_DECORATIVE:
+ rAtom.eFamily = FAMILY_DECORATIVE;
+ break;
+
+ default:
+ rAtom.eFamily = FAMILY_DONTKNOW;
+ break;
+ }
+
+ switch ( lfPitchAndFamily & 0x0f )
+ {
+ case FIXED_PITCH:
+ rAtom.ePitch = PITCH_FIXED;
+ break;
+
+ case DEFAULT_PITCH:
+ case VARIABLE_PITCH:
+ default:
+ rAtom.ePitch = PITCH_VARIABLE;
+ break;
+ }
+ sal_uInt16 i;
+ for ( i = 0; i < 32; i++ )
+ {
+ nTemp = cData[ i ];
+ if ( !nTemp )
+ break;
+#ifdef OSL_BIGENDIAN
+ cData[ i ] = ( nTemp >> 8 ) | ( nTemp << 8 );
+#endif
+ }
+ rAtom.aName = OUString(cData, i);
+ OutputDevice* pDev = Application::GetDefaultDevice();
+ rAtom.bAvailable = pDev->IsFontAvailable( rAtom.aName );
+ aHd.SeekToEndOfRecord( rIn );
+ return rIn;
+}
+
+SvStream& ReadPptUserEditAtom( SvStream& rIn, PptUserEditAtom& rAtom )
+{
+ sal_Int16 lastViewType = 0;
+ ReadDffRecordHeader( rIn, rAtom.aHd );
+ rIn
+ .ReadInt32( rAtom.nLastSlideID )
+ .ReadUInt32( rAtom.nVersion )
+ .ReadUInt32( rAtom.nOffsetLastEdit )
+ .ReadUInt32( rAtom.nOffsetPersistDirectory )
+ .ReadUInt32( rAtom.nDocumentRef )
+ .ReadUInt32( rAtom.nMaxPersistWritten )
+ .ReadInt16( lastViewType );
+ rAtom.eLastViewType = static_cast<PptViewTypeEnum>(lastViewType);
+ rAtom.aHd.SeekToEndOfRecord(rIn);
+ return rIn;
+}
+
+void PptOEPlaceholderAtom::Clear()
+{
+ nPlacementId = 0;
+ nPlaceholderSize = 0;
+ nPlaceholderId = PptPlaceholder::NONE;
+}
+
+SvStream& ReadPptOEPlaceholderAtom( SvStream& rIn, PptOEPlaceholderAtom& rAtom )
+{
+ rIn.ReadUInt32( rAtom.nPlacementId );
+ sal_uInt8 nTmp;
+ rIn.ReadUChar(nTmp);
+ rAtom.nPlaceholderId = static_cast<PptPlaceholder>(nTmp);
+ rIn.ReadUChar( rAtom.nPlaceholderSize );
+ return rIn;
+}
+
+PptSlidePersistEntry::PptSlidePersistEntry() :
+ nSlidePersistStartOffset( 0 ),
+ nSlidePersistEndOffset ( 0 ),
+ nBackgroundOffset ( 0 ),
+ nDrawingDgId ( 0xffffffff ),
+ pBObj ( nullptr ),
+ ePageKind ( PPT_MASTERPAGE ),
+ bNotesMaster ( false ),
+ bHandoutMaster ( false ),
+ bStarDrawFiller ( false )
+{
+ HeaderFooterOfs[ 0 ] = HeaderFooterOfs[ 1 ] = HeaderFooterOfs[ 2 ] = HeaderFooterOfs[ 3 ] = 0;
+}
+
+PptSlidePersistEntry::~PptSlidePersistEntry()
+{
+}
+
+SdrEscherImport::SdrEscherImport( PowerPointImportParam& rParam, const OUString& rBaseURL ) :
+ SvxMSDffManager ( rParam.rDocStream, rBaseURL ),
+ nStreamLen ( 0 ),
+ rImportParam ( rParam )
+{
+}
+
+SdrEscherImport::~SdrEscherImport()
+{
+}
+
+const PptSlideLayoutAtom* SdrEscherImport::GetSlideLayoutAtom() const
+{
+ return nullptr;
+}
+
+bool SdrEscherImport::ReadString( OUString& rStr ) const
+{
+ bool bRet = false;
+ DffRecordHeader aStrHd;
+ ReadDffRecordHeader( rStCtrl, aStrHd );
+ if (aStrHd.nRecType == PPT_PST_TextBytesAtom
+ || aStrHd.nRecType == PPT_PST_TextCharsAtom
+ || aStrHd.nRecType == PPT_PST_CString)
+ {
+ bool bUniCode =
+ (aStrHd.nRecType == PPT_PST_TextCharsAtom
+ || aStrHd.nRecType == PPT_PST_CString);
+ sal_uLong nBytes = aStrHd.nRecLen;
+ rStr = MSDFFReadZString( rStCtrl, nBytes, bUniCode );
+ bRet = aStrHd.SeekToEndOfRecord( rStCtrl );
+ }
+ else
+ aStrHd.SeekToBegOfRecord( rStCtrl );
+ return bRet;
+}
+
+bool SdrEscherImport::GetColorFromPalette(sal_uInt16 /*nNum*/, Color& /*rColor*/) const
+{
+ return false;
+}
+
+bool SdrEscherImport::SeekToShape( SvStream& /*rSt*/, SvxMSDffClientData* /*pClientData*/, sal_uInt32 /*nId*/) const
+{
+ return false;
+}
+
+const PptFontEntityAtom* SdrEscherImport::GetFontEnityAtom( sal_uInt32 nNum ) const
+{
+ if (m_xFonts && nNum < m_xFonts->size())
+ return &(*m_xFonts)[ nNum ];
+ return nullptr;
+}
+
+SdrObject* SdrEscherImport::ReadObjText( PPTTextObj* /*pTextObj*/, SdrObject* pObj, SdPageCapsule /*pPage*/) const
+{
+ return pObj;
+}
+
+void SdrEscherImport::ProcessClientAnchor2( SvStream& rSt, DffRecordHeader& rHd, DffObjData& rObj )
+{
+ sal_Int32 l, t, r, b;
+ if ( rHd.nRecLen == 16 )
+ {
+ rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b );
+ }
+ else
+ {
+ sal_Int16 ls, ts, rs, bs;
+ rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange...
+ l = ls;
+ t = ts;
+ r = rs;
+ b = bs;
+ }
+ if (!rSt.good())
+ {
+ SAL_WARN("filter.ms", "ProcessClientAnchor2: short read");
+ return;
+ }
+ Scale( l );
+ Scale( t );
+ Scale( r );
+ Scale( b );
+ rObj.aChildAnchor = tools::Rectangle( l, t, r, b );
+ rObj.bChildAnchor = true;
+};
+
+void SdrEscherImport::RecolorGraphic( SvStream& rSt, sal_uInt32 nRecLen, Graphic& rGraphic )
+{
+ if ( rGraphic.GetType() != GraphicType::GdiMetafile )
+ return;
+
+ sal_uInt16 nX, nGlobalColorsCount, nFillColorsCount;
+
+ rSt.ReadUInt16( nX )
+ .ReadUInt16( nGlobalColorsCount )
+ .ReadUInt16( nFillColorsCount )
+ .ReadUInt16( nX )
+ .ReadUInt16( nX )
+ .ReadUInt16( nX );
+
+ if ( ( nGlobalColorsCount > 64 ) || ( nFillColorsCount > 64 ) )
+ return;
+
+ if ( static_cast<sal_uInt32>( ( nGlobalColorsCount + nFillColorsCount ) * 44 + 12 ) != nRecLen )
+ return;
+
+ sal_uInt32 OriginalGlobalColors[ 64 ];
+ sal_uInt32 NewGlobalColors[ 64 ];
+
+ sal_uInt32 i, j, nGlobalColorsChanged, nFillColorsChanged;
+ nGlobalColorsChanged = nFillColorsChanged = 0;
+
+ sal_uInt32* pCurrentOriginal = OriginalGlobalColors;
+ sal_uInt32* pCurrentNew = NewGlobalColors;
+ sal_uInt32* pCount = &nGlobalColorsChanged;
+ i = nGlobalColorsCount;
+
+ for ( j = 0; j < 2; j++ )
+ {
+ for ( ; i > 0; i-- )
+ {
+ sal_uInt64 nPos = rSt.Tell();
+ sal_uInt16 nChanged;
+ rSt.ReadUInt16( nChanged );
+ if ( nChanged & 1 )
+ {
+ sal_uInt8 nDummy, nRed, nGreen, nBlue;
+ sal_uInt32 nColor = 0;
+ sal_uInt32 nIndex;
+ rSt.ReadUChar( nDummy )
+ .ReadUChar( nRed )
+ .ReadUChar( nDummy )
+ .ReadUChar( nGreen )
+ .ReadUChar( nDummy )
+ .ReadUChar( nBlue )
+ .ReadUInt32( nIndex );
+
+ if ( nIndex < 8 )
+ {
+ Color aColor = MSO_CLR_ToColor( nIndex << 24 );
+ nRed = aColor.GetRed();
+ nGreen = aColor.GetGreen();
+ nBlue = aColor.GetBlue();
+ }
+ nColor = nRed | ( nGreen << 8 ) | ( nBlue << 16 );
+ *pCurrentNew++ = nColor;
+ rSt.ReadUChar( nDummy )
+ .ReadUChar( nRed )
+ .ReadUChar( nDummy )
+ .ReadUChar( nGreen )
+ .ReadUChar( nDummy )
+ .ReadUChar( nBlue );
+ nColor = nRed | ( nGreen << 8 ) | ( nBlue << 16 );
+ *pCurrentOriginal++ = nColor;
+ (*pCount)++;
+ }
+ rSt.Seek( nPos + 44 );
+ }
+ pCount = &nFillColorsChanged;
+ i = nFillColorsCount;
+ }
+ if ( !(nGlobalColorsChanged || nFillColorsChanged) )
+ return;
+
+ std::unique_ptr<Color[]> pSearchColors(new Color[ nGlobalColorsChanged ]);
+ std::unique_ptr<Color[]> pReplaceColors(new Color[ nGlobalColorsChanged ]);
+
+ for ( j = 0; j < nGlobalColorsChanged; j++ )
+ {
+ sal_uInt32 nSearch = OriginalGlobalColors[ j ];
+ sal_uInt32 nReplace = NewGlobalColors[ j ];
+
+ pSearchColors[ j ].SetRed( static_cast<sal_uInt8>(nSearch) );
+ pSearchColors[ j ].SetGreen( static_cast<sal_uInt8>( nSearch >> 8 ) );
+ pSearchColors[ j ].SetBlue( static_cast<sal_uInt8>( nSearch >> 16 ) );
+
+ pReplaceColors[ j ].SetRed( static_cast<sal_uInt8>(nReplace) );
+ pReplaceColors[ j ].SetGreen( static_cast<sal_uInt8>( nReplace >> 8 ) );
+ pReplaceColors[ j ].SetBlue( static_cast<sal_uInt8>( nReplace >> 16 ) );
+ }
+ GDIMetaFile aGdiMetaFile( rGraphic.GetGDIMetaFile() );
+ aGdiMetaFile.ReplaceColors( pSearchColors.get(), pReplaceColors.get(),
+ nGlobalColorsChanged );
+ rGraphic = aGdiMetaFile;
+}
+
+sal_uLong DffPropSet::SanitizeEndPos(SvStream &rIn, sal_uLong nEndRecPos)
+{
+ auto nStreamLen = rIn.Tell() + rIn.remainingSize();
+ if (nEndRecPos > nStreamLen)
+ {
+ SAL_WARN("filter.ms", "Parsing error: " << nStreamLen <<
+ " max end pos, but " << nEndRecPos << " claimed, truncating");
+ nEndRecPos = nStreamLen;
+ }
+ return nEndRecPos;
+}
+
+void ProcessData::NotifyFreeObj(SdrObject* pObj)
+{
+ if (rPersistEntry.xSolverContainer)
+ {
+ for (auto & pPtr : rPersistEntry.xSolverContainer->aCList)
+ {
+ if (pPtr->pAObj == pObj)
+ pPtr->pAObj = nullptr;
+ if (pPtr->pBObj == pObj)
+ pPtr->pBObj = nullptr;
+ if (pPtr->pCObj == pObj)
+ pPtr->pCObj = nullptr;
+ }
+ }
+}
+
+/* ProcessObject is called from ImplSdPPTImport::ProcessObj to handle all application specific things,
+ such as the import of text, animation effects, header footer and placeholder.
+
+ The parameter pOriginalObj is the object as it was imported by our general escher import, it must either
+ be deleted or it can be returned to be inserted into the sdr page.
+*/
+SdrObject* SdrEscherImport::ProcessObj( SvStream& rSt, DffObjData& rObjData, SvxMSDffClientData& rClientData, tools::Rectangle& rTextRect, SdrObject* pOriginalObj )
+{
+ if ( dynamic_cast<const SdrObjCustomShape* >(pOriginalObj) != nullptr )
+ pOriginalObj->SetMergedItem( SdrTextFixedCellHeightItem( true ) );
+
+ // we are initializing our return value with the object that was imported by our escher import
+ SdrObject* pRet = pOriginalObj;
+
+ ProcessData& rData = static_cast<ProcessData&>(rClientData);
+ PptSlidePersistEntry& rPersistEntry = rData.rPersistEntry;
+
+ if ( ! (rObjData.nSpFlags & ShapeFlag::Group) ) // sj: #114758# ...
+ {
+ PptOEPlaceholderAtom aPlaceholderAtom;
+
+ if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ sal_Int16 nHeaderFooterInstance = -1;
+ DffRecordHeader aClientDataHd;
+ auto nEndRecPos = SanitizeEndPos(rSt, maShapeRecords.Current()->GetRecEndFilePos());
+ while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) )
+ {
+ ReadDffRecordHeader( rSt, aClientDataHd );
+ switch ( aClientDataHd.nRecType )
+ {
+ // importing header/footer object from master page
+ case PPT_PST_OEPlaceholderAtom :
+ {
+ ReadPptOEPlaceholderAtom( rSt, aPlaceholderAtom );
+ if ( nHeaderFooterInstance == -1 )
+ {
+ switch ( aPlaceholderAtom.nPlaceholderId )
+ {
+ case PptPlaceholder::MASTERSLIDENUMBER : nHeaderFooterInstance++;
+ [[fallthrough]];
+ case PptPlaceholder::MASTERFOOTER : nHeaderFooterInstance++;
+ [[fallthrough]];
+ case PptPlaceholder::MASTERHEADER : nHeaderFooterInstance++;
+ [[fallthrough]];
+ case PptPlaceholder::MASTERDATE : nHeaderFooterInstance++; break;
+ default: break;
+
+ }
+ if ( ! ( nHeaderFooterInstance & 0xfffc ) ) // is this a valid instance ( 0->3 )
+ rPersistEntry.HeaderFooterOfs[ nHeaderFooterInstance ] = rObjData.rSpHd.GetRecBegFilePos();
+ }
+ }
+ break;
+
+ case PPT_PST_RecolorInfoAtom :
+ {
+ if ( auto pSdrGrafObj = dynamic_cast<SdrGrafObj* >(pRet) )
+ if ( pSdrGrafObj->HasGDIMetaFile() )
+ {
+ Graphic aGraphic( pSdrGrafObj->GetGraphic() );
+ RecolorGraphic( rSt, aClientDataHd.nRecLen, aGraphic );
+ pSdrGrafObj->SetGraphic( aGraphic );
+ }
+ }
+ break;
+ }
+ if (!aClientDataHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+ if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE ) && !rPersistEntry.bNotesMaster )
+ {
+ sal_uInt16 nPageNum = pSdrModel->GetPageCount();
+ if ( nPageNum > 0 )
+ nPageNum--;
+
+ // replacing the object which we will return with a SdrPageObj
+ SdrObject::Free( pRet );
+ pRet = new SdrPageObj(
+ *pSdrModel,
+ rObjData.aBoundRect,
+ pSdrModel->GetPage(nPageNum - 1));
+ }
+ else
+ {
+ // try to load some ppt text
+ PPTTextObj aTextObj( rSt, static_cast<SdrPowerPointImport&>(*this), rPersistEntry, &rObjData );
+ if ( aTextObj.Count() || aTextObj.GetOEPlaceHolderAtom() )
+ {
+ bool bVerticalText = false;
+ // and if the text object is not empty, it must be applied to pRet, the object we
+ // initially got from our escher import
+ Degree100 nTextRotationAngle(0);
+ if ( IsProperty( DFF_Prop_txflTextFlow ) )
+ {
+ auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
+ switch( eTextFlow )
+ {
+ case mso_txflBtoT : // Bottom to Top non-@
+ nTextRotationAngle += 9000_deg100;
+ break;
+ case mso_txflTtoBA : /* #68110# */ // Top to Bottom @-font
+ case mso_txflTtoBN : // Top to Bottom non-@
+ case mso_txflVertN : // Vertical, non-@, top to bottom
+ bVerticalText = !bVerticalText; // nTextRotationAngle += 27000;
+ break;
+ // case mso_txflHorzN : // Horizontal non-@, normal
+ // case mso_txflHorzA : // Horizontal @-font, normal
+ default: break;
+ }
+ }
+ sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 );
+ if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) )
+ {
+ bVerticalText = !bVerticalText;
+ }
+ const bool bFail = o3tl::checked_multiply<sal_Int32>(nFontDirection, 9000, nFontDirection);
+ if (!bFail)
+ nTextRotationAngle -= Degree100(nFontDirection);
+ else
+ SAL_WARN("filter.ms", "Parsing error: bad fontdirection: " << nFontDirection);
+ aTextObj.SetVertical( bVerticalText );
+ if ( pRet )
+ {
+ bool bDeleteSource = aTextObj.GetOEPlaceHolderAtom() != nullptr;
+ if ( bDeleteSource && dynamic_cast<const SdrGrafObj* >(pRet) == nullptr // we are not allowed to get
+ && dynamic_cast<const SdrObjGroup* >(pRet) == nullptr // grouped placeholder objects
+ && dynamic_cast<const SdrOle2Obj* >(pRet) == nullptr )
+ SdrObject::Free( pRet );
+ }
+ sal_uInt32 nTextFlags = aTextObj.GetTextFlags();
+ sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ); // 0.25 cm (emu)
+ sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ); // 0.25 cm (emu)
+ sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ); // 0.13 cm (emu)
+ sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 );
+ ScaleEmu( nTextLeft );
+ ScaleEmu( nTextRight );
+ ScaleEmu( nTextTop );
+ ScaleEmu( nTextBottom );
+
+ sal_Int32 nMinFrameWidth = 0;
+ sal_Int32 nMinFrameHeight = 0;
+ bool bAutoGrowWidth, bAutoGrowHeight;
+
+ SdrTextVertAdjust eTVA;
+ SdrTextHorzAdjust eTHA;
+
+ nTextFlags &= PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT
+ | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
+
+ if ( bVerticalText )
+ {
+ eTVA = SDRTEXTVERTADJUST_BLOCK;
+ eTHA = SDRTEXTHORZADJUST_CENTER;
+
+ // read text anchor
+ auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ case mso_anchorTopCentered:
+ case mso_anchorTopBaseline:
+ case mso_anchorTopCenteredBaseline:
+ eTHA = SDRTEXTHORZADJUST_RIGHT;
+ break;
+
+ case mso_anchorMiddle :
+ case mso_anchorMiddleCentered:
+ eTHA = SDRTEXTHORZADJUST_CENTER;
+ break;
+
+ case mso_anchorBottom:
+ case mso_anchorBottomCentered:
+ case mso_anchorBottomBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ eTHA = SDRTEXTHORZADJUST_LEFT;
+ break;
+ }
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ case mso_anchorTopCenteredBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ {
+ // check if it is sensible to use the centered alignment
+ const sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
+ switch (nTextFlags & nMask)
+ {
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT:
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER:
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT:
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK:
+ eTVA = SDRTEXTVERTADJUST_CENTER; // If the textobject has only one type of alignment, then the text has not to be displayed using the full width;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ nMinFrameWidth = rTextRect.GetWidth() - ( nTextLeft + nTextRight );
+ }
+ else
+ {
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ eTHA = SDRTEXTHORZADJUST_BLOCK;
+
+ // read text anchor
+ auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ case mso_anchorTopCentered:
+ case mso_anchorTopBaseline:
+ case mso_anchorTopCenteredBaseline:
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ break;
+
+ case mso_anchorMiddle :
+ case mso_anchorMiddleCentered:
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ break;
+
+ case mso_anchorBottom:
+ case mso_anchorBottomCentered:
+ case mso_anchorBottomBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ break;
+ }
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ case mso_anchorTopCenteredBaseline:
+ case mso_anchorBottomCenteredBaseline:
+ {
+ // check if it is sensible to use the centered alignment
+ const sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
+ switch (nTextFlags & nMask)
+ {
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT:
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER:
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT:
+ case PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK:
+ eTHA = SDRTEXTHORZADJUST_CENTER; // If the textobject has only one type of alignment, then the text has not to be displayed using the full width;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ nMinFrameHeight = rTextRect.GetHeight() - ( nTextTop + nTextBottom );
+ }
+
+ SdrObjKind eTextKind = SdrObjKind::Rectangle;
+ if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESSLIDEIMAGE )
+ || ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::MASTERNOTESSLIDEIMAGE ) )
+ {
+ aTextObj.SetInstance( TSS_Type::Notes );
+ eTextKind = SdrObjKind::TitleText;
+ }
+ else if ( ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::MASTERNOTESBODYIMAGE )
+ || ( aPlaceholderAtom.nPlaceholderId == PptPlaceholder::NOTESBODY ) )
+ {
+ aTextObj.SetInstance( TSS_Type::Notes );
+ eTextKind = SdrObjKind::Text;
+ }
+
+ TSS_Type nDestinationInstance = aTextObj.GetInstance();
+ if ( rPersistEntry.ePageKind == PPT_MASTERPAGE )
+ {
+ if ( !rPersistEntry.pPresentationObjects )
+ {
+ rPersistEntry.pPresentationObjects.reset( new sal_uInt32[ PPT_STYLESHEETENTRIES ] );
+ memset( rPersistEntry.pPresentationObjects.get(), 0, PPT_STYLESHEETENTRIES * 4 );
+ }
+ if ( !rPersistEntry.pPresentationObjects[ static_cast<int>(nDestinationInstance) ] )
+ rPersistEntry.pPresentationObjects[ static_cast<int>(nDestinationInstance) ] = rObjData.rSpHd.GetRecBegFilePos();
+ }
+ switch ( nDestinationInstance )
+ {
+ case TSS_Type::PageTitle :
+ case TSS_Type::Title :
+ {
+ if ( GetSlideLayoutAtom()->eLayout == PptSlideLayout::TITLEMASTERSLIDE )
+ nDestinationInstance = TSS_Type::Title;
+ else
+ nDestinationInstance = TSS_Type::PageTitle;
+ }
+ break;
+ case TSS_Type::Body :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody :
+ nDestinationInstance = TSS_Type::Body;
+ break;
+ default: break;
+ }
+ aTextObj.SetDestinationInstance( nDestinationInstance );
+
+ bool bAutoFit = false; // auto-scale text into shape box
+ switch ( aTextObj.GetInstance() )
+ {
+ case TSS_Type::PageTitle :
+ case TSS_Type::Title : eTextKind = SdrObjKind::TitleText; break;
+ case TSS_Type::Subtitle : eTextKind = SdrObjKind::Text; break;
+ case TSS_Type::Body :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody : eTextKind = SdrObjKind::OutlineText; bAutoFit = true; break;
+ default: break;
+ }
+ if ( aTextObj.GetDestinationInstance() != TSS_Type::TextInShape )
+ {
+ if ( !aTextObj.GetOEPlaceHolderAtom() || aTextObj.GetOEPlaceHolderAtom()->nPlaceholderId == PptPlaceholder::NONE )
+ {
+ aTextObj.SetDestinationInstance( TSS_Type::TextInShape );
+ eTextKind = SdrObjKind::Rectangle;
+ }
+ }
+ SdrObject* pTObj = nullptr;
+ bool bWordWrap = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone;
+ bool bFitShapeToText = ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0;
+
+ if ( dynamic_cast<const SdrObjCustomShape* >(pRet) != nullptr && ( eTextKind == SdrObjKind::Rectangle ) )
+ {
+ bAutoGrowHeight = bFitShapeToText;
+ bAutoGrowWidth = !bWordWrap;
+ pTObj = pRet;
+ pRet = nullptr;
+ }
+ else
+ {
+ if ( dynamic_cast<const SdrObjCustomShape* >(pRet) != nullptr )
+ {
+ SdrObject::Free( pRet );
+ pRet = nullptr;
+ }
+ pTObj = new SdrRectObj(
+ *pSdrModel,
+ eTextKind != SdrObjKind::Rectangle ? eTextKind : SdrObjKind::Text);
+ SfxItemSet aSet( pSdrModel->GetItemPool() );
+ if ( !pRet )
+ ApplyAttributes( rSt, aSet, rObjData );
+ pTObj->SetMergedItemSet( aSet );
+ if ( pRet )
+ {
+ pTObj->SetMergedItem( XLineStyleItem( drawing::LineStyle_NONE ) );
+ pTObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
+ }
+ if ( bVerticalText )
+ {
+ bAutoGrowWidth = bFitShapeToText;
+ bAutoGrowHeight = false;
+ }
+ else
+ {
+ bAutoGrowWidth = false;
+
+ // #119885# re-activating bFitShapeToText here, could not find deeper explanations
+ // for it (it was from 2005). Keeping the old comment here for reference
+ // old comment: // bFitShapeToText; can't be used, because we cut the text if it is too height,
+ bAutoGrowHeight = bFitShapeToText;
+ }
+ }
+ pTObj->SetMergedItem( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
+
+ //Autofit text only if there is no auto grow height and width
+ //See fdo#41245
+ if (bAutoFit && !bAutoGrowHeight && !bAutoGrowWidth)
+ {
+ pTObj->SetMergedItem( SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_AUTOFIT) );
+ }
+
+ if ( dynamic_cast<const SdrObjCustomShape* >(pTObj) == nullptr )
+ {
+ pTObj->SetMergedItem( makeSdrTextAutoGrowWidthItem( bAutoGrowWidth ) );
+ pTObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bAutoGrowHeight ) );
+ }
+ else
+ {
+ pTObj->SetMergedItem( makeSdrTextWordWrapItem( bWordWrap ) );
+ pTObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( bFitShapeToText ) );
+ }
+
+ pTObj->SetMergedItem( SdrTextVertAdjustItem( eTVA ) );
+ pTObj->SetMergedItem( SdrTextHorzAdjustItem( eTHA ) );
+
+ if ( nMinFrameHeight < 0 )
+ nMinFrameHeight = 0;
+ if ( dynamic_cast<const SdrObjCustomShape* >(pTObj) == nullptr )
+ pTObj->SetMergedItem( makeSdrTextMinFrameHeightItem( nMinFrameHeight ) );
+
+ if ( nMinFrameWidth < 0 )
+ nMinFrameWidth = 0;
+ if ( dynamic_cast<const SdrObjCustomShape* >(pTObj) == nullptr )
+ pTObj->SetMergedItem( makeSdrTextMinFrameWidthItem( nMinFrameWidth ) );
+
+ // set margins at the borders of the textbox
+ pTObj->SetMergedItem( makeSdrTextLeftDistItem( nTextLeft ) );
+ pTObj->SetMergedItem( makeSdrTextRightDistItem( nTextRight ) );
+ pTObj->SetMergedItem( makeSdrTextUpperDistItem( nTextTop ) );
+ pTObj->SetMergedItem( makeSdrTextLowerDistItem( nTextBottom ) );
+ pTObj->SetMergedItem( SdrTextFixedCellHeightItem( true ) );
+
+ if ( dynamic_cast<const SdrObjCustomShape* >(pTObj) == nullptr )
+ pTObj->SetSnapRect( rTextRect );
+ pTObj = ReadObjText( &aTextObj, pTObj, rData.pPage );
+
+ if ( pTObj )
+ {
+ /* check if our new snaprect makes trouble,
+ because we do not display the ADJUST_BLOCK
+ properly if the textsize is bigger than the
+ snaprect of the object. Then we will use
+ ADJUST_CENTER instead of ADJUST_BLOCK.
+ */
+ if ( dynamic_cast<const SdrObjCustomShape* >(pTObj) == nullptr && !bFitShapeToText && !bWordWrap )
+ {
+ SdrTextObj* pText = dynamic_cast<SdrTextObj*>( pTObj );
+ if ( pText )
+ {
+ if ( bVerticalText )
+ {
+ if ( eTVA == SDRTEXTVERTADJUST_BLOCK )
+ {
+ Size aTextSize( pText->GetTextSize() );
+ aTextSize.AdjustWidth(nTextLeft + nTextRight );
+ aTextSize.AdjustHeight(nTextTop + nTextBottom );
+ if ( rTextRect.GetHeight() < aTextSize.Height() )
+ pTObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
+ }
+ }
+ else
+ {
+ if ( eTHA == SDRTEXTHORZADJUST_BLOCK )
+ {
+ Size aTextSize( pText->GetTextSize() );
+ aTextSize.AdjustWidth(nTextLeft + nTextRight );
+ aTextSize.AdjustHeight(nTextTop + nTextBottom );
+ if ( rTextRect.GetWidth() < aTextSize.Width() )
+ pTObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) );
+ }
+ }
+ }
+ }
+ // rotate text with shape?
+ Degree100 nAngle = ( rObjData.nSpFlags & ShapeFlag::FlipV ) ? -mnFix16Angle : mnFix16Angle; // #72116# vertical flip -> rotate by using the other way
+ nAngle += nTextRotationAngle;
+
+ if ( dynamic_cast< const SdrObjCustomShape* >(pTObj) == nullptr )
+ {
+ if ( rObjData.nSpFlags & ShapeFlag::FlipV )
+ {
+ pTObj->Rotate( rTextRect.Center(), 18000_deg100, 0.0, -1.0 );
+ }
+ if ( rObjData.nSpFlags & ShapeFlag::FlipH )
+ nAngle = 36000_deg100 - nAngle;
+ if ( nAngle )
+ pTObj->NbcRotate( rObjData.aBoundRect.Center(), nAngle );
+ }
+ if ( pRet )
+ {
+ SdrObject* pGroup = new SdrObjGroup(*pSdrModel);
+ pGroup->GetSubList()->NbcInsertObject( pRet );
+ pGroup->GetSubList()->NbcInsertObject( pTObj );
+ pRet = pGroup;
+ }
+ else
+ pRet = pTObj;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ maShapeRecords.Current()->SeekToBegOfRecord( rSt );
+ DffPropertyReader aSecPropSet( *this );
+ aSecPropSet.ReadPropSet( rSt, &rClientData );
+ sal_Int32 nTableProperties = aSecPropSet.GetPropertyValue( DFF_Prop_tableProperties, 0 );
+ if ( nTableProperties & 3 )
+ {
+ if ( aSecPropSet.SeekToContent( DFF_Prop_tableRowProperties, rSt ) )
+ {
+ sal_Int16 i, nReadRowCount = 0;
+ rSt.ReadInt16( nReadRowCount ).ReadInt16( i ).ReadInt16( i );
+ if (nReadRowCount > 0)
+ {
+ const size_t nMinRecordSize = 4;
+ const size_t nMaxRecords = rSt.remainingSize() / nMinRecordSize;
+
+ auto nRowCount = o3tl::make_unsigned(nReadRowCount);
+ if (nRowCount > nMaxRecords)
+ {
+ SAL_WARN("filter.ms", "Parsing error: " << nMaxRecords <<
+ " max possible entries, but " << nRowCount << " claimed, truncating");
+ nRowCount = nMaxRecords;
+ }
+ if (nRowCount > 0)
+ {
+ std::unique_ptr<sal_uInt32[]> pTableArry(new sal_uInt32[ nRowCount + 2 ]);
+ pTableArry[ 0 ] = nTableProperties;
+ pTableArry[ 1 ] = nRowCount;
+ for (decltype(nRowCount) nRow = 0; nRow < nRowCount; ++nRow)
+ rSt.ReadUInt32(pTableArry[nRow + 2]);
+ rData.pTableRowProperties = std::move(pTableArry);
+ }
+ }
+ }
+ }
+ }
+ }
+ if ( pRet ) // sj: #i38501#, and taking care of connections to group objects
+ {
+ if ( rObjData.nSpFlags & ShapeFlag::Background )
+ {
+ pRet->NbcSetSnapRect( tools::Rectangle( Point(), rData.pPage.page->GetSize() ) ); // set size
+ }
+ if (rPersistEntry.xSolverContainer)
+ {
+ for (auto & pPtr : rPersistEntry.xSolverContainer->aCList)
+ {
+ if ( rObjData.nShapeId == pPtr->nShapeC )
+ pPtr->pCObj = pRet;
+ else
+ {
+ SdrObject* pConnectObj = pRet;
+ if ( pOriginalObj && dynamic_cast< const SdrObjGroup* >(pRet) != nullptr )
+ { /* check if the original object from the escherimport is part of the group object,
+ if this is the case, we will use the original object to connect to */
+ SdrObjListIter aIter( *pRet, SdrIterMode::DeepWithGroups );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pPartObj = aIter.Next();
+ if ( pPartObj == pOriginalObj )
+ {
+ pConnectObj = pPartObj;
+ break;
+ }
+ }
+ }
+ if ( rObjData.nShapeId == pPtr->nShapeA )
+ {
+ pPtr->pAObj = pConnectObj;
+ pPtr->nSpFlagsA = rObjData.nSpFlags;
+ }
+ if ( rObjData.nShapeId == pPtr->nShapeB )
+ {
+ pPtr->pBObj = pConnectObj;
+ pPtr->nSpFlagsB = rObjData.nSpFlags;
+ }
+ }
+ }
+ }
+ if ( rPersistEntry.ePageKind == PPT_MASTERPAGE )
+ { // maybe the escher clusterlist is not correct, but we have to got the right page by using the
+ // spMaster property, so we are patching the table
+ if ( rPersistEntry.nDrawingDgId != 0xffffffff )
+ {
+ sal_uInt32 nSec = ( rObjData.nShapeId >> 10 ) - 1;
+ if ( !maFidcls.empty() && ( nSec < mnIdClusters ) )
+ maFidcls[ nSec ].dgid = rPersistEntry.nDrawingDgId; // insert the correct drawing id;
+ }
+ }
+ if ( GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ) & 0x10 )
+ {
+ if (GetPropertyValue(DFF_Prop_fillType, mso_fillSolid) == mso_fillBackground)
+ {
+ rData.aBackgroundColoredObjects.push_back( pRet );
+ }
+ }
+ }
+ return pRet;
+}
+
+SdrPowerPointImport::SdrPowerPointImport( PowerPointImportParam& rParam, const OUString& rBaseURL ) :
+ SdrEscherImport ( rParam, rBaseURL ),
+ m_bOk ( rStCtrl.GetErrorCode() == ERRCODE_NONE ),
+ m_nPersistPtrCnt ( 0 ),
+ m_pDefaultSheet ( nullptr ),
+ m_nCurrentPageNum ( 0 ),
+ m_nDocStreamPos ( 0 ),
+ m_nPageColorsNum ( 0xFFFF ),
+ m_ePageColorsKind ( PPT_MASTERPAGE ),
+ m_eCurrentPageKind ( PPT_MASTERPAGE )
+{
+ if ( m_bOk )
+ {
+ nStreamLen = rStCtrl.TellEnd();
+
+ // try to allocate the UserEditAtom via CurrentUserAtom
+ sal_uInt32 nCurrentUserEdit = rParam.aCurrentUserAtom.nCurrentUserEdit;
+ if (nCurrentUserEdit && checkSeek(rStCtrl, nCurrentUserEdit))
+ {
+ ReadPptUserEditAtom( rStCtrl, m_aUserEditAtom );
+ }
+ if ( !m_aUserEditAtom.nOffsetPersistDirectory )
+ { // if there is no UserEditAtom try to search the last one
+
+ rStCtrl.Seek( 0 );
+ DffRecordManager aPptRecManager; // contains all first level container and atoms
+ aPptRecManager.Consume( rStCtrl, nStreamLen );
+ DffRecordHeader* pHd;
+ for ( pHd = aPptRecManager.Last(); pHd; pHd = aPptRecManager.Prev() )
+ {
+ if ( pHd->nRecType == PPT_PST_UserEditAtom )
+ {
+ pHd->SeekToBegOfRecord( rStCtrl );
+ ReadPptUserEditAtom( rStCtrl, m_aUserEditAtom );
+ break;
+ }
+ }
+ if ( !pHd )
+ m_bOk = false;
+ }
+ }
+ if ( rStCtrl.GetError() != ERRCODE_NONE )
+ m_bOk = false;
+
+ if ( m_bOk )
+ {
+ m_nPersistPtrCnt = m_aUserEditAtom.nMaxPersistWritten + 1;
+ if ( ( m_nPersistPtrCnt >> 2 ) > nStreamLen ) // sj: at least m_nPersistPtrCnt is not allowed to be greater than filesize
+ m_bOk = false; // (it should not be greater than the PPT_PST_PersistPtrIncrementalBlock, but
+ // we are reading this block later, so we do not have access yet)
+
+ if ( m_bOk && ( m_nPersistPtrCnt < ( SAL_MAX_UINT32 / sizeof( sal_uInt32 ) ) -1 ) )
+ m_pPersistPtr.reset( new (std::nothrow) sal_uInt32[ m_nPersistPtrCnt + 1 ] );
+ if ( !m_pPersistPtr )
+ m_bOk = false;
+ if ( m_bOk )
+ {
+ memset( m_pPersistPtr.get(), 0x00, (m_nPersistPtrCnt+1) * sizeof(sal_uInt32) );
+
+ // SJ: new search mechanism from bottom to top (Issue 21122)
+ PptUserEditAtom aCurrentEditAtom( m_aUserEditAtom );
+ sal_uInt32 nCurrentEditAtomStrmPos = aCurrentEditAtom.aHd.GetRecEndFilePos();
+ while( nCurrentEditAtomStrmPos )
+ {
+ sal_uInt32 nPersistIncPos = aCurrentEditAtom.nOffsetPersistDirectory;
+ if (nPersistIncPos && checkSeek(rStCtrl, nPersistIncPos))
+ {
+ DffRecordHeader aPersistHd;
+ ReadDffRecordHeader( rStCtrl, aPersistHd );
+ if ( aPersistHd.nRecType == PPT_PST_PersistPtrIncrementalBlock )
+ {
+ sal_uLong nPibLen = aPersistHd.GetRecEndFilePos();
+ while (m_bOk && rStCtrl.good() && (rStCtrl.Tell() < nPibLen))
+ {
+ sal_uInt32 nOfs(0);
+ rStCtrl.ReadUInt32( nOfs );
+ sal_uInt32 nCnt = nOfs;
+ nOfs &= 0x000FFFFF;
+ nCnt >>= 20;
+ while (m_bOk && rStCtrl.good() && (nCnt > 0) && (nOfs <= m_nPersistPtrCnt))
+ {
+ sal_uInt32 nPt(0);
+ rStCtrl.ReadUInt32( nPt );
+ if ( !m_pPersistPtr[ nOfs ] )
+ {
+ m_pPersistPtr[ nOfs ] = nPt;
+ if ( m_pPersistPtr[ nOfs ] > nStreamLen )
+ {
+ m_bOk = false;
+ OSL_FAIL("SdrPowerPointImport::Ctor(): Invalid Entry in Persist-Directory!");
+ }
+ }
+ nCnt--;
+ nOfs++;
+ }
+ if ( m_bOk && nCnt > 0 )
+ {
+ OSL_FAIL("SdrPowerPointImport::Ctor(): Not all entries of Persist-Directory read!");
+ m_bOk = false;
+ }
+ }
+ }
+ }
+ nCurrentEditAtomStrmPos = aCurrentEditAtom.nOffsetLastEdit < nCurrentEditAtomStrmPos ? aCurrentEditAtom.nOffsetLastEdit : 0;
+ if (nCurrentEditAtomStrmPos && checkSeek(rStCtrl, nCurrentEditAtomStrmPos))
+ {
+ ReadPptUserEditAtom( rStCtrl, aCurrentEditAtom );
+ }
+ }
+ }
+ }
+ if ( rStCtrl.GetError() != ERRCODE_NONE )
+ m_bOk = false;
+ if ( m_bOk )
+ { // check Document PersistEntry
+ m_nDocStreamPos = m_aUserEditAtom.nDocumentRef;
+ if ( m_nDocStreamPos > m_nPersistPtrCnt )
+ {
+ OSL_FAIL("SdrPowerPointImport::Ctor(): m_aUserEditAtom.nDocumentRef invalid!");
+ m_bOk = false;
+ }
+ }
+ if ( m_bOk )
+ { // check Document FilePos
+ m_nDocStreamPos = m_pPersistPtr[ m_nDocStreamPos ];
+ if ( m_nDocStreamPos >= nStreamLen )
+ {
+ OSL_FAIL("SdrPowerPointImport::Ctor(): m_nDocStreamPos >= nStreamLen!");
+ m_bOk = false;
+ }
+ }
+ if ( m_bOk )
+ {
+ rStCtrl.Seek( m_nDocStreamPos );
+ aDocRecManager.Consume( rStCtrl );
+
+ DffRecordHeader aDocHd;
+ ReadDffRecordHeader( rStCtrl, aDocHd );
+ // read DocumentAtom
+ DffRecordHeader aDocAtomHd;
+ ReadDffRecordHeader( rStCtrl, aDocAtomHd );
+ if ( aDocHd.nRecType == PPT_PST_Document && aDocAtomHd.nRecType == PPT_PST_DocumentAtom )
+ {
+ aDocAtomHd.SeekToBegOfRecord( rStCtrl );
+ ReadPptDocumentAtom( rStCtrl, aDocAtom );
+ }
+ else
+ m_bOk = false;
+
+ if ( m_bOk )
+ {
+ if (!m_xFonts)
+ ReadFontCollection();
+
+ // reading TxPF, TxSI
+ PPTTextParagraphStyleAtomInterpreter aTxPFStyle;
+ PPTTextSpecInfoAtomInterpreter aTxSIStyle; // styles (default language setting ... )
+
+ DffRecordHeader* pEnvHd = aDocRecManager.GetRecordHeader( PPT_PST_Environment );
+ if ( pEnvHd )
+ {
+ pEnvHd->SeekToContent( rStCtrl );
+ DffRecordHeader aTxPFStyleRecHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_TxPFStyleAtom, pEnvHd->GetRecEndFilePos(), &aTxPFStyleRecHd ) )
+ aTxPFStyle.Read( rStCtrl, aTxPFStyleRecHd );
+
+ pEnvHd->SeekToContent( rStCtrl );
+ DffRecordHeader aTxSIStyleRecHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_TxSIStyleAtom, pEnvHd->GetRecEndFilePos(), &aTxSIStyleRecHd ) )
+ {
+ aTxSIStyle.Read( rStCtrl, aTxSIStyleRecHd, PPT_PST_TxSIStyleAtom );
+#ifdef DBG_UTIL
+ if ( !aTxSIStyle.bValid )
+ {
+ if (!(rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT ))
+ {
+ OSL_FAIL( "SdrTextSpecInfoAtomInterpreter::Ctor(): parsing error, this document needs to be analysed (SJ)" );
+ }
+ }
+#endif
+ }
+ }
+
+ // TODO:: PPT_PST_TxPFStyleAtom
+
+ // read SlidePersists
+ m_pMasterPages.reset( new PptSlidePersistList );
+ m_pSlidePages.reset( new PptSlidePersistList );
+ m_pNotePages.reset( new PptSlidePersistList );
+
+ // now always creating the handout page, it will be the first in our masterpage list
+ std::unique_ptr<PptSlidePersistEntry> pE(new PptSlidePersistEntry);
+ pE->aPersistAtom.nPsrReference = aDocAtom.nHandoutMasterPersist;
+ pE->bHandoutMaster = true;
+ if ( !aDocAtom.nHandoutMasterPersist )
+ pE->bStarDrawFiller = true; // this is a dummy master page
+ m_pMasterPages->insert(m_pMasterPages->begin(), std::move(pE));
+
+ DffRecordHeader* pSlideListWithTextHd = aDocRecManager.GetRecordHeader( PPT_PST_SlideListWithText );
+ PptSlidePersistEntry* pPreviousPersist = nullptr;
+ DffRecordHeader* pSlideListHd = aDocRecManager.GetRecordHeader(PPT_PST_List);
+ sal_uLong nPSTList = 0;
+ if (pSlideListHd) nPSTList = pSlideListHd->GetRecBegFilePos();
+ sal_uInt16 nRealPageNum = 0;
+ // Normal PPT document has order of Master slides - Presentation slides - Note slides
+ // for document with the order of Master slides - Note slides - Presentation slides
+ // we need to swap the later two sections
+ bool notePresentationSwap = false;
+ for (sal_uInt16 nPageListNum = 0;
+ pSlideListWithTextHd && nPageListNum < 3; ++nPageListNum)
+ {
+ pSlideListWithTextHd->SeekToContent( rStCtrl );
+ PptSlidePersistList* pPageList = nullptr;
+ sal_uInt32 nSlideListWithTextHdEndOffset = pSlideListWithTextHd->GetRecEndFilePos();
+ nRealPageNum = nPageListNum;
+ while ( SeekToRec( rStCtrl, PPT_PST_SlidePersistAtom, nSlideListWithTextHdEndOffset ) )
+ {
+ if ( pPreviousPersist )
+ pPreviousPersist->nSlidePersistEndOffset = rStCtrl.Tell();
+ std::unique_ptr<PptSlidePersistEntry> pE2(new PptSlidePersistEntry);
+ ReadPptSlidePersistAtom( rStCtrl, pE2->aPersistAtom );
+ pE2->nSlidePersistStartOffset = rStCtrl.Tell();
+ // Note/Presentation section swap
+ if (nPageListNum == 1 && pE2->nSlidePersistStartOffset < nPSTList)
+ {
+ notePresentationSwap = true;
+ }
+ if (notePresentationSwap)
+ {
+ if (nPageListNum == 1) nRealPageNum = 2;
+ else if (nPageListNum == 2) nRealPageNum = 1;
+ }
+
+ pE2->ePageKind = PptPageKind(nRealPageNum);
+ pPreviousPersist = pE2.get();
+ if (!pPageList)
+ {
+ pPageList = GetPageList(PptPageKind(nRealPageNum));
+ }
+ pPageList->push_back(std::move(pE2));
+ }
+ if ( pPreviousPersist )
+ pPreviousPersist->nSlidePersistEndOffset = nSlideListWithTextHdEndOffset;
+ pSlideListWithTextHd = aDocRecManager.GetRecordHeader( PPT_PST_SlideListWithText, SEEK_FROM_CURRENT );
+ }
+
+ // we will ensure that there is at least one master page
+ if (m_pMasterPages->size() == 1) // -> there is only a handout page available
+ {
+ std::unique_ptr<PptSlidePersistEntry> pE2(new PptSlidePersistEntry);
+ pE2->bStarDrawFiller = true; // this is a dummy master page
+ m_pMasterPages->insert(m_pMasterPages->begin() + 1, std::move(pE2));
+ }
+
+ // now we will insert at least one notes master for each master page
+ sal_uInt16 nMasterPage;
+ sal_uInt16 nMasterPages = m_pMasterPages->size() - 1;
+ for ( nMasterPage = 0; nMasterPage < nMasterPages; nMasterPage++ )
+ {
+ std::unique_ptr<PptSlidePersistEntry> pE2(new PptSlidePersistEntry);
+ pE2->bNotesMaster = true;
+ pE2->bStarDrawFiller = true; // this is a dummy master page
+ if ( !nMasterPage && aDocAtom.nNotesMasterPersist )
+ { // special treatment for the first notes master
+ pE2->aPersistAtom.nPsrReference = aDocAtom.nNotesMasterPersist;
+ pE2->bStarDrawFiller = false; // this is a dummy master page
+ }
+ m_pMasterPages->insert(m_pMasterPages->begin() + ((nMasterPage + 1) << 1), std::move(pE2));
+ }
+
+ // read for each page the SlideAtom respectively the NotesAtom if it exists
+ for (sal_uInt16 nPageListNum = 0; nPageListNum < 3; ++nPageListNum)
+ {
+ PptSlidePersistList* pPageList = GetPageList( PptPageKind( nPageListNum ) );
+ for ( size_t nPageNum = 0; nPageNum < pPageList->size(); nPageNum++ )
+ {
+ PptSlidePersistEntry& rE2 = (*pPageList)[ nPageNum ];
+ sal_uLong nPersist = rE2.aPersistAtom.nPsrReference;
+ if ( ( nPersist > 0 ) && ( nPersist < m_nPersistPtrCnt ) )
+ {
+ sal_uLong nFPos = m_pPersistPtr[ nPersist ];
+ if ( nFPos < nStreamLen )
+ {
+ rStCtrl.Seek( nFPos );
+ DffRecordHeader aSlideHd;
+ ReadDffRecordHeader( rStCtrl, aSlideHd );
+ if ( SeekToRec( rStCtrl, PPT_PST_SlideAtom, aSlideHd.GetRecEndFilePos() ) )
+ ReadPptSlideAtom( rStCtrl, rE2.aSlideAtom );
+ else if ( SeekToRec( rStCtrl, PPT_PST_NotesAtom, aSlideHd.GetRecEndFilePos() ) )
+ ReadPptNotesAtom( rStCtrl, rE2.aNotesAtom );
+ aSlideHd.SeekToContent( rStCtrl );
+
+ DffRecordHeader aPPTDrawingHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, aSlideHd.GetRecEndFilePos(), &aPPTDrawingHd ) )
+ {
+ DffRecordHeader aPPTDgContainer;
+ if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, aPPTDrawingHd.GetRecEndFilePos(), &aPPTDgContainer ) )
+ {
+ if ( SeekToRec( rStCtrl, DFF_msofbtDg, aPPTDrawingHd.GetRecEndFilePos() ) )
+ {
+ DffRecordHeader aDgRecordHeader;
+ ReadDffRecordHeader( rStCtrl, aDgRecordHeader );
+ rE2.nDrawingDgId = aDgRecordHeader.nRecInstance;
+ aDgRecordHeader.SeekToEndOfRecord( rStCtrl );
+ }
+ if ( SeekToRec( rStCtrl, DFF_msofbtSolverContainer, aPPTDgContainer.GetRecEndFilePos() ) )
+ {
+ rE2.xSolverContainer.reset(new SvxMSDffSolverContainer);
+ ReadSvxMSDffSolverContainer(rStCtrl, *rE2.xSolverContainer);
+ }
+ aPPTDgContainer.SeekToBegOfRecord( rStCtrl );
+ SetDgContainer( rStCtrl ); // set this, so that the escherimport is knowing of our drawings
+ }
+ }
+ // office xp is supporting more than one stylesheet
+ if ( ( rE2.ePageKind == PPT_MASTERPAGE ) && ( rE2.aSlideAtom.nMasterId == 0 ) && !rE2.bNotesMaster )
+ {
+ PPTTextSpecInfo aTxSI( 0 );
+ if ( aTxSIStyle.bValid && !aTxSIStyle.aList.empty() )
+ aTxSI = aTxSIStyle.aList[ 0 ];
+
+ rE2.xStyleSheet = std::make_unique<PPTStyleSheet>(aSlideHd, rStCtrl, *this, aTxPFStyle, aTxSI);
+ m_pDefaultSheet = rE2.xStyleSheet.get();
+ }
+ if ( SeekToRec( rStCtrl, PPT_PST_ColorSchemeAtom, aSlideHd.GetRecEndFilePos() ) )
+ ReadPptColorSchemeAtom( rStCtrl, rE2.aColorScheme );
+ else
+ {
+ OSL_FAIL( "SdrPowerPointImport::Ctor(): could not get SlideColorScheme! (SJ)" );
+ }
+ }
+ else
+ {
+ OSL_FAIL("SdrPowerPointImport::Ctor(): Persist entry is flawed! (SJ)");
+ }
+ }
+ }
+ }
+ DffRecordHeader* pHeadersFootersHd = aDocRecManager.GetRecordHeader( PPT_PST_HeadersFooters );
+ if ( pHeadersFootersHd )
+ {
+ HeaderFooterEntry aNormalMaster, aNotesMaster;
+ for ( ; pHeadersFootersHd; pHeadersFootersHd = aDocRecManager.GetRecordHeader( PPT_PST_HeadersFooters, SEEK_FROM_CURRENT ) )
+ {
+ if ( pHeadersFootersHd->nRecInstance == 3 ) // normal master
+ ImportHeaderFooterContainer( *pHeadersFootersHd, aNormalMaster );
+ else if ( pHeadersFootersHd->nRecInstance == 4 ) // notes master
+ ImportHeaderFooterContainer( *pHeadersFootersHd, aNotesMaster );
+ }
+ for (size_t i = 0; i < m_pMasterPages->size(); i++)
+ {
+ if ((*m_pMasterPages)[ i ].bNotesMaster)
+ (*m_pMasterPages)[ i ].xHeaderFooterEntry.reset(new HeaderFooterEntry(aNotesMaster));
+ else
+ (*m_pMasterPages)[ i ].xHeaderFooterEntry.reset(new HeaderFooterEntry(aNormalMaster));
+ }
+ }
+ }
+ }
+ if ( ( rStCtrl.GetError() != ERRCODE_NONE ) || ( m_pDefaultSheet == nullptr ) )
+ m_bOk = false;
+ m_pPPTStyleSheet = m_pDefaultSheet;
+ rStCtrl.Seek( 0 );
+}
+
+SdrPowerPointImport::~SdrPowerPointImport()
+{
+ m_pMasterPages.reset();
+ m_pSlidePages.reset();
+ m_pNotePages.reset();
+}
+
+bool PPTConvertOCXControls::ReadOCXStream( tools::SvRef<SotStorage>& rSrc,
+ css::uno::Reference< css::drawing::XShape > *pShapeRef )
+{
+ bool bRes = false;
+ uno::Reference< form::XFormComponent > xFComp;
+ if ( mpPPTImporter && mpPPTImporter->ReadFormControl( rSrc, xFComp ) )
+ {
+ if ( xFComp.is() )
+ {
+ css::awt::Size aSz; // not used in import
+ bRes = InsertControl( xFComp, aSz,pShapeRef, false/*bFloatingCtrl*/);
+ }
+ }
+ return bRes;
+}
+
+bool PPTConvertOCXControls::InsertControl(
+ const css::uno::Reference< css::form::XFormComponent > &rFComp,
+ const css::awt::Size& rSize,
+ css::uno::Reference< css::drawing::XShape > *pShape,
+ bool /*bFloatingCtrl*/)
+{
+ bool bRetValue = false;
+ try
+ {
+ css::uno::Reference< css::drawing::XShape > xShape;
+
+ const css::uno::Reference< css::container::XIndexContainer > & rFormComps =
+ GetFormComps();
+
+ css::uno::Any aTmp( &rFComp, cppu::UnoType<css::form::XFormComponent>::get() );
+
+ rFormComps->insertByIndex( rFormComps->getCount(), aTmp );
+
+ const css::uno::Reference< css::lang::XMultiServiceFactory > & rServiceFactory =
+ GetServiceFactory();
+ if( rServiceFactory.is() )
+ {
+ css::uno::Reference< css::uno::XInterface > xCreate = rServiceFactory
+ ->createInstance( "com.sun.star.drawing.ControlShape" );
+ if( xCreate.is() )
+ {
+ xShape.set(xCreate, css::uno::UNO_QUERY);
+ if ( xShape.is() )
+ {
+ xShape->setSize(rSize);
+ // set the Control-Model at the Control-Shape
+ css::uno::Reference< css::drawing::XControlShape > xControlShape( xShape,
+ css::uno::UNO_QUERY );
+ css::uno::Reference< css::awt::XControlModel > xControlModel( rFComp,
+ css::uno::UNO_QUERY );
+ if ( xControlShape.is() && xControlModel.is() )
+ {
+ xControlShape->setControl( xControlModel );
+ if (pShape)
+ *pShape = xShape;
+ bRetValue = true;
+ }
+ }
+ }
+ }
+ }
+ catch( ... )
+ {
+ bRetValue = false;
+ }
+ return bRetValue;
+};
+void PPTConvertOCXControls::GetDrawPage()
+{
+ if( xDrawPage.is() || !mxModel.is() )
+ return;
+
+ css::uno::Reference< css::drawing::XDrawPages > xDrawPages;
+ switch( ePageKind )
+ {
+ case PPT_SLIDEPAGE :
+ case PPT_NOTEPAGE :
+ {
+ css::uno::Reference< css::drawing::XDrawPagesSupplier >
+ xDrawPagesSupplier( mxModel, css::uno::UNO_QUERY);
+ if ( xDrawPagesSupplier.is() )
+ xDrawPages = xDrawPagesSupplier->getDrawPages();
+ }
+ break;
+
+ case PPT_MASTERPAGE :
+ {
+ css::uno::Reference< css::drawing::XMasterPagesSupplier >
+ xMasterPagesSupplier( mxModel, css::uno::UNO_QUERY);
+ if ( xMasterPagesSupplier.is() )
+ xDrawPages = xMasterPagesSupplier->getMasterPages();
+ }
+ break;
+ }
+ if ( xDrawPages.is() && xDrawPages->getCount() )
+ {
+ xDrawPages->getCount();
+ css::uno::Any aAny( xDrawPages->getByIndex( xDrawPages->getCount() - 1 ) );
+ aAny >>= xDrawPage;
+ }
+}
+
+static bool SdrPowerPointOLEDecompress( SvStream& rOutput, SvStream& rInput, sal_uInt32 nInputSize )
+{
+ sal_uInt32 nOldPos = rInput.Tell();
+ std::unique_ptr<char[]> pBuf(new char[ nInputSize ]);
+ rInput.ReadBytes(pBuf.get(), nInputSize);
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression();
+ SvMemoryStream aSource( pBuf.get(), nInputSize, StreamMode::READ );
+ aZCodec.Decompress( aSource, rOutput );
+ const bool bSuccess(0 != aZCodec.EndCompression());
+ rInput.Seek( nOldPos );
+ return bSuccess;
+}
+
+// #i32596# - add new parameter <_nCalledByGroup>
+SdrObject* SdrPowerPointImport::ImportOLE( sal_uInt32 nOLEId,
+ const Graphic& rGraf,
+ const tools::Rectangle& rBoundRect,
+ const tools::Rectangle& rVisArea,
+ const int /*_nCalledByGroup*/ ) const
+{
+ SdrObject* pRet = nullptr;
+
+ sal_uInt32 nOldPos = rStCtrl.Tell();
+
+ Graphic aGraphic( rGraf );
+
+ if ( const_cast<SdrPowerPointImport*>(this)->maShapeRecords.SeekToContent( rStCtrl, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ DffRecordHeader aPlaceHd;
+
+ auto nEndRecPos = SanitizeEndPos(rStCtrl, const_cast<SdrPowerPointImport*>(this)->maShapeRecords.Current()->GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE )
+ && ( rStCtrl.Tell() < nEndRecPos ) )
+ {
+ ReadDffRecordHeader( rStCtrl, aPlaceHd );
+ if ( aPlaceHd.nRecType == PPT_PST_RecolorInfoAtom )
+ {
+ const_cast<SdrPowerPointImport*>(this)->RecolorGraphic( rStCtrl, aPlaceHd.nRecLen, aGraphic );
+ break;
+ }
+ else
+ {
+ if (!aPlaceHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ }
+
+ for (PPTOleEntry& rOe : const_cast<SdrPowerPointImport*>(this)->aOleObjectList)
+ {
+ if ( rOe.nId != nOLEId )
+ continue;
+
+ rStCtrl.Seek( rOe.nRecHdOfs );
+
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+
+ sal_uInt32 nLen = aHd.nRecLen - 4;
+ if ( static_cast<sal_Int32>(nLen) > 0 )
+ {
+ bool bSuccess = false;
+
+ rStCtrl.SeekRel( 4 );
+
+ ::utl::TempFile aTmpFile;
+ aTmpFile.EnableKillingFile();
+
+ if ( aTmpFile.IsValid() )
+ {
+ SvStream* pDest = aTmpFile.GetStream(StreamMode::TRUNC | StreamMode::WRITE);
+ if (pDest)
+ {
+ bSuccess = SdrPowerPointOLEDecompress( *pDest, rStCtrl, nLen );
+ }
+ aTmpFile.CloseStream();
+ }
+ if ( bSuccess )
+ {
+ SvStream* pDest = aTmpFile.GetStream(StreamMode::READ);
+ Storage* pObjStor = pDest ? new Storage( *pDest, true ) : nullptr;
+ if (pObjStor)
+ {
+ tools::SvRef<SotStorage> xObjStor( new SotStorage( pObjStor ) );
+ if ( xObjStor.is() && !xObjStor->GetError() )
+ {
+ if ( xObjStor->GetClassName() == SvGlobalName() )
+ {
+ xObjStor->SetClass( SvGlobalName( pObjStor->GetClassId() ), pObjStor->GetFormat(), pObjStor->GetUserName() );
+ }
+ tools::SvRef<SotStorageStream> xSrcTst = xObjStor->OpenSotStream( "\1Ole" );
+ if ( xSrcTst.is() )
+ {
+ sal_uInt8 aTestA[ 10 ];
+ bool bGetItAsOle = (sizeof(aTestA) == xSrcTst->ReadBytes(aTestA, sizeof(aTestA)));
+ if ( !bGetItAsOle )
+ { // maybe there is a contents stream in here
+ xSrcTst = xObjStor->OpenSotStream( "Contents", StreamMode::READWRITE | StreamMode::NOCREATE );
+ bGetItAsOle = (xSrcTst.is() &&
+ sizeof(aTestA) == xSrcTst->ReadBytes(aTestA, sizeof(aTestA)));
+ }
+ if ( bGetItAsOle )
+ {
+ OUString aNm;
+ // if ( nSvxMSDffOLEConvFlags )
+ {
+ uno::Reference < embed::XStorage > xDestStorage( rOe.pShell->GetStorage() );
+ uno::Reference < embed::XEmbeddedObject > xObj =
+ CheckForConvertToSOObj(nSvxMSDffOLEConvFlags, *xObjStor, xDestStorage, rGraf, rVisArea, maBaseURL);
+ if( xObj.is() )
+ {
+ rOe.pShell->getEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aNm );
+
+ svt::EmbeddedObjectRef aObj( xObj, rOe.nAspect );
+
+ // TODO/LATER: need MediaType for Graphic
+ aObj.SetGraphic( rGraf, OUString() );
+ pRet = new SdrOle2Obj(
+ *pSdrModel,
+ aObj,
+ aNm,
+ rBoundRect);
+ }
+ }
+ if ( !pRet && ( rOe.nType == PPT_PST_ExControl ) )
+ {
+ uno::Reference< frame::XModel > xModel( rOe.pShell->GetModel() );
+ PPTConvertOCXControls aPPTConvertOCXControls( this, xModel, m_eCurrentPageKind );
+ css::uno::Reference< css::drawing::XShape > xShape;
+ if ( aPPTConvertOCXControls.ReadOCXStream( xObjStor, &xShape ) )
+ pRet = SdrObject::getSdrObjectFromXShape(xShape);
+
+ }
+ if ( !pRet )
+ {
+ aNm = rOe.pShell->getEmbeddedObjectContainer().CreateUniqueObjectName();
+
+ // object is not an own object
+ const css::uno::Reference < css::embed::XStorage >& rStorage = rOe.pShell->GetStorage();
+ if (rStorage.is())
+ {
+ tools::SvRef<SotStorage> xTarget = SotStorage::OpenOLEStorage(rStorage, aNm, StreamMode::READWRITE);
+ if (xObjStor.is() && xTarget.is())
+ {
+ xObjStor->CopyTo(xTarget.get());
+ if (!xTarget->GetError())
+ xTarget->Commit();
+ }
+ xTarget.clear();
+ }
+
+ uno::Reference < embed::XEmbeddedObject > xObj =
+ rOe.pShell->getEmbeddedObjectContainer().GetEmbeddedObject( aNm );
+ if ( xObj.is() )
+ {
+ if ( rOe.nAspect != embed::Aspects::MSOLE_ICON )
+ {
+ //TODO/LATER: keep on hacking?!
+ // we don't want to be modified
+ //xInplaceObj->EnableSetModified( sal_False );
+ if ( rVisArea.IsEmpty() )
+ {
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( rOe.nAspect ) );
+ Size aSize( OutputDevice::LogicToLogic( aGraphic.GetPrefSize(),
+ aGraphic.GetPrefMapMode(), MapMode( aMapUnit ) ) );
+
+ awt::Size aSz;
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( rOe.nAspect, aSz );
+ }
+ else
+ {
+ awt::Size aSize( rVisArea.GetSize().Width(), rVisArea.GetSize().Height() );
+ xObj->setVisualAreaSize( rOe.nAspect, aSize );
+ }
+ //xInplaceObj->EnableSetModified( sal_True );
+ }
+
+ svt::EmbeddedObjectRef aObj( xObj, rOe.nAspect );
+
+ // TODO/LATER: need MediaType for Graphic
+ aObj.SetGraphic( aGraphic, OUString() );
+
+ pRet = new SdrOle2Obj(
+ *pSdrModel,
+ aObj,
+ aNm,
+ rBoundRect);
+ }
+ }
+ }
+ }
+ }
+ }
+ aTmpFile.CloseStream();
+ }
+ }
+ }
+ rStCtrl.Seek( nOldPos );
+
+ return pRet;
+}
+
+std::unique_ptr<SvMemoryStream> SdrPowerPointImport::ImportExOleObjStg( sal_uInt32 nPersistPtr, sal_uInt32& nOleId ) const
+{
+ std::unique_ptr<SvMemoryStream> pRet;
+ if ( nPersistPtr && ( nPersistPtr < m_nPersistPtrCnt ) )
+ {
+ sal_uInt32 nOldPos, nOfs = m_pPersistPtr[ nPersistPtr ];
+ nOldPos = rStCtrl.Tell();
+ rStCtrl.Seek( nOfs );
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ if ( aHd.nRecType == DFF_PST_ExOleObjStg )
+ {
+ sal_uInt32 nLen = aHd.nRecLen - 4;
+ if ( static_cast<sal_Int32>(nLen) > 0 )
+ {
+ rStCtrl.ReadUInt32( nOleId );
+ pRet.reset(new SvMemoryStream);
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression();
+ aZCodec.Decompress( rStCtrl, *pRet );
+ if ( !aZCodec.EndCompression() )
+ {
+ pRet.reset();
+ }
+ }
+ }
+ rStCtrl.Seek( nOldPos );
+ }
+ return pRet;
+}
+
+void SdrPowerPointImport::SeekOle( SfxObjectShell* pShell, sal_uInt32 nFilterOptions )
+{
+ if ( !pShell )
+ return;
+
+ DffRecordHeader* pHd;
+
+ sal_uInt32 nOldPos = rStCtrl.Tell();
+ if ( nFilterOptions & 1 )
+ {
+ pHd = aDocRecManager.GetRecordHeader( PPT_PST_List );
+ if ( pHd )
+ {
+ // we try to locate the basic atom
+ pHd->SeekToContent( rStCtrl );
+ if ( SeekToRec( rStCtrl, PPT_PST_VBAInfo, pHd->GetRecEndFilePos(), pHd ) )
+ {
+ if ( SeekToRec( rStCtrl, PPT_PST_VBAInfoAtom, pHd->GetRecEndFilePos(), pHd ) )
+ {
+ sal_uInt32 nPersistPtr, nIDoNotKnow1, nIDoNotKnow2;
+ rStCtrl.ReadUInt32( nPersistPtr )
+ .ReadUInt32( nIDoNotKnow1 )
+ .ReadUInt32( nIDoNotKnow2 );
+
+ sal_uInt32 nOleId;
+ std::unique_ptr<SvMemoryStream> pBas = ImportExOleObjStg( nPersistPtr, nOleId );
+ if ( pBas )
+ {
+ tools::SvRef<SotStorage> xSource( new SotStorage( pBas.release(), true ) );
+ tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
+ if ( xSource.is() && xDest.is() )
+ {
+ // is this a visual basic storage ?
+ tools::SvRef<SotStorage> xSubStorage = xSource->OpenSotStorage( "VBA",
+ StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
+ if( xSubStorage.is() && ( ERRCODE_NONE == xSubStorage->GetError() ) )
+ {
+ tools::SvRef<SotStorage> xMacros = xDest->OpenSotStorage( "MACROS" );
+ if ( xMacros.is() )
+ {
+ SvStorageInfoList aList;
+ xSource->FillInfoList( &aList );
+ SvStorageInfoList::size_type i;
+
+ bool bCopied = true;
+ for ( i = 0; i < aList.size(); i++ ) // copy all entries
+ {
+ const SvStorageInfo& rInfo = aList[ i ];
+ if ( !xSource->CopyTo( rInfo.GetName(), xMacros.get(), rInfo.GetName() ) )
+ bCopied = false;
+ }
+ if ( i && bCopied )
+ {
+ uno::Reference < embed::XStorage > xDoc( pShell->GetStorage() );
+ if ( xDoc.is() )
+ {
+ tools::SvRef<SotStorage> xVBA = SotStorage::OpenOLEStorage( xDoc, SvxImportMSVBasic::GetMSBasicStorageName() );
+ if ( xVBA.is() && ( xVBA->GetError() == ERRCODE_NONE ) )
+ {
+ tools::SvRef<SotStorage> xSubVBA = xVBA->OpenSotStorage( "_MS_VBA_Overhead" );
+ if ( xSubVBA.is() && ( xSubVBA->GetError() == ERRCODE_NONE ) )
+ {
+ tools::SvRef<SotStorageStream> xOriginal = xSubVBA->OpenSotStream( "_MS_VBA_Overhead2" );
+ if ( xOriginal.is() && ( xOriginal->GetError() == ERRCODE_NONE ) )
+ {
+ if ( nPersistPtr && ( nPersistPtr < m_nPersistPtrCnt ) )
+ {
+ rStCtrl.Seek( m_pPersistPtr[ nPersistPtr ] );
+ ReadDffRecordHeader( rStCtrl, *pHd );
+
+ xOriginal->WriteUInt32( nIDoNotKnow1 )
+ .WriteUInt32( nIDoNotKnow2 );
+
+ sal_uInt32 nToCopy, nBufSize;
+ nToCopy = pHd->nRecLen;
+ std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ 0x40000 ]); // 256KB Buffer
+ while ( nToCopy )
+ {
+ nBufSize = ( nToCopy >= 0x40000 ) ? 0x40000 : nToCopy;
+ rStCtrl.ReadBytes(pBuf.get(), nBufSize);
+ xOriginal->WriteBytes(pBuf.get(), nBufSize);
+ nToCopy -= nBufSize;
+ }
+ }
+ }
+ }
+ }
+ xVBA->Commit();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ pHd = aDocRecManager.GetRecordHeader( PPT_PST_ExObjList );
+ if ( pHd )
+ {
+ DffRecordHeader* pExEmbed = nullptr;
+
+ pHd->SeekToBegOfRecord( rStCtrl );
+ DffRecordManager aExObjListManager( rStCtrl );
+ sal_uInt16 i, nRecType(PPT_PST_ExEmbed);
+
+ for ( i = 0; i < 2; i++ )
+ {
+ switch ( i )
+ {
+ case 0 : nRecType = PPT_PST_ExEmbed; break;
+ case 1 : nRecType = PPT_PST_ExControl; break;
+ }
+ for ( pExEmbed = aExObjListManager.GetRecordHeader( nRecType );
+ pExEmbed; pExEmbed = aExObjListManager.GetRecordHeader( nRecType, SEEK_FROM_CURRENT ) )
+ {
+ pExEmbed->SeekToContent( rStCtrl );
+
+ DffRecordHeader aExOleAtHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_ExOleObjAtom, pExEmbed->GetRecEndFilePos(), &aExOleAtHd ) )
+ {
+ PptExOleObjAtom aAt;
+ ReadPptExOleObjAtom( rStCtrl, aAt );
+
+ if ( aAt.nPersistPtr && ( aAt.nPersistPtr < m_nPersistPtrCnt ) )
+ {
+ rStCtrl.Seek( m_pPersistPtr[ aAt.nPersistPtr ] );
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ if ( aHd.nRecType == DFF_PST_ExOleObjStg )
+ {
+ sal_uInt32 nId;
+ rStCtrl.ReadUInt32( nId );
+ aOleObjectList.emplace_back(
+ aAt.nId, aHd.nFilePos, pShell, nRecType, aAt.nAspect );
+ }
+ }
+ }
+ }
+ }
+ }
+ rStCtrl.Seek( nOldPos );
+}
+
+bool SdrPowerPointImport::ReadFontCollection()
+{
+ bool bRet = false;
+ DffRecordHeader* pEnvHd = aDocRecManager.GetRecordHeader( PPT_PST_Environment );
+ if ( pEnvHd )
+ {
+ sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it later
+ pEnvHd->SeekToContent( rStCtrl );
+ DffRecordHeader aListHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_FontCollection, pEnvHd->GetRecEndFilePos(), &aListHd ) )
+ {
+ sal_uInt16 nCount2 = 0;
+ while ( SeekToRec( rStCtrl, PPT_PST_FontEntityAtom, aListHd.GetRecEndFilePos() ) )
+ {
+ bRet = true;
+ if (!m_xFonts)
+ m_xFonts.emplace();
+ PptFontEntityAtom aFontAtom;
+ ReadPptFontEntityAtom( rStCtrl, aFontAtom );
+
+ vcl::Font aFont;
+ aFont.SetCharSet( aFontAtom.eCharSet );
+ aFont.SetFamilyName( aFontAtom.aName );
+ aFont.SetFamily( aFontAtom.eFamily );
+ aFont.SetPitch( aFontAtom.ePitch );
+ aFont.SetFontHeight( 100 );
+
+ // following block is necessary, because our old PowerPoint export did not set the
+ // correct charset
+ if ( aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings 2" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "Wingdings 3" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "Monotype Sorts" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "Monotype Sorts 2" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "Webdings" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "StarBats" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "StarMath" ) ||
+ aFontAtom.aName.equalsIgnoreAsciiCase( "ZapfDingbats" ) )
+ {
+ aFontAtom.eCharSet = RTL_TEXTENCODING_SYMBOL;
+ };
+ m_xFonts->insert(m_xFonts->begin() + nCount2++, std::move(aFontAtom));
+ }
+ }
+ rStCtrl.Seek( nOldFPos ); // restore FilePos
+ }
+ return bRet;
+}
+
+PptSlidePersistList* SdrPowerPointImport::GetPageList(PptPageKind ePageKind) const
+{
+ switch (ePageKind)
+ {
+ case PPT_MASTERPAGE:
+ return m_pMasterPages.get();
+ case PPT_SLIDEPAGE:
+ return m_pSlidePages.get();
+ case PPT_NOTEPAGE:
+ return m_pNotePages.get();
+ }
+ return nullptr;
+}
+
+SdrOutliner* SdrPowerPointImport::GetDrawOutliner( SdrTextObj const * pSdrText )
+{
+ if ( !pSdrText )
+ return nullptr;
+ else
+ return &pSdrText->ImpGetDrawOutliner();
+}
+
+
+SdrObject* SdrPowerPointImport::ReadObjText( PPTTextObj* pTextObj, SdrObject* pSdrObj, SdPageCapsule pPage ) const
+{
+ SdrTextObj* pText = dynamic_cast<SdrTextObj*>( pSdrObj );
+ if ( pText )
+ {
+ if ( !ApplyTextObj( pTextObj, pText, pPage, nullptr, nullptr ) )
+ pSdrObj = nullptr;
+ }
+ return pSdrObj;
+}
+
+SdrObject* SdrPowerPointImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj* pSdrText, SdPageCapsule /*pPage*/,
+ SfxStyleSheet* pSheet, SfxStyleSheet** ppStyleSheetAry ) const
+{
+ SdrTextObj* pText = pSdrText;
+ if ( pTextObj->Count() )
+ {
+ TSS_Type nDestinationInstance = pTextObj->GetDestinationInstance() ;
+ SdrOutliner& rOutliner = pText->ImpGetDrawOutliner();
+ bool bUndoEnabled = rOutliner.IsUndoEnabled();
+ rOutliner.EnableUndo(false);
+
+ if ( ( pText->GetObjInventor() == SdrInventor::Default ) && ( pText->GetObjIdentifier() == SdrObjKind::TitleText ) ) // Outliner-Style for Title-Text object?!? (->of DL)
+ rOutliner.Init( OutlinerMode::TitleObject ); // Outliner reset
+
+ bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
+ if ( pSheet )
+ {
+ if ( rOutliner.GetStyleSheet( 0 ) != pSheet )
+ rOutliner.SetStyleSheet( 0, pSheet );
+ }
+ rOutliner.SetVertical( pTextObj->GetVertical() );
+ for ( PPTParagraphObj* pPara = pTextObj->First(); pPara; pPara = pTextObj->Next() )
+ {
+ sal_uInt32 nTextSize = pPara->GetTextSize();
+ if ( ! ( nTextSize & 0xffff0000 ) )
+ {
+ PPTPortionObj* pPortion;
+ std::unique_ptr<sal_Unicode[]> pParaText(new sal_Unicode[ nTextSize ]);
+ sal_Int32 nCurrentIndex = 0;
+ for ( pPortion = pPara->First(); pPortion; pPortion = pPara->Next() )
+ {
+ if ( pPortion->mpFieldItem )
+ pParaText[ nCurrentIndex++ ] = ' ';
+ else
+ {
+ sal_Int32 nCharacters = pPortion->Count();
+ const sal_Unicode* pSource = pPortion->maString.getStr();
+ sal_Unicode* pDest = pParaText.get() + nCurrentIndex;
+
+ sal_uInt32 nFont;
+ pPortion->GetAttrib( PPT_CharAttr_Font, nFont, pTextObj->GetInstance() );
+ const PptFontEntityAtom* pFontEnityAtom = GetFontEnityAtom( nFont );
+ if ( pFontEnityAtom && ( pFontEnityAtom->eCharSet == RTL_TEXTENCODING_SYMBOL ) )
+ {
+ sal_Unicode nUnicode;
+ for (sal_Int32 i = 0; i < nCharacters; i++ )
+ {
+ nUnicode = pSource[ i ];
+ if ( ! ( nUnicode & 0xff00 ) )
+ nUnicode |= 0xf000;
+ pDest[ i ] = nUnicode;
+ }
+ }
+ else
+ memcpy( pDest, pSource, nCharacters << 1 );
+ nCurrentIndex += nCharacters;
+ }
+ }
+ sal_Int32 nParaIndex = pTextObj->GetCurrentIndex();
+ SfxStyleSheet* pS = ppStyleSheetAry ? ppStyleSheetAry[ pPara->mxParaSet->mnDepth ] : pSheet;
+
+ ESelection aSelection( nParaIndex, 0, nParaIndex, 0 );
+ rOutliner.Insert( OUString(), nParaIndex, pPara->mxParaSet->mnDepth );
+ rOutliner.QuickInsertText( OUString(pParaText.get(), nCurrentIndex), aSelection );
+ rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() );
+ if ( pS )
+ rOutliner.SetStyleSheet( nParaIndex, pS );
+
+ for ( pPortion = pPara->First(); pPortion; pPortion = pPara->Next() )
+ {
+ SfxItemSet aPortionAttribs( rOutliner.GetEmptyItemSet() );
+ std::unique_ptr<SvxFieldItem> pFieldItem(pPortion->GetTextField());
+ if ( pFieldItem )
+ {
+ rOutliner.QuickInsertField( *pFieldItem, ESelection( nParaIndex, aSelection.nEndPos, nParaIndex, aSelection.nEndPos + 1 ) );
+ aSelection.nEndPos++;
+ }
+ else
+ {
+ const sal_Unicode *pF, *pPtr = pPortion->maString.getStr();
+ const sal_Unicode *pMax = pPtr + pPortion->maString.getLength();
+ sal_Int32 nLen;
+ for ( pF = pPtr; pPtr < pMax; pPtr++ )
+ {
+ if ( *pPtr == 0xb )
+ {
+ nLen = pPtr - pF;
+ if ( nLen )
+ aSelection.nEndPos =
+ sal::static_int_cast< sal_uInt16 >(
+ aSelection.nEndPos + nLen );
+ pF = pPtr + 1;
+ rOutliner.QuickInsertLineBreak( ESelection( nParaIndex, aSelection.nEndPos, nParaIndex, aSelection.nEndPos + 1 ) );
+ aSelection.nEndPos++;
+ }
+ }
+ nLen = pPtr - pF;
+ if ( nLen )
+ aSelection.nEndPos = sal::static_int_cast< sal_uInt16 >(
+ aSelection.nEndPos + nLen );
+ }
+ pPortion->ApplyTo( aPortionAttribs, const_cast<SdrPowerPointImport&>(*this), nDestinationInstance, pTextObj );
+ rOutliner.QuickSetAttribs( aPortionAttribs, aSelection );
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+ std::optional< sal_Int16 > oStartNumbering;
+ SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
+ pPara->ApplyTo( aParagraphAttribs, oStartNumbering, *this, nDestinationInstance );
+
+ sal_uInt32 nIsBullet2 = 0; //, nInstance = nDestinationInstance != 0xffffffff ? nDestinationInstance : pTextObj->GetInstance();
+ pPara->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance );
+ if ( !nIsBullet2 )
+ aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
+
+ if ( !aSelection.nStartPos ) // in PPT empty paragraphs never gets a bullet
+ {
+ aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
+ }
+ aSelection.nStartPos = 0;
+ rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
+ }
+ }
+ std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
+ rOutliner.Clear();
+ rOutliner.SetUpdateLayout( bOldUpdateMode );
+ rOutliner.EnableUndo(bUndoEnabled);
+ pText->SetOutlinerParaObject( std::move(pNewText) );
+ }
+ return pText;
+}
+
+bool SdrPowerPointImport::SeekToDocument( DffRecordHeader* pRecHd ) const
+{
+ bool bRet;
+ sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it, if the situation should happen
+ rStCtrl.Seek( m_nDocStreamPos );
+ DffRecordHeader aDocHd;
+ ReadDffRecordHeader( rStCtrl, aDocHd );
+ bRet = aDocHd.nRecType == PPT_PST_Document;
+ if ( bRet )
+ {
+ if ( pRecHd )
+ *pRecHd = aDocHd;
+ else
+ aDocHd.SeekToBegOfRecord( rStCtrl );
+ }
+ if ( !bRet )
+ rStCtrl.Seek( nOldFPos ); // restore FilePos
+ return bRet;
+}
+
+bool SdrPowerPointImport::SeekToContentOfProgTag( sal_Int32 nVersion, SvStream& rSt,
+ const DffRecordHeader& rSourceHd, DffRecordHeader& rContentHd )
+{
+ bool bRetValue = false;
+ sal_uInt32 nOldPos = rSt.Tell();
+
+ DffRecordHeader aProgTagsHd, aProgTagBinaryDataHd;
+ rSourceHd.SeekToContent( rSt );
+ bool bFound = rSourceHd.nRecType == PPT_PST_ProgTags;
+ if ( !bFound )
+ bFound = SeekToRec( rSt, PPT_PST_ProgTags, rSourceHd.GetRecEndFilePos(), &aProgTagsHd );
+ if ( bFound )
+ {
+ while( SeekToRec( rSt, PPT_PST_ProgBinaryTag, aProgTagsHd.GetRecEndFilePos(), &aProgTagBinaryDataHd ) )
+ {
+ ReadDffRecordHeader( rSt, rContentHd );
+ if ( rContentHd.nRecType == PPT_PST_CString )
+ {
+ sal_uInt16 n = 6;
+ sal_uInt32 i = rContentHd.nRecLen >> 1;
+ if ( i > n )
+ {
+ OUString aPre = read_uInt16s_ToOUString(rSt, n);
+ n = static_cast<sal_uInt16>( i - 6 );
+ OUString aSuf = read_uInt16s_ToOUString(rSt, n);
+ sal_Int32 nV = aSuf.toInt32();
+ if ( ( nV == nVersion ) && ( aPre == "___PPT" ) )
+ {
+ if (!rContentHd.SeekToEndOfRecord(rSt))
+ {
+ break;
+ }
+ ReadDffRecordHeader( rSt, rContentHd );
+ if ( rContentHd.nRecType == PPT_PST_BinaryTagData )
+ {
+ bRetValue = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!aProgTagBinaryDataHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+ if ( !bRetValue )
+ rSt.Seek( nOldPos );
+ return bRetValue;
+}
+
+sal_uInt32 SdrPowerPointImport::GetCurrentPageId()
+{
+ PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
+ if ( pList && m_nCurrentPageNum < pList->size() )
+ return (*pList)[ m_nCurrentPageNum ].aPersistAtom.nSlideId;
+ return 0;
+}
+
+bool SdrPowerPointImport::SeekToCurrentPage( DffRecordHeader* pRecHd ) const
+{
+ bool bRet = false;
+ PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
+ if ( pList && ( m_nCurrentPageNum < pList->size() ) )
+ {
+ sal_uLong nPersist = (*pList)[ m_nCurrentPageNum ].aPersistAtom.nPsrReference;
+ if ( nPersist > 0 && nPersist < m_nPersistPtrCnt )
+ {
+ sal_uLong nFPos = m_pPersistPtr[ nPersist ];
+ if ( nFPos < nStreamLen )
+ {
+ rStCtrl.Seek( nFPos );
+ if ( pRecHd )
+ ReadDffRecordHeader( rStCtrl, *pRecHd );
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+sal_uInt16 SdrPowerPointImport::GetPageCount( PptPageKind ePageKind ) const
+{
+ PptSlidePersistList* pList = GetPageList( ePageKind );
+ if ( pList )
+ return pList->size();
+ return 0;
+}
+
+void SdrPowerPointImport::SetPageNum( sal_uInt16 nPageNum, PptPageKind eKind )
+{
+ m_eCurrentPageKind = eKind;
+ m_nCurrentPageNum = nPageNum;
+
+ m_pPPTStyleSheet = nullptr;
+
+ bool bHasMasterPage = true;
+ sal_uInt16 nMasterIndex = 0;
+
+ if ( eKind == PPT_MASTERPAGE )
+ nMasterIndex = nPageNum;
+ else
+ {
+ if ( HasMasterPage( nPageNum, eKind ) )
+ nMasterIndex = GetMasterPageIndex( nPageNum, eKind );
+ else
+ bHasMasterPage = false;
+ }
+ if ( bHasMasterPage )
+ {
+ PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
+ if ( pPageList && nMasterIndex < pPageList->size() )
+ {
+ PptSlidePersistEntry* pMasterPersist = &(*pPageList)[ nMasterIndex ];
+ if (!pMasterPersist->xStyleSheet && pMasterPersist->aSlideAtom.nMasterId)
+ {
+ nMasterIndex = m_pMasterPages->FindPage( pMasterPersist->aSlideAtom.nMasterId );
+ if ( nMasterIndex != PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ pMasterPersist = &(*pPageList)[ nMasterIndex ];
+ }
+ m_pPPTStyleSheet = pMasterPersist->xStyleSheet.get();
+ }
+ }
+ if ( !m_pPPTStyleSheet )
+ m_pPPTStyleSheet = m_pDefaultSheet;
+}
+
+Size SdrPowerPointImport::GetPageSize() const
+{
+ Size aRet( IsNoteOrHandout( m_nCurrentPageNum ) ? aDocAtom.GetNotesPageSize() : aDocAtom.GetSlidesPageSize() );
+ Scale( aRet );
+ // PPT works with units of 576 dpi in any case. To avoid inaccuracies
+ // I do round the last decimal digit away.
+ if ( nMapMul > 2 * nMapDiv )
+ {
+ MapUnit eMap = pSdrModel->GetScaleUnit();
+ bool bInch = IsInch( eMap );
+ tools::Long nInchMul = 1, nInchDiv = 1;
+ if ( bInch )
+ { // temporarily convert size (for rounding it) from inch to metric units
+ Fraction aFact(GetMapFactor(eMap,MapUnit::Map100thMM).X());
+ nInchMul = aFact.GetNumerator();
+ nInchDiv = aFact.GetDenominator();
+ aRet.setWidth( BigMulDiv( aRet.Width(), nInchMul, nInchDiv ) );
+ aRet.setHeight( BigMulDiv( aRet.Height(), nInchMul, nInchDiv ) );
+ }
+ aRet.AdjustWidth(5 ); aRet.setWidth( aRet.Width() / 10 ); aRet.setWidth( aRet.Width() * 10 );
+ aRet.AdjustHeight(5 ); aRet.setHeight( aRet.Height() / 10 ); aRet.setHeight( aRet.Height() * 10 );
+ if ( bInch )
+ {
+ aRet.setWidth( BigMulDiv( aRet.Width(), nInchDiv, nInchMul ) );
+ aRet.setHeight( BigMulDiv( aRet.Height(), nInchDiv, nInchMul ) );
+ }
+ }
+ return aRet;
+}
+
+bool SdrPowerPointImport::GetColorFromPalette( sal_uInt16 nNum, Color& rColor ) const
+{
+ if ( m_nPageColorsNum != m_nCurrentPageNum || m_ePageColorsKind != m_eCurrentPageKind )
+ {
+ sal_uInt16 nSlideFlags = 0;
+ PptSlidePersistList* pPageList = GetPageList( m_eCurrentPageKind );
+ if ( pPageList && ( m_nCurrentPageNum < pPageList->size() ) )
+ {
+ assert( !pPageList->is_null( m_nCurrentPageNum ) );
+ const PptSlidePersistEntry& rE = (*pPageList)[ m_nCurrentPageNum ];
+ nSlideFlags = rE.aSlideAtom.nFlags;
+ if ( ! ( nSlideFlags & 2 ) )
+ const_cast<SdrPowerPointImport*>(this)->m_aPageColors = rE.aColorScheme;
+ }
+ if ( nSlideFlags & 2 ) // follow master colorscheme?
+ {
+ PptSlidePersistList* pPageList2 = GetPageList( PPT_MASTERPAGE );
+ if ( pPageList2 )
+ {
+ PptSlidePersistEntry* pMasterPersist = nullptr;
+ if ( m_eCurrentPageKind == PPT_MASTERPAGE )
+ pMasterPersist = &(*pPageList2)[ m_nCurrentPageNum ];
+ else
+ {
+ if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
+ {
+ sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
+ if ( nMasterNum < pPageList2->size() )
+ pMasterPersist = &(*pPageList2)[ nMasterNum ];
+ }
+ }
+ if ( pMasterPersist )
+ {
+ while( (pMasterPersist->aSlideAtom.nFlags & 2) // it is possible that a masterpage
+ && pMasterPersist->aSlideAtom.nMasterId ) // itself is following a master colorscheme
+ {
+ auto nOrigMasterId = pMasterPersist->aSlideAtom.nMasterId;
+ sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId);
+ if (nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND)
+ break;
+ pMasterPersist = &(*pPageList2)[ nNextMaster ];
+ if (pMasterPersist->aSlideAtom.nMasterId == nOrigMasterId)
+ {
+ SAL_WARN("filter.ms", "loop in atom chain");
+ break;
+ }
+ }
+ const_cast<SdrPowerPointImport*>(this)->m_aPageColors = pMasterPersist->aColorScheme;
+ }
+ }
+ }
+ // register current color scheme
+ const_cast<SdrPowerPointImport*>(this)->m_nPageColorsNum = m_nCurrentPageNum;
+ const_cast<SdrPowerPointImport*>(this)->m_ePageColorsKind = m_eCurrentPageKind;
+ }
+ rColor = m_aPageColors.GetColor( nNum );
+ return true;
+}
+
+bool SdrPowerPointImport::SeekToShape( SvStream& rSt, SvxMSDffClientData* pClientData, sal_uInt32 nId ) const
+{
+ bool bRet = SvxMSDffManager::SeekToShape( rSt, pClientData, nId );
+ if (!bRet && pClientData)
+ {
+ ProcessData& rData = *static_cast<ProcessData*>(pClientData);
+ PptSlidePersistEntry& rPersistEntry = rData.rPersistEntry;
+ if ( rPersistEntry.ePageKind == PPT_SLIDEPAGE )
+ {
+ if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
+ {
+ sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
+ PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
+ if ( pPageList && ( nMasterNum < pPageList->size() ) )
+ {
+ assert( !pPageList->is_null( nMasterNum ) );
+ const PptSlidePersistEntry& rPersist = (*pPageList)[ nMasterNum ]; // get the masterpage's persistentry
+ if ( rPersist.pPresentationObjects )
+ {
+ sal_uInt32 nCurrent(0);
+ DffRecordList* pCList = maShapeRecords.pCList; // we got a backup of the current position
+ if ( pCList )
+ nCurrent = pCList->nCurrent;
+ if ( const_cast<SdrPowerPointImport*>(this)->maShapeRecords.SeekToContent( rSt, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ sal_uInt32 nStreamPos = rSt.Tell();
+ PPTTextObj aTextObj( rSt, const_cast<SdrPowerPointImport&>(*this), rPersistEntry, nullptr );
+ if ( aTextObj.Count() || aTextObj.GetOEPlaceHolderAtom() )
+ {
+ sal_uInt32 nShapePos = 0;
+ switch ( aTextObj.GetInstance() )
+ {
+ case TSS_Type::Title :
+ nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::PageTitle) ];
+ break;
+ case TSS_Type::PageTitle :
+ nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::PageTitle) ];
+ break;
+ case TSS_Type::Subtitle :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody :
+ case TSS_Type::Body :
+ nShapePos = rPersist.pPresentationObjects[ int(TSS_Type::Body) ];
+ break;
+ default: break;
+ }
+ if ( nShapePos )
+ {
+ rSt.Seek( nShapePos );
+ bRet = true;
+ }
+ }
+ if ( !bRet )
+ rSt.Seek( nStreamPos );
+ }
+ if ( pCList ) // restoring
+ pCList->nCurrent = nCurrent;
+ const_cast<SdrPowerPointImport*>(this)->maShapeRecords.pCList = pCList;
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+rtl::Reference<SdrPage> SdrPowerPointImport::MakeBlankPage( bool bMaster ) const
+{
+ rtl::Reference<SdrPage> pRet = pSdrModel->AllocPage( bMaster );
+ pRet->SetSize( GetPageSize() );
+
+ return pRet;
+}
+
+static void ImportComment10( SvxMSDffManager const & rMan, SvStream& rStCtrl, SdrPage* pPage, DffRecordHeader const & rComment10Hd )
+{
+ OUString sAuthor;
+ OUString sText;
+ OUString sInitials;
+
+ sal_Int32 nIndex = 0;
+ util::DateTime aDateTime;
+ sal_Int32 nPosX = 0;
+ sal_Int32 nPosY = 0;
+
+
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rStCtrl, rComment10Hd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
+ {
+ DffRecordHeader aCommentHd;
+ ReadDffRecordHeader( rStCtrl, aCommentHd );
+ switch( aCommentHd.nRecType )
+ {
+ case PPT_PST_CString :
+ {
+ OUString aString = SvxMSDffManager::MSDFFReadZString( rStCtrl,
+ aCommentHd.nRecLen, true );
+ switch ( aCommentHd.nRecInstance )
+ {
+ case 0 : sAuthor = aString; break;
+ case 1 : sText = aString; break;
+ case 2 : sInitials = aString; break;
+ }
+ }
+ break;
+
+ case PPT_PST_CommentAtom10 :
+ {
+ sal_uInt16 millisec = 0;
+ rStCtrl.ReadInt32( nIndex )
+ .ReadInt16( aDateTime.Year )
+ .ReadUInt16( aDateTime.Month )
+ .ReadUInt16( aDateTime.Day ) // DayOfWeek
+ .ReadUInt16( aDateTime.Day )
+ .ReadUInt16( aDateTime.Hours )
+ .ReadUInt16( aDateTime.Minutes )
+ .ReadUInt16( aDateTime.Seconds )
+ .ReadUInt16( millisec )
+ .ReadInt32( nPosX )
+ .ReadInt32( nPosY );
+
+ aDateTime.NanoSeconds = millisec * ::tools::Time::nanoPerMilli;
+ }
+ break;
+ }
+ if (!aCommentHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ Point aPosition( nPosX, nPosY );
+ rMan.Scale( aPosition );
+
+ try
+ {
+ uno::Reference< office::XAnnotationAccess > xAnnotationAccess( pPage->getUnoPage(), UNO_QUERY_THROW );
+ uno::Reference< office::XAnnotation > xAnnotation( xAnnotationAccess->createAndInsertAnnotation() );
+ xAnnotation->setPosition( geometry::RealPoint2D( aPosition.X() / 100.0, aPosition.Y() / 100.0 ) );
+ xAnnotation->setAuthor( sAuthor );
+ xAnnotation->setDateTime( aDateTime );
+ xAnnotation->setInitials( sInitials );
+ uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
+ xText->setString( sText );
+ }
+ catch( const uno::Exception& )
+ {
+
+ }
+}
+
+
+// be sure not to import masterpages with this method
+void SdrPowerPointImport::ImportPage( SdrPage* pRet, const PptSlidePersistEntry* pMasterPersist )
+{
+ sal_uInt32 nOldPos = rStCtrl.Tell();
+ PptSlidePersistList* pList = GetPageList( m_eCurrentPageKind );
+ if ( ( !pList ) || ( pList->size() <= m_nCurrentPageNum ) )
+ return;
+ PptSlidePersistEntry& rSlidePersist = (*pList)[ m_nCurrentPageNum ];
+ if ( rSlidePersist.bStarDrawFiller )
+ return;
+
+ DffRecordHeader aPageHd;
+ if ( SeekToCurrentPage( &aPageHd ) )
+ {
+ rSlidePersist.xHeaderFooterEntry.reset(new HeaderFooterEntry(pMasterPersist));
+ ProcessData aProcessData( rSlidePersist, SdPageCapsule(pRet) );
+ auto nEndRecPos = SanitizeEndPos(rStCtrl, aPageHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
+ {
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_HeadersFooters :
+ {
+ ImportHeaderFooterContainer(aHd, *rSlidePersist.xHeaderFooterEntry);
+ }
+ break;
+
+ case PPT_PST_ProgTags :
+ {
+ DffRecordHeader aContentDataHd;
+ if ( SeekToContentOfProgTag( 10, rStCtrl, aHd, aContentDataHd ) )
+ {
+ DffRecordHeader aComment10Hd;
+ while( ( rStCtrl.GetError() == ERRCODE_NONE ) && SeekToRec( rStCtrl, PPT_PST_Comment10, aContentDataHd.GetRecEndFilePos(), &aComment10Hd ) )
+ {
+ ImportComment10( *this, rStCtrl, pRet, aComment10Hd );
+ if (!aComment10Hd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ }
+ }
+ break;
+
+ case PPT_PST_PPDrawing :
+ {
+ DffRecordHeader aPPDrawHd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, aHd.GetRecEndFilePos(), &aPPDrawHd ) )
+ {
+ sal_uInt32 nPPDrawOfs = rStCtrl.Tell();
+
+ // importing the background object before importing the page
+ auto nPPEndRecPos = SanitizeEndPos(rStCtrl, aPPDrawHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nPPEndRecPos ) )
+ {
+ DffRecordHeader aEscherObjListHd;
+ ReadDffRecordHeader( rStCtrl, aEscherObjListHd );
+ switch ( aEscherObjListHd.nRecType )
+ {
+ case DFF_msofbtSpContainer :
+ {
+ tools::Rectangle aPageSize( Point(), pRet->GetSize() );
+ if ( rSlidePersist.aSlideAtom.nFlags & 4 ) // follow master background?
+ {
+ if ( HasMasterPage( m_nCurrentPageNum, m_eCurrentPageKind ) )
+ {
+ sal_uInt16 nMasterNum = GetMasterPageIndex( m_nCurrentPageNum, m_eCurrentPageKind );
+ PptSlidePersistList* pPageList = GetPageList( PPT_MASTERPAGE );
+ PptSlidePersistEntry* pE = &(*pPageList)[ nMasterNum ];
+ while( ( pE->aSlideAtom.nFlags & 4 ) && pE->aSlideAtom.nMasterId )
+ {
+ auto nOrigMasterId = pE->aSlideAtom.nMasterId;
+ sal_uInt16 nNextMaster = m_pMasterPages->FindPage(nOrigMasterId);
+ if ( nNextMaster == PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ break;
+ else
+ pE = &(*pPageList)[ nNextMaster ];
+ if (pE->aSlideAtom.nMasterId == nOrigMasterId)
+ {
+ SAL_WARN("filter.ms", "loop in atom chain");
+ break;
+ }
+ }
+ if ( pE->nBackgroundOffset )
+ {
+ // do not follow master colorscheme?
+ sal_uInt32 nPos = rStCtrl.Tell();
+ rStCtrl.Seek( pE->nBackgroundOffset );
+ rSlidePersist.pBObj = ImportObj( rStCtrl, aProcessData, aPageSize, aPageSize, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
+ rStCtrl.Seek( nPos );
+ }
+ }
+ }
+ else
+ {
+ DffRecordHeader aShapeHd;
+ ReadDffRecordHeader( rStCtrl, aShapeHd );
+ if ( aShapeHd.nRecType == DFF_msofbtSp )
+ {
+ sal_uInt32 nSpFlags;
+ rStCtrl.ReadUInt32( nSpFlags ).ReadUInt32( nSpFlags );
+ if (rStCtrl.good() && ShapeFlag(nSpFlags) & ShapeFlag::Background)
+ {
+ aEscherObjListHd.SeekToBegOfRecord( rStCtrl );
+ rSlidePersist.pBObj = ImportObj( rStCtrl, aProcessData, aPageSize, aPageSize, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
+ }
+ }
+ }
+ }
+ break;
+ }
+ if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer )
+ break;
+ if (!aEscherObjListHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+
+ // now importing page
+ rStCtrl.Seek( nPPDrawOfs );
+ auto nHdEndRecPos = SanitizeEndPos(rStCtrl, aPPDrawHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nHdEndRecPos ) )
+ {
+ DffRecordHeader aEscherObjListHd;
+ ReadDffRecordHeader( rStCtrl, aEscherObjListHd );
+ switch ( aEscherObjListHd.nRecType )
+ {
+ case DFF_msofbtSpgrContainer :
+ {
+ DffRecordHeader aShapeHd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtSpContainer, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) )
+ {
+ if (!aShapeHd.SeekToEndOfRecord(rStCtrl))
+ {
+ break;
+ }
+ auto nListEndRecPos = SanitizeEndPos(rStCtrl, aEscherObjListHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nListEndRecPos ) )
+ {
+ ReadDffRecordHeader( rStCtrl, aShapeHd );
+ if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) || ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
+ {
+ tools::Rectangle aEmpty;
+ aShapeHd.SeekToBegOfRecord( rStCtrl );
+ sal_Int32 nShapeId;
+ aProcessData.pTableRowProperties.reset();
+ SdrObject* pObj = ImportObj( rStCtrl, aProcessData, aEmpty, aEmpty, 0, &nShapeId );
+ if ( pObj )
+ {
+ if ( aProcessData.pTableRowProperties )
+ pObj = CreateTable(pObj, aProcessData.pTableRowProperties.get(), aProcessData.rPersistEntry.xSolverContainer.get(), aProcessData.aBackgroundColoredObjects);
+
+ pRet->NbcInsertObject( pObj );
+
+ if( nShapeId )
+ insertShapeId( nShapeId, pObj );
+ }
+ }
+ bool bSuccess = aShapeHd.SeekToEndOfRecord(rStCtrl);
+ if (!bSuccess)
+ break;
+ }
+ }
+ }
+ break;
+ }
+ if ( aEscherObjListHd.nRecType == DFF_msofbtSpgrContainer )
+ break;
+ if (!aEscherObjListHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+
+ // Handle shapes where the fill matches the background
+ // fill (mso_fillBackground).
+ if (rSlidePersist.ePageKind == PPT_SLIDEPAGE)
+ {
+ if (!aProcessData.aBackgroundColoredObjects.empty())
+ {
+ if (!rSlidePersist.pBObj)
+ {
+ for (auto pObject : aProcessData.aBackgroundColoredObjects)
+ {
+ // The shape wants a background, but the slide doesn't have
+ // one: default to white.
+ SfxItemSet aNewSet(*pObject->GetMergedItemSet().GetPool());
+ aNewSet.Put(XFillStyleItem(css::drawing::FillStyle_SOLID));
+ aNewSet.Put(XFillColorItem(OUString(), COL_WHITE));
+ pObject->SetMergedItemSet(aNewSet);
+ }
+ }
+ }
+ }
+
+ if ( rSlidePersist.pBObj )
+ {
+ // #i99386# transfer the attributes from the temporary BackgroundObject
+ // to the Page and delete it.
+ pRet->getSdrPageProperties().ClearItem();
+ pRet->getSdrPageProperties().PutItemSet(rSlidePersist.pBObj->GetMergedItemSet());
+ if (rSlidePersist.xSolverContainer)
+ {
+ for (auto & pPtr : rSlidePersist.xSolverContainer->aCList)
+ {
+ // check connections to the group object
+ if (pPtr->pAObj == rSlidePersist.pBObj)
+ pPtr->pAObj = nullptr;
+ if (pPtr->pBObj == rSlidePersist.pBObj)
+ pPtr->pBObj = nullptr;
+ if (pPtr->pCObj == rSlidePersist.pBObj)
+ pPtr->pCObj = nullptr;
+ }
+ }
+ SdrObject::Free(rSlidePersist.pBObj);
+ }
+ }
+ }
+ break;
+ }
+ if (!aHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+ if (rSlidePersist.xSolverContainer)
+ SolveSolver(*rSlidePersist.xSolverContainer);
+ }
+ rStCtrl.Seek( nOldPos );
+}
+
+const PptSlideLayoutAtom* SdrPowerPointImport::GetSlideLayoutAtom() const
+{
+ PptSlidePersistList* pPageList = GetPageList( m_eCurrentPageKind );
+ if ( pPageList && m_nCurrentPageNum < pPageList->size() )
+ {
+ assert( !pPageList->is_null( m_nCurrentPageNum ) );
+ return &(*pPageList)[ m_nCurrentPageNum ].aSlideAtom.aLayout;
+ }
+ return nullptr;
+}
+
+bool SdrPowerPointImport::IsNoteOrHandout( sal_uInt16 nPageNum ) const
+{
+ bool bNote = m_eCurrentPageKind == PPT_NOTEPAGE;
+ if ( m_eCurrentPageKind == PPT_MASTERPAGE )
+ bNote = ( nPageNum & 1 ) == 0;
+ return bNote;
+}
+
+sal_uInt32 SdrPowerPointImport::GetMasterPageId( sal_uInt16 nPageNum, PptPageKind ePageKind ) const
+{
+ PptSlidePersistList* pPageList = GetPageList( ePageKind );
+ if ( pPageList && nPageNum < pPageList->size() )
+ return (*pPageList)[ nPageNum ].aSlideAtom.nMasterId;
+ return 0;
+}
+
+sal_uInt32 SdrPowerPointImport::GetNotesPageId( sal_uInt16 nPageNum ) const
+{
+ PptSlidePersistList* pPageList=GetPageList( PPT_SLIDEPAGE );
+ if ( pPageList && nPageNum < pPageList->size() )
+ return (*pPageList)[ nPageNum ].aSlideAtom.nNotesId;
+ return 0;
+}
+
+bool SdrPowerPointImport::HasMasterPage( sal_uInt16 nPageNum, PptPageKind ePageKind ) const
+{
+ if ( ePageKind == PPT_NOTEPAGE )
+ return aDocAtom.nNotesMasterPersist != 0;
+ if ( ePageKind == PPT_MASTERPAGE )
+ return false;
+ return GetMasterPageId( nPageNum, ePageKind ) != 0;
+}
+
+sal_uInt16 SdrPowerPointImport::GetMasterPageIndex( sal_uInt16 nPageNum, PptPageKind ePageKind ) const
+{
+ sal_uInt16 nIdx = 0;
+ if ( ePageKind == PPT_NOTEPAGE )
+ return 2;
+ sal_uInt32 nId = GetMasterPageId( nPageNum, ePageKind );
+ if (nId && m_pMasterPages)
+ {
+ nIdx = m_pMasterPages->FindPage( nId );
+ if ( nIdx == PPTSLIDEPERSIST_ENTRY_NOTFOUND )
+ nIdx = 0;
+ }
+ return nIdx;
+}
+
+SdrObject* SdrPowerPointImport::ImportPageBackgroundObject( const SdrPage& rPage, sal_uInt32& nBgFileOffset )
+{
+ SdrObject* pRet = nullptr;
+ std::optional<SfxItemSet> pSet;
+ sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for restoring it later
+ DffRecordHeader aPageHd;
+ if ( SeekToCurrentPage( &aPageHd ) )
+ { // and now search for the background attributes of the Page
+ sal_uLong nPageRecEnd = aPageHd.GetRecEndFilePos();
+ DffRecordHeader aPPDrawHd;
+ if ( SeekToRec( rStCtrl, PPT_PST_PPDrawing, nPageRecEnd, &aPPDrawHd ) )
+ {
+ sal_uLong nPPDrawEnd = aPPDrawHd.GetRecEndFilePos();
+ DffRecordHeader aEscherF002Hd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtDgContainer, nPPDrawEnd, &aEscherF002Hd ) )
+ {
+ sal_uLong nEscherF002End = aEscherF002Hd.GetRecEndFilePos();
+ DffRecordHeader aEscherObjectHd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtSpContainer, nEscherF002End, &aEscherObjectHd ) )
+ {
+ nBgFileOffset = aEscherObjectHd.GetRecBegFilePos();
+ //sal_uLong nEscherObjectEnd = aEscherObjectHd.GetRecEndFilePos();
+ //DffRecordHeader aEscherPropertiesHd;
+ if ( SeekToRec( rStCtrl, DFF_msofbtOPT,nEscherF002End ) )
+ {
+ ReadDffPropSet( rStCtrl, static_cast<DffPropertyReader&>(*this) );
+ mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) );
+ sal_uInt32 nColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
+ pSet.emplace( pSdrModel->GetItemPool() );
+ DffObjData aObjData( aEscherObjectHd, tools::Rectangle( 0, 0, 28000, 21000 ), 0 );
+ ApplyAttributes( rStCtrl, *pSet, aObjData );
+ Color aColor( MSO_CLR_ToColor( nColor ) );
+ pSet->Put( XFillColorItem( OUString(), aColor ) );
+ }
+ }
+ }
+ }
+ }
+ rStCtrl.Seek( nOldFPos ); // restore FilePos
+ if ( !pSet )
+ {
+ pSet.emplace( pSdrModel->GetItemPool() );
+ pSet->Put( XFillStyleItem( drawing::FillStyle_NONE ) );
+ }
+ pSet->Put( XLineStyleItem( drawing::LineStyle_NONE ) );
+ tools::Rectangle aRect(
+ rPage.GetLeftBorder(),
+ rPage.GetUpperBorder(),
+ rPage.GetWidth() - rPage.GetRightBorder(),
+ rPage.GetHeight() - rPage.GetLowerBorder());
+
+ pRet = new SdrRectObj(
+ *pSdrModel,
+ aRect);
+
+ pRet->SetMergedItemSet(*pSet);
+ pRet->SetMarkProtect( true );
+ pRet->SetMoveProtect( true );
+ pRet->SetResizeProtect( true );
+ return pRet;
+}
+
+HeaderFooterEntry::HeaderFooterEntry( const PptSlidePersistEntry* pMPE ) :
+ pMasterPersist ( pMPE ),
+ nAtom ( 0 )
+{
+ if ( pMPE )
+ {
+ HeaderFooterEntry* pMHFE = pMPE->xHeaderFooterEntry.get();
+ if ( pMHFE )
+ {
+ nAtom = pMPE->xHeaderFooterEntry->nAtom;
+ pPlaceholder[ 0 ] = pMHFE->pPlaceholder[ 0 ];
+ pPlaceholder[ 1 ] = pMHFE->pPlaceholder[ 1 ];
+ pPlaceholder[ 2 ] = pMHFE->pPlaceholder[ 2 ];
+ pPlaceholder[ 3 ] = pMHFE->pPlaceholder[ 3 ];
+ }
+ }
+}
+
+sal_uInt32 HeaderFooterEntry::IsToDisplay( sal_uInt32 nInstance )
+{
+ sal_uInt32 nMask = 0;
+ switch ( nInstance )
+ {
+ case 0 : nMask = 0x010000; break;
+ case 1 : nMask = 0x100000; break;
+ case 2 : nMask = 0x200000; break;
+ case 3 : nMask = 0x080000; break;
+ }
+ return ( nAtom & nMask );
+}
+
+// The following method checks if the slide is using a different colorscheme than
+// its master, if this is the fact, then the HeaderFooter must probably be
+// imported as real sdrobject. In this case, the return value is the offset to the
+// master header footer object, so it can be re-loaded with a different color set
+sal_uInt32 HeaderFooterEntry::NeedToImportInstance( const sal_uInt32 nInstance, const PptSlidePersistEntry& rSlidePersist )
+{
+ sal_uInt32 nRet = 0;
+ if ( pMasterPersist )
+ {
+ if ( !( rSlidePersist.aSlideAtom.nFlags & 2 ) )
+ { // not following the master persist, so we have to check if the colors are changed
+ if ( memcmp( &rSlidePersist.aColorScheme, &pMasterPersist->aColorScheme, 32 ) )
+ {
+ nRet = pMasterPersist->HeaderFooterOfs[ nInstance ];
+ }
+ }
+ }
+ return nRet;
+}
+
+void SdrEscherImport::ImportHeaderFooterContainer( DffRecordHeader const & rHd, HeaderFooterEntry& rE )
+{
+ rHd.SeekToContent( rStCtrl );
+ auto nEndRecPos = SanitizeEndPos(rStCtrl, rHd.GetRecEndFilePos());
+ while ( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( rStCtrl.Tell() < nEndRecPos ) )
+ {
+ DffRecordHeader aHd;
+ ReadDffRecordHeader( rStCtrl, aHd );
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_HeadersFootersAtom :
+ rStCtrl.ReadUInt32( rE.nAtom );
+ break;
+
+ case PPT_PST_CString :
+ {
+ if ( aHd.nRecInstance < 4 )
+ {
+ rE.pPlaceholder[ aHd.nRecInstance ] = MSDFFReadZString( rStCtrl,
+ aHd.nRecLen, true );
+ }
+ }
+ break;
+ }
+ if (!aHd.SeekToEndOfRecord(rStCtrl))
+ break;
+ }
+}
+
+PPTBuGraEntry::PPTBuGraEntry( Graphic aGraphic, sal_uInt32 nInst ) :
+ nInstance ( nInst ),
+ aBuGra (std::move( aGraphic )) {}
+
+PPTExtParaLevel::PPTExtParaLevel()
+: mnExtParagraphMask( 0 )
+, mnBuBlip( 0xffff )
+, mnHasAnm( 0 )
+, mnAnmScheme( 0 )
+, mpfPP10Ext( 0 )
+, mnExtCharacterMask( 0 )
+, mcfPP10Ext( 0 )
+, mbSet( false )
+{}
+
+SvStream& ReadPPTExtParaLevel( SvStream& rIn, PPTExtParaLevel& rLevel )
+{
+ rLevel.mbSet = true;
+ rIn.ReadUInt32( rLevel.mnExtParagraphMask );
+ if ( rLevel.mnExtParagraphMask & 0x00800000 )
+ rIn.ReadUInt16( rLevel.mnBuBlip );
+ if ( rLevel.mnExtParagraphMask & 0x02000000 )
+ rIn.ReadUInt16( rLevel.mnHasAnm );
+ if ( rLevel.mnExtParagraphMask & 0x01000000 )
+ rIn.ReadUInt32( rLevel.mnAnmScheme );
+ if ( rLevel.mnExtParagraphMask & 0x04000000 )
+ rIn.ReadUInt32( rLevel.mpfPP10Ext );
+ rIn.ReadUInt32( rLevel.mnExtCharacterMask );
+ if ( rLevel.mnExtCharacterMask & 0x100000 )
+ rIn.ReadUInt32( rLevel.mcfPP10Ext );
+ return rIn;
+}
+
+bool PPTExtParaProv::GetGraphic( sal_uInt32 nInstance, Graphic& rGraph ) const
+{
+ bool bRetValue = false;
+ PPTBuGraEntry* pPtr = nullptr;
+ if ( nInstance < aBuGraList.size() )
+ {
+ pPtr = aBuGraList[ nInstance ].get();
+ if ( pPtr->nInstance == nInstance )
+ bRetValue = true;
+ }
+ if ( !bRetValue )
+ {
+ for (std::unique_ptr<PPTBuGraEntry> const & i : aBuGraList)
+ {
+ pPtr = i.get();
+ if ( pPtr->nInstance == nInstance )
+ {
+ bRetValue = true;
+ break;
+ }
+ }
+ }
+ if ( bRetValue )
+ rGraph = pPtr->aBuGra;
+ return bRetValue;
+}
+
+PPTExtParaProv::PPTExtParaProv( SdrPowerPointImport& rMan, SvStream& rSt, const DffRecordHeader* pHd ) :
+ bStyles ( false )
+{
+ sal_uInt32 nOldPos = rSt.Tell();
+
+ // here we have to get the graphical bullets...
+
+ DffRecordHeader aHd;
+ DffRecordHeader aContentDataHd;
+
+ const DffRecordHeader* pListHd = rMan.aDocRecManager.GetRecordHeader( PPT_PST_List );
+ if( pListHd )
+ pListHd->SeekToContent( rSt );
+ if ( pListHd && SdrPowerPointImport::SeekToContentOfProgTag( 9, rSt, *pListHd, aContentDataHd ) )
+ {
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rSt, aContentDataHd.GetRecEndFilePos());
+ while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) )
+ {
+ ReadDffRecordHeader( rSt, aHd );
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_ExtendedBuGraContainer :
+ {
+ auto nHdEndRecPos = DffPropSet::SanitizeEndPos(rSt, aHd.GetRecEndFilePos());
+ while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nHdEndRecPos ) )
+ {
+ DffRecordHeader aBuGraAtomHd;
+ ReadDffRecordHeader( rSt, aBuGraAtomHd );
+ if ( aBuGraAtomHd.nRecType == PPT_PST_ExtendedBuGraAtom )
+ {
+ sal_uInt16 nType;
+ rSt.ReadUInt16( nType );
+ Graphic aGraphic;
+ if ( SvxMSDffManager::GetBLIPDirect( rSt, aGraphic ) )
+ {
+ sal_uInt32 nInstance = aBuGraAtomHd.nRecInstance;
+ PPTBuGraEntry* pBuGra = new PPTBuGraEntry( std::move(aGraphic), nInstance );
+ size_t n = 0;
+ size_t nBuGraCount = aBuGraList.size();
+ if ( nBuGraCount )
+ {
+ if ( aBuGraList[ nBuGraCount - 1 ]->nInstance < nInstance )
+ n = nBuGraCount;
+ else
+ { // maybe the instances are not sorted, we sort it
+ for ( n = 0; n < nBuGraCount; n++ )
+ { // sorting fields ( hi >> lo )
+ if ( aBuGraList[ n ]->nInstance < nInstance )
+ break;
+ }
+ }
+ }
+ if ( n < nBuGraCount ) {
+ aBuGraList.emplace( aBuGraList.begin() + n, pBuGra );
+ } else {
+ aBuGraList.emplace_back( pBuGra );
+ }
+ }
+#ifdef DBG_UTIL
+ else OSL_FAIL( "PPTExParaProv::PPTExParaProv - bullet graphic is not valid (SJ)" );
+#endif
+ }
+#ifdef DBG_UTIL
+ else OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom interpreting the PPT_PST_ExtendedBuGraContainer (SJ)" );
+#endif
+ if (!aBuGraAtomHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+ break;
+
+ case PPT_PST_ExtendedPresRuleContainer :
+ aExtendedPresRules.Consume( rSt, aHd.GetRecEndFilePos() );
+ break;
+#ifdef DBG_UTIL
+ default :
+ OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom reading ppt2000 num rules (SJ)" );
+ break;
+ case PPT_PST_MasterText : // first seen in: ms-tt02.ppt
+ case PPT_PST_SrKinsoku :
+ case PPT_PST_TextDefaults9Atom :
+ case PPT_PST_PresentationAdvisorFlags9Atom :
+ case PPT_PST_HtmlDocInfo9Atom :
+ case PPT_PST_GridSpacing10Atom :
+ case PPT_PST_CommentIndex10 :
+ case PPT_PST_DocToolbarStates10Atom :
+ break;
+#endif
+ }
+ if (!aHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+
+ if ( pHd && SdrPowerPointImport::SeekToContentOfProgTag( 9, rSt, *pHd, aContentDataHd ) )
+ { // get the extended paragraph styles on mainmaster ( graphical bullets, num ruling ... )
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rSt, aContentDataHd.GetRecEndFilePos());
+ while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nEndRecPos ) )
+ {
+ ReadDffRecordHeader( rSt, aHd );
+ switch ( aHd.nRecType )
+ {
+ case PPT_PST_ExtendedParagraphMasterAtom :
+ {
+ if ( aHd.nRecInstance < PPT_STYLESHEETENTRIES )
+ {
+ sal_uInt16 nDepth = 0, i = 0;
+ rSt.ReadUInt16(nDepth);
+ nDepth = std::min<sal_uInt16>(nDepth, nMaxPPTLevels);
+ auto nHdEndRecPos = DffPropSet::SanitizeEndPos(rSt, aHd.GetRecEndFilePos());
+ while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < nHdEndRecPos ) && ( i < nDepth ) )
+ {
+ bStyles = true;
+ ReadPPTExtParaLevel( rSt, aExtParaSheet[ static_cast<TSS_Type>(aHd.nRecInstance) ].aExtParaLevel[ i++ ] );
+ }
+#ifdef DBG_UTIL
+ if ( rSt.Tell() != aHd.GetRecEndFilePos() )
+ OSL_FAIL( "PPTExParaProv::PPTExParaProv - error reading PPT_PST_ExtendedParagraphMasterAtom (SJ)" );
+#endif
+ }
+#ifdef DBG_UTIL
+ else OSL_FAIL( "PPTExParaProv::PPTExParaProv - instance out of range (SJ)" );
+#endif
+ }
+ break;
+ default :
+ OSL_FAIL( "PPTExParaProv::PPTExParaProv - unknown atom, assuming PPT_PST_ExtendedParagraphMasterAtom (SJ)" );
+ break;
+ case PPT_PST_HashCodeAtom :
+ case PPT_PST_BuildList :
+ case PPT_PST_SlideFlags10Atom :
+ case PPT_PST_SlideTime10Atom :
+ case 0xf144 :
+ break;
+ }
+ if (!aHd.SeekToEndOfRecord(rSt))
+ break;
+ }
+ }
+ rSt.Seek( nOldPos );
+}
+
+PPTExtParaProv::~PPTExtParaProv()
+{
+}
+
+PPTNumberFormatCreator::PPTNumberFormatCreator( std::unique_ptr<PPTExtParaProv> pParaProv )
+ : nIsBullet(0)
+ , nBulletChar(0)
+ , nBulletFont(0)
+ , nBulletHeight(0)
+ , nBulletColor(0)
+ , nTextOfs(0)
+ , nBulletOfs(0)
+ , pExtParaProv(std::move(pParaProv))
+{
+}
+
+PPTNumberFormatCreator::~PPTNumberFormatCreator()
+{
+}
+
+bool PPTNumberFormatCreator::ImplGetExtNumberFormat( SdrPowerPointImport const & rManager,
+ SvxNumberFormat& rNumberFormat, sal_uInt32 nLevel, TSS_Type nInstance, TSS_Type nDestinationInstance,
+ std::optional< sal_Int16 >& rStartNumbering, sal_uInt32 nFontHeight, PPTParagraphObj const * pPara )
+{
+ bool bHardAttribute = ( nDestinationInstance == TSS_Type::Unknown );
+
+ sal_uInt32 nBuFlags = 0;
+ sal_uInt16 nHasAnm = 0;
+ sal_uInt32 nAnmScheme = 0xFFFF0003;
+ sal_uInt16 nBuBlip = 0xffff;
+
+ const PPTExtParaProv* pParaProv = pExtParaProv.get();
+ if ( !pExtParaProv )
+ pParaProv = pPara ? pPara->mrStyleSheet.pExtParaProv.get()
+ : rManager.m_pPPTStyleSheet->pExtParaProv.get();
+ if ( pPara )
+ {
+ nBuFlags = pPara->mxParaSet->mnExtParagraphMask;
+ if ( nBuFlags )
+ {
+ if ( nBuFlags & 0x00800000 )
+ nBuBlip = pPara->mxParaSet->mnBuBlip;
+ if ( nBuFlags & 0x01000000 )
+ nAnmScheme = pPara->mxParaSet->mnAnmScheme;
+ if ( nBuFlags & 0x02000000 )
+ nHasAnm = pPara->mxParaSet->mnHasAnm;
+ bHardAttribute = true;
+ }
+ }
+
+ if ( ( nBuFlags & 0x03800000 ) != 0x03800000 ) // merge style sheet
+ {
+ // we have to read the master attributes
+ if (pParaProv && nLevel < nMaxPPTLevels)
+ {
+ if ( pParaProv->bStyles )
+ {
+ const PPTExtParaLevel& rLev = pParaProv->aExtParaSheet[ nInstance ].aExtParaLevel[ nLevel ];
+ if ( rLev.mbSet )
+ {
+ sal_uInt32 nMaBuFlags = rLev.mnExtParagraphMask;
+
+ if ( (!( nBuFlags & 0x00800000)) && ( nMaBuFlags & 0x00800000 ) )
+ {
+ if (!( nBuFlags & 0x02000000)) // if there is a BuStart without BuInstance,
+ nBuBlip = rLev.mnBuBlip; // then there is no graphical Bullet possible
+ }
+ if ( (!( nBuFlags & 0x01000000)) && ( nMaBuFlags & 0x01000000 ) )
+ nAnmScheme = rLev.mnAnmScheme;
+ if ( (!( nBuFlags & 0x02000000)) && ( nMaBuFlags & 0x02000000 ) )
+ nHasAnm = rLev.mnHasAnm;
+ nBuFlags |= nMaBuFlags;
+ }
+ }
+ }
+ }
+ if ( nBuBlip != 0xffff ) // set graphical bullet
+ {
+ Graphic aGraphic;
+ if ( pParaProv && pParaProv->GetGraphic( nBuBlip, aGraphic ) )
+ {
+ SvxBrushItem aBrush( aGraphic, GPOS_MM, SID_ATTR_BRUSH );
+ rNumberFormat.SetGraphicBrush( &aBrush );
+ sal_uInt32 nHeight = static_cast<sal_uInt32>( static_cast<double>(nFontHeight) * 0.2540 * nBulletHeight + 0.5 );
+ Size aPrefSize( aGraphic.GetPrefSize() );
+ sal_uInt32 nWidth;
+ if (aPrefSize.Height())
+ nWidth = ( nHeight * aPrefSize.Width() ) / aPrefSize.Height();
+ else
+ nWidth = 0;
+ rNumberFormat.SetGraphicSize( Size( nWidth, nHeight ) );
+ rNumberFormat.SetNumberingType ( SVX_NUM_BITMAP );
+ }
+ }
+ else if ( nHasAnm )
+ {
+ switch( static_cast< sal_uInt16 >( nAnmScheme ) )
+ {
+ default :
+ case 0 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 1 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 2 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
+ rNumberFormat.SetSuffix( ")" );
+ }
+ break;
+ case 3 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 4 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER );
+ rNumberFormat.SetSuffix( ")" );
+ rNumberFormat.SetPrefix( "(" );
+ }
+ break;
+ case 5 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER );
+ rNumberFormat.SetSuffix( ")" );
+ }
+ break;
+ case 6 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_LOWER );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 7 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 8 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER );
+ rNumberFormat.SetSuffix( ")" );
+ rNumberFormat.SetPrefix( "(" );
+ }
+ break;
+ case 9 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CHARS_LOWER_LETTER );
+ rNumberFormat.SetSuffix( ")" );
+ }
+ break;
+ case 10 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER );
+ rNumberFormat.SetSuffix( ")" );
+ rNumberFormat.SetPrefix( "(" );
+ }
+ break;
+ case 11 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CHARS_UPPER_LETTER );
+ rNumberFormat.SetSuffix( ")" );
+ }
+ break;
+ case 12 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
+ rNumberFormat.SetSuffix( ")" );
+ rNumberFormat.SetPrefix( "(" );
+ }
+ break;
+ case 13 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ARABIC );
+ }
+ break;
+ case 14 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER );
+ rNumberFormat.SetSuffix( ")" );
+ rNumberFormat.SetPrefix( "(" );
+ }
+ break;
+ case 15 :
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_ROMAN_UPPER );
+ rNumberFormat.SetSuffix( ")" );
+ }
+ break;
+ case 16: // Simplified Chinese.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH );
+ }
+ break;
+ case 17: // Simplified Chinese with single-byte period.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 18: // Double byte circle numbers.
+ case 19: // Wingdings white circle numbers.
+ case 20: // Wingdings black circle numbers.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_CIRCLE_NUMBER );
+ }
+ break;
+ case 21: // Traditional Chinese.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH_TW );
+ }
+ break;
+ case 22: // Traditional Chinese with single-byte period.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_UPPER_ZH_TW );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 25: // Bidi Hebrew 2 with ANSI minus symbol.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_HEBREW );
+ rNumberFormat.SetSuffix( "-" );
+ }
+ break;
+ case 26: // Japanese/Korean.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH );
+ }
+ break;
+ case 27: // Japanese/Korean with single-byte period.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH );
+ rNumberFormat.SetSuffix( "." );
+ }
+ break;
+ case 28: // Double-byte Arabic numbers.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_FULL_WIDTH_ARABIC );
+ }
+ break;
+ case 29: // Double-byte Arabic numbers with double-byte period.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_FULL_WIDTH_ARABIC );
+ rNumberFormat.SetSuffix( OUString( u'\xff0e' ) );
+ }
+ break;
+ case 38: // Japanese with double-byte period.
+ {
+ rNumberFormat.SetNumberingType( SVX_NUM_NUMBER_LOWER_ZH ); // No such type. Instead with Lower Chinese Number
+ rNumberFormat.SetSuffix( OUString( u'\xff0e' ) );
+ }
+ break;
+ }
+ rStartNumbering = std::optional< sal_Int16 >( nAnmScheme >> 16 );
+ sal_Int16 nBuStart = *rStartNumbering;
+ //The Seventh bit of nBuFlags that specifies whether fBulletHasAutoNumber exists,
+ //and fBulletHasAutoNumber that specifies whether this paragraph has an automatic numbering scheme.
+ if ( ( nBuFlags & 0x02000000 ) && ( nBuStart != -1 ))
+ {
+ rNumberFormat.SetStart( static_cast<sal_uInt16>(nBuStart) );
+ }
+ }
+ return bHardAttribute;
+}
+
+void PPTNumberFormatCreator::GetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat, sal_uInt32 nLevel, const PPTParaLevel& rParaLevel, const PPTCharLevel& rCharLevel, TSS_Type nInstance )
+{
+ nIsBullet = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BulletOn ) ) != 0 ? 1 : 0;
+ nBulletChar = rParaLevel.mnBulletChar;
+
+ bool bBuHardFont;
+ bBuHardFont = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0;
+ if ( bBuHardFont )
+ nBulletFont = rParaLevel.mnBulletFont;
+ else
+ nBulletFont = rCharLevel.mnFont;
+ nBulletHeight = rParaLevel.mnBulletHeight;
+ nBulletColor = rParaLevel.mnBulletColor;
+ nTextOfs = rParaLevel.mnTextOfs;
+ nBulletOfs = rParaLevel.mnBulletOfs;
+
+ std::optional< sal_Int16 > oStartNumbering;
+ ImplGetExtNumberFormat( rManager, rNumberFormat, nLevel, nInstance, TSS_Type::Unknown, oStartNumbering, rCharLevel.mnFontHeight, nullptr );
+ if ( ( rNumberFormat.GetNumberingType() != SVX_NUM_BITMAP ) && ( nBulletHeight > 0x7fff ) )
+ nBulletHeight = rCharLevel.mnFontHeight ? ((- static_cast<sal_Int16>(nBulletHeight)) * 100 ) / rCharLevel.mnFontHeight : 100;
+ ImplGetNumberFormat( rManager, rNumberFormat );
+ switch ( rNumberFormat.GetNumberingType() )
+ {
+ case SVX_NUM_CHARS_UPPER_LETTER :
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_ROMAN_UPPER :
+ case SVX_NUM_ROMAN_LOWER :
+ case SVX_NUM_ARABIC :
+ case SVX_NUM_CHARS_UPPER_LETTER_N :
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ {
+ sal_uInt32 nFont = rCharLevel.mnFont;
+ const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nFont );
+ if ( pFontEnityAtom )
+ {
+ vcl::Font aFont;
+ aFont.SetCharSet( pFontEnityAtom->eCharSet );
+ aFont.SetFamilyName( pFontEnityAtom->aName );
+ aFont.SetFamily( pFontEnityAtom->eFamily );
+ aFont.SetPitch( pFontEnityAtom->ePitch );
+ rNumberFormat.SetBulletFont( &aFont );
+ }
+ }
+ break;
+ default: break;
+ }
+}
+
+bool PPTNumberFormatCreator::GetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat, PPTParagraphObj* pParaObj,
+ TSS_Type nDestinationInstance, std::optional< sal_Int16 >& rStartNumbering )
+{
+ sal_uInt32 nHardCount = 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet, nDestinationInstance ) ? 1 : 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletChar, nBulletChar, nDestinationInstance ) ? 1 : 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletFont, nBulletFont, nDestinationInstance ) ? 1 : 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletHeight, nBulletHeight, nDestinationInstance ) ? 1 : 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletColor, nBulletColor, nDestinationInstance ) ? 1 : 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_TextOfs, nTextOfs, nDestinationInstance ) ? 1 : 0;
+ nHardCount += pParaObj->GetAttrib( PPT_ParaAttr_BulletOfs, nBulletOfs, nDestinationInstance ) ? 1 : 0;
+
+ if ( nIsBullet )
+ rNumberFormat.SetNumberingType( SVX_NUM_CHAR_SPECIAL );
+
+ sal_uInt32 nFontHeight = 24;
+ PPTPortionObj* pPtr = pParaObj->First();
+ if ( pPtr )
+ pPtr->GetAttrib( PPT_CharAttr_FontHeight, nFontHeight, nDestinationInstance );
+ if ( nIsBullet )
+ nHardCount += ImplGetExtNumberFormat( rManager, rNumberFormat, pParaObj->mxParaSet->mnDepth,
+ pParaObj->mnInstance, nDestinationInstance, rStartNumbering, nFontHeight, pParaObj ) ? 1 : 0;
+
+ if ( rNumberFormat.GetNumberingType() != SVX_NUM_BITMAP )
+ pParaObj->UpdateBulletRelSize( nBulletHeight );
+ if ( nHardCount )
+ {
+ ImplGetNumberFormat( rManager, rNumberFormat );
+ switch ( rNumberFormat.GetNumberingType() )
+ {
+ case SVX_NUM_CHARS_UPPER_LETTER :
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_ROMAN_UPPER :
+ case SVX_NUM_ROMAN_LOWER :
+ case SVX_NUM_ARABIC :
+ case SVX_NUM_CHARS_UPPER_LETTER_N :
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ {
+ if ( pPtr )
+ {
+ sal_uInt32 nFont;
+ pPtr->GetAttrib( PPT_CharAttr_Font, nFont, nDestinationInstance );
+ const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nFont );
+ if ( pFontEnityAtom )
+ {
+ vcl::Font aFont;
+ aFont.SetCharSet( pFontEnityAtom->eCharSet );
+ aFont.SetFamilyName( pFontEnityAtom->aName );
+ aFont.SetFamily( pFontEnityAtom->eFamily );
+ aFont.SetPitch( pFontEnityAtom->ePitch );
+ rNumberFormat.SetBulletFont( &aFont );
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+ return nHardCount != 0;
+}
+
+void PPTNumberFormatCreator::ImplGetNumberFormat( SdrPowerPointImport const & rManager, SvxNumberFormat& rNumberFormat )
+{
+ vcl::Font aFont;
+ const PptFontEntityAtom* pAtom = rManager.GetFontEnityAtom( nBulletFont );
+ if ( pAtom )
+ {
+ rtl_TextEncoding eCharSet( pAtom->eCharSet );
+ aFont.SetFamilyName( pAtom->aName );
+ aFont.SetCharSet( eCharSet );
+ aFont.SetFamily( pAtom->eFamily );
+ aFont.SetPitch( pAtom->ePitch );
+ }
+ Color aCol( rManager.MSO_TEXT_CLR_ToColor( nBulletColor ) );
+ aFont.SetColor( aCol );
+
+ sal_uInt16 nBuChar = static_cast<sal_uInt16>(nBulletChar);
+ if ( aFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
+ {
+ nBuChar &= 0x00ff;
+ nBuChar |= 0xf000;
+ }
+ rNumberFormat.SetBulletFont( &aFont );
+ rNumberFormat.SetBulletChar( nBuChar );
+ rNumberFormat.SetBulletRelSize( static_cast<sal_uInt16>(nBulletHeight) );
+ rNumberFormat.SetBulletColor( aCol );
+ sal_uInt32 nAbsLSpace = convertMasterUnitToMm100(nTextOfs);
+ sal_uInt32 nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(nBulletOfs);
+ rNumberFormat.SetAbsLSpace( nAbsLSpace );
+ rNumberFormat.SetFirstLineOffset( -static_cast<sal_Int32>(nFirstLineOffset) );
+}
+
+PPTCharSheet::PPTCharSheet( TSS_Type nInstance )
+{
+ sal_uInt32 nColor = PPT_COLSCHEME_TEXT_UND_ZEILEN;
+ sal_uInt16 nFontHeight(0);
+ switch ( nInstance )
+ {
+ case TSS_Type::PageTitle :
+ case TSS_Type::Title :
+ {
+ nColor = PPT_COLSCHEME_TITELTEXT;
+ nFontHeight = 44;
+ }
+ break;
+ case TSS_Type::Body :
+ case TSS_Type::Subtitle :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody :
+ nFontHeight = 32;
+ break;
+ case TSS_Type::Notes :
+ nFontHeight = 12;
+ break;
+ case TSS_Type::Unused :
+ case TSS_Type::TextInShape :
+ nFontHeight = 24;
+ break;
+ default: break;
+ }
+ for (PPTCharLevel & nDepth : maCharLevel)
+ {
+ nDepth.mnFlags = 0;
+ nDepth.mnFont = 0;
+ nDepth.mnAsianOrComplexFont = 0xffff;
+ nDepth.mnFontHeight = nFontHeight;
+ nDepth.mnFontColor = nColor;
+ nDepth.mnFontColorInStyleSheet = Color( static_cast<sal_uInt8>(nColor), static_cast<sal_uInt8>( nColor >> 8 ), static_cast<sal_uInt8>( nColor >> 16 ) );
+ nDepth.mnEscapement = 0;
+ }
+}
+
+void PPTCharSheet::Read( SvStream& rIn, sal_uInt32 nLevel)
+{
+ // character attributes
+ sal_uInt32 nCMask(0);
+ sal_uInt16 nVal16;
+ rIn.ReadUInt32(nCMask);
+
+ if ( nCMask & 0x0000FFFF )
+ {
+ sal_uInt16 nBitAttr(0);
+ maCharLevel[ nLevel ].mnFlags &= ~static_cast<sal_uInt16>(nCMask);
+ rIn.ReadUInt16( nBitAttr ); // Bit attributes (bold, underlined, ...)
+ maCharLevel[ nLevel ].mnFlags |= nBitAttr;
+ }
+ if ( nCMask & ( 1 << PPT_CharAttr_Font ) ) // 0x00010000
+ rIn.ReadUInt16( maCharLevel[ nLevel ].mnFont );
+ if ( nCMask & ( 1 << PPT_CharAttr_AsianOrComplexFont ) ) // 0x00200000
+ rIn.ReadUInt16( maCharLevel[ nLevel ].mnAsianOrComplexFont );
+ if ( nCMask & ( 1 << PPT_CharAttr_ANSITypeface ) ) // 0x00400000
+ rIn.ReadUInt16( nVal16 );
+ if ( nCMask & ( 1 << PPT_CharAttr_Symbol ) ) // 0x00800000
+ rIn.ReadUInt16( nVal16 );
+ if ( nCMask & ( 1 << PPT_CharAttr_FontHeight ) ) // 0x00020000
+ rIn.ReadUInt16( maCharLevel[ nLevel ].mnFontHeight );
+ if ( nCMask & ( 1 << PPT_CharAttr_FontColor ) ) // 0x00040000
+ {
+ rIn.ReadUInt32( maCharLevel[ nLevel ].mnFontColor );
+ if( ! (maCharLevel[ nLevel ].mnFontColor & 0xff000000 ) )
+ maCharLevel[ nLevel ].mnFontColor = PPT_COLSCHEME_HINTERGRUND;
+ }
+ if ( nCMask & ( 1 << PPT_CharAttr_Escapement ) ) // 0x00080000
+ rIn.ReadUInt16( maCharLevel[ nLevel ].mnEscapement );
+ if ( nCMask & 0x00100000 ) // 0x00100000
+ rIn.ReadUInt16( nVal16 );
+
+ nCMask >>= 24;
+ while( nCMask )
+ {
+ if ( nCMask & 1 )
+ {
+ OSL_FAIL( "PPTCharSheet::Read - unknown attribute, send me this document (SJ)" );
+ rIn.ReadUInt16( nVal16 );
+ }
+ nCMask >>= 1;
+ }
+}
+
+PPTParaSheet::PPTParaSheet( TSS_Type nInstance )
+{
+ sal_uInt16 nBuFlags = 0;
+ sal_uInt32 nBulletColor = 0x8000000;
+ sal_uInt16 nUpperDist = 0;
+
+ switch ( nInstance )
+ {
+ case TSS_Type::PageTitle :
+ case TSS_Type::Title :
+ nBulletColor = PPT_COLSCHEME_TITELTEXT;
+ break;
+ case TSS_Type::Body :
+ case TSS_Type::Subtitle :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody :
+ {
+ nBuFlags = 1;
+ nUpperDist = 0x14;
+ }
+ break;
+ case TSS_Type::Notes :
+ nUpperDist = 0x1e;
+ break;
+ default: break;
+ }
+ for (PPTParaLevel & i : maParaLevel)
+ {
+ i.mnBuFlags = nBuFlags;
+ i.mnBulletChar = 0x2022;
+ i.mnBulletFont = 0;
+ i.mnBulletHeight = 100;
+ i.mnBulletColor = nBulletColor;
+ i.mnAdjust = 0;
+ i.mnLineFeed = 100;
+ i.mnLowerDist = 0;
+ i.mnUpperDist = nUpperDist;
+ i.mnTextOfs = 0;
+ i.mnBulletOfs = 0;
+ i.mnDefaultTab = 0x240;
+ i.mnAsianLineBreak = 0;
+ i.mnBiDi = 0;
+ }
+}
+
+void PPTParaSheet::Read( SdrPowerPointImport const &
+#ifdef DBG_UTIL
+ rManager
+#endif
+ , SvStream& rIn
+ , sal_uInt32 nLevel, bool bFirst )
+{
+ // paragraph attributes
+ sal_uInt32 nPMask(0);
+ rIn.ReadUInt32(nPMask);
+
+ sal_uInt16 nMask16 = static_cast<sal_uInt16>(nPMask) & 0xf;
+ if ( nMask16 )
+ {
+ sal_uInt16 nVal16(0);
+ rIn.ReadUInt16( nVal16 );
+ maParaLevel[ nLevel ].mnBuFlags &=~ nMask16;
+ nVal16 &= nMask16;
+ maParaLevel[ nLevel ].mnBuFlags |= nVal16;
+ }
+ if ( nPMask & 0x0080 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletChar );
+ if ( nPMask & 0x0010 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletFont );
+ if ( nPMask & 0x0040 )
+ {
+ sal_uInt16 nVal16(0);
+ rIn.ReadUInt16( nVal16 );
+ maParaLevel[ nLevel ].mnBulletHeight = nVal16;
+ }
+ if ( nPMask & 0x0020 )
+ {
+ sal_uInt32 nVal32(0);
+ rIn.ReadUInt32(nVal32);
+ maParaLevel[ nLevel ].mnBulletColor = nVal32;
+ }
+ if ( bFirst )
+ {
+ if ( nPMask & 0xF00 )
+ {
+ // AbsJust!
+ sal_uInt16 nVal16(0);
+ rIn.ReadUInt16( nVal16 );
+ maParaLevel[ nLevel ].mnAdjust = nVal16 & 3;
+ }
+ if ( nPMask & 0x1000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnLineFeed );
+ if ( nPMask & 0x2000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnUpperDist );
+ if ( nPMask & 0x4000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnLowerDist );
+ if ( nPMask & 0x8000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnTextOfs );
+ if ( nPMask & 0x10000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletOfs );
+ if ( nPMask & 0x20000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnDefaultTab );
+ if ( nPMask & 0x200000 )
+ {
+ sal_uInt16 nVal16;
+ sal_uInt32 nVal32;
+ // number of tabulators
+ rIn.ReadUInt16( nVal16 );
+ if (!rIn.good() || rIn.remainingSize() / sizeof(nVal32) < nVal16)
+ return;
+ for (sal_uInt16 i = 0; i < nVal16; ++i)
+ rIn.ReadUInt32( nVal32 ); // reading the tabulators
+ }
+ if ( nPMask & 0x40000 )
+ {
+ sal_uInt16 nVal16;
+ rIn.ReadUInt16( nVal16 );
+ }
+ if ( nPMask & 0x80000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnAsianLineBreak );
+ if ( nPMask & 0x100000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnBiDi );
+ }
+ else
+ {
+ if ( nPMask & 0x800 )
+ {
+ sal_uInt16 nVal16(0);
+ rIn.ReadUInt16( nVal16 );
+ maParaLevel[ nLevel ].mnAdjust = nVal16 & 3;
+ }
+ if ( nPMask & 0x1000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnLineFeed );
+ if ( nPMask & 0x2000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnUpperDist );
+ if ( nPMask & 0x4000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnLowerDist );
+ if ( nPMask & 0x8000 )
+ {
+ sal_uInt16 nVal16;
+ rIn.ReadUInt16( nVal16 );
+ }
+ if ( nPMask & 0x100 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnTextOfs );
+ if ( nPMask & 0x200 )
+ {
+ sal_uInt16 nVal16;
+ rIn.ReadUInt16( nVal16 );
+ }
+ if ( nPMask & 0x400 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnBulletOfs );
+ if ( nPMask & 0x10000 )
+ {
+ sal_uInt16 nVal16;
+ rIn.ReadUInt16( nVal16 );
+ }
+ if ( nPMask & 0xe0000 )
+ {
+ sal_uInt16 nFlagsToModifyMask = static_cast<sal_uInt16>( ( nPMask >> 17 ) & 7 );
+ sal_uInt16 nVal16(0);
+ rIn.ReadUInt16( nVal16 );
+ // bits that are not involved to zero
+ nVal16 &= nFlagsToModifyMask;
+ // bits that are to change to zero
+ maParaLevel[ nLevel ].mnAsianLineBreak &=~nFlagsToModifyMask;
+ // now set the corresponding bits
+ maParaLevel[ nLevel ].mnAsianLineBreak |= nVal16;
+ }
+ if ( nPMask & 0x100000 )
+ {
+ sal_uInt16 nVal16;
+ sal_uInt32 nVal32;
+ // number of tabulators
+ rIn.ReadUInt16( nVal16 );
+ if (!rIn.good() || rIn.remainingSize() / sizeof(nVal32) < nVal16)
+ return;
+ for (sal_uInt16 i = 0; i < nVal16; ++i)
+ rIn.ReadUInt32( nVal32 ); // reading the tabulators
+ }
+ if ( nPMask & 0x200000 )
+ rIn.ReadUInt16( maParaLevel[ nLevel ].mnBiDi );
+ }
+
+ nPMask >>= 22;
+ while( nPMask )
+ {
+ if ( nPMask & 1 )
+ {
+#ifdef DBG_UTIL
+ if (!(rManager.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT))
+ {
+ OSL_FAIL( "PPTParaSheet::Read - unknown attribute, send me this document (SJ)" );
+ }
+#endif
+ sal_uInt16 nVal16;
+ rIn.ReadUInt16( nVal16 );
+ }
+ nPMask >>= 1;
+ }
+}
+
+void PPTParaSheet::UpdateBulletRelSize( sal_uInt32 nLevel, sal_uInt16 nFontHeight )
+{
+ if ( maParaLevel[ nLevel ].mnBulletHeight > 0x7fff ) // a negative value is the absolute bullet height
+ {
+ sal_Int16 nBulletRelSize = static_cast<sal_Int16>(maParaLevel[ nLevel ].mnBulletHeight);
+ nBulletRelSize = nFontHeight ? ((-nBulletRelSize) * 100 ) / nFontHeight : 100;
+ if ( nBulletRelSize < 0 ) //bullet size over flow
+ nBulletRelSize = 100;
+ maParaLevel[ nLevel ].mnBulletHeight = nBulletRelSize;
+ }
+}
+
+PPTStyleSheet::PPTStyleSheet( const DffRecordHeader& rSlideHd, SvStream& rIn, SdrPowerPointImport& rManager,
+ const PPTTextParagraphStyleAtomInterpreter& rTxPFStyle,
+ const PPTTextSpecInfo& rTextSpecInfo ) :
+
+ PPTNumberFormatCreator ( std::make_unique<PPTExtParaProv>( rManager, rIn, &rSlideHd ) ),
+ maTxSI ( rTextSpecInfo )
+{
+ sal_uInt32 nOldFilePos = rIn.Tell();
+
+ // default stylesheets
+ mpCharSheet[ TSS_Type::PageTitle ] = std::make_unique<PPTCharSheet>( TSS_Type::PageTitle );
+ mpCharSheet[ TSS_Type::Body ] = std::make_unique<PPTCharSheet>( TSS_Type::Body );
+ mpCharSheet[ TSS_Type::Notes ] = std::make_unique<PPTCharSheet>( TSS_Type::Notes );
+ mpCharSheet[ TSS_Type::Unused ] = std::make_unique<PPTCharSheet>( TSS_Type::Unused ); // this entry is not used by ppt
+ mpCharSheet[ TSS_Type::TextInShape ] = std::make_unique<PPTCharSheet>( TSS_Type::TextInShape );
+ mpParaSheet[ TSS_Type::PageTitle ] = std::make_unique<PPTParaSheet>( TSS_Type::PageTitle );
+ mpParaSheet[ TSS_Type::Body ] = std::make_unique<PPTParaSheet>( TSS_Type::Body );
+ mpParaSheet[ TSS_Type::Notes ] = std::make_unique<PPTParaSheet>( TSS_Type::Notes );
+ mpParaSheet[ TSS_Type::Unused ] = std::make_unique<PPTParaSheet>( TSS_Type::Unused );
+ mpParaSheet[ TSS_Type::TextInShape ] = std::make_unique<PPTParaSheet>( TSS_Type::TextInShape );
+ // mpCharSheet[ TSS_Type::QuarterBody ], mpCharSheet[ TSS_Type::HalfBody ], mpCharSheet[ TSS_Type::Title ], mpCharSheet[ TSS_Type::Subtitle ] intentionally null
+ // mpParaSheet[ TSS_Type::QuarterBody ], mpParaSheet[ TSS_Type::HalfBody ], mpParaSheet[ TSS_Type::Title ], mpParaSheet[ TSS_Type::Subtitle ] intentionally null
+
+ /* SJ: try to locate the txMasterStyleAtom in the Environment
+
+ it seems that the environment TextStyle is having a higher priority
+ than the TextStyle that can be found within the master page
+ */
+ bool bFoundTxMasterStyleAtom04 = false;
+ DffRecordHeader* pEnvHeader = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment );
+ if ( pEnvHeader )
+ {
+ pEnvHeader->SeekToContent( rIn );
+ DffRecordHeader aTxMasterStyleHd;
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pEnvHeader->GetRecEndFilePos());
+ while (rIn.Tell() < nEndRecPos)
+ {
+ ReadDffRecordHeader( rIn, aTxMasterStyleHd );
+ if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom )
+ {
+ sal_uInt16 nLevelCnt(0);
+ rIn.ReadUInt16(nLevelCnt);
+
+ sal_uInt16 nLev = 0;
+ bool bFirst = true;
+ bFoundTxMasterStyleAtom04 = true;
+ auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd.GetRecEndFilePos());
+ while (rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt && nLev < nMaxPPTLevels)
+ {
+ if ( nLev )
+ {
+ mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev ] = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev - 1 ];
+ mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ] = mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev - 1 ];
+ }
+ mpParaSheet[ TSS_Type::TextInShape ]->Read( rManager, rIn, nLev, bFirst );
+ if ( !nLev )
+ {
+ // set paragraph defaults for instance 4 (TSS_Type::TextInShape)
+ if ( rTxPFStyle.bValid )
+ {
+ PPTParaLevel& rParaLevel = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ 0 ];
+ rParaLevel.mnAsianLineBreak = 0;
+ if ( rTxPFStyle.bForbiddenRules )
+ rParaLevel.mnAsianLineBreak |= 1;
+ if ( !rTxPFStyle.bLatinTextWrap )
+ rParaLevel.mnAsianLineBreak |= 2;
+ if ( rTxPFStyle.bHangingPunctuation )
+ rParaLevel.mnAsianLineBreak |= 4;
+ }
+ }
+ mpCharSheet[ TSS_Type::TextInShape ]->Read( rIn, nLev );
+ mpParaSheet[ TSS_Type::TextInShape ]->UpdateBulletRelSize( nLev, mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ].mnFontHeight );
+ bFirst = false;
+ nLev++;
+ }
+ break;
+ }
+ else
+ {
+ if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn))
+ break;
+ }
+ }
+ }
+
+ rSlideHd.SeekToContent( rIn );
+
+ DffRecordHeader aTxMasterStyleHd;
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rSlideHd.GetRecEndFilePos());
+ while (rIn.Tell() < nEndRecPos)
+ {
+ ReadDffRecordHeader( rIn, aTxMasterStyleHd );
+ if ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom )
+ break;
+ else
+ {
+ if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn))
+ break;
+ }
+ }
+ while ( ( aTxMasterStyleHd.nRecType == PPT_PST_TxMasterStyleAtom ) && ( rIn.Tell() < nEndRecPos ) ) //TODO: aTxMasterStyleHd may be used without having been properly initialized
+ {
+ TSS_Type nInstance = static_cast<TSS_Type>(aTxMasterStyleHd.nRecInstance);
+ if ( ( nInstance <= TSS_Type::LAST ) &&
+ ( ( nInstance != TSS_Type::TextInShape ) || !bFoundTxMasterStyleAtom04 ) )
+ {
+ if ( nInstance > TSS_Type::TextInShape )
+ {
+ mpCharSheet[ nInstance ].reset(); // be sure to delete the old one if this instance comes twice
+ mpParaSheet[ nInstance ].reset();
+
+ switch ( nInstance )
+ {
+ case TSS_Type::Subtitle :
+ {
+ mpCharSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
+ mpParaSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
+ }
+ break;
+ case TSS_Type::Title :
+ {
+ mpCharSheet[ TSS_Type::Title ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::PageTitle ] ) );
+ mpParaSheet[ TSS_Type::Title ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::PageTitle ] ) );
+ }
+ break;
+ case TSS_Type::HalfBody :
+ {
+ mpCharSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
+ mpParaSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
+ }
+ break;
+
+ case TSS_Type::QuarterBody :
+ {
+ mpCharSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
+ mpParaSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
+ }
+ break;
+ default: break;
+ }
+ }
+ sal_uInt16 nLevelCnt(0);
+ rIn.ReadUInt16(nLevelCnt);
+ if (nLevelCnt > nMaxPPTLevels)
+ {
+ OSL_FAIL( "PPTStyleSheet::Ppt-TextStylesheet has more than 5 levels! (SJ)" );
+ nLevelCnt = nMaxPPTLevels;
+ }
+ sal_uInt16 nLev = 0;
+ bool bFirst = true;
+
+ auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd.GetRecEndFilePos());
+ while ( rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt )
+ {
+ if ( nLev && ( nInstance < TSS_Type::Subtitle ) )
+ {
+ mpParaSheet[ nInstance ]->maParaLevel[ nLev ] = mpParaSheet[ nInstance ]->maParaLevel[ nLev - 1 ];
+ mpCharSheet[ nInstance ]->maCharLevel[ nLev ] = mpCharSheet[ nInstance ]->maCharLevel[ nLev - 1 ];
+ }
+
+ // Exception: Template 5, 6 (MasterTitle Title and SubTitle)
+ if ( nInstance >= TSS_Type::Subtitle )
+ {
+ bFirst = false;
+
+ sal_uInt16 nDontKnow;
+ rIn.ReadUInt16( nDontKnow );
+ }
+ mpParaSheet[ nInstance ]->Read( rManager, rIn, nLev, bFirst );
+ mpCharSheet[ nInstance ]->Read( rIn, nLev );
+ mpParaSheet[ nInstance ]->UpdateBulletRelSize( nLev, mpCharSheet[ nInstance ]->maCharLevel[ nLev ].mnFontHeight );
+ bFirst = false;
+ nLev++;
+ }
+#ifdef DBG_UTIL
+ if (!(rManager.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT))
+ {
+ if ( rIn.GetError() == ERRCODE_NONE )
+ {
+ OStringBuffer aMsg;
+ if ( rIn.Tell() > aTxMasterStyleHd.GetRecEndFilePos() )
+ {
+ aMsg.append("\n reading too many bytes:" +
+ OString::number(rIn.Tell() - aTxMasterStyleHd.GetRecEndFilePos()));
+ }
+ if ( rIn.Tell() < aTxMasterStyleHd.GetRecEndFilePos() )
+ {
+ aMsg.append("\n reading too few bytes:" +
+ OString::number(aTxMasterStyleHd.GetRecEndFilePos() - rIn.Tell()));
+ }
+ if (aMsg.getLength())
+ {
+ aMsg.insert(0, "PptStyleSheet::operator>>[]");
+ OSL_FAIL(aMsg.getStr());
+ }
+ }
+ if ( rIn.Tell() != aTxMasterStyleHd.GetRecEndFilePos() )
+ SAL_WARN( "filter.ms", "SJ: Wrong number of bytes read during import of PPT style");
+ }
+#endif
+ }
+ if (!aTxMasterStyleHd.SeekToEndOfRecord(rIn))
+ break;
+ ReadDffRecordHeader( rIn, aTxMasterStyleHd );
+ }
+ if ( !mpCharSheet[ TSS_Type::Subtitle ] )
+ {
+ mpCharSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
+ mpParaSheet[ TSS_Type::Subtitle ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
+ }
+ if ( !mpCharSheet[ TSS_Type::Title ] )
+ {
+ mpCharSheet[ TSS_Type::Title ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::PageTitle ] ) );
+ mpParaSheet[ TSS_Type::Title ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::PageTitle ] ) );
+ }
+ if ( !mpCharSheet[ TSS_Type::HalfBody ] )
+ {
+ mpCharSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
+ mpParaSheet[ TSS_Type::HalfBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
+ }
+ if ( !mpCharSheet[ TSS_Type::QuarterBody ] )
+ {
+ mpCharSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTCharSheet>( *( mpCharSheet[ TSS_Type::Body ] ) );
+ mpParaSheet[ TSS_Type::QuarterBody ] = std::make_unique<PPTParaSheet>( *( mpParaSheet[ TSS_Type::Body ] ) );
+ }
+ if ( !bFoundTxMasterStyleAtom04 )
+ { // try to locate the txMasterStyleAtom in the Environment
+ DffRecordHeader* pEnvHeader2 = rManager.aDocRecManager.GetRecordHeader( PPT_PST_Environment );
+ if ( pEnvHeader2 )
+ {
+ pEnvHeader2->SeekToContent( rIn );
+ DffRecordHeader aTxMasterStyleHd2;
+ auto nEnvEndRecPos = DffPropSet::SanitizeEndPos(rIn, pEnvHeader2->GetRecEndFilePos());
+ while (rIn.Tell() < nEnvEndRecPos)
+ {
+ ReadDffRecordHeader( rIn, aTxMasterStyleHd2 );
+ if ( aTxMasterStyleHd2.nRecType == PPT_PST_TxMasterStyleAtom )
+ {
+ sal_uInt16 nLevelCnt;
+ rIn.ReadUInt16( nLevelCnt );
+
+ sal_uInt16 nLev = 0;
+ bool bFirst = true;
+ auto nTxEndRecPos = DffPropSet::SanitizeEndPos(rIn, aTxMasterStyleHd2.GetRecEndFilePos());
+ while ( rIn.GetError() == ERRCODE_NONE && rIn.Tell() < nTxEndRecPos && nLev < nLevelCnt )
+ {
+ if ( nLev )
+ {
+ mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev ] = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ nLev - 1 ];
+ mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ] = mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev - 1 ];
+ }
+ mpParaSheet[ TSS_Type::TextInShape ]->Read( rManager, rIn, nLev, bFirst );
+ if ( !nLev )
+ {
+ // set paragraph defaults for instance 4 (TSS_Type::TextInShape)
+ if ( rTxPFStyle.bValid )
+ {
+ PPTParaLevel& rParaLevel = mpParaSheet[ TSS_Type::TextInShape ]->maParaLevel[ 0 ];
+ rParaLevel.mnAsianLineBreak = 0;
+ if ( rTxPFStyle.bForbiddenRules )
+ rParaLevel.mnAsianLineBreak |= 1;
+ if ( !rTxPFStyle.bLatinTextWrap )
+ rParaLevel.mnAsianLineBreak |= 2;
+ if ( rTxPFStyle.bHangingPunctuation )
+ rParaLevel.mnAsianLineBreak |= 4;
+ }
+ }
+ mpCharSheet[ TSS_Type::TextInShape ]->Read( rIn, nLev );
+ mpParaSheet[ TSS_Type::TextInShape ]->UpdateBulletRelSize( nLev, mpCharSheet[ TSS_Type::TextInShape ]->maCharLevel[ nLev ].mnFontHeight );
+ bFirst = false;
+ nLev++;
+ }
+ break;
+ }
+ else
+ {
+ if (!aTxMasterStyleHd2.SeekToEndOfRecord(rIn))
+ break;
+ }
+ }
+ }
+ }
+ rIn.Seek( nOldFilePos );
+
+ // will create the default numbulletitem for each instance
+ for ( auto i : o3tl::enumrange<TSS_Type>() )
+ {
+ sal_uInt16 nLevels, nDepth = 0;
+ SvxNumRuleType eNumRuleType;
+
+ switch ( i )
+ {
+ case TSS_Type::PageTitle :
+ case TSS_Type::Title :
+ nLevels = 1;
+ eNumRuleType = SvxNumRuleType::NUMBERING;
+ break;
+ case TSS_Type::Subtitle :
+ nLevels = SVX_MAX_NUM;
+ eNumRuleType = SvxNumRuleType::NUMBERING;
+ break;
+ case TSS_Type::Body :
+ case TSS_Type::HalfBody :
+ case TSS_Type::QuarterBody :
+ nLevels = SVX_MAX_NUM;
+ eNumRuleType = SvxNumRuleType::PRESENTATION_NUMBERING;
+ break;
+ default :
+ case TSS_Type::Notes :
+ case TSS_Type::Unused :
+ case TSS_Type::TextInShape :
+ nLevels = SVX_MAX_NUM;
+ eNumRuleType = SvxNumRuleType::NUMBERING;
+ break;
+ }
+ SvxNumRule aRule( SvxNumRuleFlags::BULLET_REL_SIZE | SvxNumRuleFlags::BULLET_COLOR,
+ nLevels, false, eNumRuleType );
+ for ( sal_uInt16 nCount = 0; nDepth < nLevels; nCount++ )
+ {
+ const PPTParaLevel& rParaLevel = mpParaSheet[ i ]->maParaLevel[ nCount ];
+ const PPTCharLevel& rCharLevel = mpCharSheet[ i ]->maCharLevel[ nCount ];
+ SvxNumberFormat aNumberFormat( SVX_NUM_CHAR_SPECIAL );
+ aNumberFormat.SetBulletChar( ' ' );
+ GetNumberFormat( rManager, aNumberFormat, nCount, rParaLevel, rCharLevel, i );
+ aRule.SetLevel( nDepth++, aNumberFormat );
+ if ( nCount >= 4 )
+ {
+ for ( ;nDepth < nLevels; nDepth++ )
+ aRule.SetLevel( nDepth, aNumberFormat );
+ }
+ }
+ mpNumBulletItem[ i ] = std::make_unique<SvxNumBulletItem>( std::move(aRule), EE_PARA_NUMBULLET );
+ }
+}
+
+PPTStyleSheet::~PPTStyleSheet()
+{
+ for ( auto i : o3tl::enumrange<TSS_Type>() )
+ {
+ mpCharSheet[i].reset();
+ mpParaSheet[i].reset();
+ mpNumBulletItem[i].reset();
+ }
+}
+
+PPTParaPropSet::PPTParaPropSet()
+ : mnOriginalTextPos(0)
+ , mxParaSet( new ImplPPTParaPropSet )
+{
+ mxParaSet->mnHasAnm = 1;
+}
+
+PPTParaPropSet::PPTParaPropSet( PPTParaPropSet const & rParaPropSet )
+{
+ mxParaSet = rParaPropSet.mxParaSet;
+ mnOriginalTextPos = rParaPropSet.mnOriginalTextPos;
+}
+
+PPTParaPropSet::~PPTParaPropSet()
+{
+}
+
+PPTParaPropSet& PPTParaPropSet::operator=( const PPTParaPropSet& rParaPropSet )
+{
+ if ( this != &rParaPropSet )
+ {
+ mxParaSet = rParaPropSet.mxParaSet;
+ mnOriginalTextPos = rParaPropSet.mnOriginalTextPos;
+ }
+ return *this;
+}
+
+PPTCharPropSet::PPTCharPropSet(sal_uInt32 nParagraph)
+ : mnOriginalTextPos(0)
+ , mnParagraph(nParagraph)
+{
+ mnHylinkOrigColor = 0;
+ mbIsHyperlink = false;
+ mbHardHylinkOrigColor = false;
+ mnLanguage[ 0 ] = mnLanguage[ 1 ] = mnLanguage[ 2 ] = LANGUAGE_SYSTEM;
+}
+
+PPTCharPropSet::PPTCharPropSet( const PPTCharPropSet& rCharPropSet )
+ : mpImplPPTCharPropSet( rCharPropSet.mpImplPPTCharPropSet )
+{
+ mnHylinkOrigColor = rCharPropSet.mnHylinkOrigColor;
+ mbIsHyperlink = rCharPropSet.mbIsHyperlink;
+ mbHardHylinkOrigColor = rCharPropSet.mbHardHylinkOrigColor;
+
+ mnParagraph = rCharPropSet.mnParagraph;
+ mnOriginalTextPos = rCharPropSet.mnOriginalTextPos;
+ maString = rCharPropSet.maString;
+ mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr );
+ mnLanguage[ 0 ] = rCharPropSet.mnLanguage[ 0 ];
+ mnLanguage[ 1 ] = rCharPropSet.mnLanguage[ 1 ];
+ mnLanguage[ 2 ] = rCharPropSet.mnLanguage[ 2 ];
+}
+
+PPTCharPropSet::PPTCharPropSet( const PPTCharPropSet& rCharPropSet, sal_uInt32 nParagraph )
+ : mpImplPPTCharPropSet(rCharPropSet.mpImplPPTCharPropSet)
+{
+ mnHylinkOrigColor = rCharPropSet.mnHylinkOrigColor;
+ mbIsHyperlink = rCharPropSet.mbIsHyperlink;
+ mbHardHylinkOrigColor = rCharPropSet.mbHardHylinkOrigColor;
+
+ mnParagraph = nParagraph;
+ mnOriginalTextPos = rCharPropSet.mnOriginalTextPos;
+ maString = rCharPropSet.maString;
+ mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr );
+ mnLanguage[ 0 ] = mnLanguage[ 1 ] = mnLanguage[ 2 ] = LANGUAGE_SYSTEM;
+}
+
+PPTCharPropSet::~PPTCharPropSet()
+{
+}
+
+PPTCharPropSet& PPTCharPropSet::operator=( const PPTCharPropSet& rCharPropSet )
+{
+ if ( this != &rCharPropSet )
+ {
+ mpImplPPTCharPropSet = rCharPropSet.mpImplPPTCharPropSet;
+ mnOriginalTextPos = rCharPropSet.mnOriginalTextPos;
+ mnParagraph = rCharPropSet.mnParagraph;
+ maString = rCharPropSet.maString;
+ mpFieldItem.reset( rCharPropSet.mpFieldItem ? new SvxFieldItem( *rCharPropSet.mpFieldItem ) : nullptr );
+ }
+ return *this;
+}
+
+void PPTCharPropSet::SetFont( sal_uInt16 nFont )
+{
+ sal_uInt32 nMask = 1 << PPT_CharAttr_Font;
+ bool bDoNotMake = (mpImplPPTCharPropSet->mnAttrSet & nMask) != 0;
+
+ if ( bDoNotMake )
+ bDoNotMake = nFont == mpImplPPTCharPropSet->mnFont;
+
+ if ( !bDoNotMake )
+ {
+ mpImplPPTCharPropSet->mnFont = nFont;
+ mpImplPPTCharPropSet->mnAttrSet |= nMask;
+ }
+}
+
+void PPTCharPropSet::SetColor( sal_uInt32 nColor )
+{
+ mpImplPPTCharPropSet->mnColor = nColor;
+ mpImplPPTCharPropSet->mnAttrSet |= 1 << PPT_CharAttr_FontColor;
+}
+
+PPTRuler::PPTRuler()
+ : nFlags(0)
+ , nDefaultTab(0x240)
+ , nTabCount(0)
+{
+}
+
+PPTRuler::~PPTRuler()
+{
+};
+
+
+PPTTextRulerInterpreter::PPTTextRulerInterpreter() :
+ mxImplRuler ( new PPTRuler() )
+{
+}
+
+PPTTextRulerInterpreter::PPTTextRulerInterpreter( PPTTextRulerInterpreter const & rRuler )
+{
+ mxImplRuler = rRuler.mxImplRuler;
+}
+
+PPTTextRulerInterpreter::PPTTextRulerInterpreter( sal_uInt32 nFileOfs, DffRecordHeader const & rHeader, SvStream& rIn ) :
+ mxImplRuler ( new PPTRuler() )
+{
+ if ( nFileOfs == 0xffffffff )
+ return;
+
+ sal_uInt32 nOldPos = rIn.Tell();
+ DffRecordHeader rHd;
+ if ( nFileOfs )
+ {
+ rIn.Seek( nFileOfs );
+ ReadDffRecordHeader( rIn, rHd );
+ }
+ else
+ {
+ rHeader.SeekToContent( rIn );
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextRulerAtom, rHeader.GetRecEndFilePos(), &rHd ) )
+ nFileOfs++;
+ }
+ if ( nFileOfs )
+ {
+ bool bRecordOk = true;
+
+ sal_Int16 nTCount(0);
+ sal_Int32 i;
+ rIn.ReadInt32( mxImplRuler->nFlags );
+
+ // number of indent levels, unused now
+ if ( mxImplRuler->nFlags & 2 )
+ rIn.ReadInt16( nTCount );
+ if ( mxImplRuler->nFlags & 1 )
+ rIn.ReadUInt16( mxImplRuler->nDefaultTab );
+ if ( mxImplRuler->nFlags & 4 )
+ {
+ rIn.ReadInt16(nTCount);
+
+ const size_t nMaxPossibleRecords = rIn.remainingSize() / (2*sizeof(sal_uInt16));
+ const sal_uInt16 nTabCount(nTCount);
+
+ bRecordOk = nTabCount <= nMaxPossibleRecords;
+
+ if (nTCount && bRecordOk)
+ {
+ mxImplRuler->nTabCount = nTabCount;
+ mxImplRuler->pTab.reset( new PPTTabEntry[ mxImplRuler->nTabCount ] );
+ for ( i = 0; i < nTCount; i++ )
+ {
+ rIn.ReadUInt16( mxImplRuler->pTab[ i ].nOffset )
+ .ReadUInt16( mxImplRuler->pTab[ i ].nStyle );
+ }
+ }
+ }
+
+ if (bRecordOk)
+ {
+ for ( i = 0; i < 5; i++ )
+ {
+ if ( mxImplRuler->nFlags & ( 8 << i ) )
+ rIn.ReadUInt16( mxImplRuler->nTextOfs[ i ] );
+ if ( mxImplRuler->nFlags & ( 256 << i ) )
+ rIn.ReadUInt16( mxImplRuler->nBulletOfs[ i ] );
+ if( mxImplRuler->nBulletOfs[ i ] > 0x7fff)
+ {
+ // workaround
+ // when bullet offset is > 0x7fff, the paragraph should look like
+ // * first line text
+ // second line text
+
+ // we add to bullet para indent 0xffff - bullet offset. It looks like
+ // best we can do for now
+ mxImplRuler->nTextOfs[ i ] += 0xffff - mxImplRuler->nBulletOfs[ i ];
+ mxImplRuler->nBulletOfs[ i ] = 0;
+ }
+ }
+ }
+ }
+ rIn.Seek( nOldPos );
+}
+
+bool PPTTextRulerInterpreter::GetDefaultTab( sal_uInt16& nValue ) const
+{
+ if ( ! ( mxImplRuler->nFlags & 1 ) )
+ return false;
+ nValue = mxImplRuler->nDefaultTab;
+ return true;
+}
+
+bool PPTTextRulerInterpreter::GetTextOfs( sal_uInt32 nLevel, sal_uInt16& nValue ) const
+{
+ if ( ! ( ( nLevel < 5 ) && ( mxImplRuler->nFlags & ( 8 << nLevel ) ) ) )
+ return false;
+ nValue = mxImplRuler->nTextOfs[ nLevel ];
+ return true;
+}
+
+bool PPTTextRulerInterpreter::GetBulletOfs( sal_uInt32 nLevel, sal_uInt16& nValue ) const
+{
+ if ( ! ( ( nLevel < 5 ) && ( mxImplRuler->nFlags & ( 256 << nLevel ) ) ) )
+ return false;
+ nValue = mxImplRuler->nBulletOfs[ nLevel ];
+ return true;
+}
+
+PPTTextRulerInterpreter& PPTTextRulerInterpreter::operator=( const PPTTextRulerInterpreter& rRuler )
+{
+ if ( this != &rRuler )
+ {
+ mxImplRuler = rRuler.mxImplRuler;
+ }
+ return *this;
+}
+
+PPTTextRulerInterpreter::~PPTTextRulerInterpreter()
+{
+}
+
+PPTTextParagraphStyleAtomInterpreter::PPTTextParagraphStyleAtomInterpreter() :
+ bValid ( false ),
+ bForbiddenRules ( false ),
+ bHangingPunctuation ( false ),
+ bLatinTextWrap ( false )
+{
+}
+
+bool PPTTextParagraphStyleAtomInterpreter::Read( SvStream& rIn, const DffRecordHeader& rRecHd )
+{
+ bValid = false;
+ rRecHd.SeekToContent( rIn );
+ sal_uInt32 nDummy32, nFlags, nRecEndPos = rRecHd.GetRecEndFilePos();
+ sal_uInt16 nDummy16;
+
+ rIn.ReadUInt16( nDummy16 )
+ .ReadUInt32( nFlags );
+
+ if ( nFlags & 0xf && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // BuFlags
+ if ( nFlags & 0x80 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // BuChar
+ if ( nFlags & 0x10 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // nBuFont;
+ if ( nFlags & 0x40 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // nBuHeight;
+ if ( nFlags & 0x0020 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt32( nDummy32 ); // nBuColor;
+ if ( nFlags & 0x800 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // AbsJust!
+ if ( nFlags & 0x400 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 );
+ if ( nFlags & 0x200 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 );
+ if ( nFlags & 0x100 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 );
+ if ( nFlags & 0x1000 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // LineFeed
+ if ( nFlags & 0x2000 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // nUpperDist
+ if ( nFlags & 0x4000 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 ); // nLowerDist
+ if ( nFlags & 0x8000 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 );
+ if ( nFlags & 0x10000 && ( rIn.Tell() < nRecEndPos ) )
+ rIn.ReadUInt16( nDummy16 );
+ if ( nFlags & 0xe0000 && ( rIn.Tell() < nRecEndPos ) )
+ {
+ rIn.ReadUInt16( nDummy16 );
+ if ( nFlags & 0x20000 )
+ bForbiddenRules = ( nDummy16 & 1 ) == 1;
+ if ( nFlags & 0x40000 )
+ bLatinTextWrap = ( nDummy16 & 2 ) == 0;
+ if ( nFlags & 0x80000 )
+ bHangingPunctuation = ( nDummy16 & 4 ) == 4;
+ }
+ nFlags &=~ 0xfffff;
+ sal_uInt32 nMask = 0x100000;
+ while ( nFlags && nMask && ( rIn.Tell() < nRecEndPos ) )
+ {
+ if ( nFlags & nMask )
+ {
+ rIn.ReadUInt16( nDummy16 );
+ nFlags ^= nMask;
+ }
+ nMask <<= 1;
+ }
+ bValid = rIn.Tell() == nRecEndPos;
+ return bValid;
+}
+
+PPTTextSpecInfo::PPTTextSpecInfo( sal_uInt32 _nCharIdx ) :
+ nCharIdx ( _nCharIdx ),
+ nDontKnow ( 1 )
+{
+ nLanguage[ 0 ] = LANGUAGE_PROCESS_OR_USER_DEFAULT;
+ nLanguage[ 1 ] = LANGUAGE_SYSTEM;
+ nLanguage[ 2 ] = LANGUAGE_SYSTEM;
+}
+
+PPTTextSpecInfoAtomInterpreter::PPTTextSpecInfoAtomInterpreter() :
+ bValid ( false )
+{
+}
+
+bool PPTTextSpecInfoAtomInterpreter::Read( SvStream& rIn, const DffRecordHeader& rRecHd,
+ sal_uInt16 nRecordType, const PPTTextSpecInfo* pTextSpecDefault )
+{
+ bValid = false;
+ sal_uInt32 nCharIdx = 0;
+ rRecHd.SeekToContent( rIn );
+
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rRecHd.GetRecEndFilePos());
+ while (rIn.Tell() < nEndRecPos && rIn.good())
+ {
+ if ( nRecordType == PPT_PST_TextSpecInfoAtom )
+ {
+ sal_uInt32 nCharCount(0);
+ rIn.ReadUInt32( nCharCount );
+ nCharIdx += nCharCount;
+ }
+
+ sal_uInt32 nFlags(0);
+ rIn.ReadUInt32(nFlags);
+
+ PPTTextSpecInfo aEntry( nCharIdx );
+ if ( pTextSpecDefault )
+ {
+ aEntry.nDontKnow = pTextSpecDefault->nDontKnow;
+ aEntry.nLanguage[ 0 ] = pTextSpecDefault->nLanguage[ 0 ];
+ aEntry.nLanguage[ 1 ] = pTextSpecDefault->nLanguage[ 1 ];
+ aEntry.nLanguage[ 2 ] = pTextSpecDefault->nLanguage[ 2 ];
+ }
+ for (sal_uInt32 i = 1; nFlags && i ; i <<= 1)
+ {
+ sal_uInt16 nLang = 0;
+ switch( nFlags & i )
+ {
+ case 0 : break;
+ case 1 : rIn.ReadUInt16( aEntry.nDontKnow ); break;
+ case 2 : rIn.ReadUInt16( nLang ); break;
+ case 4 : rIn.ReadUInt16( nLang ); break;
+ default :
+ {
+ rIn.SeekRel( 2 );
+ }
+ }
+ if ( nLang )
+ {
+ // #i119985#, we could probably handle this better if we have a
+ // place to override the final language for weak
+ // characters/fields to fallback to, rather than the current
+ // application locale. Assuming that we can determine what the
+ // default fallback language for a given .ppt, etc is during
+ // load time.
+ if (i == 2)
+ {
+ aEntry.nLanguage[ 0 ] = aEntry.nLanguage[ 1 ] = aEntry.nLanguage[ 2 ] = LanguageType(nLang);
+ }
+ }
+ nFlags &= ~i;
+ }
+ aList.push_back( aEntry );
+ }
+ bValid = rIn.Tell() == rRecHd.GetRecEndFilePos();
+ return bValid;
+}
+
+PPTTextSpecInfoAtomInterpreter::~PPTTextSpecInfoAtomInterpreter()
+{
+}
+
+void StyleTextProp9::Read( SvStream& rIn )
+{
+ rIn.ReadUInt32( mnExtParagraphMask );
+ if ( mnExtParagraphMask & 0x800000 )
+ rIn.ReadUInt16( mnBuBlip );
+ if ( mnExtParagraphMask & 0x2000000 )
+ rIn.ReadUInt16( mnHasAnm );
+ if ( mnExtParagraphMask & 0x1000000 )
+ rIn.ReadUInt32( mnAnmScheme );
+ if ( mnExtParagraphMask & 0x4000000 )
+ rIn.ReadUInt32( mpfPP10Ext );
+ rIn.ReadUInt32( mnExtCharacterMask );
+ if ( mnExtCharacterMask & 0x100000 )
+ rIn.ReadUInt32( mncfPP10Ext );
+ rIn.ReadUInt32( mnSpecialInfoMask );
+ if ( mnSpecialInfoMask & 0x20 )
+ rIn.ReadUInt32( mnPP10Ext );
+ if ( mnSpecialInfoMask & 0x40 )
+ rIn.ReadUInt16( mfBidi );
+}
+
+PPTStyleTextPropReader::PPTStyleTextPropReader( SvStream& rIn, const DffRecordHeader& rTextHeader,
+ PPTTextRulerInterpreter const & rRuler, const DffRecordHeader& rExtParaHd, TSS_Type nInstance )
+{
+ Init(rIn, rTextHeader, rRuler, rExtParaHd, nInstance);
+}
+
+void PPTStyleTextPropReader::ReadParaProps( SvStream& rIn, const DffRecordHeader& rTextHeader,
+ const OUString& aString, PPTTextRulerInterpreter const & rRuler,
+ sal_uInt32& nCharCount, bool& bTextPropAtom )
+{
+ sal_uInt32 nMask = 0; //TODO: nMask initialized here to suppress warning for now, see corresponding TODO below
+ sal_uInt32 nCharReadCnt = 0;
+ sal_uInt16 nDummy16;
+
+ sal_uInt16 nStringLen = aString.getLength();
+
+ DffRecordHeader aTextHd2;
+ rTextHeader.SeekToContent( rIn );
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_StyleTextPropAtom, rTextHeader.GetRecEndFilePos(), &aTextHd2 ) )
+ bTextPropAtom = true;
+ while ( nCharReadCnt <= nStringLen )
+ {
+ PPTParaPropSet aParaPropSet;
+ ImplPPTParaPropSet& aSet = *aParaPropSet.mxParaSet;
+ if ( bTextPropAtom )
+ {
+ rIn.ReadUInt32( nCharCount )
+ .ReadUInt16( aParaPropSet.mxParaSet->mnDepth ); // indent depth
+
+ aParaPropSet.mxParaSet->mnDepth = // taking care of about using not more than 9 outliner levels
+ std::min(sal_uInt16(8),
+ aParaPropSet.mxParaSet->mnDepth);
+
+ nCharCount--;
+
+ rIn.ReadUInt32( nMask );
+ aSet.mnAttrSet = nMask & 0x207df7;
+ sal_uInt16 nBulFlg = 0;
+ if ( nMask & 0xF )
+ rIn.ReadUInt16( nBulFlg ); // Bullet-HardAttr-Flags
+ aSet.mpArry[ PPT_ParaAttr_BulletOn ] = ( nBulFlg & 1 ) ? 1 : 0;
+ aSet.mpArry[ PPT_ParaAttr_BuHardFont ] = ( nBulFlg & 2 ) ? 1 : 0;
+ aSet.mpArry[ PPT_ParaAttr_BuHardColor ] = ( nBulFlg & 4 ) ? 1 : 0;
+
+ // NOTE: one might think that the hard-coded numbers here are the
+ // same as the PPT_ParaAttr_* constants, but it's NOT always true!
+ if ( nMask & 0x0080 ) // buChar
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletChar ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletChar);
+ }
+ }
+ if ( nMask & 0x0010 ) // buTypeface
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletFont ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletFont);
+ }
+ }
+ if ( nMask & 0x0040 ) // buSize
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletHeight ] );
+ if (!rIn.good()
+ || !((nMask & (1 << PPT_ParaAttr_BuHardHeight))
+ && (nBulFlg & (1 << PPT_ParaAttr_BuHardHeight))))
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletHeight);
+ }
+ }
+ if ( nMask & 0x0020 ) // buColor
+ {
+ sal_uInt32 nVal32;
+ rIn.ReadUInt32( nVal32 );
+ if (!rIn.good())
+ {
+ aSet.mnBulletColor = 0; // no flag for this? default it
+ }
+ else
+ {
+ sal_uInt32 nHiByte;
+ nHiByte = nVal32 >> 24;
+ if ( nHiByte <= 8 )
+ nVal32 = nHiByte | PPT_COLSCHEME;
+ aSet.mnBulletColor = nVal32;
+ }
+ }
+ if ( nMask & 0x0800 ) // pfAlignment
+ {
+ rIn.ReadUInt16( nDummy16 );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_Adjust);
+ }
+ else
+ {
+ aSet.mpArry[ PPT_ParaAttr_Adjust ] = nDummy16 & 3;
+ }
+ }
+ if ( nMask & 0x1000 ) // pfLineSpacing
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_LineFeed ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_LineFeed);
+ }
+ }
+ if ( nMask & 0x2000 ) // pfSpaceBefore
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_UpperDist ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_UpperDist);
+ }
+ }
+ if ( nMask & 0x4000 ) // pfSpaceAfter
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_LowerDist ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_LowerDist);
+ }
+ }
+ if ( nMask & 0x100 ) // pfLeftMargin
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_TextOfs ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_TextOfs);
+ }
+ else
+ {
+ aSet.mnAttrSet |= 1 << PPT_ParaAttr_TextOfs;
+ }
+ }
+ if ( nMask & 0x400 ) // pfIndent
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BulletOfs ] );
+ if (!rIn.good())
+ {
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BulletOfs);
+ }
+ else
+ {
+ aSet.mnAttrSet |= 1 << PPT_ParaAttr_BulletOfs;
+ }
+ }
+ if ( nMask & 0x8000 ) // pfDefaultTabSize
+ {
+ rIn.ReadUInt16( nDummy16 );
+ if (!rIn.good())
+ {
+ // TODO?
+ }
+ }
+ if ( nMask & 0x100000 ) // pfTabStops
+ {
+ sal_uInt16 i, nDistance, nAlignment, nNumberOfTabStops = 0;
+ rIn.ReadUInt16( nNumberOfTabStops );
+ if (!rIn.good())
+ {
+ // TODO?
+ }
+ else
+ {
+ const size_t nMinRecordSize = 4;
+ const size_t nMaxRecords = rIn.remainingSize() / nMinRecordSize;
+ if (nNumberOfTabStops > nMaxRecords)
+ {
+ SAL_WARN("filter.ms", "Parsing error: " << nMaxRecords <<
+ " max possible entries, but " << nNumberOfTabStops << " claimed, truncating");
+ nNumberOfTabStops = nMaxRecords;
+ }
+ for (i = 0; i < nNumberOfTabStops; ++i)
+ {
+ rIn.ReadUInt16( nDistance )
+ .ReadUInt16( nAlignment );
+ }
+ }
+ }
+ if ( nMask & 0x10000 ) // pfBaseLine
+ {
+ rIn.ReadUInt16( nDummy16 );
+ if (!rIn.good())
+ {
+ // TODO?
+ }
+ }
+ if ( nMask & 0xe0000 ) // pfCharWrap, pfWordWrap, pfOverflow
+ {
+ rIn.ReadUInt16( nDummy16 );
+ if (!rIn.good())
+ { // clear flag to avoid invalid access
+ aSet.mnAttrSet &= ~((1 << PPT_ParaAttr_AsianLB_1)
+ | (1 << PPT_ParaAttr_AsianLB_2)
+ | (1 << PPT_ParaAttr_AsianLB_3));
+ }
+ else
+ {
+ if (nMask & 0x20000)
+ aSet.mpArry[PPT_ParaAttr_AsianLB_1] = nDummy16 & 1;
+ if (nMask & 0x40000)
+ aSet.mpArry[PPT_ParaAttr_AsianLB_2] = (nDummy16 >> 1) & 1;
+ if (nMask & 0x80000)
+ aSet.mpArry[PPT_ParaAttr_AsianLB_3] = (nDummy16 >> 2) & 1;
+ aSet.mnAttrSet |= ((nMask >> 17) & 7) << PPT_ParaAttr_AsianLB_1;
+ }
+ }
+ if ( nMask & 0x200000 ) // pfTextDirection
+ {
+ rIn.ReadUInt16( aSet.mpArry[ PPT_ParaAttr_BiDi ] );
+ if (!rIn.good())
+ { // clear flag to avoid invalid access
+ aSet.mnAttrSet &= ~(1 << PPT_ParaAttr_BiDi);
+ }
+ }
+ }
+ else
+ nCharCount = nStringLen;
+
+ //if the textofs attr has been read at above, need not to reset.
+ if ( ( !( aSet.mnAttrSet & 1 << PPT_ParaAttr_TextOfs ) ) && rRuler.GetTextOfs( aParaPropSet.mxParaSet->mnDepth, aSet.mpArry[ PPT_ParaAttr_TextOfs ] ) )
+ aSet.mnAttrSet |= 1 << PPT_ParaAttr_TextOfs;
+ if ( ( !( aSet.mnAttrSet & 1 << PPT_ParaAttr_BulletOfs ) ) && rRuler.GetBulletOfs( aParaPropSet.mxParaSet->mnDepth, aSet.mpArry[ PPT_ParaAttr_BulletOfs ] ) )
+ aSet.mnAttrSet |= 1 << PPT_ParaAttr_BulletOfs;
+ if ( rRuler.GetDefaultTab( aSet.mpArry[ PPT_ParaAttr_DefaultTab ] ) )
+ aSet.mnAttrSet |= 1 << PPT_ParaAttr_DefaultTab;
+
+ if ( ( nCharCount > nStringLen ) || ( nStringLen < nCharReadCnt + nCharCount ) )
+ {
+ bTextPropAtom = false;
+ nCharCount = nStringLen - nCharReadCnt;
+ // please fix the right hand side of
+ // PPTParaPropSet& PPTParaPropSet::operator=(PPTParaPropSet&),
+ // it should be a const reference
+ PPTParaPropSet aTmpPPTParaPropSet;
+ aParaPropSet = aTmpPPTParaPropSet;
+ OSL_FAIL( "SJ:PPTStyleTextPropReader::could not get this PPT_PST_StyleTextPropAtom by reading the paragraph attributes" );
+ }
+ PPTParaPropSet* pPara = new PPTParaPropSet( aParaPropSet );
+ pPara->mnOriginalTextPos = nCharReadCnt;
+ aParaPropList.emplace_back( pPara );
+ if ( nCharCount )
+ {
+ sal_uInt32 nCount;
+ const sal_Unicode* pDat = aString.getStr() + nCharReadCnt;
+ for ( nCount = 0; nCount < nCharCount; nCount++ )
+ {
+ if ( pDat[ nCount ] == 0xd )
+ {
+ pPara = new PPTParaPropSet( aParaPropSet );
+ pPara->mnOriginalTextPos = nCharReadCnt + nCount + 1;
+ aParaPropList.emplace_back( pPara );
+ }
+ }
+ }
+ nCharReadCnt += nCharCount + 1;
+ }
+}
+
+void PPTStyleTextPropReader::ReadCharProps( SvStream& rIn, PPTCharPropSet& aCharPropSet, const OUString& aString,
+ sal_uInt32& nCharCount, sal_uInt32 nCharReadCnt,
+ bool& bTextPropAtom, sal_uInt32 nExtParaPos,
+ const std::vector< StyleTextProp9 >& aStyleTextProp9,
+ sal_uInt32& nExtParaFlags, sal_uInt16& nBuBlip,
+ sal_uInt16& nHasAnm, sal_uInt32& nAnmScheme )
+{
+ sal_uInt16 nStringLen = aString.getLength();
+
+ sal_uInt16 nDummy16;
+ rIn.ReadUInt16( nDummy16 );
+ nCharCount = (rIn.good()) ? nDummy16 : 0;
+ rIn.ReadUInt16( nDummy16 );
+
+ sal_Int32 nCharsToRead = nStringLen - ( nCharReadCnt + nCharCount );
+ if ( nCharsToRead < 0 )
+ {
+ nCharCount = nStringLen - nCharReadCnt;
+ if ( nCharsToRead < -1 )
+ {
+ bTextPropAtom = false;
+ OSL_FAIL( "SJ:PPTStyleTextPropReader::could not get this PPT_PST_StyleTextPropAtom by reading the character attributes" );
+ }
+ }
+ ImplPPTCharPropSet& aSet = *aCharPropSet.mpImplPPTCharPropSet;
+
+ // character attributes
+ sal_uInt32 nMask(0);
+ rIn.ReadUInt32( nMask );
+ if ( static_cast<sal_uInt16>(nMask) )
+ {
+ aSet.mnAttrSet |= static_cast<sal_uInt16>(nMask);
+ rIn.ReadUInt16( aSet.mnFlags );
+ }
+ if ( nMask & 0x10000 ) // cfTypeface
+ {
+ rIn.ReadUInt16( aSet.mnFont );
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_Font;
+ }
+ if ( nMask & 0x200000 ) // cfFEOldTypeface
+ {
+ rIn.ReadUInt16( aSet.mnAsianOrComplexFont );
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_AsianOrComplexFont;
+ }
+ if ( nMask & 0x400000 ) // cfANSITypeface
+ {
+ rIn.ReadUInt16( aSet.mnANSITypeface );
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_ANSITypeface;
+ }
+ if ( nMask & 0x800000 ) // cfSymbolTypeface
+ {
+ rIn.ReadUInt16( aSet.mnSymbolFont );
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_Symbol;
+ }
+ if ( nMask & 0x20000 ) // cfSize
+ {
+ rIn.ReadUInt16( aSet.mnFontHeight );
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_FontHeight;
+ }
+ if ( nMask & 0x40000 ) // cfColor
+ {
+ sal_uInt32 nVal(0);
+ rIn.ReadUInt32( nVal );
+ if ( !( nVal & 0xff000000 ) )
+ nVal = PPT_COLSCHEME_HINTERGRUND;
+ aSet.mnColor = nVal;
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_FontColor;
+ }
+ if ( nMask & 0x80000 ) // cfPosition
+ {
+ rIn.ReadUInt16( aSet.mnEscapement );
+ aSet.mnAttrSet |= 1 << PPT_CharAttr_Escapement;
+ }
+ if ( !nExtParaPos )
+ return;
+
+ sal_uInt32 nExtBuInd = nMask & 0x3c00;
+ if ( nExtBuInd )
+ nExtBuInd = ( aSet.mnFlags & 0x3c00 ) >> 10;
+ if ( nExtBuInd < aStyleTextProp9.size() )
+ {
+ nExtParaFlags = aStyleTextProp9[ nExtBuInd ].mnExtParagraphMask;
+ nBuBlip = aStyleTextProp9[ nExtBuInd ].mnBuBlip;
+ nHasAnm = aStyleTextProp9[ nExtBuInd ].mnHasAnm;
+ nAnmScheme = aStyleTextProp9[ nExtBuInd ].mnAnmScheme;
+ }
+}
+
+void PPTStyleTextPropReader::Init( SvStream& rIn, const DffRecordHeader& rTextHeader,
+ PPTTextRulerInterpreter const & rRuler, const DffRecordHeader& rExtParaHd, TSS_Type nInstance )
+{
+ sal_uInt32 nOldPos = rIn.Tell();
+ sal_uInt32 nExtParaPos = ( rExtParaHd.nRecType == PPT_PST_ExtendedParagraphAtom ) ? rExtParaHd.nFilePos + 8 : 0;
+
+ std::vector< StyleTextProp9 > aStyleTextProp9;
+ if ( rExtParaHd.nRecType == PPT_PST_ExtendedParagraphAtom )
+ {
+ rIn.Seek( rExtParaHd.nFilePos + 8 );
+
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, rExtParaHd.GetRecEndFilePos());
+ while( ( rIn.GetError() == ERRCODE_NONE ) && ( rIn.Tell() < nEndRecPos ) )
+ {
+ aStyleTextProp9.emplace_back();
+ aStyleTextProp9.back().Read( rIn );
+ }
+ rIn.Seek( nOldPos );
+ }
+
+ OUString aString;
+ DffRecordHeader aTextHd;
+ ReadDffRecordHeader( rIn, aTextHd );
+ sal_uInt32 nMaxLen = aTextHd.nRecLen;
+ if ( nMaxLen >= 0xFFFF )
+ nMaxLen = 0xFFFE;
+
+ if( aTextHd.nRecType == PPT_PST_TextCharsAtom )
+ {
+ std::vector<sal_Unicode> aBuf(( nMaxLen >> 1 ) + 1);
+ void* pDest = aBuf.data();
+ auto nRead = rIn.ReadBytes(pDest, nMaxLen);
+ if (nRead != nMaxLen)
+ memset(static_cast<char*>(pDest) + nRead, 0, nMaxLen - nRead);
+ nMaxLen >>= 1;
+ aBuf[nMaxLen] = 0;
+
+ sal_uInt32 i;
+ sal_Unicode* pPtr = aBuf.data();
+
+#ifdef OSL_BIGENDIAN
+ sal_Unicode nTemp;
+ for ( i = 0; i < nMaxLen; i++ )
+ {
+ nTemp = *pPtr;
+ *pPtr++ = ( nTemp << 8 ) | ( nTemp >> 8 );
+ }
+ pPtr = aBuf.data();
+#endif
+
+ for ( i = 0; i < nMaxLen; pPtr++, i++ )
+ {
+ sal_Unicode nChar = *pPtr;
+ if ( !nChar )
+ break;
+ if ( ( nChar & 0xff00 ) == 0xf000 ) // in this special case we got a symbol
+ aSpecMarkerList.push_back( static_cast<sal_uInt32>( i | PPT_SPEC_SYMBOL ) );
+ else if ( nChar == 0xd )
+ {
+ if ( nInstance == TSS_Type::PageTitle )
+ *pPtr = 0xb;
+ else
+ aSpecMarkerList.push_back( static_cast<sal_uInt32>( i | PPT_SPEC_NEWLINE ) );
+ }
+ }
+ if ( i )
+ aString = OUString(aBuf.data(), i);
+ }
+ else if( aTextHd.nRecType == PPT_PST_TextBytesAtom )
+ {
+ std::unique_ptr<char[]> pBuf(new char[ nMaxLen + 1 ]);
+ nMaxLen = rIn.ReadBytes(pBuf.get(), nMaxLen);
+ pBuf[ nMaxLen ] = 0;
+ char* pPtr = pBuf.get();
+ for (;;)
+ {
+ char cLo = *pPtr;
+ if ( cLo == 0 )
+ break;
+ if ( cLo == 0xd )
+ {
+ if ( nInstance == TSS_Type::PageTitle )
+ *pPtr = 0xb;
+ else
+ aSpecMarkerList.push_back( static_cast<sal_uInt32>( (pPtr - pBuf.get()) | PPT_SPEC_NEWLINE ) );
+ }
+ pPtr++;
+ }
+ sal_Int32 nLen = pPtr - pBuf.get();
+ if ( nLen )
+ aString = OUString( pBuf.get(), nLen, RTL_TEXTENCODING_MS_1252 );
+ }
+ else
+ {
+ // no chars, but potentially char/para props?
+ sal_uInt32 nCharCount;
+ bool bTextPropAtom = false;
+ ReadParaProps( rIn, rTextHeader, aString, rRuler, nCharCount, bTextPropAtom );
+
+ if ( bTextPropAtom )
+ {
+ // yeah, StyleTextProp is there, read it all & push to
+ // aParaPropList
+ PPTCharPropSet aCharPropSet(0);
+ aCharPropSet.mnOriginalTextPos = 0;
+
+ sal_uInt32 nExtParaFlags = 0, nAnmScheme = 0;
+ sal_uInt16 nBuBlip = 0xffff, nHasAnm = 0;
+ ReadCharProps( rIn, aCharPropSet, aString, nCharCount, 0/*nCharReadCnt*/,
+ bTextPropAtom, nExtParaPos, aStyleTextProp9, nExtParaFlags,
+ nBuBlip, nHasAnm, nAnmScheme );
+
+ aCharPropList.push_back(std::make_unique<PPTCharPropSet>(aCharPropSet, 0));
+ }
+ }
+
+ if ( !aString.isEmpty() )
+ {
+ sal_uInt32 nCharCount;
+ bool bTextPropAtom = false;
+
+ ReadParaProps( rIn, rTextHeader, aString, rRuler, nCharCount, bTextPropAtom );
+
+ bool bEmptyParaPossible = true;
+ sal_uInt32 nCharReadCnt = 0;
+ sal_uInt32 nCurrentPara = 0;
+ size_t i = 1; // points to the next element to process
+ sal_uInt32 nCurrentSpecMarker = aSpecMarkerList.empty() ? 0 : aSpecMarkerList[0];
+ sal_uInt32 nStringLen = aString.getLength();
+
+ while ( nCharReadCnt < nStringLen )
+ {
+ sal_uInt32 nExtParaFlags = 0, nLatestParaUpdate = 0xffffffff, nAnmScheme = 0;
+ sal_uInt16 nBuBlip = 0xffff, nHasAnm = 0;
+
+ PPTCharPropSet aCharPropSet( nCurrentPara );
+ if ( bTextPropAtom )
+ {
+ ReadCharProps( rIn, aCharPropSet, aString, nCharCount, nCharReadCnt,
+ bTextPropAtom, nExtParaPos, aStyleTextProp9, nExtParaFlags,
+ nBuBlip, nHasAnm, nAnmScheme );
+ if (!rIn.good())
+ break;
+ }
+ else
+ nCharCount = nStringLen;
+
+ sal_uInt32 nLen;
+ while( nCharCount )
+ {
+ if ( nExtParaPos && ( nLatestParaUpdate != nCurrentPara ) && ( nCurrentPara < aParaPropList.size() ) )
+ {
+ PPTParaPropSet* pPropSet = aParaPropList[ nCurrentPara ].get();
+ pPropSet->mxParaSet->mnExtParagraphMask = nExtParaFlags;
+ if ( nExtParaFlags & 0x800000 )
+ pPropSet->mxParaSet->mnBuBlip = nBuBlip;
+ if ( nExtParaFlags & 0x01000000 )
+ pPropSet->mxParaSet->mnAnmScheme = nAnmScheme;
+ if ( nExtParaFlags & 0x02000000 )
+ pPropSet->mxParaSet->mnHasAnm = nHasAnm;
+ nLatestParaUpdate = nCurrentPara;
+ }
+ aCharPropSet.mnOriginalTextPos = nCharReadCnt;
+ if ( nCurrentSpecMarker && ( ( nCurrentSpecMarker & 0xffff ) < ( nCharReadCnt + nCharCount ) ) )
+ {
+ if ( nCurrentSpecMarker & PPT_SPEC_NEWLINE )
+ {
+ nLen = ( nCurrentSpecMarker & 0xffff ) - nCharReadCnt;
+ if ( nLen )
+ aCharPropSet.maString = aString.copy( nCharReadCnt, nLen );
+ else if ( bEmptyParaPossible )
+ aCharPropSet.maString.clear();
+ if ( nLen || bEmptyParaPossible )
+ aCharPropList.push_back(
+ std::make_unique<PPTCharPropSet>(aCharPropSet, nCurrentPara));
+ nCurrentPara++;
+ nLen++;
+ nCharReadCnt += nLen;
+ nCharCount -= nLen;
+ bEmptyParaPossible = true;
+ }
+ else if ( nCurrentSpecMarker & PPT_SPEC_SYMBOL )
+ {
+ if ( ( nCurrentSpecMarker & 0xffff ) != nCharReadCnt )
+ {
+ nLen = ( nCurrentSpecMarker & 0xffff ) - nCharReadCnt;
+ aCharPropSet.maString = aString.copy(nCharReadCnt, nLen);
+ aCharPropList.push_back(
+ std::make_unique<PPTCharPropSet>(aCharPropSet, nCurrentPara));
+ nCharCount -= nLen;
+ nCharReadCnt += nLen;
+ }
+ PPTCharPropSet* pCPropSet = new PPTCharPropSet( aCharPropSet, nCurrentPara );
+ pCPropSet->maString = aString.copy(nCharReadCnt, 1);
+ if ( aCharPropSet.mpImplPPTCharPropSet->mnAttrSet & ( 1 << PPT_CharAttr_Symbol ) )
+ pCPropSet->SetFont( aCharPropSet.mpImplPPTCharPropSet->mnSymbolFont );
+ aCharPropList.emplace_back( pCPropSet );
+ nCharCount--;
+ nCharReadCnt++;
+ bEmptyParaPossible = false;
+ }
+ nCurrentSpecMarker = ( i < aSpecMarkerList.size() ) ? aSpecMarkerList[ i++ ] : 0;
+ }
+ else
+ {
+ if (nCharReadCnt > o3tl::make_unsigned(aString.getLength()))
+ aCharPropSet.maString = OUString();
+ else
+ {
+ sal_Int32 nStrLen = nCharCount;
+ sal_Int32 nMaxStrLen = aString.getLength() - nCharReadCnt;
+ if (nStrLen > nMaxStrLen)
+ nStrLen = nMaxStrLen;
+ aCharPropSet.maString = aString.copy(nCharReadCnt, nStrLen);
+ }
+ aCharPropList.push_back(
+ std::make_unique<PPTCharPropSet>(aCharPropSet, nCurrentPara));
+ nCharReadCnt += nCharCount;
+ bEmptyParaPossible = false;
+ break;
+ }
+ }
+ }
+ if ( !aCharPropList.empty() && ( aCharPropList.back()->mnParagraph != nCurrentPara ) )
+ {
+ PPTCharPropSet* pCharPropSet = new PPTCharPropSet( *aCharPropList.back(), nCurrentPara );
+ pCharPropSet->maString.clear();
+ pCharPropSet->mnOriginalTextPos = nStringLen - 1;
+ aCharPropList.emplace_back( pCharPropSet );
+ }
+ }
+ rIn.Seek( nOldPos );
+}
+
+PPTStyleTextPropReader::~PPTStyleTextPropReader()
+{
+}
+
+PPTPortionObj::PPTPortionObj( const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt32 nDepth ) :
+ PPTCharPropSet ( 0 ),
+ mrStyleSheet ( rStyleSheet ),
+ mnInstance ( nInstance ),
+ mnDepth ( std::min<sal_uInt32>( nDepth, 4 ) )
+{
+}
+
+PPTPortionObj::PPTPortionObj( const PPTCharPropSet& rCharPropSet, const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt32 nDepth ) :
+ PPTCharPropSet ( rCharPropSet ),
+ mrStyleSheet ( rStyleSheet ),
+ mnInstance ( nInstance ),
+ mnDepth ( std::min<sal_uInt32>( nDepth, 4 ) )
+{
+}
+
+PPTPortionObj::PPTPortionObj( const PPTPortionObj& rPortionObj ) :
+ PPTCharPropSet ( rPortionObj ),
+ mrStyleSheet ( rPortionObj.mrStyleSheet ),
+ mnInstance ( rPortionObj.mnInstance ),
+ mnDepth ( rPortionObj.mnDepth )
+{
+}
+
+PPTPortionObj::~PPTPortionObj()
+{
+}
+
+bool PPTPortionObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Type nDestinationInstance ) const
+{
+ sal_uInt32 nMask = 1 << nAttr;
+ rRetValue = 0;
+
+ bool bIsHardAttribute = ( ( mpImplPPTCharPropSet->mnAttrSet & nMask ) != 0 );
+
+ if ( bIsHardAttribute )
+ {
+ switch ( nAttr )
+ {
+ case PPT_CharAttr_Bold :
+ case PPT_CharAttr_Italic :
+ case PPT_CharAttr_Underline :
+ case PPT_CharAttr_Shadow :
+ case PPT_CharAttr_Strikeout :
+ case PPT_CharAttr_Embossed :
+ rRetValue = ( mpImplPPTCharPropSet->mnFlags & nMask ) ? 1 : 0;
+ break;
+ case PPT_CharAttr_Font :
+ rRetValue = mpImplPPTCharPropSet->mnFont;
+ break;
+ case PPT_CharAttr_AsianOrComplexFont :
+ rRetValue = mpImplPPTCharPropSet->mnAsianOrComplexFont;
+ break;
+ case PPT_CharAttr_FontHeight :
+ rRetValue = mpImplPPTCharPropSet->mnFontHeight;
+ break;
+ case PPT_CharAttr_FontColor :
+ rRetValue = mpImplPPTCharPropSet->mnColor;
+ break;
+ case PPT_CharAttr_Escapement :
+ rRetValue = mpImplPPTCharPropSet->mnEscapement;
+ break;
+ default :
+ OSL_FAIL( "SJ:PPTPortionObj::GetAttrib ( hard attribute does not exist )" );
+ }
+ }
+ else
+ {
+ const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ];
+ PPTCharLevel* pCharLevel = nullptr;
+ if ( ( nDestinationInstance == TSS_Type::Unknown )
+ || ( mnDepth && ( ( mnInstance == TSS_Type::Subtitle ) || ( mnInstance == TSS_Type::TextInShape ) ) ) )
+ bIsHardAttribute = true;
+ else if ( nDestinationInstance != mnInstance )
+ pCharLevel = &mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[ mnDepth ];
+ switch( nAttr )
+ {
+ case PPT_CharAttr_Bold :
+ case PPT_CharAttr_Italic :
+ case PPT_CharAttr_Underline :
+ case PPT_CharAttr_Shadow :
+ case PPT_CharAttr_Strikeout :
+ case PPT_CharAttr_Embossed :
+ {
+ rRetValue = ( rCharLevel.mnFlags & nMask ) ? 1 : 0;
+ if ( pCharLevel )
+ {
+ sal_uInt32 nTmp = ( pCharLevel->mnFlags & nMask ) ? 1 : 0;
+ if ( rRetValue != nTmp )
+ bIsHardAttribute = true;
+ }
+ }
+ break;
+ case PPT_CharAttr_Font :
+ {
+ rRetValue = rCharLevel.mnFont;
+ if ( pCharLevel && ( rRetValue != pCharLevel->mnFont ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_CharAttr_AsianOrComplexFont :
+ {
+ rRetValue = rCharLevel.mnAsianOrComplexFont;
+ if ( pCharLevel && ( rRetValue != pCharLevel->mnAsianOrComplexFont ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_CharAttr_FontHeight :
+ {
+ rRetValue = rCharLevel.mnFontHeight;
+ if ( pCharLevel && ( rRetValue != pCharLevel->mnFontHeight ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_CharAttr_FontColor :
+ {
+ rRetValue = rCharLevel.mnFontColor;
+ if ( pCharLevel && ( rRetValue != pCharLevel->mnFontColor ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_CharAttr_Escapement :
+ {
+ rRetValue = rCharLevel.mnEscapement;
+ if ( pCharLevel && ( rRetValue != pCharLevel->mnEscapement ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ default :
+ OSL_FAIL( "SJ:PPTPortionObj::GetAttrib ( attribute does not exist )" );
+ }
+ }
+ return bIsHardAttribute;
+}
+
+void PPTPortionObj::ApplyTo( SfxItemSet& rSet, SdrPowerPointImport& rManager, TSS_Type nDestinationInstance )
+{
+ ApplyTo( rSet, rManager, nDestinationInstance, nullptr );
+}
+
+void PPTPortionObj::ApplyTo( SfxItemSet& rSet, SdrPowerPointImport& rManager, TSS_Type nDestinationInstance, const PPTTextObj* pTextObj )
+{
+ sal_uInt32 nVal;
+ if ( GetAttrib( PPT_CharAttr_Bold, nVal, nDestinationInstance ) )
+ {
+ rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
+ rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ) );
+ rSet.Put( SvxWeightItem( nVal != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ) );
+ }
+ if ( GetAttrib( PPT_CharAttr_Italic, nVal, nDestinationInstance ) )
+ {
+ rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
+ rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC_CJK ) );
+ rSet.Put( SvxPostureItem( nVal != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC_CTL ) );
+ }
+ if ( GetAttrib( PPT_CharAttr_Underline, nVal, nDestinationInstance ) )
+ rSet.Put( SvxUnderlineItem( nVal != 0 ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
+
+ if ( GetAttrib( PPT_CharAttr_Shadow, nVal, nDestinationInstance ) )
+ rSet.Put( SvxShadowedItem( nVal != 0, EE_CHAR_SHADOW ) );
+
+ if ( GetAttrib( PPT_CharAttr_Strikeout, nVal, nDestinationInstance ) )
+ rSet.Put( SvxCrossedOutItem( nVal != 0 ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
+
+ sal_uInt32 nAsianFontId = 0xffff;
+ if ( GetAttrib( PPT_CharAttr_AsianOrComplexFont, nAsianFontId, nDestinationInstance ) )
+ {
+ if ( nAsianFontId != 0xffff )
+ {
+ const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nAsianFontId );
+ if ( pFontEnityAtom )
+ {
+ rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName,
+ OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CJK ) );
+ rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName,
+ OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CTL ) );
+ }
+ }
+ }
+ if ( GetAttrib( PPT_CharAttr_Font, nVal, nDestinationInstance ) )
+ {
+ const PptFontEntityAtom* pFontEnityAtom = rManager.GetFontEnityAtom( nVal );
+ if ( pFontEnityAtom )
+ {
+ rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO ) );
+
+ // #i119475# bullet font info for CJK and CTL
+ if ( RTL_TEXTENCODING_SYMBOL == pFontEnityAtom->eCharSet )
+ {
+ rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CJK ) );
+ rSet.Put( SvxFontItem( pFontEnityAtom->eFamily, pFontEnityAtom->aName, OUString(), pFontEnityAtom->ePitch, pFontEnityAtom->eCharSet, EE_CHAR_FONTINFO_CTL ) );
+ }
+ }
+ }
+ if ( GetAttrib( PPT_CharAttr_FontHeight, nVal, nDestinationInstance ) ) // Schriftgrad in Point
+ {
+ sal_uInt32 nHeight = rManager.ScalePoint( nVal );
+ rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
+ rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ rSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+ }
+
+ if ( GetAttrib( PPT_CharAttr_Embossed, nVal, nDestinationInstance ) )
+ rSet.Put( SvxCharReliefItem( nVal != 0 ? FontRelief::Embossed : FontRelief::NONE, EE_CHAR_RELIEF ) );
+ if ( nVal ) /* if Embossed is set, the font color depends to the fillstyle/color of the object,
+ if the object has no fillstyle, the font color depends to fillstyle of the background */
+ {
+ Color aDefColor( COL_BLACK );
+ sal_uInt32 eFillType = mso_fillSolid;
+ if ( rManager.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ) & 0x10 )
+ eFillType = rManager.GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
+ else
+ eFillType = mso_fillBackground;
+ switch( eFillType )
+ {
+ case mso_fillShade :
+ case mso_fillShadeCenter :
+ case mso_fillShadeShape :
+ case mso_fillShadeScale :
+ case mso_fillShadeTitle :
+ case mso_fillSolid :
+ aDefColor = rManager.MSO_CLR_ToColor( rManager.GetPropertyValue( DFF_Prop_fillColor, 0 ) );
+ break;
+ case mso_fillPattern :
+ aDefColor = rManager.MSO_CLR_ToColor( rManager.GetPropertyValue( DFF_Prop_fillBackColor, 0 ) );
+ break;
+ case mso_fillTexture :
+ {
+ Graphic aGraf;
+ if ( rManager.GetBLIP( rManager.GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf ) )
+ {
+ Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() );
+ Size aSize( aBmp.GetSizePixel() );
+ if ( aSize.Width() && aSize.Height() )
+ {
+ if ( aSize.Width () > 64 )
+ aSize.setWidth( 64 );
+ if ( aSize.Height() > 64 )
+ aSize.setHeight( 64 );
+
+ Bitmap::ScopedReadAccess pAcc(aBmp);
+ if( pAcc )
+ {
+ sal_uLong nRt = 0, nGn = 0, nBl = 0;
+ const tools::Long nWidth = aSize.Width();
+ const tools::Long nHeight = aSize.Height();
+
+ if( pAcc->HasPalette() )
+ {
+ for( tools::Long nY = 0; nY < nHeight; nY++ )
+ {
+ Scanline pScanline = pAcc->GetScanline( nY );
+ for( tools::Long nX = 0; nX < nWidth; nX++ )
+ {
+ const BitmapColor& rCol = pAcc->GetPaletteColor( pAcc->GetIndexFromData( pScanline, nX ) );
+ nRt+=rCol.GetRed(); nGn+=rCol.GetGreen(); nBl+=rCol.GetBlue();
+ }
+ }
+ }
+ else
+ {
+ for( tools::Long nY = 0; nY < nHeight; nY++ )
+ {
+ Scanline pScanline = pAcc->GetScanline( nY );
+ for( tools::Long nX = 0; nX < nWidth; nX++ )
+ {
+ const BitmapColor aCol( pAcc->GetPixelFromData( pScanline, nX ) );
+ nRt+=aCol.GetRed(); nGn+=aCol.GetGreen(); nBl+=aCol.GetBlue();
+ }
+ }
+ }
+ pAcc.reset();
+ sal_uInt32 nC = aSize.Width() * aSize.Height();
+ nRt /= nC;
+ nGn /= nC;
+ nBl /= nC;
+ aDefColor = Color(sal_uInt8( nRt ), sal_uInt8( nGn ),sal_uInt8( nBl ) );
+ }
+ }
+ }
+ }
+ break;
+ case mso_fillBackground :
+ {
+ if ( pTextObj ) // the textobject is needed
+ {
+ const SfxItemSet* pItemSet = pTextObj->GetBackground();
+ if ( pItemSet )
+ {
+ const XFillStyleItem* pFillStyleItem = pItemSet->GetItemIfSet( XATTR_FILLSTYLE, false );
+ if ( pFillStyleItem )
+ {
+ drawing::FillStyle eFillStyle = pFillStyleItem->GetValue();
+ switch( eFillStyle )
+ {
+ case drawing::FillStyle_SOLID :
+ {
+ const XColorItem* pFillColorItem = pItemSet->GetItemIfSet( XATTR_FILLCOLOR, false );
+ if ( pFillColorItem )
+ aDefColor = pFillColorItem->GetColorValue();
+ }
+ break;
+ case drawing::FillStyle_GRADIENT :
+ {
+ const XFillGradientItem* pGradientItem = pItemSet->GetItemIfSet( XATTR_FILLGRADIENT, false );
+ if ( pGradientItem )
+ aDefColor = pGradientItem->GetGradientValue().GetStartColor();
+ }
+ break;
+ case drawing::FillStyle_HATCH :
+ case drawing::FillStyle_BITMAP :
+ aDefColor = COL_WHITE;
+ break;
+ default: break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+ rSet.Put( SvxColorItem( aDefColor, EE_CHAR_COLOR ) );
+ }
+ else
+ {
+ if ( GetAttrib( PPT_CharAttr_FontColor, nVal, nDestinationInstance ) ) // text color (4Byte-Arg)
+ {
+ Color aCol( rManager.MSO_TEXT_CLR_ToColor( nVal ) );
+ rSet.Put( SvxColorItem( aCol, EE_CHAR_COLOR ) );
+ if ( nDestinationInstance == TSS_Type::Unknown )
+ mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ].mnFontColorInStyleSheet = aCol;
+ }
+ else if ( nVal & 0x0f000000 ) // this is not a hard attribute, but maybe the page has a different colorscheme,
+ { // so that in this case we must use a hard color attribute
+ Color aCol( rManager.MSO_TEXT_CLR_ToColor( nVal ) );
+ Color& aColorInSheet = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[ mnDepth ].mnFontColorInStyleSheet;
+ if ( aColorInSheet != aCol )
+ rSet.Put( SvxColorItem( aCol, EE_CHAR_COLOR ) );
+ }
+ }
+
+ if ( GetAttrib( PPT_CharAttr_Escapement, nVal, nDestinationInstance ) ) // super-/subscript in %
+ {
+ sal_uInt16 nEsc = 0;
+ sal_uInt8 nProp = 100;
+
+ if ( nVal )
+ {
+ nEsc = static_cast<sal_Int16>(nVal);
+ nProp = DFLT_ESC_PROP;
+ }
+ SvxEscapementItem aItem( nEsc, nProp, EE_CHAR_ESCAPEMENT );
+ rSet.Put( aItem );
+ }
+ if ( mnLanguage[ 0 ] )
+ rSet.Put( SvxLanguageItem( mnLanguage[ 0 ], EE_CHAR_LANGUAGE ) );
+ if ( mnLanguage[ 1 ] )
+ rSet.Put( SvxLanguageItem( mnLanguage[ 1 ], EE_CHAR_LANGUAGE_CJK ) );
+ if ( mnLanguage[ 2 ] )
+ rSet.Put( SvxLanguageItem( mnLanguage[ 2 ], EE_CHAR_LANGUAGE_CTL ) );
+}
+
+SvxFieldItem* PPTPortionObj::GetTextField()
+{
+ if ( mpFieldItem )
+ return new SvxFieldItem( *mpFieldItem );
+ return nullptr;
+}
+
+namespace
+{
+ sal_uInt16 sanitizeForMaxPPTLevels(sal_uInt16 nDepth)
+ {
+ if (nDepth >= nMaxPPTLevels)
+ {
+ SAL_WARN("filter.ms", "Para Style Sheet depth " << nDepth << " but " << nMaxPPTLevels - 1 << " is max possible");
+ nDepth = nMaxPPTLevels - 1;
+ }
+ return nDepth;
+ }
+}
+
+PPTParagraphObj::PPTParagraphObj( const PPTStyleSheet& rStyleSheet, TSS_Type nInstance, sal_uInt16 nDepth ) :
+ PPTNumberFormatCreator ( nullptr ),
+ mrStyleSheet ( rStyleSheet ),
+ mnInstance ( nInstance ),
+ mnCurrentObject ( 0 )
+{
+ mxParaSet->mnDepth = sanitizeForMaxPPTLevels(nDepth);
+}
+
+PPTParagraphObj::PPTParagraphObj( PPTStyleTextPropReader& rPropReader,
+ size_t const nCurParaPos, size_t& rnCurCharPos,
+ const PPTStyleSheet& rStyleSheet,
+ TSS_Type nInstance, PPTTextRulerInterpreter const & rRuler ) :
+ PPTParaPropSet ( *rPropReader.aParaPropList[nCurParaPos] ),
+ PPTNumberFormatCreator ( nullptr ),
+ PPTTextRulerInterpreter ( rRuler ),
+ mrStyleSheet ( rStyleSheet ),
+ mnInstance ( nInstance ),
+ mnCurrentObject ( 0 )
+{
+ if (rnCurCharPos >= rPropReader.aCharPropList.size())
+ return;
+
+ sal_uInt32 const nCurrentParagraph =
+ rPropReader.aCharPropList[rnCurCharPos]->mnParagraph;
+ for (; rnCurCharPos < rPropReader.aCharPropList.size() &&
+ rPropReader.aCharPropList[rnCurCharPos]->mnParagraph == nCurrentParagraph;
+ ++rnCurCharPos)
+ {
+ PPTCharPropSet *const pCharPropSet =
+ rPropReader.aCharPropList[rnCurCharPos].get();
+ std::unique_ptr<PPTPortionObj> pPPTPortion(new PPTPortionObj(
+ *pCharPropSet, rStyleSheet, nInstance, mxParaSet->mnDepth));
+ m_PortionList.push_back(std::move(pPPTPortion));
+ }
+}
+
+PPTParagraphObj::~PPTParagraphObj()
+{
+}
+
+void PPTParagraphObj::AppendPortion( PPTPortionObj& rPPTPortion )
+{
+ m_PortionList.push_back(
+ std::make_unique<PPTPortionObj>(rPPTPortion));
+}
+
+void PPTParagraphObj::UpdateBulletRelSize( sal_uInt32& nBulletRelSize ) const
+{
+ if ( nBulletRelSize <= 0x7fff ) // a negative value is the absolute bullet height
+ return;
+
+ sal_uInt16 nFontHeight = 0;
+ if (!m_PortionList.empty())
+ {
+ PPTPortionObj const& rPortion = *m_PortionList.front();
+ if (rPortion.mpImplPPTCharPropSet->mnAttrSet & (1 << PPT_CharAttr_FontHeight))
+ {
+ nFontHeight = rPortion.mpImplPPTCharPropSet->mnFontHeight;
+ }
+ }
+ // if we do not have a hard attributed fontheight, the fontheight is taken from the style
+ if ( !nFontHeight )
+ {
+ nFontHeight = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[sanitizeForMaxPPTLevels(mxParaSet->mnDepth)].mnFontHeight;
+ }
+ nBulletRelSize = nFontHeight ? ((- static_cast<sal_Int16>(nBulletRelSize)) * 100 ) / nFontHeight : 100;
+}
+
+bool PPTParagraphObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Type nDestinationInstance )
+{
+ sal_uInt32 nMask = 1 << nAttr;
+ rRetValue = 0;
+
+ if ( nAttr > 21 )
+ {
+ OSL_FAIL( "SJ:PPTParagraphObj::GetAttrib - attribute does not exist" );
+ return false;
+ }
+
+ bool bIsHardAttribute = ( ( mxParaSet->mnAttrSet & nMask ) != 0 );
+
+ sal_uInt16 nDepth = sanitizeForMaxPPTLevels(mxParaSet->mnDepth);
+
+ if ( bIsHardAttribute )
+ {
+ if ( nAttr == PPT_ParaAttr_BulletColor )
+ {
+ bool bHardBulletColor;
+ if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardColor ) )
+ bHardBulletColor = mxParaSet->mpArry[ PPT_ParaAttr_BuHardColor ] != 0;
+ else
+ bHardBulletColor = ( mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth].mnBuFlags
+ & ( 1 << PPT_ParaAttr_BuHardColor ) ) != 0;
+ if ( bHardBulletColor )
+ rRetValue = mxParaSet->mnBulletColor;
+ else
+ {
+ rRetValue = PPT_COLSCHEME_TEXT_UND_ZEILEN;
+ if ((nDestinationInstance != TSS_Type::Unknown) && !m_PortionList.empty())
+ {
+ PPTPortionObj const& rPortion = *m_PortionList.front();
+ if (rPortion.mpImplPPTCharPropSet->mnAttrSet & (1 << PPT_CharAttr_FontColor))
+ {
+ rRetValue = rPortion.mpImplPPTCharPropSet->mnColor;
+ }
+ else
+ {
+ rRetValue = mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[nDepth].mnFontColor;
+ }
+ }
+ }
+ }
+ else if ( nAttr == PPT_ParaAttr_BulletFont )
+ {
+ bool bHardBuFont;
+ if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardFont ) )
+ bHardBuFont = mxParaSet->mpArry[ PPT_ParaAttr_BuHardFont ] != 0;
+ else
+ bHardBuFont = ( mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth].mnBuFlags
+ & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0;
+ if ( bHardBuFont )
+ rRetValue = mxParaSet->mpArry[ PPT_ParaAttr_BulletFont ];
+ else
+ {
+ // it is the font used which assigned to the first character of the following text
+ rRetValue = 0;
+ if ((nDestinationInstance != TSS_Type::Unknown) && !m_PortionList.empty())
+ {
+ PPTPortionObj const& rPortion = *m_PortionList.front();
+ if (rPortion.mpImplPPTCharPropSet->mnAttrSet & ( 1 << PPT_CharAttr_Font ) )
+ {
+ rRetValue = rPortion.mpImplPPTCharPropSet->mnFont;
+ }
+ else
+ {
+ rRetValue = mrStyleSheet.mpCharSheet[ nDestinationInstance ]->maCharLevel[nDepth].mnFont;
+ }
+ }
+ }
+ }
+ else
+ rRetValue = mxParaSet->mpArry[ nAttr ];
+ }
+ else
+ {
+ const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ mnInstance ]->maParaLevel[nDepth];
+
+ PPTParaLevel* pParaLevel = nullptr;
+ if ( ( nDestinationInstance == TSS_Type::Unknown )
+ || ( nDepth && ( ( mnInstance == TSS_Type::Subtitle ) || ( mnInstance == TSS_Type::TextInShape ) ) ) )
+ bIsHardAttribute = true;
+ else if ( nDestinationInstance != mnInstance )
+ pParaLevel = &mrStyleSheet.mpParaSheet[ nDestinationInstance ]->maParaLevel[nDepth];
+ switch ( nAttr )
+ {
+ case PPT_ParaAttr_BulletOn :
+ {
+ rRetValue = rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BulletOn );
+ if ( pParaLevel )
+ {
+ if ( rRetValue != ( static_cast<sal_uInt32>(pParaLevel->mnBuFlags) & ( 1 << PPT_ParaAttr_BulletOn ) ) )
+ bIsHardAttribute = true;
+ }
+ }
+ break;
+ case PPT_ParaAttr_BuHardFont :
+ case PPT_ParaAttr_BuHardColor :
+ case PPT_ParaAttr_BuHardHeight :
+ OSL_FAIL( "SJ:PPTParagraphObj::GetAttrib - this attribute does not make sense" );
+ break;
+ case PPT_ParaAttr_BulletChar :
+ {
+ rRetValue = rParaLevel.mnBulletChar;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletChar ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_BulletFont :
+ {
+ bool bHardBuFont;
+ if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardFont ) )
+ bHardBuFont = mxParaSet->mpArry[ PPT_ParaAttr_BuHardFont ] != 0;
+ else
+ bHardBuFont = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardFont ) ) != 0;
+ if ( bHardBuFont )
+ {
+ rRetValue = rParaLevel.mnBulletFont;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletFont ) )
+ bIsHardAttribute = true;
+ }
+ else
+ {
+ if (!m_PortionList.empty())
+ {
+ PPTPortionObj const& rPortion = *m_PortionList.front();
+ bIsHardAttribute = rPortion.GetAttrib(
+ PPT_CharAttr_Font, rRetValue, nDestinationInstance);
+ }
+ else
+ {
+ rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFont;
+ bIsHardAttribute = true;
+ }
+ }
+ }
+ break;
+ case PPT_ParaAttr_BulletHeight :
+ {
+ rRetValue = rParaLevel.mnBulletHeight;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletHeight ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_BulletColor :
+ {
+ bool bHardBulletColor;
+ if ( mxParaSet->mnAttrSet & ( 1 << PPT_ParaAttr_BuHardColor ) )
+ bHardBulletColor = mxParaSet->mpArry[ PPT_ParaAttr_BuHardColor ] != 0;
+ else
+ bHardBulletColor = ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) ) != 0;
+ if ( bHardBulletColor )
+ {
+ rRetValue = rParaLevel.mnBulletColor;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletColor ) )
+ bIsHardAttribute = true;
+ }
+ else
+ {
+ if (!m_PortionList.empty())
+ {
+ PPTPortionObj const& rPortion = *m_PortionList.front();
+ if (rPortion.mbIsHyperlink )
+ {
+ if( rPortion.mbHardHylinkOrigColor )
+ rRetValue = rPortion.mnHylinkOrigColor;
+ else
+ rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFontColor;
+ bIsHardAttribute = true;
+ }
+ else
+ {
+ bIsHardAttribute = rPortion.GetAttrib( PPT_CharAttr_FontColor, rRetValue, nDestinationInstance );
+ }
+ }
+ else
+ {
+ rRetValue = mrStyleSheet.mpCharSheet[ mnInstance ]->maCharLevel[nDepth].mnFontColor;
+ bIsHardAttribute = true;
+ }
+ }
+ }
+ break;
+ case PPT_ParaAttr_Adjust :
+ {
+ rRetValue = rParaLevel.mnAdjust;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnAdjust ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_LineFeed :
+ {
+ rRetValue = rParaLevel.mnLineFeed;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnLineFeed ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_UpperDist :
+ {
+ rRetValue = rParaLevel.mnUpperDist;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnUpperDist ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_LowerDist :
+ {
+ rRetValue = rParaLevel.mnLowerDist;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnLowerDist ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_TextOfs :
+ {
+ rRetValue = rParaLevel.mnTextOfs;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnTextOfs ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_BulletOfs :
+ {
+ rRetValue = rParaLevel.mnBulletOfs;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnBulletOfs ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_DefaultTab :
+ {
+ rRetValue = rParaLevel.mnDefaultTab;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnDefaultTab ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_AsianLB_1 :
+ {
+ rRetValue = rParaLevel.mnAsianLineBreak & 1;
+ if ( pParaLevel && ( rRetValue != ( static_cast<sal_uInt32>(pParaLevel->mnAsianLineBreak) & 1 ) ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_AsianLB_2 :
+ {
+ rRetValue = ( rParaLevel.mnAsianLineBreak >> 1 ) & 1;
+ if ( pParaLevel && ( rRetValue != ( ( static_cast<sal_uInt32>(pParaLevel->mnAsianLineBreak) >> 1 ) & 1 ) ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_AsianLB_3 :
+ {
+ rRetValue = ( rParaLevel.mnAsianLineBreak >> 2 ) & 1;
+ if ( pParaLevel && ( rRetValue != ( ( static_cast<sal_uInt32>(pParaLevel->mnAsianLineBreak) >> 2 ) & 1 ) ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ case PPT_ParaAttr_BiDi :
+ {
+ rRetValue = rParaLevel.mnBiDi;
+ if ( pParaLevel && ( rRetValue != pParaLevel->mnBiDi ) )
+ bIsHardAttribute = true;
+ }
+ break;
+ }
+ }
+ return bIsHardAttribute;
+}
+
+void PPTParagraphObj::ApplyTo( SfxItemSet& rSet, std::optional< sal_Int16 >& rStartNumbering, SdrPowerPointImport const & rManager, TSS_Type nDestinationInstance )
+{
+ sal_Int16 nVal2;
+ sal_uInt32 nVal, nUpperDist, nLowerDist;
+ TSS_Type nInstance = nDestinationInstance != TSS_Type::Unknown ? nDestinationInstance : mnInstance;
+
+ if ( ( nDestinationInstance != TSS_Type::Unknown ) || ( mxParaSet->mnDepth <= 1 ) )
+ {
+ SvxNumBulletItem* pNumBulletItem = mrStyleSheet.mpNumBulletItem[ nInstance ].get();
+ if ( pNumBulletItem )
+ {
+ SvxNumberFormat aNumberFormat( SVX_NUM_NUMBER_NONE );
+ if ( GetNumberFormat( rManager, aNumberFormat, this, nDestinationInstance, rStartNumbering ) )
+ {
+ if ( aNumberFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE )
+ {
+ aNumberFormat.SetAbsLSpace( 0 );
+ aNumberFormat.SetFirstLineOffset( 0 );
+ aNumberFormat.SetCharTextDistance( 0 );
+ aNumberFormat.SetFirstLineIndent( 0 );
+ aNumberFormat.SetIndentAt( 0 );
+ }
+ SvxNumBulletItem aNewNumBulletItem( *pNumBulletItem );
+ SvxNumRule& rRule = aNewNumBulletItem.GetNumRule();
+ rRule.SetLevel( mxParaSet->mnDepth, aNumberFormat );
+ for (sal_uInt16 i = 0; i < rRule.GetLevelCount(); ++i)
+ {
+ if ( i != mxParaSet->mnDepth )
+ {
+ sal_uInt16 n = sanitizeForMaxPPTLevels(i);
+
+ SvxNumberFormat aNumberFormat2( rRule.GetLevel( i ) );
+ const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ nInstance ]->maParaLevel[ n ];
+ const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ nInstance ]->maCharLevel[ n ];
+ sal_uInt32 nColor;
+ if ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) )
+ nColor = rParaLevel.mnBulletColor;
+ else
+ nColor = rCharLevel.mnFontColor;
+ aNumberFormat2.SetBulletColor( rManager.MSO_TEXT_CLR_ToColor( nColor ) );
+ rRule.SetLevel( i, aNumberFormat2 );
+ }
+ }
+ rSet.Put( aNewNumBulletItem );
+ }
+ }
+ }
+
+ sal_uInt32 nIsBullet2, _nTextOfs, _nBulletOfs;
+ GetAttrib(PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance);
+ GetAttrib(PPT_ParaAttr_TextOfs, _nTextOfs, nDestinationInstance);
+ GetAttrib(PPT_ParaAttr_BulletOfs, _nBulletOfs, nDestinationInstance);
+ if ( !nIsBullet2 )
+ {
+ SvxLRSpaceItem aLRSpaceItem( EE_PARA_LRSPACE );
+ auto const nAbsLSpace = convertMasterUnitToMm100(_nTextOfs);
+ auto const nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(_nBulletOfs);
+ aLRSpaceItem.SetLeft( nAbsLSpace );
+ aLRSpaceItem.SetTextFirstLineOffsetValue( -nFirstLineOffset );
+ rSet.Put( aLRSpaceItem );
+ }
+ else
+ {
+ SvxLRSpaceItem aLRSpaceItem( EE_PARA_LRSPACE );
+ aLRSpaceItem.SetLeft( 0 );
+ aLRSpaceItem.SetTextFirstLineOffsetValue( 0 );
+ rSet.Put( aLRSpaceItem );
+ }
+ if ( GetAttrib( PPT_ParaAttr_Adjust, nVal, nDestinationInstance ) )
+ {
+ if ( nVal <= 3 )
+ { // paragraph adjustment
+ static SvxAdjust const aAdj[ 4 ] = { SvxAdjust::Left, SvxAdjust::Center, SvxAdjust::Right, SvxAdjust::Block };
+ rSet.Put( SvxAdjustItem( aAdj[ nVal ], EE_PARA_JUST ) );
+ }
+ }
+
+ if ( GetAttrib( PPT_ParaAttr_AsianLB_1, nVal, nDestinationInstance ) )
+ rSet.Put(SvxForbiddenRuleItem(nVal != 0, EE_PARA_FORBIDDENRULES));
+ if ( GetAttrib( PPT_ParaAttr_AsianLB_3, nVal, nDestinationInstance ) )
+ rSet.Put(SvxHangingPunctuationItem(nVal != 0, EE_PARA_HANGINGPUNCTUATION));
+
+ if ( GetAttrib( PPT_ParaAttr_BiDi, nVal, nDestinationInstance ) )
+ rSet.Put( SvxFrameDirectionItem( nVal == 1 ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
+
+ // LineSpacing
+ PPTPortionObj* pPortion = First();
+ bool bIsHardAttribute = GetAttrib( PPT_ParaAttr_LineFeed, nVal, nDestinationInstance );
+ nVal2 = static_cast<sal_Int16>(nVal);
+ sal_uInt32 nFont = sal_uInt32();
+ if ( pPortion && pPortion->GetAttrib( PPT_CharAttr_Font, nFont, nDestinationInstance ) )
+ bIsHardAttribute = true;
+
+ if ( bIsHardAttribute )
+ {
+ SdrTextFixedCellHeightItem aHeightItem(true);
+ aHeightItem.SetWhich(SDRATTR_TEXT_USEFIXEDCELLHEIGHT);
+ rSet.Put( aHeightItem );
+ SvxLineSpacingItem aItem( 200, EE_PARA_SBL );
+ if ( nVal2 <= 0 ) {
+ aItem.SetLineHeight( static_cast<sal_uInt16>( rManager.ScalePoint( -nVal2 ) / 8 ) );
+ aItem.SetLineSpaceRule( SvxLineSpaceRule::Fix );
+ aItem.SetInterLineSpaceRule(SvxInterLineSpaceRule::Off);
+ } else
+ {
+ sal_uInt16 nPropLineSpace = static_cast<sal_uInt16>(nVal2);
+ aItem.SetPropLineSpace( nPropLineSpace );
+ aItem.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ }
+ rSet.Put( aItem );
+ }
+
+ // Paragraph Spacing
+ bIsHardAttribute = ( static_cast<sal_uInt32>(GetAttrib( PPT_ParaAttr_UpperDist, nUpperDist, nDestinationInstance )) +
+ static_cast<sal_uInt32>(GetAttrib( PPT_ParaAttr_LowerDist, nLowerDist, nDestinationInstance )) ) != 0;
+ if ( ( nUpperDist > 0 ) || ( nLowerDist > 0 ) )
+ {
+ if (!m_PortionList.empty())
+ {
+ sal_uInt32 nFontHeight = 0;
+ m_PortionList.back()->GetAttrib(
+ PPT_CharAttr_FontHeight, nFontHeight, nDestinationInstance);
+ if ( static_cast<sal_Int16>(nUpperDist) > 0 )
+ nUpperDist = - static_cast<sal_Int16>( ( nFontHeight * nUpperDist * 100 ) / 1000 );
+ if ( static_cast<sal_Int16>(nLowerDist) > 0 )
+ nLowerDist = - static_cast<sal_Int16>( ( nFontHeight * nLowerDist * 100 ) / 1000 );
+ }
+ bIsHardAttribute = true;
+ }
+ if ( bIsHardAttribute )
+ {
+ SvxULSpaceItem aULSpaceItem( EE_PARA_ULSPACE );
+ nVal2 = static_cast<sal_Int16>(nUpperDist);
+ if ( nVal2 <= 0 )
+ aULSpaceItem.SetUpper(static_cast<sal_uInt16>(convertMasterUnitToMm100(-nVal2)));
+ else
+ {
+ aULSpaceItem.SetUpperValue( 0 );
+ aULSpaceItem.SetPropUpper( static_cast<sal_uInt16>(nUpperDist) == 100 ? 101 : static_cast<sal_uInt16>(nUpperDist) );
+ }
+ nVal2 = static_cast<sal_Int16>(nLowerDist);
+ if ( nVal2 <= 0 )
+ aULSpaceItem.SetLower(static_cast<sal_uInt16>(convertMasterUnitToMm100(-nVal2)));
+ else
+ {
+ aULSpaceItem.SetLowerValue( 0 );
+ aULSpaceItem.SetPropLower( static_cast<sal_uInt16>(nLowerDist) == 100 ? 101 : static_cast<sal_uInt16>(nLowerDist) );
+ }
+ rSet.Put( aULSpaceItem );
+ }
+
+ sal_uInt32 i, nDefaultTab, nTab, nTextOfs2 = 0;
+ sal_uInt32 nLatestManTab = 0;
+ GetAttrib( PPT_ParaAttr_TextOfs, nTextOfs2, nDestinationInstance );
+ GetAttrib( PPT_ParaAttr_BulletOfs, nTab, nDestinationInstance );
+ GetAttrib( PPT_ParaAttr_DefaultTab, nDefaultTab, nDestinationInstance );
+
+ SvxTabStopItem aTabItem( 0, 0, SvxTabAdjust::Default, EE_PARA_TABS );
+ if ( GetTabCount() )
+ {
+ for ( i = 0; i < GetTabCount(); i++ )
+ {
+ SvxTabAdjust eTabAdjust;
+ nTab = GetTabOffsetByIndex( static_cast<sal_uInt16>(i) );
+ switch( GetTabStyleByIndex( static_cast<sal_uInt16>(i) ) )
+ {
+ case 1 : eTabAdjust = SvxTabAdjust::Center; break;
+ case 2 : eTabAdjust = SvxTabAdjust::Right; break;
+ case 3 : eTabAdjust = SvxTabAdjust::Decimal; break;
+ default : eTabAdjust = SvxTabAdjust::Left;
+ }
+ aTabItem.Insert(SvxTabStop(convertMasterUnitToMm100(nTab), eTabAdjust));
+ }
+ nLatestManTab = nTab;
+ }
+ if ( nIsBullet2 == 0 )
+ aTabItem.Insert( SvxTabStop( sal_uInt16(0) ) );
+ if ( nDefaultTab )
+ {
+ nTab = std::max( nTextOfs2, nLatestManTab );
+ nTab /= nDefaultTab;
+ nTab = nDefaultTab * ( 1 + nTab );
+ for ( i = 0; ( i < 20 ) && ( nTab < 0x1b00 ); i++ )
+ {
+ aTabItem.Insert( SvxTabStop( convertMasterUnitToMm100(nTab)));
+ nTab += nDefaultTab;
+ }
+ }
+ rSet.Put( aTabItem );
+}
+
+sal_uInt32 PPTParagraphObj::GetTextSize()
+{
+ sal_uInt32 nCount, nRetValue = 0;
+ for (const std::unique_ptr<PPTPortionObj> & i : m_PortionList)
+ {
+ PPTPortionObj const& rPortionObj = *i;
+ nCount = rPortionObj.Count();
+ if ((!nCount) && rPortionObj.mpFieldItem)
+ nCount++;
+ nRetValue += nCount;
+ }
+ return nRetValue;
+}
+
+PPTPortionObj* PPTParagraphObj::First()
+{
+ mnCurrentObject = 0;
+ if (m_PortionList.empty())
+ return nullptr;
+ return m_PortionList.front().get();
+}
+
+PPTPortionObj* PPTParagraphObj::Next()
+{
+ sal_uInt32 i = mnCurrentObject + 1;
+ if (i >= m_PortionList.size())
+ return nullptr;
+ mnCurrentObject++;
+ return m_PortionList[i].get();
+}
+
+PPTFieldEntry::~PPTFieldEntry()
+{
+}
+
+void PPTFieldEntry::GetDateTime( const sal_uInt32 nVal, SvxDateFormat& eDateFormat, SvxTimeFormat& eTimeFormat )
+{
+ eDateFormat = SvxDateFormat::AppDefault;
+ eTimeFormat = SvxTimeFormat::AppDefault;
+ // evaluate ID
+ switch( nVal )
+ {
+ case 0:
+ case 6:
+ eDateFormat = SvxDateFormat::A;
+ break;
+ case 1:
+ eDateFormat = SvxDateFormat::F;
+ break;
+ case 2:
+ case 3:
+ eDateFormat = SvxDateFormat::D;
+ break;
+ case 4:
+ case 5:
+ eDateFormat = SvxDateFormat::C;
+ break;
+ case 7:
+ eDateFormat = SvxDateFormat::A;
+ [[fallthrough]];
+ case 9:
+ eTimeFormat = SvxTimeFormat::HH24_MM;
+ break;
+ case 8:
+ eDateFormat = SvxDateFormat::A;
+ [[fallthrough]];
+ case 11:
+ eTimeFormat = SvxTimeFormat::HH12_MM;
+ break;
+ case 10:
+ eTimeFormat = SvxTimeFormat::HH24_MM_SS;
+ break;
+ case 12:
+ eTimeFormat = SvxTimeFormat::HH12_MM_SS;
+ break;
+ }
+}
+
+void PPTFieldEntry::SetDateTime( sal_uInt32 nVal )
+{
+ SvxDateFormat eDateFormat;
+ SvxTimeFormat eTimeFormat;
+ GetDateTime( nVal, eDateFormat, eTimeFormat );
+ if ( eDateFormat != SvxDateFormat::AppDefault )
+ xField1.reset(new SvxFieldItem(SvxDateField( Date( Date::SYSTEM ), SvxDateType::Var, eDateFormat ), EE_FEATURE_FIELD));
+ if ( eTimeFormat != SvxTimeFormat::AppDefault )
+ {
+ std::unique_ptr<SvxFieldItem> xFieldItem(new SvxFieldItem(SvxExtTimeField( tools::Time( tools::Time::SYSTEM ), SvxTimeType::Var, eTimeFormat ), EE_FEATURE_FIELD));
+ if (xField1)
+ xField2 = std::move(xFieldItem);
+ else
+ xField1 = std::move(xFieldItem);
+ }
+}
+
+PPTTextObj::PPTTextObj( SvStream& rIn, SdrPowerPointImport& rSdrPowerPointImport, PptSlidePersistEntry& rPersistEntry, DffObjData const * pObjData ) :
+ mxImplTextObj ( new ImplPPTTextObj( rPersistEntry ) )
+{
+ mxImplTextObj->mnShapeId = 0;
+ mxImplTextObj->mnShapeMaster = 0;
+ mxImplTextObj->mnDestinationInstance = mxImplTextObj->mnInstance = TSS_Type::TextInShape;
+ mxImplTextObj->mnCurrentObject = 0;
+ mxImplTextObj->mnParagraphCount = 0;
+ mxImplTextObj->mnTextFlags = 0;
+ mxImplTextObj->meShapeType = ( pObjData && pObjData->bShapeType ) ? pObjData->eShapeType : mso_sptMin;
+
+ DffRecordHeader aExtParaHd;
+ aExtParaHd.nRecType = 0; // set empty
+
+
+ DffRecordHeader aShapeContainerHd;
+ ReadDffRecordHeader( rIn, aShapeContainerHd );
+
+ if ( !(( pObjData == nullptr ) || ( pObjData->bShapeType )) )
+ return;
+
+ PPTExtParaProv* pExtParaProv = rSdrPowerPointImport.m_pPPTStyleSheet->pExtParaProv.get();
+ if ( pObjData )
+ {
+ mxImplTextObj->mnShapeId = pObjData->nShapeId;
+ if ( pObjData->nSpFlags & ShapeFlag::HaveMaster )
+ mxImplTextObj->mnShapeMaster = rSdrPowerPointImport.GetPropertyValue( DFF_Prop_hspMaster, 0 );
+ }
+ // ClientData
+ if ( rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
+ {
+ sal_uInt32 nOldPos = rIn.Tell();
+ DffRecordHeader& aClientDataContainerHd = *rSdrPowerPointImport.maShapeRecords.Current();
+ DffRecordHeader aPlaceHolderAtomHd;
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_OEPlaceholderAtom, aClientDataContainerHd.GetRecEndFilePos(), &aPlaceHolderAtomHd ) )
+ {
+ mxImplTextObj->mpPlaceHolderAtom.reset( new PptOEPlaceholderAtom );
+ ReadPptOEPlaceholderAtom( rIn, *( mxImplTextObj->mpPlaceHolderAtom ) );
+ }
+ rIn.Seek( nOldPos );
+ DffRecordHeader aProgTagHd;
+ if ( SdrPowerPointImport::SeekToContentOfProgTag( 9, rIn, aClientDataContainerHd, aProgTagHd ) )
+ {
+ ReadDffRecordHeader( rIn, aExtParaHd );
+ }
+ }
+
+ // ClientTextBox
+ if ( !rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientTextbox, SEEK_FROM_CURRENT_AND_RESTART ) )
+ return;
+
+ bool bStatus = true;
+
+
+ DffRecordHeader aClientTextBoxHd( *rSdrPowerPointImport.maShapeRecords.Current() );
+ sal_uInt32 nTextRulerAtomOfs = 0; // case of zero -> this atom may be found in aClientDataContainerHd;
+ // case of -1 -> there is no atom of this kind
+ // else -> this is the fileofs where we can get it
+
+ // checkout if this is a referenced
+ // textobj, if so the we will patch
+ // the ClientTextBoxHd for a
+ // equivalent one
+ DffRecordHeader aTextHd;
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_OutlineTextRefAtom, aClientTextBoxHd.GetRecEndFilePos(), &aTextHd ) )
+ {
+ sal_uInt32 nRefNum;
+ rIn.ReadUInt32( nRefNum );
+
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextRulerAtom, aClientTextBoxHd.GetRecEndFilePos() ) )
+ nTextRulerAtomOfs = rIn.Tell();
+ else
+ nTextRulerAtomOfs = 0xffffffff;
+
+ switch( rSdrPowerPointImport.m_eCurrentPageKind )
+ {
+ case PPT_NOTEPAGE :
+ case PPT_MASTERPAGE :
+ case PPT_SLIDEPAGE :
+ break;
+ default :
+ bStatus = false;
+ }
+ if ( bStatus )
+ {
+ sal_uInt32 nSlideId = rSdrPowerPointImport.GetCurrentPageId();
+ if ( !nSlideId )
+ bStatus = false;
+ else
+ {
+ if ( !aExtParaHd.nRecType )
+ {
+ sal_uInt32 nOldPos = rIn.Tell();
+ // try to locate the referenced ExtendedParaHd
+ DffRecordHeader* pHd = pExtParaProv->
+ aExtendedPresRules.GetRecordHeader( PPT_PST_ExtendedParagraphHeaderAtom,
+ SEEK_FROM_CURRENT_AND_RESTART );
+ DffRecordHeader aPresRuleHd;
+ DffRecordHeader* pFirst = pHd;
+
+ while ( pHd )
+ {
+ pHd->SeekToContent( rIn );
+ sal_uInt32 nTmpSlideId(0), nTmpRef;
+ rIn.ReadUInt32( nTmpSlideId )
+ .ReadUInt32( nTmpRef ); // this seems to be the instance
+
+ if ( ( nTmpSlideId == nSlideId ) && ( pHd->nRecInstance == nRefNum ) )
+ {
+ if (!pHd->SeekToEndOfRecord(rIn))
+ break;
+ ReadDffRecordHeader( rIn, aPresRuleHd );
+ if ( aPresRuleHd.nRecType == PPT_PST_ExtendedParagraphAtom )
+ {
+ aExtParaHd = aPresRuleHd;
+ break;
+ }
+ }
+ pHd = pExtParaProv->
+ aExtendedPresRules.GetRecordHeader( PPT_PST_ExtendedParagraphHeaderAtom,
+ SEEK_FROM_CURRENT_AND_RESTART );
+ if ( pHd == pFirst )
+ break;
+ }
+ rIn.Seek( nOldPos );
+ }
+ // now pHd points to the right SlideListWithText Container
+ PptSlidePersistList* pPageList = rSdrPowerPointImport.GetPageList( rSdrPowerPointImport.m_eCurrentPageKind );
+ PptSlidePersistEntry* pE = nullptr;
+ if ( pPageList && ( rSdrPowerPointImport.m_nCurrentPageNum < pPageList->size() ) )
+ pE = &(*pPageList)[ rSdrPowerPointImport.m_nCurrentPageNum ];
+ if ( (!pE) || (!pE->nSlidePersistStartOffset) || ( pE->aPersistAtom.nSlideId != nSlideId ) )
+ bStatus = false;
+ else
+ {
+ auto nOffset(pE->nSlidePersistStartOffset);
+ bStatus = (nOffset == rIn.Seek(nOffset));
+ // now we got the right page and are searching for the right
+ // TextHeaderAtom
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pE->nSlidePersistEndOffset);
+ while (bStatus && rIn.Tell() < nEndRecPos)
+ {
+ ReadDffRecordHeader( rIn, aClientTextBoxHd );
+ if ( aClientTextBoxHd.nRecType == PPT_PST_TextHeaderAtom )
+ {
+ if ( aClientTextBoxHd.nRecInstance == nRefNum )
+ {
+ aClientTextBoxHd.SeekToEndOfRecord( rIn );
+ break;
+ }
+ }
+ if (!aClientTextBoxHd.SeekToEndOfRecord(rIn))
+ break;
+ }
+ if ( rIn.Tell() > pE->nSlidePersistEndOffset )
+ bStatus = false;
+ else
+ { // patching the RecordHeader
+ aClientTextBoxHd.nFilePos -= DFF_COMMON_RECORD_HEADER_SIZE;
+ aClientTextBoxHd.nRecLen += DFF_COMMON_RECORD_HEADER_SIZE;
+ aClientTextBoxHd.nRecType = DFF_msofbtClientTextbox;
+ aClientTextBoxHd.nRecVer = DFF_PSFLAG_CONTAINER;
+
+ // we have to calculate the correct record len
+ DffRecordHeader aTmpHd;
+ nEndRecPos = DffPropSet::SanitizeEndPos(rIn, pE->nSlidePersistEndOffset);
+ while (rIn.Tell() < nEndRecPos)
+ {
+ ReadDffRecordHeader( rIn, aTmpHd );
+ if ( ( aTmpHd.nRecType == PPT_PST_SlidePersistAtom ) || ( aTmpHd.nRecType == PPT_PST_TextHeaderAtom ) )
+ break;
+ if (!aTmpHd.SeekToEndOfRecord(rIn))
+ break;
+ aClientTextBoxHd.nRecLen += aTmpHd.nRecLen + DFF_COMMON_RECORD_HEADER_SIZE;
+ }
+ aClientTextBoxHd.SeekToContent( rIn );
+ }
+ }
+ }
+ }
+ }
+
+ if ( !bStatus )
+ return;
+
+ if ( !SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextHeaderAtom, aClientTextBoxHd.GetRecEndFilePos(), &aTextHd ) )
+ return;
+
+ // TextHeaderAtom is always the first Atom
+ sal_uInt16 nTmp(0);
+ rIn.ReadUInt16(nTmp); // this number tells us the TxMasterStyleAtom Instance
+ if (nTmp > 8)
+ nTmp = 4;
+ TSS_Type nInstance = static_cast<TSS_Type>(nTmp);
+ aTextHd.SeekToEndOfRecord( rIn );
+ mxImplTextObj->mnInstance = nInstance;
+
+ sal_uInt32 nFilePos = rIn.Tell();
+ if ( !(rSdrPowerPointImport.SeekToRec2( PPT_PST_TextBytesAtom,
+ PPT_PST_TextCharsAtom,
+ aClientTextBoxHd.GetRecEndFilePos() )
+ || SvxMSDffManager::SeekToRec( rIn,
+ PPT_PST_StyleTextPropAtom,
+ aClientTextBoxHd.GetRecEndFilePos() )) )
+ return;
+
+ PPTTextRulerInterpreter aTextRulerInterpreter( nTextRulerAtomOfs, aClientTextBoxHd, rIn );
+
+ PPTStyleTextPropReader aStyleTextPropReader( rIn, aClientTextBoxHd,
+ aTextRulerInterpreter, aExtParaHd, nInstance );
+ sal_uInt32 nParagraphs = mxImplTextObj->mnParagraphCount = aStyleTextPropReader.aParaPropList.size();
+ if ( !nParagraphs )
+ return;
+
+ // the language settings will be merged into the list of PPTCharPropSet
+ DffRecordHeader aTextSpecInfoHd;
+ PPTTextSpecInfoAtomInterpreter aTextSpecInfoAtomInterpreter;
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_TextSpecInfoAtom,
+ aClientTextBoxHd.GetRecEndFilePos(), &aTextSpecInfoHd ) )
+ {
+ if ( aTextSpecInfoAtomInterpreter.Read( rIn, aTextSpecInfoHd, PPT_PST_TextSpecInfoAtom,
+ &(rSdrPowerPointImport.m_pPPTStyleSheet->maTxSI) ) )
+ {
+ size_t nI = 0;
+ for (const PPTTextSpecInfo& rSpecInfo : aTextSpecInfoAtomInterpreter.aList)
+ {
+ sal_uInt32 nCharIdx = rSpecInfo.nCharIdx;
+
+ // portions and text have to been split in some cases
+ for ( ; nI < aStyleTextPropReader.aCharPropList.size(); ++nI)
+ {
+ PPTCharPropSet* pSet = aStyleTextPropReader.aCharPropList[nI].get();
+ if (pSet->mnOriginalTextPos >= nCharIdx)
+ break;
+ pSet->mnLanguage[0] = rSpecInfo.nLanguage[0];
+ pSet->mnLanguage[1] = rSpecInfo.nLanguage[1];
+ pSet->mnLanguage[2] = rSpecInfo.nLanguage[2];
+ // test if the current portion needs to be split
+ if (pSet->maString.getLength() <= 1)
+ continue;
+ sal_Int32 nIndexOfNextPortion = pSet->maString.getLength() + pSet->mnOriginalTextPos;
+ sal_Int32 nNewLen = nIndexOfNextPortion - nCharIdx;
+ if (nNewLen <= 0)
+ continue;
+ sal_Int32 nOldLen = pSet->maString.getLength() - nNewLen;
+ if (nOldLen <= 0)
+ continue;
+ OUString aString(pSet->maString);
+ PPTCharPropSet* pNew = new PPTCharPropSet(*pSet);
+ pSet->maString = aString.copy(0, nOldLen);
+ pNew->maString = aString.copy(nOldLen, nNewLen);
+ pNew->mnOriginalTextPos += nOldLen;
+ aStyleTextPropReader.aCharPropList.emplace(aStyleTextPropReader.aCharPropList.begin() + nI + 1, pNew);
+ }
+ }
+ }
+#ifdef DBG_UTIL
+ else
+ {
+ if (!(rSdrPowerPointImport.rImportParam.nImportFlags & PPT_IMPORTFLAGS_NO_TEXT_ASSERT))
+ {
+ OSL_FAIL( "SdrTextSpecInfoAtomInterpreter::Ctor(): parsing error, this document needs to be analysed (SJ)" );
+ }
+ }
+#endif
+ }
+ // now will search for possible textextensions such as date/time fields
+ // or ParaTabStops and append them on this textobj
+ rIn.Seek( nFilePos );
+ ::std::vector< std::unique_ptr<PPTFieldEntry> > FieldList;
+ auto nEndRecPos = DffPropSet::SanitizeEndPos(rIn, aClientTextBoxHd.GetRecEndFilePos());
+ while (rIn.Tell() < nEndRecPos)
+ {
+ ReadDffRecordHeader( rIn, aTextHd );
+ sal_uInt16 nVal = 0;
+ std::unique_ptr<PPTFieldEntry> xEntry;
+ switch ( aTextHd.nRecType )
+ {
+ case PPT_PST_DateTimeMCAtom :
+ {
+ xEntry.reset(new PPTFieldEntry);
+ rIn.ReadUInt16(xEntry->nPos)
+ .ReadUInt16( nVal )
+ .ReadUInt16( nVal );
+ xEntry->SetDateTime( nVal & 0xff );
+ }
+ break;
+
+ case PPT_PST_FooterMCAtom :
+ {
+ xEntry.reset(new PPTFieldEntry);
+ rIn.ReadUInt16(xEntry->nPos);
+ xEntry->xField1.reset(new SvxFieldItem(SvxFooterField(), EE_FEATURE_FIELD));
+ }
+ break;
+
+ case PPT_PST_HeaderMCAtom :
+ {
+ xEntry.reset(new PPTFieldEntry);
+ rIn.ReadUInt16(xEntry->nPos);
+ xEntry->xField1.reset(new SvxFieldItem(SvxHeaderField(), EE_FEATURE_FIELD));
+ }
+ break;
+
+ case PPT_PST_GenericDateMCAtom :
+ {
+ xEntry.reset(new PPTFieldEntry);
+ rIn.ReadUInt16(xEntry->nPos);
+ xEntry->xField1.reset(new SvxFieldItem(SvxDateTimeField(), EE_FEATURE_FIELD));
+ if (rPersistEntry.xHeaderFooterEntry) // sj: #i34111# on master pages it is possible
+ { // that there is no HeaderFooterEntry available
+ if (rPersistEntry.xHeaderFooterEntry->nAtom & 0x20000) // auto date time
+ xEntry->SetDateTime(rPersistEntry.xHeaderFooterEntry->nAtom & 0xff);
+ else
+ xEntry->xString = rPersistEntry.xHeaderFooterEntry->pPlaceholder[nVal];
+ }
+ }
+ break;
+
+ case PPT_PST_SlideNumberMCAtom :
+ case PPT_PST_RTFDateTimeMCAtom :
+ {
+ xEntry.reset(new PPTFieldEntry);
+ if ( aTextHd.nRecLen >= 4 )
+ {
+ rIn.ReadUInt16(xEntry->nPos)
+ .ReadUInt16( nVal );
+
+ // evaluate ID
+ //SvxFieldItem* pFieldItem = NULL;
+ switch( aTextHd.nRecType )
+ {
+ case PPT_PST_SlideNumberMCAtom:
+ xEntry->xField1.reset(new SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD));
+ break;
+
+ case PPT_PST_RTFDateTimeMCAtom:
+ {
+ // Rude workaround for one special case reported
+ // by a customer. (#i75203#)
+
+ // Don't even attempt to handle the general use
+ // case for PPT_PST_RTFDateTimeMCAtom (a generic
+ // MS style date/time format string). Just handle
+ // the special case where the format string
+ // contains only one or several possibly empty
+ // quoted strings. I.e. something that doesn't
+ // expand to any date or time at all, but to a
+ // fixed string. How on earth somebody manages to
+ // produce such things in PPT slides I have no
+ // idea.
+ if (nVal == 0)
+ {
+ OUStringBuffer aStr;
+ bool inquote = false;
+ for (int nLen = 0; nLen < 64; ++nLen)
+ {
+ sal_Unicode n(0);
+ rIn.ReadUtf16( n );
+
+ // Collect quoted characters into aStr
+ if ( n == '\'')
+ inquote = !inquote;
+ else if (!n)
+ {
+ // End of format string
+ xEntry->xString = aStr.makeStringAndClear();
+ break;
+ }
+ else if (!inquote)
+ {
+ // Non-quoted character, i.e. a real
+ // format specifier. We don't handle
+ // those. Sorry.
+ break;
+ }
+ else
+ {
+ aStr.append(OUStringChar(n));
+ }
+ }
+ }
+ if (!xEntry->xString)
+ {
+ // Handle as previously
+ xEntry->xField1.reset(new SvxFieldItem( SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD ));
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case PPT_PST_InteractiveInfo :
+ {
+ DffRecordHeader aHdInteractiveInfoAtom;
+ if ( SvxMSDffManager::SeekToRec( rIn, PPT_PST_InteractiveInfoAtom, aTextHd.GetRecEndFilePos(), &aHdInteractiveInfoAtom ) )
+ {
+ PptInteractiveInfoAtom aInteractiveInfoAtom;
+ ReadPptInteractiveInfoAtom( rIn, aInteractiveInfoAtom );
+ for (const SdHyperlinkEntry& rHyperlink : rSdrPowerPointImport.m_aHyperList)
+ {
+ if ( rHyperlink.nIndex == aInteractiveInfoAtom.nExHyperlinkId )
+ {
+ if (!aTextHd.SeekToEndOfRecord(rIn))
+ {
+ break;
+ }
+ ReadDffRecordHeader( rIn, aTextHd );
+ if ( aTextHd.nRecType != PPT_PST_TxInteractiveInfoAtom )
+ {
+ aTextHd.SeekToBegOfRecord( rIn );
+ continue;
+ }
+ else
+ {
+ sal_uInt32 nStartPos, nEndPos;
+ rIn.ReadUInt32( nStartPos )
+ .ReadUInt32( nEndPos );
+ if ( nEndPos )
+ {
+ xEntry.reset(new PPTFieldEntry);
+ xEntry->nPos = static_cast<sal_uInt16>(nStartPos);
+ xEntry->nTextRangeEnd = static_cast<sal_uInt16>(nEndPos);
+ OUString aTarget( rHyperlink.aTarget );
+ if ( !rHyperlink.aConvSubString.isEmpty() )
+ {
+ aTarget += "#" + rHyperlink.aConvSubString;
+ }
+ xEntry->xField1.reset(new SvxFieldItem( SvxURLField( aTarget, OUString(), SvxURLFormat::Repr ), EE_FEATURE_FIELD ));
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ if (!aTextHd.SeekToEndOfRecord(rIn))
+ break;
+ if (xEntry)
+ {
+ // sorting fields ( hi >> lo )
+ auto it = std::find_if(FieldList.begin(), FieldList.end(),
+ [&xEntry](const std::unique_ptr<PPTFieldEntry>& rxField) {
+ return rxField->nPos < xEntry->nPos; });
+ if ( it != FieldList.end() ) {
+ FieldList.insert(it, std::move(xEntry));
+ } else {
+ FieldList.push_back( std::move(xEntry));
+ }
+ }
+ }
+ if ( !FieldList.empty() )
+ {
+ auto FE = FieldList.begin();
+ auto& aCharPropList = aStyleTextPropReader.aCharPropList;
+
+ sal_Int32 i = nParagraphs - 1;
+ sal_Int32 n = aCharPropList.size() - 1;
+
+ // at this point we just have a list of textportions(aCharPropList)
+ // the next while loop tries to resolve the list of fields(pFieldList)
+ while( ( FE < FieldList.end() ) && ( n >= 0 ) && ( i >= 0 ) )
+ {
+ PPTCharPropSet* pSet = aCharPropList[n].get();
+ OUString aString( pSet->maString );
+ sal_uInt32 nCount = aString.getLength();
+ sal_uInt32 nPos = pSet->mnOriginalTextPos + nCount;
+ while ( ( FE < FieldList.end() ) && nCount-- )
+ {
+ nPos--;
+ FE = std::find_if(FE, FieldList.end(),
+ [&nPos](const std::unique_ptr<PPTFieldEntry>& rxField) {return rxField->nPos <= nPos;});
+ if (FE == FieldList.end())
+ break;
+
+ if ( (*FE)->nPos == nPos )
+ {
+ if ( aString[nCount] == 0x2a )
+ {
+ sal_uInt32 nBehind = aString.getLength() - ( nCount + 1 );
+ pSet->maString.clear();
+ if ( nBehind )
+ {
+ PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet );
+ pNewCPS->maString = aString.copy( nCount + 1, nBehind );
+ aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS );
+ }
+ if ( (*FE)->xField2 )
+ {
+ PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet );
+ pNewCPS->mpFieldItem = std::move((*FE)->xField2);
+ aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS );
+
+ pNewCPS = new PPTCharPropSet( *pSet );
+ pNewCPS->maString = " ";
+ aCharPropList.emplace( aCharPropList.begin() + n + 1, pNewCPS );
+ }
+ if ( nCount )
+ {
+ PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pSet );
+ pNewCPS->maString = aString.copy( 0, nCount );
+ aCharPropList.emplace( aCharPropList.begin() + n++, pNewCPS );
+ }
+ if ( (*FE)->xField1 )
+ {
+ pSet->mpFieldItem = std::move((*FE)->xField1);
+ }
+ else if ( (*FE)->xString )
+ pSet->maString = *(*FE)->xString;
+ }
+ else
+ {
+ if ( (*FE)->nTextRangeEnd ) // text range hyperlink
+ {
+ sal_uInt32 nHyperLen = (*FE)->nTextRangeEnd - nPos;
+ if ( nHyperLen )
+ {
+ PPTCharPropSet* pBefCPS = nullptr;
+ if ( nCount )
+ {
+ pBefCPS = new PPTCharPropSet( *pSet );
+ pSet->maString = pSet->maString.copy(nCount);
+ }
+ sal_uInt32 nIdx = n;
+ sal_Int32 nHyperLenLeft = nHyperLen;
+
+ while ( ( aCharPropList.size() > nIdx ) && nHyperLenLeft )
+ {
+ // the textrange hyperlink can take more than 1 paragraph
+ // the solution here is to clone the hyperlink...
+
+ PPTCharPropSet* pCurrent = aCharPropList[ nIdx ].get();
+ sal_Int32 nNextStringLen = pCurrent->maString.getLength();
+
+ DBG_ASSERT( (*FE)->xField1, "missing field!" );
+ if (!(*FE)->xField1)
+ break;
+
+ const SvxURLField* pField = static_cast<const SvxURLField*>((*FE)->xField1->GetField());
+
+ pCurrent->mbIsHyperlink = true;
+ pCurrent->mnHylinkOrigColor = pCurrent->mpImplPPTCharPropSet->mnColor;
+ pCurrent->mbHardHylinkOrigColor = ( ( pCurrent->mpImplPPTCharPropSet->mnAttrSet >>PPT_CharAttr_FontColor ) & 1)>0;
+
+ // add missing attribute to show underline property
+ pCurrent->mpImplPPTCharPropSet->mnAttrSet |= 1 << PPT_CharAttr_Underline;
+ pCurrent->mpImplPPTCharPropSet->mnFlags = 1 << PPT_CharAttr_Underline;
+
+ if ( pCurrent->mpFieldItem )
+ {
+ pCurrent->SetColor( PPT_COLSCHEME_A_UND_HYPERLINK );
+ if ( dynamic_cast< const SvxURLField* >(pCurrent->mpFieldItem->GetField()) != nullptr)
+ break;
+ nHyperLenLeft--;
+ }
+ else if ( nNextStringLen )
+ {
+ if ( nNextStringLen <= nHyperLenLeft )
+ {
+ pCurrent->mpFieldItem.reset( new SvxFieldItem( SvxURLField( pField->GetURL(), pCurrent->maString, SvxURLFormat::Repr ), EE_FEATURE_FIELD ) );
+ nHyperLenLeft -= nNextStringLen;
+
+ if ( nHyperLenLeft )
+ {
+ // if the next portion is in a higher paragraph,
+ // the textrange is to decrease (because of the LineBreak character)
+ if ( aCharPropList.size() > ( nIdx + 1 ) )
+ {
+ PPTCharPropSet* pNext = aCharPropList[ nIdx + 1 ].get();
+ if ( pNext->mnParagraph > pCurrent->mnParagraph )
+ nHyperLenLeft--;
+ }
+ }
+ }
+ else
+ {
+ PPTCharPropSet* pNewCPS = new PPTCharPropSet( *pCurrent );
+ pNewCPS->maString = pCurrent->maString.copy( nHyperLenLeft,( nNextStringLen - nHyperLenLeft ) );
+ aCharPropList.emplace( aCharPropList.begin() + nIdx + 1, pNewCPS );
+ OUString aRepresentation = pCurrent->maString.copy( 0, nHyperLenLeft );
+ pCurrent->mpFieldItem.reset( new SvxFieldItem( SvxURLField( pField->GetURL(), aRepresentation, SvxURLFormat::Repr ), EE_FEATURE_FIELD ) );
+ nHyperLenLeft = 0;
+ }
+ pCurrent->maString.clear();
+ pCurrent->SetColor( PPT_COLSCHEME_A_UND_HYPERLINK );
+ }
+ nIdx++;
+ }
+ (*FE)->xField1.reset();
+
+ if ( pBefCPS )
+ {
+ pBefCPS->maString = aString.copy( 0, nCount );
+ aCharPropList.emplace( aCharPropList.begin() + n, pBefCPS );
+ n++;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ n--;
+ }
+ }
+ mxImplTextObj->maParagraphList.resize( nParagraphs );
+ for (size_t nCurCharPos = 0, nCurPos = 0;
+ nCurPos < aStyleTextPropReader.aParaPropList.size();
+ ++nCurPos)
+ {
+ mxImplTextObj->maParagraphList[ nCurPos ].reset(
+ new PPTParagraphObj(
+ aStyleTextPropReader, nCurPos, nCurCharPos,
+ *rSdrPowerPointImport.m_pPPTStyleSheet,
+ nInstance, aTextRulerInterpreter ) );
+
+ sal_uInt32 nParaAdjust, nFlags = 0;
+ mxImplTextObj->maParagraphList[ nCurPos ]->GetAttrib( PPT_ParaAttr_Adjust, nParaAdjust, GetInstance() );
+
+ switch ( nParaAdjust )
+ {
+ case 0 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT; break;
+ case 1 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER; break;
+ case 2 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT; break;
+ case 3 : nFlags = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK; break;
+ }
+ mxImplTextObj->mnTextFlags |= nFlags;
+ }
+}
+
+PPTTextObj::PPTTextObj( PPTTextObj const & rTextObj )
+{
+ mxImplTextObj = rTextObj.mxImplTextObj;
+}
+
+PPTTextObj::~PPTTextObj()
+{
+}
+
+PPTParagraphObj* PPTTextObj::First()
+{
+ mxImplTextObj->mnCurrentObject = 0;
+ if ( !mxImplTextObj->mnParagraphCount )
+ return nullptr;
+ return mxImplTextObj->maParagraphList[ 0 ].get();
+}
+
+PPTParagraphObj* PPTTextObj::Next()
+{
+ sal_uInt32 i = mxImplTextObj->mnCurrentObject + 1;
+ if ( i >= mxImplTextObj->mnParagraphCount )
+ return nullptr;
+ mxImplTextObj->mnCurrentObject++;
+ return mxImplTextObj->maParagraphList[ i ].get();
+}
+
+const SfxItemSet* PPTTextObj::GetBackground() const
+{
+ if ( mxImplTextObj->mrPersistEntry.pBObj )
+ return &mxImplTextObj->mrPersistEntry.pBObj->GetMergedItemSet();
+ else
+ return nullptr;
+}
+
+PPTTextObj& PPTTextObj::operator=( const PPTTextObj& rTextObj )
+{
+ if ( this != &rTextObj )
+ {
+ mxImplTextObj = rTextObj.mxImplTextObj;
+ }
+ return *this;
+}
+
+static bool IsLine( const SdrObject* pObj )
+{
+ auto pSdrPathObj = dynamic_cast< const SdrPathObj* >(pObj);
+ return pSdrPathObj && pSdrPathObj->IsLine() && pSdrPathObj->GetPointCount() == 2;
+}
+
+static bool GetCellPosition( const SdrObject* pObj, const o3tl::sorted_vector< sal_Int32 >& rRows, const o3tl::sorted_vector< sal_Int32 >& rColumns,
+ sal_Int32& nTableIndex, sal_Int32& nRow, sal_Int32& nRowCount, sal_Int32& nColumn, sal_Int32& nColumnCount )
+{
+ tools::Rectangle aSnapRect( pObj->GetSnapRect() );
+ bool bCellObject = ( aSnapRect.GetWidth() > 1 ) && ( aSnapRect.GetHeight() > 1 );
+ if ( bCellObject )
+ {
+ auto aRowIter = rRows.find( aSnapRect.Top() );
+ auto aColumnIter = rColumns.find( aSnapRect.Left() );
+ if ( ( aRowIter == rRows.end() ) || ( aColumnIter == rColumns.end() ) )
+ bCellObject = false;
+ else
+ {
+ nRowCount = 1;
+ nRow = std::distance( rRows.begin(), aRowIter );
+ while( ++aRowIter != rRows.end() )
+ {
+ if ( *aRowIter >= aSnapRect.Bottom() )
+ break;
+ nRowCount++;
+ }
+ nColumnCount = 1;
+ nColumn = std::distance( rColumns.begin(), aColumnIter );
+ while( ++aColumnIter != rColumns.end() )
+ {
+ if ( *aColumnIter >= aSnapRect.Right() )
+ break;
+ nColumnCount++;
+ }
+ nTableIndex = nRow * rColumns.size() + nColumn;
+ }
+ }
+ return bCellObject;
+}
+
+#define LinePositionLeft 0x01000000
+#define LinePositionTop 0x02000000
+#define LinePositionRight 0x04000000
+#define LinePositionBottom 0x08000000
+#define LinePositionTLBR 0x10000000
+#define LinePositionBLTR 0x20000000
+
+
+static void GetRowPositions( const tools::Rectangle& rSnapRect, const o3tl::sorted_vector< sal_Int32 >& rRows,
+ const o3tl::sorted_vector< sal_Int32 >& rColumns, std::vector< sal_Int32 >& rPositions, sal_Int32 nColumn, sal_Int32 nFlags )
+{
+ auto aRow = rRows.find( rSnapRect.Top() );
+ if ( aRow == rRows.end() )
+ return;
+
+ sal_Int32 nRow = std::distance( rRows.begin(), aRow );
+ while( ( aRow != rRows.end() ) && ((*aRow) < rSnapRect.Bottom() ) )
+ {
+ if ( nFlags & LinePositionLeft )
+ rPositions.push_back( ( ( nRow * rColumns.size() ) + nColumn ) | LinePositionLeft );
+ if ( nFlags & LinePositionRight )
+ rPositions.push_back( ( ( nRow * rColumns.size() ) + ( nColumn - 1 ) ) | LinePositionRight );
+
+ ++nRow;
+ ++aRow;
+ }
+}
+
+
+static void GetColumnPositions( const tools::Rectangle& rSnapRect,
+ const o3tl::sorted_vector< sal_Int32 >& rColumns, std::vector< sal_Int32 >& rPositions, sal_Int32 nRow, sal_Int32 nFlags )
+{
+ auto aColumn = rColumns.find( rSnapRect.Left() );
+ if ( aColumn == rColumns.end() )
+ return;
+
+ sal_Int32 nColumn = std::distance( rColumns.begin(), aColumn );
+ while( ( aColumn != rColumns.end() ) && ((*aColumn) < rSnapRect.Right() ) )
+ {
+ if ( nFlags & LinePositionTop )
+ rPositions.push_back( ( ( nRow * rColumns.size() ) + nColumn ) | LinePositionTop );
+ if ( nFlags & LinePositionBottom )
+ rPositions.push_back( ( ( ( nRow - 1 ) * rColumns.size() ) + nColumn ) | LinePositionBottom );
+
+ ++nColumn;
+ ++aColumn;
+ }
+}
+
+static void GetLinePositions( const SdrObject* pObj, const o3tl::sorted_vector< sal_Int32 >& rRows, const o3tl::sorted_vector< sal_Int32 >& rColumns,
+ std::vector< sal_Int32 >& rPositions, const tools::Rectangle& rGroupSnap )
+{
+ tools::Rectangle aSnapRect( pObj->GetSnapRect() );
+ if ( aSnapRect.Left() == aSnapRect.Right() )
+ {
+ auto aColumn = rColumns.find( aSnapRect.Left() );
+ if ( ( aColumn != rColumns.end() ) || ( aSnapRect.Left() == rGroupSnap.Right() ) )
+ {
+ sal_Int32 nColumn, nFlags;
+ if ( aColumn != rColumns.end() )
+ {
+ nColumn = std::distance( rColumns.begin(), aColumn );
+ nFlags = LinePositionLeft;
+ if ( aColumn != rColumns.begin() )
+ nFlags |= LinePositionRight;
+ }
+ else
+ {
+ nColumn = rColumns.size();
+ nFlags = LinePositionRight;
+ }
+ GetRowPositions( aSnapRect, rRows, rColumns, rPositions, nColumn, nFlags );
+ }
+ }
+ else if ( aSnapRect.Top() == aSnapRect.Bottom() )
+ {
+ auto aRow = rRows.find( aSnapRect.Top() );
+ if ( ( aRow != rRows.end() ) || ( aSnapRect.Top() == rGroupSnap.Bottom() ) )
+ {
+ sal_Int32 nRow, nFlags;
+ if ( aRow != rRows.end() )
+ {
+ nRow = std::distance( rRows.begin(), aRow );
+ nFlags = LinePositionTop;
+ if ( aRow != rRows.begin() )
+ nFlags |= LinePositionBottom;
+ }
+ else
+ {
+ nRow = rRows.size();
+ nFlags = LinePositionBottom;
+ }
+ GetColumnPositions( aSnapRect, rColumns, rPositions, nRow, nFlags );
+ }
+ }
+ else
+ {
+ sal_uInt32 nPosition = 0;
+ Point aPt1( static_cast<const SdrPathObj*>(pObj)->GetPoint( 0 ) );
+ Point aPt2( static_cast<const SdrPathObj*>(pObj)->GetPoint( 1 ) );
+ if ( aPt1.X() < aPt2.X() )
+ nPosition |= aPt1.Y() < aPt2.Y() ? LinePositionTLBR : LinePositionBLTR;
+ else
+ nPosition |= aPt1.Y() < aPt2.Y() ? LinePositionBLTR : LinePositionTLBR;
+
+ auto aRow = rRows.find( std::min(aPt1.Y(), aPt2.Y() ) );
+ auto aColumn = rColumns.find( std::min(aPt1.X(), aPt2.X() ) );
+ if ( ( aRow != rRows.end() ) && ( aColumn != rColumns.end() ) )
+ {
+ nPosition |= ( std::distance( rRows.begin(), aRow ) * rColumns.size() ) + std::distance( rColumns.begin(), aColumn );
+ rPositions.push_back( nPosition );
+ }
+ }
+}
+
+static void CreateTableRows( const Reference< XTableRows >& xTableRows, const o3tl::sorted_vector< sal_Int32 >& rRows, sal_Int32 nTableBottom )
+{
+ if ( rRows.size() > 1 )
+ xTableRows->insertByIndex( 0, rRows.size() - 1 );
+
+ auto aIter = rRows.begin();
+ sal_Int32 nLastPosition( *aIter );
+ for ( sal_Int32 n = 0; n < xTableRows->getCount(); n++ )
+ {
+ sal_Int32 nHeight;
+ if ( ++aIter != rRows.end() )
+ {
+ if (o3tl::checked_sub<sal_Int32>(*aIter, nLastPosition, nHeight))
+ throw lang::IllegalArgumentException();
+ nLastPosition = *aIter;
+ }
+ else
+ {
+ if (o3tl::checked_sub<sal_Int32>(nTableBottom, nLastPosition, nHeight))
+ throw lang::IllegalArgumentException();
+ }
+
+ Reference< XPropertySet > xPropSet( xTableRows->getByIndex( n ), UNO_QUERY_THROW );
+ xPropSet->setPropertyValue( "Height", Any( nHeight ) );
+ }
+}
+
+static void CreateTableColumns( const Reference< XTableColumns >& xTableColumns, const o3tl::sorted_vector< sal_Int32 >& rColumns, sal_Int32 nTableRight )
+{
+ if ( rColumns.size() > 1 )
+ xTableColumns->insertByIndex( 0, rColumns.size() - 1 );
+
+ auto aIter = rColumns.begin();
+ sal_Int32 nLastPosition( *aIter );
+ for ( sal_Int32 n = 0; n < xTableColumns->getCount(); n++ )
+ {
+ sal_Int32 nWidth;
+ if ( ++aIter != rColumns.end() )
+ {
+ if (o3tl::checked_sub<sal_Int32>(*aIter, nLastPosition, nWidth))
+ throw lang::IllegalArgumentException();
+ nLastPosition = *aIter;
+ }
+ else
+ {
+ if (o3tl::checked_sub<sal_Int32>(nTableRight, nLastPosition, nWidth))
+ throw lang::IllegalArgumentException();
+ }
+
+ Reference< XPropertySet > xPropSet( xTableColumns->getByIndex( n ), UNO_QUERY_THROW );
+ xPropSet->setPropertyValue( "Width", Any( nWidth ) );
+ }
+}
+
+static void MergeCells( const Reference< XTable >& xTable, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
+{
+ DBG_ASSERT( (nColSpan > 1) || (nRowSpan > 1), "nonsense parameter!!" );
+ DBG_ASSERT( (nCol >= 0) && (nCol < xTable->getColumnCount()) && (nRow >= 0) && (nRow < xTable->getRowCount()), "the cell does not exists!!" );
+ DBG_ASSERT( (nColSpan >= 1) && ((nCol + nColSpan - 1) < xTable->getColumnCount()), "nColSpan botch!" );
+ DBG_ASSERT( (nRowSpan >= 1) && ((nRow + nRowSpan - 1) < xTable->getRowCount()), "nRowSpan botch!" );
+
+ if( xTable.is() ) try
+ {
+ Reference< XMergeableCellRange > xRange( xTable->createCursorByRange( xTable->getCellRangeByPosition( nCol, nRow,nCol + nColSpan - 1, nRow + nRowSpan - 1 ) ), UNO_QUERY_THROW );
+ if( xRange->isMergeable() )
+ xRange->merge();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("filter.ms");
+ }
+}
+
+static void ApplyCellAttributes( const SdrObject* pObj, Reference< XCell > const & xCell )
+{
+ try
+ {
+ Reference< XPropertySet > xPropSet( xCell, UNO_QUERY_THROW );
+
+ const sal_Int32 nLeftDist(pObj->GetMergedItem(SDRATTR_TEXT_LEFTDIST).GetValue());
+ const sal_Int32 nRightDist(pObj->GetMergedItem(SDRATTR_TEXT_RIGHTDIST).GetValue());
+ const sal_Int32 nUpperDist(pObj->GetMergedItem(SDRATTR_TEXT_UPPERDIST).GetValue());
+ const sal_Int32 nLowerDist(pObj->GetMergedItem(SDRATTR_TEXT_LOWERDIST).GetValue());
+ xPropSet->setPropertyValue( "TextUpperDistance", Any( nUpperDist ) );
+ xPropSet->setPropertyValue( "TextRightDistance", Any( nRightDist ) );
+ xPropSet->setPropertyValue( "TextLeftDistance", Any( nLeftDist ) );
+ xPropSet->setPropertyValue( "TextLowerDistance", Any( nLowerDist ) );
+
+ const SdrTextVertAdjust eTextVertAdjust(pObj->GetMergedItem(SDRATTR_TEXT_VERTADJUST).GetValue());
+ drawing::TextVerticalAdjust eVA( drawing::TextVerticalAdjust_TOP );
+ if ( eTextVertAdjust == SDRTEXTVERTADJUST_CENTER )
+ eVA = drawing::TextVerticalAdjust_CENTER;
+ else if ( eTextVertAdjust == SDRTEXTVERTADJUST_BOTTOM )
+ eVA = drawing::TextVerticalAdjust_BOTTOM;
+ xPropSet->setPropertyValue( "TextVerticalAdjust", Any( eVA ) );
+
+ //set textHorizontalAdjust and TextWritingMode attr
+ const sal_Int32 eHA(pObj->GetMergedItem(SDRATTR_TEXT_HORZADJUST).GetValue());
+ const SvxFrameDirection eDirection = pObj->GetMergedItem(EE_PARA_WRITINGDIR).GetValue();
+ xPropSet->setPropertyValue( "TextHorizontalAdjust" , Any( eHA ) );
+ if ( eDirection == SvxFrameDirection::Vertical_RL_TB )
+ {//vertical writing
+ xPropSet->setPropertyValue( "TextWritingMode" , Any( css::text::WritingMode_TB_RL ) );
+ }
+ drawing::FillStyle eFillStyle(pObj->GetMergedItem( XATTR_FILLSTYLE ).GetValue());
+ css::drawing::FillStyle eFS( css::drawing::FillStyle_NONE );
+ switch( eFillStyle )
+ {
+ case drawing::FillStyle_SOLID :
+ {
+ eFS = css::drawing::FillStyle_SOLID;
+ Color aFillColor( pObj->GetMergedItem( XATTR_FILLCOLOR ).GetColorValue() );
+ xPropSet->setPropertyValue( "FillColor", Any( aFillColor ) );
+ }
+ break;
+ case drawing::FillStyle_GRADIENT :
+ {
+ eFS = css::drawing::FillStyle_GRADIENT;
+ XGradient aXGradient(pObj->GetMergedItem(XATTR_FILLGRADIENT).GetGradientValue());
+
+ css::awt::Gradient aGradient;
+ aGradient.Style = aXGradient.GetGradientStyle();
+ aGradient.StartColor = static_cast<sal_Int32>(aXGradient.GetStartColor());
+ aGradient.EndColor = static_cast<sal_Int32>(aXGradient.GetEndColor());
+ aGradient.Angle = static_cast<short>(aXGradient.GetAngle());
+ aGradient.Border = aXGradient.GetBorder();
+ aGradient.XOffset = aXGradient.GetXOffset();
+ aGradient.YOffset = aXGradient.GetYOffset();
+ aGradient.StartIntensity = aXGradient.GetStartIntens();
+ aGradient.EndIntensity = aXGradient.GetEndIntens();
+ aGradient.StepCount = aXGradient.GetSteps();
+
+ xPropSet->setPropertyValue( "FillGradient", Any( aGradient ) );
+ }
+ break;
+ case drawing::FillStyle_HATCH :
+ eFS = css::drawing::FillStyle_HATCH;
+ break;
+ case drawing::FillStyle_BITMAP :
+ {
+ eFS = css::drawing::FillStyle_BITMAP;
+
+ const XFillBitmapItem & rXFillBitmapItem(pObj->GetMergedItem( XATTR_FILLBITMAP ));
+ uno::Reference<graphic::XGraphic> xGraphic = rXFillBitmapItem.GetGraphicObject().GetGraphic().GetXGraphic();
+ uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
+ xPropSet->setPropertyValue("FillBitmap", uno::Any(xBitmap));
+
+ const XFillBmpStretchItem & rStretchItem(pObj->GetMergedItem( XATTR_FILLBMP_STRETCH ));
+ const XFillBmpTileItem & rTileItem(pObj->GetMergedItem( XATTR_FILLBMP_TILE ));
+ if( rTileItem.GetValue() )
+ xPropSet->setPropertyValue("FillBitmapMode", uno::Any(drawing::BitmapMode_REPEAT));
+ else if( rStretchItem.GetValue() )
+ xPropSet->setPropertyValue("FillBitmapMode", uno::Any(drawing::BitmapMode_STRETCH));
+ else
+ xPropSet->setPropertyValue("FillBitmapMode", uno::Any(drawing::BitmapMode_NO_REPEAT));
+ }
+ break;
+ default:
+ case drawing::FillStyle_NONE :
+ eFS = css::drawing::FillStyle_NONE;
+ break;
+
+ }
+ xPropSet->setPropertyValue( "FillStyle", Any( eFS ) );
+ if ( eFillStyle != drawing::FillStyle_NONE )
+ {
+ sal_Int16 nFillTransparence( pObj->GetMergedItem( XATTR_FILLTRANSPARENCE ).GetValue() );
+ xPropSet->setPropertyValue( "FillTransparence", Any( nFillTransparence ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ }
+}
+
+static void ApplyCellLineAttributes( const SdrObject* pLine, Reference< XTable > const & xTable, const std::vector< sal_Int32 >& vPositions, sal_Int32 nColumns )
+{
+ try
+ {
+ drawing::LineStyle eLineStyle(pLine->GetMergedItem( XATTR_LINESTYLE ).GetValue());
+ css::table::BorderLine2 aBorderLine;
+ switch( eLineStyle )
+ {
+ case drawing::LineStyle_DASH :
+ case drawing::LineStyle_SOLID :
+ {
+ Color aLineColor( pLine->GetMergedItem( XATTR_LINECOLOR ).GetColorValue() );
+ aBorderLine.Color = sal_Int32(aLineColor);
+ // Avoid width = 0, the min value should be 1.
+ sal_Int32 nLineWidth = std::max(sal_Int32(1), pLine->GetMergedItem(XATTR_LINEWIDTH) .GetValue() / 4);
+ aBorderLine.LineWidth = static_cast< sal_Int16 >( nLineWidth );
+ aBorderLine.LineStyle = eLineStyle == drawing::LineStyle_SOLID ? table::BorderLineStyle::SOLID : table::BorderLineStyle::DASHED;
+ }
+ break;
+ default:
+ case drawing::LineStyle_NONE :
+ {
+ aBorderLine.LineWidth = 0;
+ aBorderLine.LineStyle = table::BorderLineStyle::NONE;
+ }
+ break;
+ }
+ for (auto const& vPos : vPositions)
+ {
+ sal_Int32 nPosition = vPos & 0xffffff;
+ sal_Int32 nFlags = vPos &~0xffffff;
+ sal_Int32 nRow = nPosition / nColumns;
+ sal_Int32 nColumn = nPosition - ( nRow * nColumns );
+ Reference< XCell > xCell( xTable->getCellByPosition( nColumn, nRow ) );
+ Reference< XPropertySet > xPropSet( xCell, UNO_QUERY_THROW );
+
+ if ( nFlags & LinePositionLeft )
+ xPropSet->setPropertyValue( "LeftBorder", Any( aBorderLine ) );
+ if ( nFlags & LinePositionTop )
+ xPropSet->setPropertyValue( "TopBorder", Any( aBorderLine ) );
+ if ( nFlags & LinePositionRight )
+ xPropSet->setPropertyValue( "RightBorder", Any( aBorderLine ) );
+ if ( nFlags & LinePositionBottom )
+ xPropSet->setPropertyValue( "BottomBorder", Any( aBorderLine ) );
+ if ( nFlags & LinePositionTLBR )
+ xPropSet->setPropertyValue( "DiagonalTLBR", Any( true ) );
+ if ( nFlags & LinePositionBLTR )
+ xPropSet->setPropertyValue( "DiagonalBLTR", Any( true ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ }
+}
+
+SdrObject* SdrPowerPointImport::CreateTable(SdrObject* pGroup, const sal_uInt32* pTableArry, SvxMSDffSolverContainer* pSolverContainer, std::vector<SdrObject*>& rBackgroundColoredObjects)
+{
+ SdrObject* pRet = pGroup;
+
+ sal_uInt32 nRows = pTableArry[ 1 ];
+ if (!nRows)
+ return pRet;
+
+ const SdrObjGroup* pObjGroup = dynamic_cast<const SdrObjGroup*>(pGroup);
+ if (!pObjGroup)
+ return pRet;
+
+ SdrObjList* pSubList(pObjGroup->GetSubList());
+ if (!pSubList)
+ return pRet;
+
+ o3tl::sorted_vector< sal_Int32 > aRows;
+ o3tl::sorted_vector< sal_Int32 > aColumns;
+
+ SdrObjListIter aGroupIter( pSubList, SdrIterMode::DeepNoGroups, false );
+ while( aGroupIter.IsMore() )
+ {
+ const SdrObject* pObj( aGroupIter.Next() );
+ if ( !IsLine( pObj ) )
+ {
+ tools::Rectangle aSnapRect( pObj->GetSnapRect() );
+ aRows.insert( aSnapRect.Top() );
+ aColumns.insert( aSnapRect.Left() );
+ }
+ }
+
+ if (aRows.empty())
+ return pRet;
+
+ sdr::table::SdrTableObj* pTable = new sdr::table::SdrTableObj(*pSdrModel);
+ pTable->uno_lock();
+ Reference< XTable > xTable( pTable->getTable() );
+
+ try
+ {
+ CreateTableRows( xTable->getRows(), aRows, pGroup->GetSnapRect().Bottom() );
+ CreateTableColumns( xTable->getColumns(), aColumns, pGroup->GetSnapRect().Right() );
+
+ sal_Int32 nCellCount = aRows.size() * aColumns.size();
+ std::unique_ptr<sal_Int32[]> pMergedCellIndexTable(new sal_Int32[ nCellCount ]);
+ for ( sal_Int32 i = 0; i < nCellCount; i++ )
+ pMergedCellIndexTable[ i ] = i;
+
+ aGroupIter.Reset();
+ while( aGroupIter.IsMore() )
+ {
+ SdrObject* pObj( aGroupIter.Next() );
+ if ( !IsLine( pObj ) )
+ {
+ sal_Int32 nTableIndex = 0;
+ sal_Int32 nRow = 0;
+ sal_Int32 nRowCount = 0;
+ sal_Int32 nColumn = 0;
+ sal_Int32 nColumnCount = 0;
+ if ( GetCellPosition( pObj, aRows, aColumns, nTableIndex, nRow, nRowCount, nColumn, nColumnCount ) )
+ {
+ Reference< XCell > xCell( xTable->getCellByPosition( nColumn, nRow ) );
+
+ ApplyCellAttributes( pObj, xCell );
+
+ if ( ( nRowCount > 1 ) || ( nColumnCount > 1 ) ) // cell merging
+ {
+ MergeCells( xTable, nColumn, nRow, nColumnCount, nRowCount );
+ for ( sal_Int32 nRowIter = 0; nRowIter < nRowCount; nRowIter++ )
+ {
+ for ( sal_Int32 nColumnIter = 0; nColumnIter < nColumnCount; nColumnIter++ )
+ { // now set the correct index for the merged cell
+ pMergedCellIndexTable[ ( ( nRow + nRowIter ) * aColumns.size() ) + nColumn + nColumnIter ] = nTableIndex;
+ }
+ }
+ }
+
+ // applying text
+ OutlinerParaObject* pParaObject = pObj->GetOutlinerParaObject();
+ if ( pParaObject )
+ {
+ SdrText* pSdrText = pTable->getText( nTableIndex );
+ if ( pSdrText )
+ pSdrText->SetOutlinerParaObject(*pParaObject);
+ }
+ }
+ }
+ }
+ aGroupIter.Reset();
+ while( aGroupIter.IsMore() )
+ {
+ SdrObject* pObj( aGroupIter.Next() );
+ if ( IsLine( pObj ) )
+ {
+ std::vector< sal_Int32 > vPositions; // containing cell indexes + cell position
+ GetLinePositions( pObj, aRows, aColumns, vPositions, pGroup->GetSnapRect() );
+
+ // correcting merged cell position
+ for (auto & vPos : vPositions)
+ {
+ sal_Int32 nOldPosition = vPos & 0xffff;
+ sal_Int32 nOldFlags = vPos & 0xffff0000;
+ sal_Int32 nNewPosition = pMergedCellIndexTable[ nOldPosition ] | nOldFlags;
+ vPos = nNewPosition;
+ }
+ ApplyCellLineAttributes( pObj, xTable, vPositions, aColumns.size() );
+ }
+ }
+ pMergedCellIndexTable.reset();
+
+ // we are replacing the whole group object by a single table object, so
+ // possibly connections to the group object have to be removed.
+ if ( pSolverContainer )
+ {
+ for (auto & pPtr : pSolverContainer->aCList)
+ {
+ // check connections to the group object
+ if ( pPtr->pAObj == pGroup )
+ pPtr->pAObj = nullptr;
+ if ( pPtr->pBObj == pGroup )
+ pPtr->pBObj = nullptr;
+
+ // check connections to all its subobjects
+ SdrObjListIter aIter( *pGroup, SdrIterMode::DeepWithGroups );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pPartObj = aIter.Next();
+ if ( pPtr->pAObj == pPartObj )
+ pPtr->pAObj = nullptr;
+ if ( pPtr->pBObj == pPartObj )
+ pPtr->pBObj = nullptr;
+ }
+ //In MS, the one_row_one_col table is made up of five
+ //shape,the connector is connected to some part of a
+ //table. But for us, the connector is connected to the
+ //whole group table,so the connector obj is a group
+ //table when export by us. We should process this
+ //situation when importing.
+ if ( pPtr->pAObj == pGroup )
+ pPtr->pAObj = pTable;
+ if ( pPtr->pBObj == pGroup )
+ pPtr->pBObj = pTable;
+ }
+ }
+ pTable->uno_unlock();
+ pTable->SetSnapRect( pGroup->GetSnapRect() );
+ pRet = pTable;
+
+ //Remove Objects from shape map
+ SdrObjListIter aIter( *pGroup, SdrIterMode::DeepWithGroups );
+ while( aIter.IsMore() )
+ {
+ SdrObject* pPartObj = aIter.Next();
+ removeShapeId(pPartObj);
+ // ofz#41510 make sure rBackgroundColoredObjects doesn't contain deleted objects
+ std::replace(rBackgroundColoredObjects.begin(), rBackgroundColoredObjects.end(), pPartObj, pRet);
+ }
+
+ SdrObject::Free( pGroup );
+ }
+ catch( const Exception& )
+ {
+ pTable->uno_unlock();
+ SdrObject* pObj = pTable;
+ SdrObject::Free( pObj );
+ }
+
+ return pRet;
+}
+
+bool SdrPowerPointImport::IsVerticalText() const
+{
+ bool bVerticalText = false;
+ if ( IsProperty( DFF_Prop_txflTextFlow ) )
+ {
+ auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
+ switch( eTextFlow )
+ {
+ case mso_txflTtoBA : // Top to Bottom @-font, above -> below
+ case mso_txflTtoBN : // Top to Bottom non-@, above -> below
+ case mso_txflVertN : // Vertical, non-@, above -> below
+ bVerticalText = !bVerticalText;
+ break;
+ default: break;
+ }
+ }
+
+ return bVerticalText;
+}
+
+void SdrPowerPointImport::ApplyTextAnchorAttributes( PPTTextObj const & rTextObj, SfxItemSet& rSet ) const
+{
+ SdrTextVertAdjust eTVA;
+ SdrTextHorzAdjust eTHA;
+
+ sal_uInt32 nTextFlags = rTextObj.GetTextFlags();
+
+ nTextFlags &= PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT
+ | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_CENTER | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_BLOCK;
+
+ if ( IsVerticalText() )
+ {
+ eTVA = SDRTEXTVERTADJUST_BLOCK;
+ eTHA = SDRTEXTHORZADJUST_CENTER;
+
+ // read text anchor
+ auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ case mso_anchorTopCentered:
+ eTHA = SDRTEXTHORZADJUST_RIGHT;
+ break;
+
+ case mso_anchorMiddle :
+ case mso_anchorMiddleCentered:
+ eTHA = SDRTEXTHORZADJUST_CENTER;
+ break;
+
+ case mso_anchorBottom:
+ case mso_anchorBottomCentered:
+ eTHA = SDRTEXTHORZADJUST_LEFT;
+ break;
+
+ default:
+ break;
+ }
+ // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ {
+ // check if it is sensible to use the centered alignment
+ sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT;
+ if ( ( nTextFlags & nMask ) != nMask ) // if the textobject has left or also right aligned paragraphs
+ eTVA = SDRTEXTVERTADJUST_CENTER; // the text has to be displayed using the full width;
+ }
+ break;
+
+ default :
+ {
+ if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT )
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ else if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT )
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ }
+ break;
+ }
+ }
+ else
+ {
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ eTHA = SDRTEXTHORZADJUST_BLOCK;
+
+ // read text anchor
+ auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, mso_anchorTop);
+
+ switch( eTextAnchor )
+ {
+ case mso_anchorTop:
+ case mso_anchorTopCentered:
+ eTVA = SDRTEXTVERTADJUST_TOP;
+ break;
+
+ case mso_anchorMiddle :
+ case mso_anchorMiddleCentered:
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ break;
+
+ case mso_anchorBottom:
+ case mso_anchorBottomCentered:
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ break;
+
+ default:
+ break;
+ }
+
+ // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction
+ switch ( eTextAnchor )
+ {
+ case mso_anchorTopCentered :
+ case mso_anchorMiddleCentered :
+ case mso_anchorBottomCentered :
+ {
+ // check if it is sensible to use the centered alignment
+ sal_uInt32 nMask = PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT | PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT;
+ if ( ( nTextFlags & nMask ) != nMask ) // if the textobject has left or also right aligned paragraphs
+ eTHA = SDRTEXTHORZADJUST_CENTER; // the text has to be displayed using the full width;
+ }
+ break;
+
+ default :
+ {
+ if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_LEFT )
+ eTHA = SDRTEXTHORZADJUST_LEFT;
+ else if ( nTextFlags == PPT_TEXTOBJ_FLAGS_PARA_ALIGNMENT_USED_RIGHT )
+ eTHA = SDRTEXTHORZADJUST_RIGHT;
+ }
+ break;
+ }
+ }
+ rSet.Put( SdrTextVertAdjustItem( eTVA ) );
+ rSet.Put( SdrTextHorzAdjustItem( eTHA ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/svxmsbas2.cxx b/filter/source/msfilter/svxmsbas2.cxx
new file mode 100644
index 000000000..8a4ce43f1
--- /dev/null
+++ b/filter/source/msfilter/svxmsbas2.cxx
@@ -0,0 +1,80 @@
+/* -*- 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/.
+ *
+ * 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 <config_features.h>
+
+#include <basic/basmgr.hxx>
+#include <sfx2/objsh.hxx>
+#include <sot/storage.hxx>
+#include <svx/svxerr.hxx>
+#include <filter/msfilter/svxmsbas.hxx>
+
+using namespace com::sun::star;
+
+ErrCode SvxImportMSVBasic::SaveOrDelMSVBAStorage( bool bSaveInto,
+ const OUString& rStorageName )
+{
+ ErrCode nRet = ERRCODE_NONE;
+ uno::Reference < embed::XStorage > xSrcRoot( rDocSh.GetStorage() );
+ OUString aDstStgName( GetMSBasicStorageName() );
+ tools::SvRef<SotStorage> xVBAStg( SotStorage::OpenOLEStorage( xSrcRoot, aDstStgName,
+ StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL ) );
+ if( xVBAStg.is() && !xVBAStg->GetError() )
+ {
+ xVBAStg = nullptr;
+ if( bSaveInto )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ BasicManager *pBasicMan = rDocSh.GetBasicManager();
+ if( pBasicMan && pBasicMan->IsBasicModified() )
+ nRet = ERRCODE_SVX_MODIFIED_VBASIC_STORAGE;
+#endif
+ tools::SvRef<SotStorage> xSrc = SotStorage::OpenOLEStorage( xSrcRoot, aDstStgName, StreamMode::STD_READ );
+ tools::SvRef<SotStorage> xDst = xRoot->OpenSotStorage( rStorageName, StreamMode::READWRITE | StreamMode::TRUNC );
+ xSrc->CopyTo( xDst.get() );
+ xDst->Commit();
+ ErrCode nError = xDst->GetError();
+ if ( nError == ERRCODE_NONE )
+ nError = xSrc->GetError();
+ if ( nError != ERRCODE_NONE )
+ xRoot->SetError( nError );
+ }
+ }
+
+ return nRet;
+}
+
+// check if the MS-VBA-Storage exists in the RootStorage of the DocShell.
+// If it exists, then return the WarningId for losing the information.
+ErrCode SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( SfxObjectShell &rDocSh)
+{
+ uno::Reference < embed::XStorage > xSrcRoot( rDocSh.GetStorage() );
+ tools::SvRef<SotStorage> xVBAStg( SotStorage::OpenOLEStorage( xSrcRoot, GetMSBasicStorageName(),
+ StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL ));
+ return ( xVBAStg.is() && !xVBAStg->GetError() )
+ ? ERRCODE_SVX_VBASIC_STORAGE_EXIST
+ : ERRCODE_NONE;
+}
+
+OUString SvxImportMSVBasic::GetMSBasicStorageName()
+{
+ return "_MS_VBA_Macros";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/util.cxx b/filter/source/msfilter/util.cxx
new file mode 100644
index 000000000..aea2f816b
--- /dev/null
+++ b/filter/source/msfilter/util.cxx
@@ -0,0 +1,1340 @@
+/* -*- 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 <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <rtl/ustring.hxx>
+#include <comphelper/string.hxx>
+#include <unotools/fontcvt.hxx>
+#include <unotools/fontdefs.hxx>
+#include <utility>
+#include <vcl/BitmapPalette.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <filter/msfilter/util.hxx>
+#include <o3tl/string_view.hxx>
+#include <memory>
+#include <unordered_map>
+
+namespace msfilter::util {
+
+rtl_TextEncoding getBestTextEncodingFromLocale(const css::lang::Locale &rLocale)
+{
+ // Obviously not comprehensive, feel free to expand these, they're for ultimate fallbacks
+ // in last-ditch broken-file-format cases to guess the right 8bit encodings
+ const OUString &rLanguage = rLocale.Language;
+ if (rLanguage == "cs" || rLanguage == "hu" || rLanguage == "pl")
+ return RTL_TEXTENCODING_MS_1250;
+ if (rLanguage == "ru" || rLanguage == "uk")
+ return RTL_TEXTENCODING_MS_1251;
+ if (rLanguage == "el")
+ return RTL_TEXTENCODING_MS_1253;
+ if (rLanguage == "tr")
+ return RTL_TEXTENCODING_MS_1254;
+ if (rLanguage == "lt")
+ return RTL_TEXTENCODING_MS_1257;
+ if (rLanguage == "th")
+ return RTL_TEXTENCODING_MS_874;
+ if (rLanguage == "vi")
+ return RTL_TEXTENCODING_MS_1258;
+ return RTL_TEXTENCODING_MS_1252;
+}
+
+::Color BGRToRGB(sal_uInt32 nColor)
+{
+ sal_uInt8
+ r(static_cast<sal_uInt8>(nColor&0xFF)),
+ g(static_cast<sal_uInt8>((nColor>>8)&0xFF)),
+ b(static_cast<sal_uInt8>((nColor>>16)&0xFF)),
+ t(static_cast<sal_uInt8>((nColor>>24)&0xFF));
+ return ::Color(ColorTransparency, t, r, g, b);
+}
+
+DateTime DTTM2DateTime( tools::Long lDTTM )
+{
+ /*
+ mint short :6 0000003F minutes (0-59)
+ hr short :5 000007C0 hours (0-23)
+ dom short :5 0000F800 days of month (1-31)
+ mon short :4 000F0000 months (1-12)
+ yr short :9 1FF00000 years (1900-2411)-1900
+ wdy short :3 E0000000 weekday(Sunday=0
+ Monday=1
+ ( wdy can be ignored ) Tuesday=2
+ Wednesday=3
+ Thursday=4
+ Friday=5
+ Saturday=6)
+ */
+ DateTime aDateTime(Date( 0 ), ::tools::Time( 0 ));
+ if( lDTTM )
+ {
+ sal_uInt16 lMin = static_cast<sal_uInt16>(lDTTM & 0x0000003F);
+ lDTTM >>= 6;
+ sal_uInt16 lHour= static_cast<sal_uInt16>(lDTTM & 0x0000001F);
+ lDTTM >>= 5;
+ sal_uInt16 lDay = static_cast<sal_uInt16>(lDTTM & 0x0000001F);
+ lDTTM >>= 5;
+ sal_uInt16 lMon = static_cast<sal_uInt16>(lDTTM & 0x0000000F);
+ lDTTM >>= 4;
+ sal_uInt16 lYear= static_cast<sal_uInt16>(lDTTM & 0x000001FF) + 1900;
+ aDateTime = DateTime(Date(lDay, lMon, lYear), tools::Time(lHour, lMin));
+ }
+ return aDateTime;
+}
+
+sal_Unicode bestFitOpenSymbolToMSFont(sal_Unicode cChar,
+ rtl_TextEncoding& rChrSet, OUString& rFontName)
+{
+ std::unique_ptr<StarSymbolToMSMultiFont> pConvert(CreateStarSymbolToMSMultiFont());
+ OUString sFont = pConvert->ConvertChar(cChar);
+ pConvert.reset();
+ if (!sFont.isEmpty())
+ {
+ cChar = static_cast< sal_Unicode >(cChar | 0xF000);
+ rFontName = sFont;
+ rChrSet = RTL_TEXTENCODING_SYMBOL;
+ }
+ else if (cChar < 0xE000 || cChar > 0xF8FF)
+ {
+ /*
+ Ok we can't fit into a known windows unicode font, but
+ we are not in the private area, so we are a
+ standardized symbol, so turn off the symbol bit and
+ let words own font substitution kick in
+ */
+ rChrSet = RTL_TEXTENCODING_UNICODE;
+ sal_Int32 nIndex = 0;
+ rFontName = ::GetNextFontToken(rFontName, nIndex);
+ }
+ else
+ {
+ /*
+ Well we don't have an available substitution, and we're
+ in our private area, so give up and show a standard
+ bullet symbol
+ */
+ rFontName = "Wingdings";
+ cChar = u'\x6C';
+ }
+ return cChar;
+}
+
+
+OString ConvertColor( const Color &rColor )
+{
+ static constexpr OStringLiteral AUTO( "auto" );
+
+ if ( rColor == COL_AUTO )
+ return AUTO;
+
+ const char pHexDigits[] = "0123456789ABCDEF";
+ char pBuffer[] = "000000";
+
+ pBuffer[0] = pHexDigits[ ( rColor.GetRed() >> 4 ) & 0x0F ];
+ pBuffer[1] = pHexDigits[ rColor.GetRed() & 0x0F ];
+ pBuffer[2] = pHexDigits[ ( rColor.GetGreen() >> 4 ) & 0x0F ];
+ pBuffer[3] = pHexDigits[ rColor.GetGreen() & 0x0F ];
+ pBuffer[4] = pHexDigits[ ( rColor.GetBlue() >> 4 ) & 0x0F ];
+ pBuffer[5] = pHexDigits[ rColor.GetBlue() & 0x0F ];
+
+ return OString( pBuffer );
+}
+
+OUString ConvertColorOU( const Color &rColor )
+{
+ static constexpr OUStringLiteral AUTO( u"auto" );
+
+ if ( rColor == COL_AUTO )
+ return AUTO;
+
+ const char pHexDigits[] = "0123456789ABCDEF";
+ sal_Unicode pBuffer[] = u"000000";
+
+ pBuffer[0] = pHexDigits[ ( rColor.GetRed() >> 4 ) & 0x0F ];
+ pBuffer[1] = pHexDigits[ rColor.GetRed() & 0x0F ];
+ pBuffer[2] = pHexDigits[ ( rColor.GetGreen() >> 4 ) & 0x0F ];
+ pBuffer[3] = pHexDigits[ rColor.GetGreen() & 0x0F ];
+ pBuffer[4] = pHexDigits[ ( rColor.GetBlue() >> 4 ) & 0x0F ];
+ pBuffer[5] = pHexDigits[ rColor.GetBlue() & 0x0F ];
+
+ return OUString( pBuffer );
+}
+
+#define IN2MM100( v ) static_cast< sal_Int32 >( (v) * 2540.0 + 0.5 )
+#define MM2MM100( v ) static_cast< sal_Int32 >( (v) * 100.0 + 0.5 )
+
+// see XclPaperSize pPaperSizeTable in calc and aDinTab in i18nutil
+const ApiPaperSize spPaperSizeTable[] =
+{
+ { 0, 0 }, // 0 - (undefined)
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 1 - Letter paper
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 2 - Letter small paper
+ { IN2MM100( 11 ), IN2MM100( 17 ) }, // 3 - Tabloid paper
+ { IN2MM100( 17 ), IN2MM100( 11 ) }, // 4 - Ledger paper
+ { IN2MM100( 8.5 ), IN2MM100( 14 ) }, // 5 - Legal paper
+ { IN2MM100( 5.5 ), IN2MM100( 8.5 ) }, // 6 - Statement paper
+ { IN2MM100( 7.25 ), IN2MM100( 10.5 ) }, // 7 - Executive paper
+ { MM2MM100( 297 ), MM2MM100( 420 ) }, // 8 - A3 paper
+ { MM2MM100( 210 ), MM2MM100( 297 ) }, // 9 - A4 paper
+ { MM2MM100( 210 ), MM2MM100( 297 ) }, // 10 - A4 small paper
+ { MM2MM100( 148 ), MM2MM100( 210 ) }, // 11 - A5 paper
+ /* for JIS vs ISO B confusion see:
+ https://docs.microsoft.com/en-us/windows/win32/intl/paper-sizes
+ http://wiki.openoffice.org/wiki/DefaultPaperSize comments
+ http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf */
+ { MM2MM100( 257 ), MM2MM100( 364 ) }, // 12 - B4 (JIS) paper
+ { MM2MM100( 182 ), MM2MM100( 257 ) }, // 13 - B5 (JIS) paper
+ { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 14 - Folio paper
+ { MM2MM100( 215 ), MM2MM100( 275 ) }, // 15 - Quarto paper
+ { IN2MM100( 10 ), IN2MM100( 14 ) }, // 16 - Standard paper
+ { IN2MM100( 11 ), IN2MM100( 17 ) }, // 17 - Standard paper
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 18 - Note paper
+ { IN2MM100( 3.875 ), IN2MM100( 8.875 ) }, // 19 - #9 envelope
+ { IN2MM100( 4.125 ), IN2MM100( 9.5 ) }, // 20 - #10 envelope
+ { IN2MM100( 4.5 ), IN2MM100( 10.375 ) }, // 21 - #11 envelope
+ { IN2MM100( 4.75 ), IN2MM100( 11 ) }, // 22 - #12 envelope
+ { IN2MM100( 5 ), IN2MM100( 11.5 ) }, // 23 - #14 envelope
+ { IN2MM100( 17 ), IN2MM100( 22 ) }, // 24 - C paper
+ { IN2MM100( 22 ), IN2MM100( 34 ) }, // 25 - D paper
+ { IN2MM100( 34 ), IN2MM100( 44 ) }, // 26 - E paper
+ { MM2MM100( 110 ), MM2MM100( 220 ) }, // 27 - DL envelope
+ { MM2MM100( 162 ), MM2MM100( 229 ) }, // 28 - C5 envelope
+ { MM2MM100( 324 ), MM2MM100( 458 ) }, // 29 - C3 envelope
+ { MM2MM100( 229 ), MM2MM100( 324 ) }, // 30 - C4 envelope
+ { MM2MM100( 114 ), MM2MM100( 162 ) }, // 31 - C6 envelope
+ { MM2MM100( 114 ), MM2MM100( 229 ) }, // 32 - C65 envelope
+ { MM2MM100( 250 ), MM2MM100( 353 ) }, // 33 - B4 envelope
+ { MM2MM100( 176 ), MM2MM100( 250 ) }, // 34 - B5 envelope
+ { MM2MM100( 176 ), MM2MM100( 125 ) }, // 35 - B6 envelope
+ { MM2MM100( 110 ), MM2MM100( 230 ) }, // 36 - Italy envelope
+ { IN2MM100( 3.875 ), IN2MM100( 7.5 ) }, // 37 - Monarch envelope
+ { IN2MM100( 3.625 ), IN2MM100( 6.5 ) }, // 38 - 6 3/4 envelope
+ { IN2MM100( 14.875 ), IN2MM100( 11 ) }, // 39 - US standard fanfold
+ { IN2MM100( 8.5 ), IN2MM100( 12 ) }, // 40 - German standard fanfold
+ { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 41 - German legal fanfold
+ { MM2MM100( 250 ), MM2MM100( 353 ) }, // 42 - ISO B4
+ { MM2MM100( 200 ), MM2MM100( 148 ) }, // 43 - Japanese double postcard
+ { IN2MM100( 9 ), IN2MM100( 11 ) }, // 44 - Standard paper
+ { IN2MM100( 10 ), IN2MM100( 11 ) }, // 45 - Standard paper
+ { IN2MM100( 15 ), IN2MM100( 11 ) }, // 46 - Standard paper
+ { MM2MM100( 220 ), MM2MM100( 220 ) }, // 47 - Invite envelope
+ { 0, 0 }, // 48 - (undefined)
+ { 0, 0 }, // 49 - (undefined)
+ /* See: https://docs.microsoft.com/en-us/windows/win32/intl/paper-sizes */
+ { IN2MM100( 9.5 ), IN2MM100( 12 ) }, // 50 - Letter extra paper
+ { IN2MM100( 9.5 ), IN2MM100( 15 ) }, // 51 - Legal extra paper
+ { IN2MM100( 11.69 ), IN2MM100( 18 ) }, // 52 - Tabloid extra paper
+ { MM2MM100( 235 ), MM2MM100( 322 ) }, // 53 - A4 extra paper
+ { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 54 - Letter transverse paper
+ { MM2MM100( 210 ), MM2MM100( 297 ) }, // 55 - A4 transverse paper
+ { IN2MM100( 9.5 ), IN2MM100( 12 ) }, // 56 - Letter extra transverse paper
+ { MM2MM100( 227 ), MM2MM100( 356 ) }, // 57 - SuperA/SuperA/A4 paper
+ { MM2MM100( 305 ), MM2MM100( 487 ) }, // 58 - SuperB/SuperB/A3 paper
+ { IN2MM100( 8.5 ), IN2MM100( 12.69 ) }, // 59 - Letter plus paper
+ { MM2MM100( 210 ), MM2MM100( 330 ) }, // 60 - A4 plus paper
+ { MM2MM100( 148 ), MM2MM100( 210 ) }, // 61 - A5 transverse paper
+ { MM2MM100( 182 ), MM2MM100( 257 ) }, // 62 - JIS B5 transverse paper
+ { MM2MM100( 322 ), MM2MM100( 445 ) }, // 63 - A3 extra paper
+ { MM2MM100( 174 ), MM2MM100( 235 ) }, // 64 - A5 extra paper
+ { MM2MM100( 201 ), MM2MM100( 276 ) }, // 65 - ISO B5 extra paper
+ { MM2MM100( 420 ), MM2MM100( 594 ) }, // 66 - A2 paper
+ { MM2MM100( 297 ), MM2MM100( 420 ) }, // 67 - A3 transverse paper
+ { MM2MM100( 322 ), MM2MM100( 445 ) }, // 68 - A3 extra transverse paper
+ { MM2MM100( 200 ), MM2MM100( 148 ) }, // 69 - Japanese double postcard
+ { MM2MM100( 105 ), MM2MM100( 148 ), }, // 70 - A6 paper
+ { 0, 0 }, // 71 - Japanese Envelope Kaku #2
+ { 0, 0 }, // 72 - Japanese Envelope Kaku #3
+ { 0, 0 }, // 73 - Japanese Envelope Chou #3
+ { 0, 0 }, // 74 - Japanese Envelope Chou #4
+ { IN2MM100( 11 ), IN2MM100( 8.5 ) }, // 75 - Letter Rotated
+ { MM2MM100( 420 ), MM2MM100( 297 ) }, // 76 - A3 Rotated
+ { MM2MM100( 297 ), MM2MM100( 210 ) }, // 77 - A4 Rotated
+ { MM2MM100( 210 ), MM2MM100( 148 ) }, // 78 - A5 Rotated
+ { MM2MM100( 364 ), MM2MM100( 257 ) }, // 79 - B4 (JIS) Rotated
+ { MM2MM100( 257 ), MM2MM100( 182 ) }, // 80 - B5 (JIS) Rotated
+ { MM2MM100( 148 ), MM2MM100( 100 ) }, // 81 - Japanese Postcard Rotated
+ { MM2MM100( 148 ), MM2MM100( 200 ) }, // 82 - Double Japanese Postcard Rotated
+ { MM2MM100( 148 ), MM2MM100( 105 ) }, // 83 - A6 Rotated
+ { 0, 0 }, // 84 - Japanese Envelope Kaku #2 Rotated
+ { 0, 0 }, // 85 - Japanese Envelope Kaku #3 Rotated
+ { 0, 0 }, // 86 - Japanese Envelope Chou #3 Rotated
+ { 0, 0 }, // 87 - Japanese Envelope Chou #4 Rotated
+ { MM2MM100( 128 ), MM2MM100( 182 ) }, // 88 - B6 (JIS)
+ { MM2MM100( 182 ), MM2MM100( 128 ) }, // 89 - B6 (JIS) Rotated
+ { IN2MM100( 12 ), IN2MM100( 11 ) } // 90 - 12x11
+};
+
+sal_Int32 PaperSizeConv::getMSPaperSizeIndex( const css::awt::Size& rSize )
+{
+ // Need to find the best match for current size
+ sal_Int32 nDeltaWidth = 0;
+ sal_Int32 nDeltaHeight = 0;
+
+ sal_Int32 nPaperSizeIndex = 0; // Undefined
+ const ApiPaperSize* pItem = spPaperSizeTable;
+ const ApiPaperSize* pEnd = spPaperSizeTable + SAL_N_ELEMENTS( spPaperSizeTable );
+ for ( ; pItem != pEnd; ++pItem )
+ {
+ sal_Int32 nCurDeltaHeight = std::abs( pItem->mnHeight - rSize.Height );
+ sal_Int32 nCurDeltaWidth = std::abs( pItem->mnWidth - rSize.Width );
+ if ( pItem == spPaperSizeTable ) // initialize delta with first item
+ {
+ nDeltaWidth = nCurDeltaWidth;
+ nDeltaHeight = nCurDeltaHeight;
+ }
+ else
+ {
+ if ( nCurDeltaWidth < nDeltaWidth && nCurDeltaHeight < nDeltaHeight )
+ {
+ nDeltaWidth = nCurDeltaWidth;
+ nDeltaHeight = nCurDeltaHeight;
+ nPaperSizeIndex = (pItem - spPaperSizeTable);
+ }
+ }
+ }
+ sal_Int32 nTol = 10; // hmm not sure is this the best way
+ if ( nDeltaWidth <= nTol && nDeltaHeight <= nTol )
+ return nPaperSizeIndex;
+ return 0;
+}
+
+const ApiPaperSize& PaperSizeConv::getApiSizeForMSPaperSizeIndex( sal_Int32 nMSOPaperIndex )
+{
+ if ( nMSOPaperIndex < 0 || nMSOPaperIndex > sal_Int32(SAL_N_ELEMENTS( spPaperSizeTable )) - 1 )
+ return spPaperSizeTable[ 0 ];
+ return spPaperSizeTable[ nMSOPaperIndex ];
+}
+
+std::u16string_view findQuotedText( std::u16string_view rCommand,
+ const char* cStartQuote, const sal_Unicode uEndQuote )
+{
+ std::u16string_view sRet;
+ OUString sStartQuote( OUString::createFromAscii(cStartQuote) );
+ size_t nStartIndex = rCommand.find( sStartQuote );
+ if( nStartIndex != std::u16string_view::npos )
+ {
+ sal_Int32 nStartLength = sStartQuote.getLength();
+ size_t nEndIndex = rCommand.find( uEndQuote, nStartIndex + nStartLength);
+ if( nEndIndex != std::u16string_view::npos && nEndIndex > nStartIndex )
+ {
+ sRet = rCommand.substr( nStartIndex + nStartLength, nEndIndex - nStartIndex - nStartLength);
+ }
+ }
+ return sRet;
+
+}
+
+WW8ReadFieldParams::WW8ReadFieldParams( OUString _aData )
+ : aData(std::move( _aData ))
+ , nFnd( 0 )
+ , nNext( 0 )
+ , nSavPtr( 0 )
+{
+
+ /*
+ First look for an opening bracket or a space or a question mark or a backslash, so that the field (i.e. INCLUDEPICTURE or EINFUEGENGRAFIK or...) gets read over
+ */
+ const sal_Int32 nLen = aData.getLength();
+
+ while ( nNext<nLen && aData[nNext]==' ' )
+ ++nNext;
+
+ while ( nNext<nLen )
+ {
+ const sal_Unicode c = aData[nNext];
+ if ( c==' ' || c=='"' || c=='\\' || c==132 || c==0x201c )
+ break;
+ ++nNext;
+ }
+
+ nFnd = nNext;
+ nSavPtr = nNext;
+}
+
+OUString WW8ReadFieldParams::GetResult() const
+{
+ if (nFnd<0 && nSavPtr>nFnd)
+ return OUString();
+ else
+ {
+ return nSavPtr < nFnd ? aData.copy(nFnd) : aData.copy(nFnd, nSavPtr-nFnd);
+ }
+}
+
+
+bool WW8ReadFieldParams::GoToTokenParam()
+{
+ const sal_Int32 nOld = nNext;
+ if( -2 == SkipToNextToken() )
+ return GetTokenSttPtr()>=0;
+ nNext = nOld;
+ return false;
+}
+
+// ret: -2: NOT a '\' parameter but normal text
+sal_Int32 WW8ReadFieldParams::SkipToNextToken()
+{
+ if ( nNext<0 || nNext>=aData.getLength() )
+ return -1;
+
+ nFnd = FindNextStringPiece(nNext);
+ if ( nFnd<0 )
+ return -1;
+
+ nSavPtr = nNext;
+
+ if (nFnd+1<aData.getLength() && aData[nFnd+1]!='\\' && aData[nFnd]=='\\')
+ {
+ const sal_Int32 nRet = aData[++nFnd];
+ nNext = ++nFnd; // and set after
+ return nRet;
+ }
+
+ if ( nSavPtr>0 && (aData[nSavPtr-1]=='"' || aData[nSavPtr-1]==0x201d ) )
+ {
+ --nSavPtr;
+ }
+ return -2;
+}
+
+// FindNextPara searches the next backslash parameter or the next string
+// until the next blank or "\" or closing quotation mark
+// or the end of the string of pStr.
+//
+// Output ppNext (if ppNext != 0) search begin of next parameter resp. 0
+//
+// Return value: 0 if end of string reached,
+// otherwise beginning of the parameter resp. string
+//
+sal_Int32 WW8ReadFieldParams::FindNextStringPiece(const sal_Int32 nStart)
+{
+ const sal_Int32 nLen = aData.getLength();
+ sal_Int32 n = nStart<0 ? nFnd : nStart; // start
+ sal_Int32 n2; // end
+
+ nNext = -1; // if not found -> Default
+
+ while ( n<nLen && aData[n]==' ' )
+ ++n;
+
+ if ( n==nLen )
+ return -1;
+
+ if ( aData[n]==0x13 )
+ {
+ // Skip the nested field code since it's not supported
+ while ( n<nLen && aData[n]!=0x14 )
+ ++n;
+ if ( n==nLen )
+ return -1;
+ }
+
+ // quotation marks before paragraph?
+ if ( aData[n]=='"' || aData[n]==0x201c || aData[n]==132 || aData[n]==0x14 )
+ {
+ n++; // read over quotation marks
+ n2 = n; // search for the end from here on
+ while( (nLen > n2)
+ && (aData[n2] != '"')
+ && (aData[n2] != 0x201d)
+ && (aData[n2] != 147)
+ && (aData[n2] != 0x15) )
+ n2++; // search for the end of the paragraph
+ }
+ else // no quotation mark
+ {
+ n2 = n; // search for the end from here on
+ while ( n2<nLen && aData[n2]!=' ' ) // search for the end of the paragraph
+ {
+ if ( aData[n2]=='\\' )
+ {
+ if ( n2+1<nLen && aData[n2+1]=='\\' )
+ n2 += 2; // double backslash -> OK
+ else
+ {
+ if( n2 > n )
+ n2--;
+ break; // single backslash -> end
+ }
+ }
+ else
+ n2++; // no backslash -> OK
+ }
+ }
+ if( nLen > n2 )
+ {
+ if (aData[n2]!=' ') ++n2;
+ nNext = n2;
+ }
+ return n;
+}
+
+
+// read parameters "1-3" or 1-3 with both values between 1 and nMax
+bool WW8ReadFieldParams::GetTokenSttFromTo(sal_Int32* pFrom, sal_Int32* pTo, sal_Int32 nMax)
+{
+ sal_Int32 nStart = 0;
+ sal_Int32 nEnd = 0;
+ if ( GoToTokenParam() )
+ {
+
+ const OUString sParams( GetResult() );
+
+ sal_Int32 nIndex = 0;
+ const std::u16string_view sStart = o3tl::getToken(sParams, 0, '-', nIndex);
+ if (nIndex>=0)
+ {
+ nStart = o3tl::toInt32(sStart);
+ nEnd = o3tl::toInt32(sParams.subView(nIndex));
+ }
+ }
+ if( pFrom ) *pFrom = nStart;
+ if( pTo ) *pTo = nEnd;
+
+ return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd);
+}
+
+static EquationResult Read_SubF_Combined(WW8ReadFieldParams& rReadParam)
+{
+ EquationResult aResult;
+
+ OUString sCombinedCharacters;
+ WW8ReadFieldParams aOriFldParam = rReadParam;
+ const sal_Int32 cGetChar = rReadParam.SkipToNextToken();
+ switch( cGetChar )
+ {
+ case 'a':
+ case 'A':
+ if ( !rReadParam.GetResult().startsWithIgnoreAsciiCase("d") )
+ {
+ break;
+ }
+ (void)rReadParam.SkipToNextToken();
+ [[fallthrough]];
+ case -2:
+ {
+ if ( rReadParam.GetResult().startsWithIgnoreAsciiCase("(") )
+ {
+ for (int i=0;i<2;i++)
+ {
+ if ('s' == rReadParam.SkipToNextToken())
+ {
+ const sal_Int32 cChar = rReadParam.SkipToNextToken();
+ if (-2 != rReadParam.SkipToNextToken())
+ break;
+ const OUString sF = rReadParam.GetResult();
+ if ((('u' == cChar) && sF.startsWithIgnoreAsciiCase("p"))
+ || (('d' == cChar) && sF.startsWithIgnoreAsciiCase("o")))
+ {
+ if (-2 == rReadParam.SkipToNextToken())
+ {
+ OUString sPart = rReadParam.GetResult();
+ sal_Int32 nBegin = sPart.indexOf('(');
+
+ // Word disallows brackets in this field, which
+ // aids figuring out the case of an end of )) vs )
+ sal_Int32 nEnd = sPart.indexOf(')');
+
+ if (nBegin != -1 && nEnd != -1)
+ {
+ sCombinedCharacters +=
+ sPart.subView(nBegin+1,nEnd-nBegin-1);
+ }
+ }
+ }
+ }
+ }
+ if (!sCombinedCharacters.isEmpty())
+ {
+ aResult.sType = "CombinedCharacters";
+ aResult.sResult = sCombinedCharacters;
+ }
+ else
+ {
+ const OUString sPart = aOriFldParam.GetResult();
+ sal_Int32 nBegin = sPart.indexOf('(');
+ sal_Int32 nEnd = sPart.indexOf(',');
+ if ( nEnd == -1 )
+ {
+ nEnd = sPart.indexOf(')');
+ }
+ if ( nBegin != -1 && nEnd != -1 )
+ {
+ // skip certain leading characters
+ for (int i = nBegin;i < nEnd-1;i++)
+ {
+ const sal_Unicode cC = sPart[nBegin+1];
+ if ( cC < 32 )
+ {
+ nBegin++;
+ }
+ else
+ break;
+ }
+ sCombinedCharacters = sPart.copy( nBegin+1, nEnd-nBegin-1 );
+ if ( !sCombinedCharacters.isEmpty() )
+ {
+ aResult.sType = "Input";
+ aResult.sResult = sCombinedCharacters;
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return aResult;
+}
+
+EquationResult ParseCombinedChars(const OUString& rStr)
+{
+ EquationResult aResult;
+ WW8ReadFieldParams aReadParam( rStr );
+ const sal_Int32 cChar = aReadParam.SkipToNextToken();
+ if ('o' == cChar || 'O' == cChar)
+ aResult = Read_SubF_Combined(aReadParam);
+ return aResult;
+}
+
+OString GetOOXMLPresetGeometry( std::u16string_view rShapeType )
+{
+ typedef std::unordered_map<std::u16string_view, OString> CustomShapeTypeTranslationHashMap;
+ static const CustomShapeTypeTranslationHashMap aCustomShapeTypeTranslationHashMap{
+ // { "non-primitive", mso_sptMin },
+ { u"frame", "frame" },
+ { u"rectangle", "rect" },
+ { u"round-rectangle", "roundRect" },
+ { u"ellipse", "ellipse" },
+ { u"diamond", "diamond" },
+ { u"isosceles-triangle", "triangle" },
+ { u"right-triangle", "rtTriangle" },
+ { u"parallelogram", "parallelogram" },
+ { u"trapezoid", "trapezoid" },
+ { u"hexagon", "hexagon" },
+ { u"octagon", "octagon" },
+ { u"cross", "plus" },
+ { u"star5", "star5" },
+ { u"right-arrow", "rightArrow" },
+ // { u"mso-spt14", mso_sptThickArrow },
+ { u"pentagon-right", "homePlate" },
+ { u"cube", "cube" },
+ // { u"mso-spt17", mso_sptBalloon },
+ // { u"mso-spt18", mso_sptSeal },
+ { u"mso-spt19", "arc" },
+ { u"mso-spt20", "line" },
+ { u"mso-spt21", "plaque" },
+ { u"can", "can" },
+ { u"ring", "donut" },
+ { u"mso-spt24", "textPlain" },
+ { u"mso-spt25", "textStop" },
+ { u"mso-spt26", "textTriangle" },
+ { u"mso-spt27", "textCanDown" },
+ { u"mso-spt28", "textWave1" },
+ { u"mso-spt29", "textArchUpPour" },
+ { u"mso-spt30", "textCanDown" },
+ { u"mso-spt31", "textArchUp" },
+ { u"mso-spt32", "straightConnector1" },
+ { u"mso-spt33", "bentConnector2" },
+ { u"mso-spt34", "bentConnector3" },
+ { u"mso-spt35", "bentConnector4" },
+ { u"mso-spt36", "bentConnector5" },
+ { u"mso-spt37", "curvedConnector2" },
+ { u"mso-spt38", "curvedConnector3" },
+ { u"mso-spt39", "curvedConnector4" },
+ { u"mso-spt40", "curvedConnector5" },
+ { u"mso-spt41", "callout1" },
+ { u"mso-spt42", "callout2" },
+ { u"mso-spt43", "callout3" },
+ { u"mso-spt44", "accentCallout1" },
+ { u"mso-spt45", "accentCallout2" },
+ { u"mso-spt46", "accentCallout3" },
+ { u"line-callout-1", "borderCallout1" },
+ { u"line-callout-2", "borderCallout2" },
+ { u"line-callout-3", "borderCallout3" },
+ { u"mso-spt49", "borderCallout3" },
+ { u"mso-spt50", "accentBorderCallout1" },
+ { u"mso-spt51", "accentBorderCallout2" },
+ { u"mso-spt52", "accentBorderCallout3" },
+ { u"mso-spt53", "ribbon" },
+ { u"mso-spt54", "ribbon2" },
+ { u"chevron", "chevron" },
+ { u"pentagon", "pentagon" },
+ { u"forbidden", "noSmoking" },
+ { u"star8", "star8" },
+ { u"mso-spt59", "star16" },
+ { u"mso-spt60", "star32" },
+ { u"rectangular-callout", "wedgeRectCallout" },
+ { u"round-rectangular-callout", "wedgeRoundRectCallout" },
+ { u"round-callout", "wedgeEllipseCallout" },
+ { u"mso-spt64", "wave" },
+ { u"paper", "foldedCorner" },
+ { u"left-arrow", "leftArrow" },
+ { u"down-arrow", "downArrow" },
+ { u"up-arrow", "upArrow" },
+ { u"left-right-arrow", "leftRightArrow" },
+ { u"up-down-arrow", "upDownArrow" },
+ { u"mso-spt71", "irregularSeal1" },
+ { u"bang", "irregularSeal2" },
+ { u"lightning", "lightningBolt" },
+ { u"heart", "heart" },
+ { u"quad-arrow", "quadArrow" },
+ { u"left-arrow-callout", "leftArrowCallout" },
+ { u"right-arrow-callout", "rightArrowCallout" },
+ { u"up-arrow-callout", "upArrowCallout" },
+ { u"down-arrow-callout", "downArrowCallout" },
+ { u"left-right-arrow-callout", "leftRightArrowCallout" },
+ { u"up-down-arrow-callout", "upDownArrowCallout" },
+ { u"quad-arrow-callout", "quadArrowCallout" },
+ { u"quad-bevel", "bevel" },
+ { u"left-bracket", "leftBracket" },
+ { u"right-bracket", "rightBracket" },
+ { u"left-brace", "leftBrace" },
+ { u"right-brace", "rightBrace" },
+ { u"mso-spt89", "leftUpArrow" },
+ { u"mso-spt90", "bentUpArrow" },
+ { u"mso-spt91", "bentArrow" },
+ { u"star24", "star24" },
+ { u"striped-right-arrow", "stripedRightArrow" },
+ { u"notched-right-arrow", "notchedRightArrow" },
+ { u"block-arc", "blockArc" },
+ { u"smiley", "smileyFace" },
+ { u"vertical-scroll", "verticalScroll" },
+ { u"horizontal-scroll", "horizontalScroll" },
+ { u"circular-arrow", "circularArrow" },
+ { u"mso-spt100", "pie" }, // looks like MSO_SPT is wrong here
+ { u"mso-spt101", "uturnArrow" },
+ { u"mso-spt102", "curvedRightArrow" },
+ { u"mso-spt103", "curvedLeftArrow" },
+ { u"mso-spt104", "curvedUpArrow" },
+ { u"mso-spt105", "curvedDownArrow" },
+ { u"cloud-callout", "cloudCallout" },
+ { u"mso-spt107", "ellipseRibbon" },
+ { u"mso-spt108", "ellipseRibbon2" },
+ { u"flowchart-process", "flowChartProcess" },
+ { u"flowchart-decision", "flowChartDecision" },
+ { u"flowchart-data", "flowChartInputOutput" },
+ { u"flowchart-predefined-process", "flowChartPredefinedProcess" },
+ { u"flowchart-internal-storage", "flowChartInternalStorage" },
+ { u"flowchart-document", "flowChartDocument" },
+ { u"flowchart-multidocument", "flowChartMultidocument" },
+ { u"flowchart-terminator", "flowChartTerminator" },
+ { u"flowchart-preparation", "flowChartPreparation" },
+ { u"flowchart-manual-input", "flowChartManualInput" },
+ { u"flowchart-manual-operation", "flowChartManualOperation" },
+ { u"flowchart-connector", "flowChartConnector" },
+ { u"flowchart-card", "flowChartPunchedCard" },
+ { u"flowchart-punched-tape", "flowChartPunchedTape" },
+ { u"flowchart-summing-junction", "flowChartSummingJunction" },
+ { u"flowchart-or", "flowChartOr" },
+ { u"flowchart-collate", "flowChartCollate" },
+ { u"flowchart-sort", "flowChartSort" },
+ { u"flowchart-extract", "flowChartExtract" },
+ { u"flowchart-merge", "flowChartMerge" },
+ { u"mso-spt129", "flowChartOfflineStorage" },
+ { u"flowchart-stored-data", "flowChartOnlineStorage" },
+ { u"flowchart-sequential-access", "flowChartMagneticTape" },
+ { u"flowchart-magnetic-disk", "flowChartMagneticDisk" },
+ { u"flowchart-direct-access-storage", "flowChartMagneticDrum" },
+ { u"flowchart-display", "flowChartDisplay" },
+ { u"flowchart-delay", "flowChartDelay" },
+ // { u"fontwork-plain-text", "textPlainText" },
+ // { u"fontwork-stop", "textStop" },
+ // { u"fontwork-triangle-up", "textTriangle" },
+ // { u"fontwork-triangle-down", "textTriangleInverted" },
+ // { u"fontwork-chevron-up", "textChevron" },
+ // { u"fontwork-chevron-down", "textChevronInverted" },
+ // { u"mso-spt142", "textRingInside" },
+ // { u"mso-spt143", "textRingOutside" },
+ // { u"fontwork-arch-up-curve", "textArchUpCurve" },
+ // { u"fontwork-arch-down-curve", "textArchDownCurve" },
+ // { u"fontwork-circle-curve", "textCircleCurve" },
+ // { u"fontwork-open-circle-curve", "textButtonCurve" },
+ // { u"fontwork-arch-up-pour", "textArchUpPour" },
+ // { u"fontwork-arch-down-pour", "textArchDownPour" },
+ // { u"fontwork-circle-pour", "textCirclePour" },
+ // { u"fontwork-open-circle-pour", "textButtonPour" },
+ // { u"fontwork-curve-up", "textCurveUp" },
+ // { u"fontwork-curve-down", "textCurveDown" },
+ // { u"fontwork-fade-up-and-right", "textCascadeUp" },
+ // { u"fontwork-fade-up-and-left", "textCascadeDown" },
+ // { u"fontwork-wave", "textWave1" },
+ // { u"mso-spt157", "textWave2" },
+ // { u"mso-spt158", "textWave3" },
+ // { u"mso-spt159", "textWave4" },
+ // { u"fontwork-inflate", "textInflate" },
+ // { u"mso-spt161", "textDeflate" },
+ // { u"mso-spt162", "textInflateBottom" },
+ // { u"mso-spt163", "textDeflateBottom" },
+ // { u"mso-spt164", "textInflateTop" },
+ // { u"mso-spt165", "textDeflateTop" },
+ // { u"mso-spt166", "textDeflateInflate" },
+ // { u"mso-spt167", "textDeflateInflateDeflate" },
+ // { u"fontwork-fade-right", "textFadeRight" },
+ // { u"fontwork-fade-left", "textFadeLeft" },
+ // { u"fontwork-fade-up", "textFadeUp" },
+ // { u"fontwork-fade-down", "textFadeDown" },
+ // { u"fontwork-slant-up", "textSlantUp" },
+ // { u"fontwork-slant-down", "textSlantDown" },
+ // { u"mso-spt174", "textCanUp" },
+ // { u"mso-spt175", "textCanDown" },
+ { u"flowchart-alternate-process", "flowChartAlternateProcess" },
+ { u"flowchart-off-page-connector", "flowChartOffpageConnector" },
+ { u"mso-spt178", "callout1" },
+ { u"mso-spt179", "accentCallout1" },
+ { u"mso-spt180", "borderCallout1" },
+ { u"mso-spt182", "leftRightUpArrow" },
+ { u"sun", "sun" },
+ { u"moon", "moon" },
+ { u"bracket-pair", "bracketPair" },
+ { u"brace-pair", "bracePair" },
+ { u"star4", "star4" },
+ { u"mso-spt188", "doubleWave" },
+ { u"mso-spt189", "actionButtonBlank" },
+ { u"mso-spt190", "actionButtonHome" },
+ { u"mso-spt191", "actionButtonHelp" },
+ { u"mso-spt192", "actionButtonInformation" },
+ { u"mso-spt193", "actionButtonForwardNext" },
+ { u"mso-spt194", "actionButtonBackPrevious" },
+ { u"mso-spt195", "actionButtonEnd" },
+ { u"mso-spt196", "actionButtonBeginning" },
+ { u"mso-spt197", "actionButtonReturn" },
+ { u"mso-spt198", "actionButtonDocument" },
+ { u"mso-spt199", "actionButtonSound" },
+ { u"mso-spt200", "actionButtonMovie" },
+ // { u"mso-spt201", "hostControl" },
+ { u"mso-spt202", "rect" },
+ { u"ooxml-actionButtonSound", "actionButtonSound" },
+ { u"ooxml-borderCallout1", "borderCallout1" },
+ { u"ooxml-plaqueTabs", "plaqueTabs" },
+ { u"ooxml-curvedLeftArrow", "curvedLeftArrow" },
+ { u"ooxml-octagon", "octagon" },
+ { u"ooxml-leftRightRibbon", "leftRightRibbon" },
+ { u"ooxml-actionButtonInformation", "actionButtonInformation" },
+ { u"ooxml-bentConnector5", "bentConnector5" },
+ { u"ooxml-circularArrow", "circularArrow" },
+ { u"ooxml-downArrowCallout", "downArrowCallout" },
+ { u"ooxml-mathMinus", "mathMinus" },
+ { u"ooxml-gear9", "gear9" },
+ { u"ooxml-round1Rect", "round1Rect" },
+ { u"ooxml-sun", "sun" },
+ { u"ooxml-plaque", "plaque" },
+ { u"ooxml-chevron", "chevron" },
+ { u"ooxml-flowChartPreparation", "flowChartPreparation" },
+ { u"ooxml-diagStripe", "diagStripe" },
+ { u"ooxml-pentagon", "pentagon" },
+ { u"ooxml-funnel", "funnel" },
+ { u"ooxml-chartStar", "chartStar" },
+ { u"ooxml-accentBorderCallout1", "accentBorderCallout1" },
+ { u"ooxml-notchedRightArrow", "notchedRightArrow" },
+ { u"ooxml-rightBracket", "rightBracket" },
+ { u"ooxml-flowChartOffpageConnector", "flowChartOffpageConnector" },
+ { u"ooxml-leftRightArrow", "leftRightArrow" },
+ { u"ooxml-decagon", "decagon" },
+ { u"ooxml-actionButtonHelp", "actionButtonHelp" },
+ { u"ooxml-star24", "star24" },
+ { u"ooxml-mathDivide", "mathDivide" },
+ { u"ooxml-curvedConnector4", "curvedConnector4" },
+ { u"ooxml-flowChartOr", "flowChartOr" },
+ { u"ooxml-borderCallout3", "borderCallout3" },
+ { u"ooxml-upDownArrowCallout", "upDownArrowCallout" },
+ { u"ooxml-flowChartDecision", "flowChartDecision" },
+ { u"ooxml-leftRightArrowCallout", "leftRightArrowCallout" },
+ { u"ooxml-flowChartManualOperation", "flowChartManualOperation" },
+ { u"ooxml-snipRoundRect", "snipRoundRect" },
+ { u"ooxml-mathPlus", "mathPlus" },
+ { u"ooxml-actionButtonForwardNext", "actionButtonForwardNext" },
+ { u"ooxml-can", "can" },
+ { u"ooxml-foldedCorner", "foldedCorner" },
+ { u"ooxml-star32", "star32" },
+ { u"ooxml-flowChartInternalStorage", "flowChartInternalStorage" },
+ { u"ooxml-upDownArrow", "upDownArrow" },
+ { u"ooxml-irregularSeal2", "irregularSeal2" },
+ { u"ooxml-mathEqual", "mathEqual" },
+ { u"ooxml-star12", "star12" },
+ { u"ooxml-uturnArrow", "uturnArrow" },
+ { u"ooxml-squareTabs", "squareTabs" },
+ { u"ooxml-leftRightUpArrow", "leftRightUpArrow" },
+ { u"ooxml-homePlate", "homePlate" },
+ { u"ooxml-dodecagon", "dodecagon" },
+ { u"ooxml-leftArrowCallout", "leftArrowCallout" },
+ { u"ooxml-chord", "chord" },
+ { u"ooxml-quadArrowCallout", "quadArrowCallout" },
+ { u"ooxml-actionButtonBeginning", "actionButtonBeginning" },
+ { u"ooxml-ellipse", "ellipse" },
+ { u"ooxml-actionButtonEnd", "actionButtonEnd" },
+ { u"ooxml-arc", "arc" },
+ { u"ooxml-star16", "star16" },
+ { u"ooxml-parallelogram", "parallelogram" },
+ { u"ooxml-bevel", "bevel" },
+ { u"ooxml-roundRect", "roundRect" },
+ { u"ooxml-accentCallout1", "accentCallout1" },
+ { u"ooxml-flowChartSort", "flowChartSort" },
+ { u"ooxml-star8", "star8" },
+ { u"ooxml-flowChartAlternateProcess", "flowChartAlternateProcess" },
+ { u"ooxml-moon", "moon" },
+ { u"ooxml-star6", "star6" },
+ { u"ooxml-round2SameRect", "round2SameRect" },
+ { u"ooxml-nonIsoscelesTrapezoid", "nonIsoscelesTrapezoid" },
+ { u"ooxml-diamond", "diamond" },
+ { u"ooxml-ellipseRibbon", "ellipseRibbon" },
+ { u"ooxml-callout2", "callout2" },
+ { u"ooxml-pie", "pie" },
+ { u"ooxml-star4", "star4" },
+ { u"ooxml-flowChartPredefinedProcess", "flowChartPredefinedProcess" },
+ { u"ooxml-flowChartPunchedTape", "flowChartPunchedTape" },
+ { u"ooxml-curvedConnector2", "curvedConnector2" },
+ { u"ooxml-bentConnector3", "bentConnector3" },
+ { u"ooxml-cornerTabs", "cornerTabs" },
+ { u"ooxml-hexagon", "hexagon" },
+ { u"ooxml-flowChartConnector", "flowChartConnector" },
+ { u"ooxml-flowChartMagneticDisk", "flowChartMagneticDisk" },
+ { u"ooxml-heart", "heart" },
+ { u"ooxml-ribbon2", "ribbon2" },
+ { u"ooxml-bracePair", "bracePair" },
+ { u"ooxml-flowChartExtract", "flowChartExtract" },
+ { u"ooxml-actionButtonHome", "actionButtonHome" },
+ { u"ooxml-accentBorderCallout3", "accentBorderCallout3" },
+ { u"ooxml-flowChartOfflineStorage", "flowChartOfflineStorage" },
+ { u"ooxml-irregularSeal1", "irregularSeal1" },
+ { u"ooxml-quadArrow", "quadArrow" },
+ { u"ooxml-leftBrace", "leftBrace" },
+ { u"ooxml-leftBracket", "leftBracket" },
+ { u"ooxml-blockArc", "blockArc" },
+ { u"ooxml-curvedConnector3", "curvedConnector3" },
+ { u"ooxml-wedgeRoundRectCallout", "wedgeRoundRectCallout" },
+ { u"ooxml-actionButtonMovie", "actionButtonMovie" },
+ { u"ooxml-flowChartOnlineStorage", "flowChartOnlineStorage" },
+ { u"ooxml-gear6", "gear6" },
+ { u"ooxml-halfFrame", "halfFrame" },
+ { u"ooxml-snip2SameRect", "snip2SameRect" },
+ { u"ooxml-triangle", "triangle" },
+ { u"ooxml-teardrop", "teardrop" },
+ { u"ooxml-flowChartDocument", "flowChartDocument" },
+ { u"ooxml-rightArrowCallout", "rightArrowCallout" },
+ { u"ooxml-rightBrace", "rightBrace" },
+ { u"ooxml-chartPlus", "chartPlus" },
+ { u"ooxml-flowChartManualInput", "flowChartManualInput" },
+ { u"ooxml-flowChartMerge", "flowChartMerge" },
+ { u"ooxml-line", "line" },
+ { u"ooxml-downArrow", "downArrow" },
+ { u"ooxml-upArrow", "upArrow" },
+ { u"ooxml-curvedDownArrow", "curvedDownArrow" },
+ { u"ooxml-actionButtonReturn", "actionButtonReturn" },
+ { u"ooxml-flowChartInputOutput", "flowChartInputOutput" },
+ { u"ooxml-bracketPair", "bracketPair" },
+ { u"ooxml-smileyFace", "smileyFace" },
+ { u"ooxml-actionButtonBlank", "actionButtonBlank" },
+ { u"ooxml-wave", "wave" },
+ { u"ooxml-swooshArrow", "swooshArrow" },
+ { u"ooxml-flowChartSummingJunction", "flowChartSummingJunction" },
+ { u"ooxml-lightningBolt", "lightningBolt" },
+ { u"ooxml-flowChartDisplay", "flowChartDisplay" },
+ { u"ooxml-actionButtonBackPrevious", "actionButtonBackPrevious" },
+ { u"ooxml-frame", "frame" },
+ { u"ooxml-rtTriangle", "rtTriangle" },
+ { u"ooxml-flowChartMagneticTape", "flowChartMagneticTape" },
+ { u"ooxml-curvedRightArrow", "curvedRightArrow" },
+ { u"ooxml-leftUpArrow", "leftUpArrow" },
+ { u"ooxml-wedgeEllipseCallout", "wedgeEllipseCallout" },
+ { u"ooxml-doubleWave", "doubleWave" },
+ { u"ooxml-bentArrow", "bentArrow" },
+ { u"ooxml-star10", "star10" },
+ { u"ooxml-leftArrow", "leftArrow" },
+ { u"ooxml-curvedUpArrow", "curvedUpArrow" },
+ { u"ooxml-snip1Rect", "snip1Rect" },
+ { u"ooxml-ellipseRibbon2", "ellipseRibbon2" },
+ { u"ooxml-plus", "plus" },
+ { u"ooxml-accentCallout3", "accentCallout3" },
+ { u"ooxml-leftCircularArrow", "leftCircularArrow" },
+ { u"ooxml-rightArrow", "rightArrow" },
+ { u"ooxml-flowChartPunchedCard", "flowChartPunchedCard" },
+ { u"ooxml-snip2DiagRect", "snip2DiagRect" },
+ { u"ooxml-verticalScroll", "verticalScroll" },
+ { u"ooxml-star7", "star7" },
+ { u"ooxml-chartX", "chartX" },
+ { u"ooxml-cloud", "cloud" },
+ { u"ooxml-cube", "cube" },
+ { u"ooxml-round2DiagRect", "round2DiagRect" },
+ { u"ooxml-flowChartMultidocument", "flowChartMultidocument" },
+ { u"ooxml-actionButtonDocument", "actionButtonDocument" },
+ { u"ooxml-flowChartTerminator", "flowChartTerminator" },
+ { u"ooxml-flowChartDelay", "flowChartDelay" },
+ { u"ooxml-curvedConnector5", "curvedConnector5" },
+ { u"ooxml-horizontalScroll", "horizontalScroll" },
+ { u"ooxml-bentConnector4", "bentConnector4" },
+ { u"ooxml-leftRightCircularArrow", "leftRightCircularArrow" },
+ { u"ooxml-wedgeRectCallout", "wedgeRectCallout" },
+ { u"ooxml-accentCallout2", "accentCallout2" },
+ { u"ooxml-flowChartMagneticDrum", "flowChartMagneticDrum" },
+ { u"ooxml-corner", "corner" },
+ { u"ooxml-borderCallout2", "borderCallout2" },
+ { u"ooxml-donut", "donut" },
+ { u"ooxml-flowChartCollate", "flowChartCollate" },
+ { u"ooxml-mathNotEqual", "mathNotEqual" },
+ { u"ooxml-bentConnector2", "bentConnector2" },
+ { u"ooxml-mathMultiply", "mathMultiply" },
+ { u"ooxml-heptagon", "heptagon" },
+ { u"ooxml-rect", "rect" },
+ { u"ooxml-accentBorderCallout2", "accentBorderCallout2" },
+ { u"ooxml-pieWedge", "pieWedge" },
+ { u"ooxml-upArrowCallout", "upArrowCallout" },
+ { u"ooxml-flowChartProcess", "flowChartProcess" },
+ { u"ooxml-star5", "star5" },
+ { u"ooxml-lineInv", "lineInv" },
+ { u"ooxml-straightConnector1", "straightConnector1" },
+ { u"ooxml-stripedRightArrow", "stripedRightArrow" },
+ { u"ooxml-callout3", "callout3" },
+ { u"ooxml-bentUpArrow", "bentUpArrow" },
+ { u"ooxml-noSmoking", "noSmoking" },
+ { u"ooxml-trapezoid", "trapezoid" },
+ { u"ooxml-cloudCallout", "cloudCallout" },
+ { u"ooxml-callout1", "callout1" },
+ { u"ooxml-ribbon", "ribbon" },
+ { u"ooxml-rect", "rect" },
+ };
+ auto i(aCustomShapeTypeTranslationHashMap.find(rShapeType));
+ return i == aCustomShapeTypeTranslationHashMap.end() ? "rect" : i->second;
+}
+
+MSO_SPT GETVMLShapeType(std::u16string_view aType)
+{
+ typedef std::unordered_map<std::string_view, MSO_SPT> DMLToVMLTranslationHashMap;
+ static const DMLToVMLTranslationHashMap aDMLToVMLMap{
+ {"notPrimitive", mso_sptNotPrimitive},
+ {"rectangle", mso_sptRectangle},
+ {"roundRectangle", mso_sptRoundRectangle},
+ {"ellipse", mso_sptEllipse},
+ {"diamond", mso_sptDiamond},
+ {"triangle", mso_sptIsocelesTriangle},
+ {"rtTriangle", mso_sptRightTriangle},
+ {"parallelogram", mso_sptParallelogram},
+ {"trapezoid", mso_sptTrapezoid},
+ {"hexagon", mso_sptHexagon},
+ {"octagon", mso_sptOctagon},
+ {"plus", mso_sptPlus},
+ {"star5", mso_sptStar},
+ {"rightArrow", mso_sptArrow},
+ {"thickArrow", mso_sptThickArrow},
+ {"homePlate", mso_sptHomePlate},
+ {"cube", mso_sptCube},
+ {"wedgeRoundRectCallout", mso_sptBalloon},
+ {"star16", mso_sptSeal},
+ {"arc", mso_sptArc},
+ {"line", mso_sptLine},
+ {"plaque", mso_sptPlaque},
+ {"can", mso_sptCan},
+ {"donut", mso_sptDonut},
+ {"textPlain", mso_sptTextSimple},
+ {"textStop", mso_sptTextOctagon},
+ {"textTriangle", mso_sptTextHexagon},
+ {"textCanDown", mso_sptTextCurve},
+ {"textWave1", mso_sptTextWave},
+ {"textArchUpPour", mso_sptTextRing},
+ {"textCanDown", mso_sptTextOnCurve},
+ {"textArchUp", mso_sptTextOnRing},
+ {"straightConnector1", mso_sptStraightConnector1},
+ {"bentConnector2", mso_sptBentConnector2},
+ {"bentConnector3", mso_sptBentConnector3},
+ {"bentConnector4", mso_sptBentConnector4},
+ {"bentConnector5", mso_sptBentConnector5},
+ {"curvedConnector2", mso_sptCurvedConnector2},
+ {"curvedConnector3", mso_sptCurvedConnector3},
+ {"curvedConnector4", mso_sptCurvedConnector4},
+ {"curvedConnector5", mso_sptCurvedConnector5},
+ {"callout1", mso_sptCallout1},
+ {"callout2", mso_sptCallout2},
+ {"callout3", mso_sptCallout3},
+ {"accentCallout1", mso_sptAccentCallout1},
+ {"accentCallout2", mso_sptAccentCallout2},
+ {"accentCallout3", mso_sptAccentCallout3},
+ {"borderCallout1", mso_sptBorderCallout1},
+ {"borderCallout2", mso_sptBorderCallout2},
+ {"borderCallout3", mso_sptBorderCallout3},
+ {"accentBorderCallout1", mso_sptAccentBorderCallout1},
+ {"accentBorderCallout2", mso_sptAccentBorderCallout2},
+ {"accentBorderCallout3", mso_sptAccentBorderCallout3},
+ {"ribbon", mso_sptRibbon},
+ {"ribbon2", mso_sptRibbon2},
+ {"chevron", mso_sptChevron},
+ {"pentagon", mso_sptPentagon},
+ {"noSmoking", mso_sptNoSmoking},
+ {"star8", mso_sptSeal8},
+ {"star16", mso_sptSeal16},
+ {"star32", mso_sptSeal32},
+ {"wedgeRectCallout", mso_sptWedgeRectCallout},
+ {"wedgeRoundRectCallout", mso_sptWedgeRRectCallout},
+ {"wedgeEllipseCallout", mso_sptWedgeEllipseCallout},
+ {"wave", mso_sptWave},
+ {"foldedCorner", mso_sptFoldedCorner},
+ {"leftArrow", mso_sptLeftArrow},
+ {"downArrow", mso_sptDownArrow},
+ {"upArrow", mso_sptUpArrow},
+ {"leftRightArrow", mso_sptLeftRightArrow},
+ {"upDownArrow", mso_sptUpDownArrow},
+ {"irregularSeal1", mso_sptIrregularSeal1},
+ {"irregularSeal2", mso_sptIrregularSeal2},
+ {"lightningBolt", mso_sptLightningBolt},
+ {"heart", mso_sptHeart},
+ {"pictureFrame", mso_sptPictureFrame},
+ {"quadArrow", mso_sptQuadArrow},
+ {"leftArrowCallout", mso_sptLeftArrowCallout},
+ {"rightArrowCallout", mso_sptRightArrowCallout},
+ {"upArrowCallout", mso_sptUpArrowCallout},
+ {"downArrowCallout", mso_sptDownArrowCallout},
+ {"leftRightArrowCallout", mso_sptLeftRightArrowCallout},
+ {"upDownArrowCallout", mso_sptUpDownArrowCallout},
+ {"quadArrowCallout", mso_sptQuadArrowCallout},
+ {"bevel", mso_sptBevel},
+ {"leftBracket", mso_sptLeftBracket},
+ {"rightBracket", mso_sptRightBracket},
+ {"leftBrace", mso_sptLeftBrace},
+ {"rightBrace", mso_sptRightBrace},
+ {"leftUpArrow", mso_sptLeftUpArrow},
+ {"bentUpArrow", mso_sptBentUpArrow},
+ {"bentArrow", mso_sptBentArrow},
+ {"star24", mso_sptSeal24},
+ {"stripedRightArrow", mso_sptStripedRightArrow},
+ {"notchedRightArrow", mso_sptNotchedRightArrow},
+ {"blockArc", mso_sptBlockArc},
+ {"smileyFace", mso_sptSmileyFace},
+ {"verticalScroll", mso_sptVerticalScroll},
+ {"horizontalScroll", mso_sptHorizontalScroll},
+ {"circularArrow", mso_sptCircularArrow},
+ {"notchedCircularArrow", mso_sptNotchedCircularArrow},
+ {"uturnArrow", mso_sptUturnArrow},
+ {"curvedRightArrow", mso_sptCurvedRightArrow},
+ {"curvedLeftArrow", mso_sptCurvedLeftArrow},
+ {"curvedUpArrow", mso_sptCurvedUpArrow},
+ {"curvedDownArrow", mso_sptCurvedDownArrow},
+ {"cloudCallout", mso_sptCloudCallout},
+ {"ellipseRibbon", mso_sptEllipseRibbon},
+ {"ellipseRibbon2", mso_sptEllipseRibbon2},
+ {"flowChartProcess", mso_sptFlowChartProcess},
+ {"flowChartDecision", mso_sptFlowChartDecision},
+ {"flowChartInputOutput", mso_sptFlowChartInputOutput},
+ {"flowChartPredefinedProcess", mso_sptFlowChartPredefinedProcess},
+ {"flowChartInternalStorage", mso_sptFlowChartInternalStorage},
+ {"flowChartDocument", mso_sptFlowChartDocument},
+ {"flowChartMultidocument", mso_sptFlowChartMultidocument},
+ {"flowChartTerminator", mso_sptFlowChartTerminator},
+ {"flowChartPreparation", mso_sptFlowChartPreparation},
+ {"flowChartManualInput", mso_sptFlowChartManualInput},
+ {"flowChartManualOperation", mso_sptFlowChartManualOperation},
+ {"flowChartConnector", mso_sptFlowChartConnector},
+ {"flowChartPunchedCard", mso_sptFlowChartPunchedCard},
+ {"flowChartPunchedTape", mso_sptFlowChartPunchedTape},
+ {"flowChartSummingJunction", mso_sptFlowChartSummingJunction},
+ {"flowChartOr", mso_sptFlowChartOr},
+ {"flowChartCollate", mso_sptFlowChartCollate},
+ {"flowChartSort", mso_sptFlowChartSort},
+ {"flowChartExtract", mso_sptFlowChartExtract},
+ {"flowChartMerge", mso_sptFlowChartMerge},
+ {"flowChartOfflineStorage", mso_sptFlowChartOfflineStorage},
+ {"flowChartOnlineStorage", mso_sptFlowChartOnlineStorage},
+ {"flowChartMagneticTape", mso_sptFlowChartMagneticTape},
+ {"flowChartMagneticDisk", mso_sptFlowChartMagneticDisk},
+ {"flowChartMagneticDrum", mso_sptFlowChartMagneticDrum},
+ {"flowChartDisplay", mso_sptFlowChartDisplay},
+ {"flowChartDelay", mso_sptFlowChartDelay},
+ {"textPlain", mso_sptTextPlainText},
+ {"textStop", mso_sptTextStop},
+ {"textTriangle", mso_sptTextTriangle},
+ {"textTriangleInverted", mso_sptTextTriangleInverted},
+ {"textChevron", mso_sptTextChevron},
+ {"textChevronInverted", mso_sptTextChevronInverted},
+ {"textRingInside", mso_sptTextRingInside},
+ {"textRingOutside", mso_sptTextRingOutside},
+ {"textArchUp", mso_sptTextArchUpCurve},
+ {"textArchDown", mso_sptTextArchDownCurve},
+ {"textCircle", mso_sptTextCircleCurve},
+ {"textButton", mso_sptTextButtonCurve},
+ {"textArchUpPour", mso_sptTextArchUpPour},
+ {"textArchDownPour", mso_sptTextArchDownPour},
+ {"textCirclePour", mso_sptTextCirclePour},
+ {"textButtonPour", mso_sptTextButtonPour},
+ {"textCurveUp", mso_sptTextCurveUp},
+ {"textCurveDown", mso_sptTextCurveDown},
+ {"textCascadeUp", mso_sptTextCascadeUp},
+ {"textCascadeDown", mso_sptTextCascadeDown},
+ {"textWave1", mso_sptTextWave1},
+ {"textWave2", mso_sptTextWave2},
+ {"textWave3", mso_sptTextWave3},
+ {"textWave4", mso_sptTextWave4},
+ {"textInflate", mso_sptTextInflate},
+ {"textDeflate", mso_sptTextDeflate},
+ {"textInflateBottom", mso_sptTextInflateBottom},
+ {"textDeflateBottom", mso_sptTextDeflateBottom},
+ {"textInflateTop", mso_sptTextInflateTop},
+ {"textDeflateTop", mso_sptTextDeflateTop},
+ {"textDeflateInflate", mso_sptTextDeflateInflate},
+ {"textDeflateInflateDeflate", mso_sptTextDeflateInflateDeflate},
+ {"textFadeRight", mso_sptTextFadeRight},
+ {"textFadeLeft", mso_sptTextFadeLeft},
+ {"textFadeUp", mso_sptTextFadeUp},
+ {"textFadeDown", mso_sptTextFadeDown},
+ {"textSlantUp", mso_sptTextSlantUp},
+ {"textSlantDown", mso_sptTextSlantDown},
+ {"textCanUp", mso_sptTextCanUp},
+ {"textCanDown", mso_sptTextCanDown},
+ {"flowChartAlternateProcess", mso_sptFlowChartAlternateProcess},
+ {"flowChartOffpageConnector", mso_sptFlowChartOffpageConnector},
+ {"callout1", mso_sptCallout90},
+ {"accentCallout1", mso_sptAccentCallout90},
+ {"borderCallout1", mso_sptBorderCallout90},
+ {"accentBorderCallout1", mso_sptAccentBorderCallout90},
+ {"leftRightUpArrow", mso_sptLeftRightUpArrow},
+ {"sun", mso_sptSun},
+ {"moon", mso_sptMoon},
+ {"bracketPair", mso_sptBracketPair},
+ {"bracePair", mso_sptBracePair},
+ {"star4", mso_sptSeal4},
+ {"doubleWave", mso_sptDoubleWave},
+ {"actionButtonBlank", mso_sptActionButtonBlank},
+ {"actionButtonHome", mso_sptActionButtonHome},
+ {"actionButtonHelp", mso_sptActionButtonHelp},
+ {"actionButtonInformation", mso_sptActionButtonInformation},
+ {"actionButtonForwardNext", mso_sptActionButtonForwardNext},
+ {"actionButtonBackPrevious", mso_sptActionButtonBackPrevious},
+ {"actionButtonEnd", mso_sptActionButtonEnd},
+ {"actionButtonBeginning", mso_sptActionButtonBeginning},
+ {"actionButtonReturn", mso_sptActionButtonReturn},
+ {"actionButtonDocument", mso_sptActionButtonDocument},
+ {"actionButtonSound", mso_sptActionButtonSound},
+ {"actionButtonMovie", mso_sptActionButtonMovie},
+ {"hostControl", mso_sptHostControl},
+ {"textBox", mso_sptTextBox},
+ };
+
+ auto i(aDMLToVMLMap.find(GetOOXMLPresetGeometry(aType)));
+ return i == aDMLToVMLMap.end() ? mso_sptNil : i->second;
+}
+
+bool HasTextBoxContent(sal_uInt32 nShapeType)
+{
+ switch (nShapeType)
+ {
+ case ESCHER_ShpInst_TextPlainText:
+ case ESCHER_ShpInst_TextSlantUp:
+ case ESCHER_ShpInst_TextDeflateInflateDeflate:
+ return false;
+ default:
+ return true;
+ }
+}
+
+namespace
+{
+
+// Scheme means pattern of chromatic values.
+// [2,2,1] -> red and green are approximately equal and blue is the dominant color (e.g. blue)
+// [1,1,1] -> all chromatic values are approximately equal (e.g. white, gray, black)
+void CalculateScheme(const BitmapColor& rBitmapColor, std::vector<int> &vScheme, sal_uInt16 nVariance)
+{
+ vScheme.resize(3,1);
+ if( rBitmapColor.GetRed() < rBitmapColor.GetGreen() + nVariance )
+ ++vScheme[0];
+ if( rBitmapColor.GetRed() < rBitmapColor.GetBlue() + nVariance )
+ ++vScheme[0];
+ if( rBitmapColor.GetGreen() < rBitmapColor.GetRed() + nVariance )
+ ++vScheme[1];
+ if( rBitmapColor.GetGreen() < rBitmapColor.GetBlue() + nVariance )
+ ++vScheme[1];
+ if( rBitmapColor.GetBlue() < rBitmapColor.GetRed() + nVariance )
+ ++vScheme[2];
+ if( rBitmapColor.GetBlue() < rBitmapColor.GetGreen() + nVariance )
+ ++vScheme[2];
+}
+
+bool HasSimilarScheme(const BitmapColor& rBitmapColor1, const BitmapColor& rBitmapColor2, sal_uInt16 nVariance)
+{
+ std::vector<int> vScheme1, vScheme2;
+ CalculateScheme(rBitmapColor1, vScheme1, nVariance);
+ CalculateScheme(rBitmapColor2, vScheme2, nVariance);
+ for( int i = 0; i < 3; ++i )
+ {
+ if( vScheme1[i] != vScheme2[i] )
+ return false;
+ }
+ return true;
+}
+
+// Find the best match in the color palette using scheme of the input color
+sal_uInt16 GetBestIndex(const BitmapPalette& rPalette, const BitmapColor& rBitmapColor)
+{
+ sal_uInt16 nReturn = 0;
+ sal_uInt16 nLastErr = SAL_MAX_UINT16;
+ bool bFound = false;
+
+ // Prefer those colors which have similar scheme as the input
+ // Allow bigger and bigger variance of the schemes until we find
+ // a color in the palette with similar scheme.
+ for( sal_uInt16 nVariance = 0; nVariance <= 255; ++nVariance )
+ {
+ for( sal_uInt16 i = 0; i < rPalette.GetEntryCount(); ++i )
+ {
+ if( HasSimilarScheme(rBitmapColor, rPalette[i], nVariance) )
+ {
+ const sal_uInt16 nActErr = rBitmapColor.GetColorError( rPalette[i] );
+ if( nActErr < nLastErr )
+ {
+ nLastErr = nActErr;
+ nReturn = i;
+ bFound = true;
+ }
+ }
+ }
+ if( bFound )
+ return nReturn;
+ }
+ return nReturn;
+}
+}
+
+sal_uInt8 TransColToIco( const Color& rCol )
+{
+ sal_uInt8 nCol = 0; // ->Auto
+ switch( sal_uInt32(rCol) )
+ {
+ case sal_uInt32(COL_BLACK): nCol = 1; break;
+ case sal_uInt32(COL_BLUE): nCol = 9; break;
+ case sal_uInt32(COL_GREEN): nCol = 11; break;
+ case sal_uInt32(COL_CYAN): nCol = 10; break;
+ case sal_uInt32(COL_RED): nCol = 13; break;
+ case sal_uInt32(COL_MAGENTA): nCol = 12; break;
+ case sal_uInt32(COL_BROWN): nCol = 14; break;
+ case sal_uInt32(COL_GRAY): nCol = 15; break;
+ case sal_uInt32(COL_LIGHTGRAY): nCol = 16; break;
+ case sal_uInt32(COL_LIGHTBLUE): nCol = 2; break;
+ case sal_uInt32(COL_LIGHTGREEN): nCol = 4; break;
+ case sal_uInt32(COL_LIGHTCYAN): nCol = 3; break;
+ case sal_uInt32(COL_LIGHTRED): nCol = 6; break;
+ case sal_uInt32(COL_LIGHTMAGENTA): nCol = 5; break;
+ case sal_uInt32(COL_YELLOW): nCol = 7; break;
+ case sal_uInt32(COL_WHITE): nCol = 8; break;
+ case sal_uInt32(COL_AUTO): nCol = 0; break;
+
+ default:
+ static const BitmapPalette aBmpPal {
+ COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
+ COL_LIGHTMAGENTA,COL_LIGHTRED, COL_YELLOW, COL_WHITE,
+ COL_BLUE, COL_CYAN, COL_GREEN, COL_MAGENTA,
+ COL_RED, COL_BROWN, COL_GRAY, COL_LIGHTGRAY
+ };
+
+ nCol = static_cast< sal_uInt8 >(GetBestIndex(aBmpPal, rCol) + 1);
+ break;
+ }
+ return nCol;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/viscache.hxx b/filter/source/msfilter/viscache.hxx
new file mode 100644
index 000000000..5111969b3
--- /dev/null
+++ b/filter/source/msfilter/viscache.hxx
@@ -0,0 +1,52 @@
+/* -*- 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/.
+ *
+ * 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 .
+ */
+#pragma once
+
+#include <memory>
+#include <sfx2/objsh.hxx>
+#include <vcl/gdimtf.hxx>
+
+class SvStream;
+
+class Impl_OlePres
+{
+ SotClipboardFormatId nFormat;
+ sal_uInt16 nAspect;
+ std::unique_ptr<GDIMetaFile>
+ pMtf;
+
+ sal_uInt32 nAdvFlags;
+ Size aSize; // size in 100TH_MM
+public:
+ explicit Impl_OlePres()
+ : nFormat( SotClipboardFormatId::GDIMETAFILE )
+ , nAspect( ASPECT_CONTENT )
+ , nAdvFlags( 0x2 ) // found in document
+ {}
+ void SetMtf( const GDIMetaFile & rMtf )
+ {
+ pMtf.reset( new GDIMetaFile( rMtf ) );
+ }
+ void SetAspect( sal_uInt16 nAsp ) { nAspect = nAsp; }
+ void SetAdviseFlags( sal_uLong nAdv ) { nAdvFlags = nAdv; }
+ void SetSize( const Size & rSize ) { aSize = rSize; }
+ void Write( SvStream & rStm );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */