diff options
author | Jonathan Clark <jonathan@libreoffice.org> | 2024-10-21 11:31:46 -0600 |
---|---|---|
committer | Jonathan Clark <jonathan@libreoffice.org> | 2024-11-02 01:09:52 +0100 |
commit | 43cd683230bc05d294b1bd64f1e7932feccdd3fb (patch) | |
tree | 8490101ef265632d22d3594d926575abfac3c7a5 | |
parent | db7cd5032068c5b9faa4c707db204b58c1dbf2b2 (diff) |
tdf#36709 Add loext:text-indent supporting font-relative units
This change adds an ODF font-relative first-line indent paragraph style
attribute as a LibreOffice extension. The corresponding ODF standard
change is tracked by OFFICE-4165.
This change only implements what is minimally necessary to serialize,
deserialize, and check for ODF files containing this attribute. Further
changes are necessary.
* Added cssLength to schema, which is equivalent to length but also
allows ic and em as units.
* Added loext:text-indent to schema as a paragraph style attribute. This
attribute is equivalent to fo:text-indent, but accepts cssLength
instead of length.
* Added XML_TYPE_UNIT_MEASURE to the ODF parser, which currently accepts
only the font-relative measures and forces fallback in other cases.
* Added loext:text-indent to the ODF parser. This attribute accepts
font-relative metrics, and will behave as an import-only alias for
fo:text-indent in other cases.
* Updated SvxFirstLineIndentItem to handle unit-denominated measures.
* Added proof-of-concept indentation handler to Writer. This
implementation is incomplete and temporary, and will be revised in
future changes.
Change-Id: I7eb5c7382093cb18a9b0afbf93dacb34ba1d35ef
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175941
Tested-by: Jenkins
Reviewed-by: Jonathan Clark <jonathan@libreoffice.org>
-rw-r--r-- | editeng/source/items/frmitems.cxx | 50 | ||||
-rw-r--r-- | include/editeng/lrspitem.hxx | 10 | ||||
-rw-r--r-- | include/editeng/memberids.h | 1 | ||||
-rw-r--r-- | include/xmloff/xmltypes.hxx | 1 | ||||
-rw-r--r-- | schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng | 19 | ||||
-rw-r--r-- | sw/inc/unoprnms.hxx | 1 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/data/tdf36709.fodt | 117 | ||||
-rw-r--r-- | sw/qa/extras/odfexport/odfexport2.cxx | 19 | ||||
-rw-r--r-- | sw/source/core/text/itrcrsr.cxx | 20 | ||||
-rw-r--r-- | sw/source/core/unocore/unomap1.cxx | 1 | ||||
-rw-r--r-- | sw/source/core/unocore/unomapproperties.hxx | 3 | ||||
-rw-r--r-- | vcl/qa/cppunit/pdfexport/data/tdf36709.fodt | 151 | ||||
-rw-r--r-- | vcl/qa/cppunit/pdfexport/pdfexport2.cxx | 51 | ||||
-rw-r--r-- | xmloff/inc/xmlbahdl.hxx | 10 | ||||
-rw-r--r-- | xmloff/inc/xmlprop.hxx | 1 | ||||
-rw-r--r-- | xmloff/source/style/prhdlfac.cxx | 3 | ||||
-rw-r--r-- | xmloff/source/style/xmlbahdl.cxx | 53 | ||||
-rw-r--r-- | xmloff/source/text/txtprmap.cxx | 3 |
18 files changed, 510 insertions, 4 deletions
diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx index 5dd0346ef47e..93d1c33fcc8f 100644 --- a/editeng/source/items/frmitems.cxx +++ b/editeng/source/items/frmitems.cxx @@ -28,6 +28,7 @@ #include <com/sun/star/style/BreakType.hpp> #include <com/sun/star/style/GraphicLocation.hpp> #include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/beans/Pair.hpp> #include <com/sun/star/text/WritingMode2.hpp> #include <com/sun/star/frame/status/UpperLowerMarginScale.hpp> #include <com/sun/star/frame/status/LeftRightMarginScale.hpp> @@ -500,6 +501,7 @@ void SvxFirstLineIndentItem::SetTextFirstLineOffset( { ASSERT_CHANGE_REFCOUNTED_ITEM; m_nFirstLineOffset = short((tools::Long(nF) * nProp ) / 100); + m_nUnit = css::util::MeasureUnit::TWIP; m_nPropFirstLineOffset = nProp; } @@ -944,20 +946,45 @@ SvxFirstLineIndentItem::SvxFirstLineIndentItem(const short nFirst, const sal_uIn bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) const { - bool bRet = true; + bool bRet = false; bool bConvert = 0 != (nMemberId & CONVERT_TWIPS); nMemberId &= ~CONVERT_TWIPS; switch (nMemberId) { case MID_FIRST_LINE_INDENT: - rVal <<= static_cast<sal_Int32>(bConvert ? convertTwipToMm100(m_nFirstLineOffset) : m_nFirstLineOffset); - break; + // MID_FIRST_LINE_INDENT only supports statically-convertible measures. + // In practice, these are always stored here in twips. + if (m_nUnit == css::util::MeasureUnit::TWIP) + { + rVal <<= static_cast<sal_Int32>(bConvert ? convertTwipToMm100(m_nFirstLineOffset) + : m_nFirstLineOffset); + bRet = true; + } + break; + case MID_FIRST_LINE_REL_INDENT: rVal <<= static_cast<sal_Int16>(m_nPropFirstLineOffset); + bRet = true; break; + + case MID_FIRST_LINE_UNIT_INDENT: + // MID_FIRST_LINE_UNIT_INDENT is used for any values that must be serialized + // as a unit-value pair. In practice, this will be limited to font-relative + // units (e.g. em, ic), and all other units will be pre-converted to twips. + if (m_nUnit != css::util::MeasureUnit::TWIP) + { + rVal <<= css::beans::Pair<double, sal_Int16>{ + static_cast<double>(m_nFirstLineOffset), m_nUnit + }; + bRet = true; + } + break; + case MID_FIRST_AUTO: rVal <<= IsAutoFirst(); + bRet = true; break; + default: assert(false); bRet = false; @@ -983,6 +1010,7 @@ bool SvxFirstLineIndentItem::PutValue(const uno::Any& rVal, sal_uInt8 nMemberId) return false; } m_nFirstLineOffset = bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal; + m_nUnit = css::util::MeasureUnit::TWIP; m_nPropFirstLineOffset = 100; break; } @@ -999,6 +1027,19 @@ bool SvxFirstLineIndentItem::PutValue(const uno::Any& rVal, sal_uInt8 nMemberId) } break; } + case MID_FIRST_LINE_UNIT_INDENT: + { + css::beans::Pair<double, sal_Int16> stVal; + if (!(rVal >>= stVal)) + { + return false; + } + + m_nFirstLineOffset = stVal.First; + m_nUnit = stVal.Second; + m_nPropFirstLineOffset = 100; + break; + } case MID_FIRST_AUTO: SetAutoFirst(Any2Bool(rVal)); break; @@ -1017,6 +1058,7 @@ bool SvxFirstLineIndentItem::operator==(const SfxPoolItem& rAttr) const const SvxFirstLineIndentItem& rOther = static_cast<const SvxFirstLineIndentItem&>(rAttr); return (m_nFirstLineOffset == rOther.GetTextFirstLineOffset() + && m_nUnit == rOther.GetTextFirstLineOffsetUnit() && m_nPropFirstLineOffset == rOther.GetPropTextFirstLineOffset() && m_bAutoFirst == rOther.IsAutoFirst()); } @@ -1025,6 +1067,7 @@ size_t SvxFirstLineIndentItem::hashCode() const { std::size_t seed(0); o3tl::hash_combine(seed, m_nFirstLineOffset); + o3tl::hash_combine(seed, m_nUnit); o3tl::hash_combine(seed, m_nPropFirstLineOffset); o3tl::hash_combine(seed, m_bAutoFirst); return seed; @@ -1096,6 +1139,7 @@ void SvxFirstLineIndentItem::dumpAsXml(xmlTextWriterPtr pWriter) const (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxFirstLineIndentItem")); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr())); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nFirstLineOffset"), BAD_CAST(OString::number(m_nFirstLineOffset).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nUnit"), BAD_CAST(OString::number(m_nUnit).getStr())); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nPropFirstLineOffset"), BAD_CAST(OString::number(m_nPropFirstLineOffset).getStr())); (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_bAutoFirst"), BAD_CAST(OString::number(int(m_bAutoFirst)).getStr())); (void)xmlTextWriterEndElement(pWriter); diff --git a/include/editeng/lrspitem.hxx b/include/editeng/lrspitem.hxx index 5fe01262e7c2..63bff2c974ca 100644 --- a/include/editeng/lrspitem.hxx +++ b/include/editeng/lrspitem.hxx @@ -21,6 +21,7 @@ #include <svl/poolitem.hxx> #include <editeng/editengdllapi.h> +#include <com/sun/star/util/MeasureUnit.hpp> // class SvxLRSpaceItem -------------------------------------------------- @@ -136,6 +137,7 @@ class EDITENG_DLLPUBLIC SvxFirstLineIndentItem final : public SfxPoolItem private: /// First-line indent always relative to GetTextLeft() short m_nFirstLineOffset = 0; + sal_Int16 m_nUnit = css::util::MeasureUnit::TWIP; sal_uInt16 m_nPropFirstLineOffset = 100; /// Automatic calculation of the first line indent bool m_bAutoFirst = false; @@ -146,12 +148,18 @@ public: void SetTextFirstLineOffset(const short nF, const sal_uInt16 nProp = 100); short GetTextFirstLineOffset() const { return m_nFirstLineOffset; } + double GetTextFirstLineOffsetDouble() const { return m_nFirstLineOffset; } + sal_Int16 GetTextFirstLineOffsetUnit() const { return m_nUnit; } void SetPropTextFirstLineOffset(const sal_uInt16 nProp) { ASSERT_CHANGE_REFCOUNTED_ITEM; m_nPropFirstLineOffset = nProp; } sal_uInt16 GetPropTextFirstLineOffset() const { return m_nPropFirstLineOffset; } void SetTextFirstLineOffsetValue(const short nValue) - { ASSERT_CHANGE_REFCOUNTED_ITEM; m_nFirstLineOffset = nValue; } + { + ASSERT_CHANGE_REFCOUNTED_ITEM; + m_nFirstLineOffset = nValue; + m_nUnit = css::util::MeasureUnit::TWIP; + } explicit SvxFirstLineIndentItem(const sal_uInt16 nId); SvxFirstLineIndentItem(const short nOffset, const sal_uInt16 nId); diff --git a/include/editeng/memberids.h b/include/editeng/memberids.h index 57250a9872e8..195eccce41c8 100644 --- a/include/editeng/memberids.h +++ b/include/editeng/memberids.h @@ -138,6 +138,7 @@ #define MID_FIRST_AUTO 10 #define MID_TXT_LMARGIN 11 #define MID_GUTTER_MARGIN 12 +#define MID_FIRST_LINE_UNIT_INDENT 13 //ProtectItem #define MID_PROTECT_CONTENT 0 diff --git a/include/xmloff/xmltypes.hxx b/include/xmloff/xmltypes.hxx index 7c7cabb43df1..a3c6f057c610 100644 --- a/include/xmloff/xmltypes.hxx +++ b/include/xmloff/xmltypes.hxx @@ -154,6 +154,7 @@ #define XML_TYPE_DOUBLE_PERCENT 0x00002024 // 50% (source is a double from 0.0 to 1.0) #define XML_TYPE_HEX 0x00002025 // 00544F1B #define XML_TYPE_PERCENT100 0x00002026 // 100th percent +#define XML_TYPE_UNIT_MEASURE 0x00002027 // Source is a double paired with a unit // special basic types #define XML_TYPE_RECTANGLE_LEFT 0x00000100 // the Left member of an awt::Rectangle as a measure diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng index a805123d7e24..5f53d50c8526 100644 --- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng @@ -3098,6 +3098,25 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:optional> </rng:define> + <!-- https://issues.oasis-open.org/browse/OFFICE-4165 --> + <rng:define name="cssLength"> + <rng:data type="string"> + <rng:param name="pattern">-?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)|(ic)|(em))</rng:param> + </rng:data> + </rng:define> + + <!-- https://issues.oasis-open.org/browse/OFFICE-4165 --> + <rng:define name="style-paragraph-properties-attlist" combine="interleave"> + <rng:optional> + <rng:attribute name="loext:text-indent"> + <rng:choice> + <rng:ref name="cssLength"/> + <rng:ref name="percent"/> + </rng:choice> + </rng:attribute> + </rng:optional> + </rng:define> + <!-- TODO no proposal --> <rng:define name="chart-data-point-attlist" combine="interleave"> <rng:optional> diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index e3d7e073c24d..13a64ef5484d 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -64,6 +64,7 @@ inline constexpr OUString UNO_NAME_PARA_IS_AUTO_FIRST_LINE_INDENT inline constexpr OUString UNO_NAME_PARA_FIRST_LINE_INDENT = u"ParaFirstLineIndent"_ustr; inline constexpr OUString UNO_NAME_PARA_FIRST_LINE_INDENT_RELATIVE = u"ParaFirstLineIndentRelative"_ustr; +inline constexpr OUString UNO_NAME_PARA_FIRST_LINE_INDENT_UNIT = u"ParaFirstLineIndentUnit"_ustr; inline constexpr OUString UNO_NAME_PARA_IS_HYPHENATION = u"ParaIsHyphenation"_ustr; inline constexpr OUString UNO_NAME_PARA_HYPHENATION_MAX_LEADING_CHARS = u"ParaHyphenationMaxLeadingChars"_ustr; diff --git a/sw/qa/extras/odfexport/data/tdf36709.fodt b/sw/qa/extras/odfexport/data/tdf36709.fodt new file mode 100644 index 000000000000..f4dddd28ee85 --- /dev/null +++ b/sw/qa/extras/odfexport/data/tdf36709.fodt @@ -0,0 +1,117 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:creation-date>2024-10-31T15:19:06.580445570</meta:creation-date><dc:date>2024-10-31T15:22:40.161604509</dc:date><meta:editing-duration>PT3M34S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="2" meta:word-count="4" meta:character-count="42" meta:non-whitespace-character-count="40"/><meta:generator>LibreOfficeDev/25.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/5f12ad737bbb930b76299df0433c8635ae27a7bd</meta:generator></office:meta> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans1" svg:font-family="'Noto Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0in" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.1965in" style:num-format="1" text:number-position="left" text:increment="5"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="3in" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="6em" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="8.2681in" fo:page-height="11.6929in" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.7874in" fo:margin-bottom="0.7874in" fo:margin-left="0.7874in" fo:margin-right="0.7874in" style:writing-mode="lr-tb" style:footnote-max-height="0in" loext:margin-gutter="0in"> + <style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P1">3in loext:text-indent</text:p> + <text:p text:style-name="P2">6em loext:text-indent</text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx index 38e4273915a4..d0353009a224 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -1800,6 +1800,25 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf163703) + autostylename.toUtf8() + "']/style:text-properties"; assertXPath(pXml, autoStyleXPath, "font-style", u"italic"); } + +CPPUNIT_TEST_FIXTURE(Test, testTdf36709) +{ + // Verifies that loext:text-indent correctly round-trips + loadAndReload("tdf36709.fodt"); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr); + + // Style P1 should have been rewritten as fo:text-indent + assertXPath(pXmlDoc, "//style:style[@style:name='P1']/style:paragraph-properties[@fo:text-indent]", 1); + assertXPath(pXmlDoc, "//style:style[@style:name='P1']/style:paragraph-properties[@loext:text-indent]", 0); + assertXPath(pXmlDoc, "//style:style[@style:name='P1']/style:paragraph-properties", "text-indent", u"3in"); + + // Style P2 should have round-tripped as loext:text-indent + assertXPath(pXmlDoc, "//style:style[@style:name='P2']/style:paragraph-properties[@fo:text-indent]", 0); + assertXPath(pXmlDoc, "//style:style[@style:name='P2']/style:paragraph-properties[@loext:text-indent]", 1); + assertXPath(pXmlDoc, "//style:style[@style:name='P2']/style:paragraph-properties", "text-indent", u"6em"); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx index f1db92073cba..c393154777a0 100644 --- a/sw/source/core/text/itrcrsr.cxx +++ b/sw/source/core/text/itrcrsr.cxx @@ -299,6 +299,26 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame *pNewFrame, SwTextSizeInfo *p } } } + else if (!pNode->GetFirstLineOfsWithNum(nFLOfst) + && rFirstLine.GetTextFirstLineOffsetUnit() != css::util::MeasureUnit::TWIP) + { + auto nFntHeight = GetFnt()->GetSize(GetFnt()->GetActual()).Height(); + + // tdf#36709: TODO: Complete and consolidate unit conversion code + switch (rFirstLine.GetTextFirstLineOffsetUnit()) + { + case css::util::MeasureUnit::FONT_IC: + case css::util::MeasureUnit::FONT_EM: + nFirstLineOfs + = static_cast<tools::Long>(static_cast<double>(nFntHeight) + * rFirstLine.GetTextFirstLineOffsetDouble()); + break; + + default: + nFirstLineOfs = 0; + break; + } + } else nFirstLineOfs = nFLOfst; diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index f9e16b1f4260..d53bdac79dfb 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -25,6 +25,7 @@ #include <com/sun/star/awt/Size.hpp> #include <com/sun/star/awt/XBitmap.hpp> #include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/Pair.hpp> #include <com/sun/star/beans/PropertyAttribute.hpp> #include <com/sun/star/beans/PropertyValue.hpp> #include <com/sun/star/container/XIndexContainer.hpp> diff --git a/sw/source/core/unocore/unomapproperties.hxx b/sw/source/core/unocore/unomapproperties.hxx index 01cae68a6de9..2401fbc42db7 100644 --- a/sw/source/core/unocore/unomapproperties.hxx +++ b/sw/source/core/unocore/unomapproperties.hxx @@ -158,6 +158,7 @@ { UNO_NAME_PARA_RIGHT_MARGIN, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_R_MARGIN | CONVERT_TWIPS }, \ { UNO_NAME_PARA_IS_AUTO_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_AUTO }, \ { UNO_NAME_PARA_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_LINE_INDENT | CONVERT_TWIPS }, \ + { UNO_NAME_PARA_FIRST_LINE_INDENT_UNIT, RES_MARGIN_FIRSTLINE, cppu::UnoType<css::beans::Pair<double, sal_Int16>>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_LINE_UNIT_INDENT }, \ STANDARD_FONT_PROPERTIES \ CJK_FONT_PROPERTIES \ CTL_FONT_PROPERTIES \ @@ -422,6 +423,7 @@ { UNO_NAME_PARA_RIGHT_MARGIN_RELATIVE, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_R_REL_MARGIN},\ { UNO_NAME_PARA_IS_AUTO_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_FIRST_AUTO},\ { UNO_NAME_PARA_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_FIRST_LINE_INDENT|CONVERT_TWIPS},\ + { UNO_NAME_PARA_FIRST_LINE_INDENT_UNIT, RES_MARGIN_FIRSTLINE, cppu::UnoType<css::beans::Pair<double, sal_Int16>>::get(), PROPERTY_NONE, MID_FIRST_LINE_UNIT_INDENT},\ { UNO_NAME_PARA_FIRST_LINE_INDENT_RELATIVE, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_FIRST_LINE_REL_INDENT|CONVERT_TWIPS},\ { UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING , cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS},\ { UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN , cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\ @@ -545,6 +547,7 @@ { UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PARA_ADJUST}, \ { UNO_NAME_PARA_BOTTOM_MARGIN, RES_UL_SPACE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_LO_MARGIN|CONVERT_TWIPS}, \ { UNO_NAME_PARA_FIRST_LINE_INDENT, RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_LINE_INDENT|CONVERT_TWIPS}, \ + { UNO_NAME_PARA_FIRST_LINE_INDENT_UNIT, RES_MARGIN_FIRSTLINE, cppu::UnoType<css::beans::Pair<double, sal_Int16>>::get(), PropertyAttribute::MAYBEVOID, MID_FIRST_LINE_UNIT_INDENT}, \ { UNO_NAME_PARA_LEFT_MARGIN, RES_MARGIN_TEXTLEFT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_TXT_LMARGIN|CONVERT_TWIPS}, \ { UNO_NAME_PARA_LINE_SPACING, RES_PARATR_LINESPACING, cppu::UnoType<css::style::LineSpacing>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ { UNO_NAME_PARA_RIGHT_MARGIN, RES_MARGIN_RIGHT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_R_MARGIN|CONVERT_TWIPS}, \ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf36709.fodt b/vcl/qa/cppunit/pdfexport/data/tdf36709.fodt new file mode 100644 index 000000000000..9aa29be8086b --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf36709.fodt @@ -0,0 +1,151 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:creation-date>2024-10-31T13:46:50.189497642</meta:creation-date><meta:generator>LibreOfficeDev/25.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/5f12ad737bbb930b76299df0433c8635ae27a7bd</meta:generator><dc:date>2024-10-31T13:49:19.200988598</dc:date><meta:editing-duration>PT2M30S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="8" meta:word-count="32" meta:character-count="144" meta:non-whitespace-character-count="120"/></office:meta> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans1" svg:font-family="'Noto Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0in" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.1965in" style:num-format="1" text:number-position="left" text:increment="5"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="0em" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="1em" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="2em" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="3em" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard"> + <style:text-properties/> + </style:style> + <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="2em" style:auto-text-indent="false"/> + <style:text-properties/> + </style:style> + <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="2em" style:auto-text-indent="false"/> + <style:text-properties fo:font-size="16pt" style:font-size-asian="16pt" style:font-size-complex="16pt"/> + </style:style> + <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="2em" style:auto-text-indent="false"/> + <style:text-properties fo:font-size="20pt" style:font-size-asian="20pt" style:font-size-complex="20pt"/> + </style:style> + <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties loext:text-indent="2em" style:auto-text-indent="false"/> + <style:text-properties fo:font-size="24pt" style:font-size-asian="24pt" style:font-size-complex="24pt"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="8.2681in" fo:page-height="11.6929in" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.7874in" fo:margin-bottom="0.7874in" fo:margin-left="0.7874in" fo:margin-right="0.7874in" style:writing-mode="lr-tb" style:footnote-max-height="0in" loext:margin-gutter="0in"> + <style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P1">0 em constant size</text:p> + <text:p text:style-name="P2">1 em constant size</text:p> + <text:p text:style-name="P3">2 em constant size</text:p> + <text:p text:style-name="P4">3 em constant size</text:p> + <text:p text:style-name="P5"/> + <text:p text:style-name="P6">2 em variable size</text:p> + <text:p text:style-name="P7">2 em variable size</text:p> + <text:p text:style-name="P8">2 em variable size</text:p> + <text:p text:style-name="P9">2 em variable size</text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index 9a1a314ad3e7..72b2038b7d73 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -5822,6 +5822,57 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf140767SyriacJustification) CPPUNIT_ASSERT_LESS(90.0, aRect.at(5).getWidth()); } +CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf36709FirstLineIndentEm) +{ + saveAsPDF(u"tdf36709.fodt"); + + auto pPdfDocument = parsePDFExport(); + CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); + + auto pPdfPage = pPdfDocument->openPage(/*nIndex*/ 0); + CPPUNIT_ASSERT(pPdfPage); + auto pTextPage = pPdfPage->getTextPage(); + CPPUNIT_ASSERT(pTextPage); + + int nPageObjectCount = pPdfPage->getObjectCount(); + + CPPUNIT_ASSERT_EQUAL(8, nPageObjectCount); + + std::vector<OUString> aText; + std::vector<basegfx::B2DRectangle> aRect; + + for (int i = 0; i < nPageObjectCount; ++i) + { + auto pPageObject = pPdfPage->getObject(i); + CPPUNIT_ASSERT_MESSAGE("no object", pPageObject != nullptr); + if (pPageObject->getType() == vcl::pdf::PDFPageObjectType::Text) + { + aText.push_back(pPageObject->getText(pTextPage)); + aRect.push_back(pPageObject->getBounds()); + } + } + + CPPUNIT_ASSERT_EQUAL(size_t(8), aText.size()); + + CPPUNIT_ASSERT_EQUAL(u"0 em constant size"_ustr, aText.at(0).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(57.256, aRect.at(0).getMinX(), /*delta*/ 2.0); + CPPUNIT_ASSERT_EQUAL(u"1 em constant size"_ustr, aText.at(1).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(69.856, aRect.at(1).getMinX(), /*delta*/ 2.0); + CPPUNIT_ASSERT_EQUAL(u"2 em constant size"_ustr, aText.at(2).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(81.328, aRect.at(2).getMinX(), /*delta*/ 2.0); + CPPUNIT_ASSERT_EQUAL(u"3 em constant size"_ustr, aText.at(3).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(93.376, aRect.at(3).getMinX(), /*delta*/ 2.0); + + CPPUNIT_ASSERT_EQUAL(u"2 em variable size"_ustr, aText.at(4).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(81.328, aRect.at(4).getMinX(), /*delta*/ 2.0); + CPPUNIT_ASSERT_EQUAL(u"2 em variable size"_ustr, aText.at(5).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(89.504, aRect.at(5).getMinX(), /*delta*/ 2.0); + CPPUNIT_ASSERT_EQUAL(u"2 em variable size"_ustr, aText.at(6).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(97.680, aRect.at(6).getMinX(), /*delta*/ 2.0); + CPPUNIT_ASSERT_EQUAL(u"2 em variable size"_ustr, aText.at(7).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(105.856, aRect.at(7).getMinX(), /*delta*/ 2.0); +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/xmloff/inc/xmlbahdl.hxx b/xmloff/inc/xmlbahdl.hxx index 09e392d6cc6b..7736d6d2f432 100644 --- a/xmloff/inc/xmlbahdl.hxx +++ b/xmloff/inc/xmlbahdl.hxx @@ -69,6 +69,16 @@ public: }; /** + PropertyHandler for the XML-data-type: XML_TYPE_UNIT_MEASURE +*/ +class XMLUnitMeasurePropHdl : public XMLPropertyHandler +{ +public: + bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** PropertyHandler for the XML-data-type: XML_TYPE_PERCENT */ class XMLPercentPropHdl : public XMLPropertyHandler diff --git a/xmloff/inc/xmlprop.hxx b/xmloff/inc/xmlprop.hxx index b7acca175a1d..8f47e328ff44 100644 --- a/xmloff/inc/xmlprop.hxx +++ b/xmloff/inc/xmlprop.hxx @@ -489,6 +489,7 @@ inline constexpr OUString PROP_ParaContextMargin = u"ParaContextMargin"_ustr; inline constexpr OUString PROP_ParaExpandSingleWord = u"ParaExpandSingleWord"_ustr; inline constexpr OUString PROP_ParaFirstLineIndent = u"ParaFirstLineIndent"_ustr; inline constexpr OUString PROP_ParaFirstLineIndentRelative = u"ParaFirstLineIndentRelative"_ustr; +inline constexpr OUString PROP_ParaFirstLineIndentUnit = u"ParaFirstLineIndentUnit"_ustr; inline constexpr OUString PROP_ParaHyphenationMaxHyphens = u"ParaHyphenationMaxHyphens"_ustr; inline constexpr OUString PROP_ParaHyphenationMaxLeadingChars = u"ParaHyphenationMaxLeadingChars"_ustr; diff --git a/xmloff/source/style/prhdlfac.cxx b/xmloff/source/style/prhdlfac.cxx index a14d61ea31c2..fd6dae604bf8 100644 --- a/xmloff/source/style/prhdlfac.cxx +++ b/xmloff/source/style/prhdlfac.cxx @@ -195,6 +195,9 @@ std::unique_ptr<XMLPropertyHandler> XMLPropertyHandlerFactory::CreatePropertyHan case XML_TYPE_MEASURE16: pPropHdl.reset(new XMLMeasurePropHdl( 2 )); break; + case XML_TYPE_UNIT_MEASURE: + pPropHdl = std::make_unique<XMLUnitMeasurePropHdl>(); + break; case XML_TYPE_PERCENT : pPropHdl.reset(new XMLPercentPropHdl( 4 )); break; diff --git a/xmloff/source/style/xmlbahdl.cxx b/xmloff/source/style/xmlbahdl.cxx index a0aea8ccb1a4..02c271ad6a2e 100644 --- a/xmloff/source/style/xmlbahdl.cxx +++ b/xmloff/source/style/xmlbahdl.cxx @@ -27,6 +27,7 @@ #include <sax/tools/converter.hxx> #include <xmloff/xmluconv.hxx> #include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/beans/Pair.hpp> #include <xmloff/xmltoken.hxx> #include <limits.h> @@ -207,6 +208,58 @@ bool XMLMeasurePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, co } +bool XMLUnitMeasurePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + double fValue = 0.0; + std::optional<sal_Int16> nValueUnit; + + auto bRet = ::sax::Converter::convertMeasureUnit( fValue, nValueUnit, rStrImpValue ); + + if(bRet) + { + // This importer may only accept font-relative units. + // Discard all other units to allow fall-through to other attributes. + if (css::util::MeasureUnit::FONT_EM != nValueUnit + && css::util::MeasureUnit::FONT_IC != nValueUnit) + { + return false; + } + + css::beans::Pair<double, sal_Int16> stValue{fValue, nValueUnit.value()}; + rValue <<= stValue; + } + + return bRet; +} + +bool XMLUnitMeasurePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + css::beans::Pair<double, sal_Int16> stValue{0.0, css::util::MeasureUnit::MM_100TH}; + + if( rValue >>= stValue ) + { + auto [fValue, nValueUnit] = stValue; + + // This exporter may only produce font-relative units. + // Discard all other units to allow fall-through to other attributes. + if (css::util::MeasureUnit::FONT_EM != nValueUnit + && css::util::MeasureUnit::FONT_IC != nValueUnit) + { + return false; + } + + OUStringBuffer aOut; + ::sax::Converter::convertMeasureUnit( aOut, fValue, nValueUnit ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + XMLBoolFalsePropHdl::~XMLBoolFalsePropHdl() { // nothing to do diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx index 25cb36ef1b0d..8553965c67d0 100644 --- a/xmloff/source/text/txtprmap.cxx +++ b/xmloff/source/text/txtprmap.cxx @@ -366,6 +366,9 @@ XMLPropertyMapEntry constexpr aXMLParaPropMap[] = MP_E( PROP_ParaFirstLineIndent, XML_NAMESPACE_FO, XML_TEXT_INDENT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARAFIRSTLINE ), MP_E( PROP_ParaFirstLineIndentRelative, XML_NAMESPACE_FO, XML_TEXT_INDENT, XML_TYPE_PERCENT, CTF_PARAFIRSTLINE_REL ), + MAP_EXT( PROP_ParaFirstLineIndentUnit, XML_NAMESPACE_LO_EXT, XML_TEXT_INDENT, XML_TYPE_PROP_PARAGRAPH|XML_TYPE_UNIT_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MAP_EXT_I( PROP_ParaFirstLineIndent, XML_NAMESPACE_LO_EXT, XML_TEXT_INDENT, XML_TYPE_PROP_PARAGRAPH|XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARAFIRSTLINE ), + MAP_EXT_I( PROP_ParaFirstLineIndentRelative, XML_NAMESPACE_LO_EXT, XML_TEXT_INDENT, XML_TYPE_PROP_PARAGRAPH|XML_TYPE_PERCENT, CTF_PARAFIRSTLINE_REL ), MP_E( PROP_ParaIsAutoFirstLineIndent, XML_NAMESPACE_STYLE, XML_AUTO_TEXT_INDENT, XML_TYPE_BOOL, 0 ), // RES_PAGEDESC MP_E( PROP_PageDescName, XML_NAMESPACE_STYLE, XML_MASTER_PAGE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STYLENAME, CTF_PAGEDESCNAME ), |