From d3a59f7a915f9cc0864f2c76ccf90b6cd6fea339 Mon Sep 17 00:00:00 2001 From: Jonathan Clark Date: Thu, 7 Nov 2024 02:23:02 -0700 Subject: [PATCH] tdf#36709 sw: Writer layout for font-relative first-line indent This change implements layout for font-relative paragraph first-line indentation in Writer. Change-Id: Ie8f386bcc13a43ab92d5c15654c24bfdfc62bd69 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176216 Tested-by: Jenkins Reviewed-by: Jonathan Clark --- cui/source/tabpages/paragrph.cxx | 20 +- editeng/source/items/frmitems.cxx | 175 ++++++++++++++---- include/editeng/lrspitem.hxx | 49 +++-- include/editeng/numitem.hxx | 5 + include/vcl/metric.hxx | 11 ++ offapi/com/sun/star/util/MeasureUnit.idl | 12 +- sax/qa/cppunit/test_converter.cxx | 2 +- sax/source/tools/converter.cxx | 4 +- sw/inc/ndtxt.hxx | 12 +- sw/qa/extras/uiwriter/uiwriter8.cxx | 21 ++- sw/source/core/crsr/crstrvl.cxx | 2 +- .../core/doc/DocumentStylePoolManager.cxx | 29 +-- sw/source/core/doc/docfmt.cxx | 3 +- sw/source/core/doc/fmtcol.cxx | 7 +- sw/source/core/edit/autofmt.cxx | 41 ++-- sw/source/core/inc/swfont.hxx | 4 + sw/source/core/layout/fly.cxx | 3 +- sw/source/core/layout/frmtool.cxx | 6 +- .../core/text/EnhancedPDFExportHelper.cxx | 2 +- sw/source/core/text/frmcrsr.cxx | 9 +- sw/source/core/text/frmpaint.cxx | 5 +- sw/source/core/text/itratr.cxx | 3 +- sw/source/core/text/itrcrsr.cxx | 29 +-- sw/source/core/text/porfld.cxx | 11 +- sw/source/core/tox/ToxTabStopTokenHandler.cxx | 6 +- sw/source/core/txtnode/ndtxt.cxx | 49 +++-- sw/source/core/txtnode/swfont.cxx | 12 ++ sw/source/core/txtnode/thints.cxx | 4 +- sw/source/filter/html/css1atr.cxx | 5 +- sw/source/filter/html/htmlatr.cxx | 6 +- sw/source/filter/html/htmlctxt.cxx | 5 +- sw/source/filter/html/htmlnumreader.cxx | 4 +- sw/source/filter/html/svxcss1.cxx | 3 +- sw/source/filter/html/swhtml.cxx | 15 +- sw/source/filter/ww8/docxattributeoutput.cxx | 3 +- sw/source/filter/ww8/rtfattributeoutput.cxx | 6 +- sw/source/filter/ww8/wrtw8nds.cxx | 22 ++- sw/source/filter/ww8/ww8atr.cxx | 6 +- sw/source/filter/ww8/ww8graf.cxx | 4 +- sw/source/filter/ww8/ww8par.cxx | 20 +- sw/source/filter/ww8/ww8par2.cxx | 2 +- sw/source/filter/ww8/ww8par3.cxx | 7 +- sw/source/filter/ww8/ww8par6.cxx | 9 +- sw/source/uibase/app/docstyle.cxx | 8 +- sw/source/uibase/shells/txtattr.cxx | 5 +- sw/source/uibase/uiview/viewtab.cxx | 19 +- sw/source/uibase/wrtsh/delete.cxx | 6 +- vcl/inc/font/FontMetricData.hxx | 6 + vcl/source/font/fontmetric.cxx | 42 ++++- vcl/source/outdev/font.cxx | 4 + xmloff/source/style/xmlbahdl.cxx | 4 +- 51 files changed, 511 insertions(+), 236 deletions(-) diff --git a/cui/source/tabpages/paragrph.cxx b/cui/source/tabpages/paragrph.cxx index 33c3005eebaa..2b262378a361 100644 --- a/cui/source/tabpages/paragrph.cxx +++ b/cui/source/tabpages/paragrph.cxx @@ -411,20 +411,26 @@ bool SvxStdParagraphTabPage::FillItemSet( SfxItemSet* rOutSet ) if (m_aFLineIndent.IsRelative()) { - item.SetTextFirstLineOffset(rOldItem.GetTextFirstLineOffset(), + item.SetTextFirstLineOffset( + rOldItem.GetTextFirstLineOffsetValue(), rOldItem.GetTextFirstLineOffsetUnit(), static_cast(m_aFLineIndent.get_value(FieldUnit::NONE))); } else { - item.SetTextFirstLineOffset(static_cast(m_aFLineIndent.GetCoreValue(eUnit))); + // tdf#36709: TODO: Handle font-relative units from GUI + item.SetTextFirstLineOffset( + static_cast(m_aFLineIndent.GetCoreValue(eUnit)), + css::util::MeasureUnit::TWIP); } } else { - item.SetTextFirstLineOffset(static_cast(m_aFLineIndent.GetCoreValue(eUnit))); + // tdf#36709: TODO: Handle font-relative units from GUI + item.SetTextFirstLineOffset(static_cast(m_aFLineIndent.GetCoreValue(eUnit)), + css::util::MeasureUnit::TWIP); } item.SetAutoFirst(m_xAutoCB->get_active()); - if (item.GetTextFirstLineOffset() < 0) + if (item.GetTextFirstLineOffsetValue() < 0) { bNullTab = true; } @@ -660,16 +666,18 @@ void SvxStdParagraphTabPage::Reset( const SfxItemSet* rSet ) } else { + // tdf#36709: TODO: Handle font-relative units from GUI m_aFLineIndent.SetRelative(false); m_aFLineIndent.set_min(-9999, FieldUnit::NONE); m_aFLineIndent.SetFieldUnit(eFUnit); - m_aFLineIndent.SetMetricValue(rOldFirstLine.GetTextFirstLineOffset(), eUnit); + m_aFLineIndent.SetMetricValue(rOldFirstLine.GetTextFirstLineOffsetValue(), eUnit); } m_xAutoCB->set_active(rOldFirstLine.IsAutoFirst()); } else { - m_aFLineIndent.SetMetricValue(rOldFirstLine.GetTextFirstLineOffset(), eUnit); + // tdf#36709: TODO: Handle font-relative units from GUI + m_aFLineIndent.SetMetricValue(rOldFirstLine.GetTextFirstLineOffsetValue(), eUnit); m_xAutoCB->set_active(rOldFirstLine.IsAutoFirst()); } AutoHdl_Impl(*m_xAutoCB); diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx index 073ad972e9ac..3f11d48057ac 100644 --- a/editeng/source/items/frmitems.cxx +++ b/editeng/source/items/frmitems.cxx @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -496,15 +497,6 @@ void SvxLRSpaceItem::SetRight(const tools::Long nR, const sal_uInt16 nProp) nPropRightMargin = nProp; } -void SvxFirstLineIndentItem::SetTextFirstLineOffset( - const short nF, const sal_uInt16 nProp) -{ - ASSERT_CHANGE_REFCOUNTED_ITEM; - m_nFirstLineOffset = short((tools::Long(nF) * nProp ) / 100); - m_nUnit = css::util::MeasureUnit::TWIP; - m_nPropFirstLineOffset = nProp; -} - void SvxLRSpaceItem::SetTextFirstLineOffset(const short nF, const sal_uInt16 nProp) { // note: left margin contains any negative first line offset - preserve it! @@ -561,12 +553,17 @@ tools::Long SvxTextLeftMarginItem::GetTextLeft() const return m_nTextLeftMargin; } -tools::Long SvxTextLeftMarginItem::GetLeft(SvxFirstLineIndentItem const& rFirstLine) const +tools::Long SvxTextLeftMarginItem::GetLeft(const SvxFirstLineIndentItem& rFirstLine, + const SvxFontUnitMetrics& rMetrics) const { // add any negative first line offset to text left margin to get left - return (rFirstLine.GetTextFirstLineOffset() < 0) - ? m_nTextLeftMargin + rFirstLine.GetTextFirstLineOffset() - : m_nTextLeftMargin; + if (rFirstLine.GetTextFirstLineOffsetValue() < 0.0) + { + auto nFirstLineOffset = rFirstLine.ResolveTextFirstLineOffset(rMetrics); + return m_nTextLeftMargin + nFirstLineOffset; + } + + return m_nTextLeftMargin; } tools::Long SvxLRSpaceItem::GetTextLeft() const @@ -938,10 +935,76 @@ SvxFirstLineIndentItem::SvxFirstLineIndentItem(const sal_uInt16 nId) { } -SvxFirstLineIndentItem::SvxFirstLineIndentItem(const short nFirst, const sal_uInt16 nId) - : SfxPoolItem(nId, SfxItemType::SvxFirstLineIndentItemType) - , m_nFirstLineOffset(nFirst) +SvxFirstLineIndentItem::SvxFirstLineIndentItem(double dValue, sal_uInt16 nUnit, + const sal_uInt16 nId) + : SvxFirstLineIndentItem(nId) { + SetTextFirstLineOffset(dValue, nUnit); +} + +bool SvxFirstLineIndentItem::IsAutoFirst() const { return m_bAutoFirst; } + +void SvxFirstLineIndentItem::SetAutoFirst(bool bNew) +{ + ASSERT_CHANGE_REFCOUNTED_ITEM; + m_bAutoFirst = bNew; +} + +void SvxFirstLineIndentItem::SetPropTextFirstLineOffset(sal_uInt16 nProp) +{ + ASSERT_CHANGE_REFCOUNTED_ITEM; + m_nPropFirstLineOffset = nProp; +} + +sal_uInt16 SvxFirstLineIndentItem::GetPropTextFirstLineOffset() const +{ + return m_nPropFirstLineOffset; +} + +void SvxFirstLineIndentItem::SetTextFirstLineOffset(double dValue, sal_Int16 nUnit, + sal_uInt16 nProp) +{ + ASSERT_CHANGE_REFCOUNTED_ITEM; + m_dFirstLineOffset = dValue; + m_nUnit = nUnit; + m_nPropFirstLineOffset = nProp; + + if (nProp != 100) + { + m_dFirstLineOffset = (dValue * static_cast(nProp)) / 100.0; + } +} + +double SvxFirstLineIndentItem::GetTextFirstLineOffsetValue() const { return m_dFirstLineOffset; } + +sal_Int16 SvxFirstLineIndentItem::GetTextFirstLineOffsetUnit() const { return m_nUnit; } + +double +SvxFirstLineIndentItem::ResolveTextFirstLineOffsetDouble(const SvxFontUnitMetrics& rMetrics) const +{ + if(m_nUnit == css::util::MeasureUnit::TWIP) + return m_dFirstLineOffset; + + SAL_WARN_IF(!rMetrics.m_bInitialized, "editeng", "font-relative indentation lost"); + + switch (m_nUnit) + { + case css::util::MeasureUnit::FONT_EM: + return m_dFirstLineOffset * rMetrics.m_dEmTwips; + + case css::util::MeasureUnit::FONT_CJK_ADVANCE: + return m_dFirstLineOffset * rMetrics.m_dIcTwips; + + default: + SAL_WARN("editeng", "unhandled type conversion"); + return 0.0; + } +} + +sal_Int32 +SvxFirstLineIndentItem::ResolveTextFirstLineOffset(const SvxFontUnitMetrics& rMetrics) const +{ + return static_cast(std::llround(ResolveTextFirstLineOffsetDouble(rMetrics))); } bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) const @@ -956,8 +1019,9 @@ bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) con // In practice, these are always stored here in twips. if (m_nUnit == css::util::MeasureUnit::TWIP) { - rVal <<= static_cast(bConvert ? convertTwipToMm100(m_nFirstLineOffset) - : m_nFirstLineOffset); + auto nConvOffset + = (bConvert ? convertTwipToMm100(m_dFirstLineOffset) : m_dFirstLineOffset); + rVal <<= static_cast(std::llround(nConvOffset)); bRet = true; } break; @@ -973,9 +1037,7 @@ bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) con // 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{ - static_cast(m_nFirstLineOffset), m_nUnit - }; + rVal <<= css::beans::Pair{ m_dFirstLineOffset, m_nUnit }; bRet = true; } break; @@ -1009,7 +1071,8 @@ bool SvxFirstLineIndentItem::PutValue(const uno::Any& rVal, sal_uInt8 nMemberId) { return false; } - m_nFirstLineOffset = bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal; + + m_dFirstLineOffset = bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : nVal; m_nUnit = css::util::MeasureUnit::TWIP; m_nPropFirstLineOffset = 100; break; @@ -1035,7 +1098,7 @@ bool SvxFirstLineIndentItem::PutValue(const uno::Any& rVal, sal_uInt8 nMemberId) return false; } - m_nFirstLineOffset = stVal.First; + m_dFirstLineOffset = stVal.First; m_nUnit = stVal.Second; m_nPropFirstLineOffset = 100; break; @@ -1057,16 +1120,15 @@ bool SvxFirstLineIndentItem::operator==(const SfxPoolItem& rAttr) const const SvxFirstLineIndentItem& rOther = static_cast(rAttr); - return (m_nFirstLineOffset == rOther.GetTextFirstLineOffset() - && m_nUnit == rOther.GetTextFirstLineOffsetUnit() - && m_nPropFirstLineOffset == rOther.GetPropTextFirstLineOffset() - && m_bAutoFirst == rOther.IsAutoFirst()); + return std::tie(m_dFirstLineOffset, m_nUnit, m_nPropFirstLineOffset, m_bAutoFirst) + == std::tie(rOther.m_dFirstLineOffset, rOther.m_nUnit, rOther.m_nPropFirstLineOffset, + rOther.m_bAutoFirst); } size_t SvxFirstLineIndentItem::hashCode() const { std::size_t seed(0); - o3tl::hash_combine(seed, m_nFirstLineOffset); + o3tl::hash_combine(seed, m_dFirstLineOffset); o3tl::hash_combine(seed, m_nUnit); o3tl::hash_combine(seed, m_nPropFirstLineOffset); o3tl::hash_combine(seed, m_bAutoFirst); @@ -1095,10 +1157,15 @@ bool SvxFirstLineIndentItem::GetPresentation rText += unicode::formatPercent(m_nPropFirstLineOffset, Application::GetSettings().GetUILanguageTag()); } + else if (m_nUnit != css::util::MeasureUnit::TWIP) + { + OUStringBuffer stBuf; + sax::Converter::convertMeasureUnit(stBuf, m_dFirstLineOffset, m_nUnit); + rText += stBuf.makeStringAndClear(); + } else { - rText += GetMetricText(static_cast(m_nFirstLineOffset), - eCoreUnit, ePresUnit, &rIntl); + rText += GetMetricText(m_dFirstLineOffset, eCoreUnit, ePresUnit, &rIntl); } return true; } @@ -1110,11 +1177,16 @@ bool SvxFirstLineIndentItem::GetPresentation rText += unicode::formatPercent(m_nPropFirstLineOffset, Application::GetSettings().GetUILanguageTag()); } + else if (m_nUnit != css::util::MeasureUnit::TWIP) + { + OUStringBuffer stBuf; + sax::Converter::convertMeasureUnit(stBuf, m_dFirstLineOffset, m_nUnit); + rText += stBuf.makeStringAndClear(); + } else { - rText += GetMetricText(static_cast(m_nFirstLineOffset), - eCoreUnit, ePresUnit, &rIntl) - + " " + EditResId(GetMetricId(ePresUnit)); + rText += GetMetricText(m_dFirstLineOffset, eCoreUnit, ePresUnit, &rIntl) + " " + + EditResId(GetMetricId(ePresUnit)); } return true; } @@ -1126,7 +1198,8 @@ bool SvxFirstLineIndentItem::GetPresentation void SvxFirstLineIndentItem::ScaleMetrics(tools::Long const nMult, tools::Long const nDiv) { ASSERT_CHANGE_REFCOUNTED_ITEM; - m_nFirstLineOffset = static_cast(BigInt::Scale(m_nFirstLineOffset, nMult, nDiv)); + m_dFirstLineOffset + = (m_dFirstLineOffset * static_cast(nMult)) / static_cast(nDiv); } bool SvxFirstLineIndentItem::HasMetrics() const @@ -1138,7 +1211,8 @@ 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_dFirstLineOffset"), + BAD_CAST(OString::number(m_dFirstLineOffset).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())); @@ -1151,13 +1225,34 @@ boost::property_tree::ptree SvxFirstLineIndentItem::dumpAsJSON() const boost::property_tree::ptree aState; - MapUnit eTargetUnit = MapUnit::MapInch; + switch (m_nUnit) + { + case css::util::MeasureUnit::TWIP: + { + MapUnit eTargetUnit = MapUnit::MapInch; - OUString sFirstline = GetMetricText(GetTextFirstLineOffset(), - MapUnit::MapTwip, eTargetUnit, nullptr); + OUString sFirstline + = GetMetricText(m_dFirstLineOffset, MapUnit::MapTwip, eTargetUnit, nullptr); - aState.put("firstline", sFirstline); - aState.put("unit", "inch"); + aState.put("firstline", sFirstline); + aState.put("unit", "inch"); + } + break; + + case css::util::MeasureUnit::FONT_EM: + aState.put("firstline", m_dFirstLineOffset); + aState.put("unit", "em"); + break; + + case css::util::MeasureUnit::FONT_CJK_ADVANCE: + aState.put("firstline", m_dFirstLineOffset); + aState.put("unit", "ic"); + break; + + default: + SAL_WARN("editeng", "unhandled type conversion"); + break; + } aTree.push_back(std::make_pair("state", aState)); diff --git a/include/editeng/lrspitem.hxx b/include/editeng/lrspitem.hxx index 63bff2c974ca..e4f0e8a3dbf7 100644 --- a/include/editeng/lrspitem.hxx +++ b/include/editeng/lrspitem.hxx @@ -47,6 +47,22 @@ SetTextLeft SetTextFirst GetLeft GetTextLeft GetTextFirst (What?) class SvxFirstLineIndentItem; +/// helper struct used for resolving font-relative indentation +struct SvxFontUnitMetrics +{ + double m_dEmTwips = 0.0; + double m_dIcTwips = 0.0; + bool m_bInitialized = false; + + SvxFontUnitMetrics() = default; + SvxFontUnitMetrics(double dEmTwips, double dIcTwips) + : m_dEmTwips(dEmTwips) + , m_dIcTwips(dIcTwips) + , m_bInitialized(true) + { + } +}; + /// GetLeft() - for everything that's not applied to a paragraph class EDITENG_DLLPUBLIC SvxLeftMarginItem final : public SfxPoolItem { @@ -100,7 +116,8 @@ public: //TODO: need this? //void SetLeft(SvxFirstLineIndentItem const& rFirstLine, const tools::Long nL, const sal_uInt16 nProp = 100); /// get left margin without negative first-line indent - tools::Long GetLeft(SvxFirstLineIndentItem const& rFirstLine) const; + tools::Long GetLeft(const SvxFirstLineIndentItem& rFirstLine, + const SvxFontUnitMetrics& rMetrics) const; sal_uInt16 GetPropLeft() const { return m_nPropLeftMargin; } void SetTextLeft(const tools::Long nL, const sal_uInt16 nProp = 100); @@ -136,33 +153,27 @@ class EDITENG_DLLPUBLIC SvxFirstLineIndentItem final : public SfxPoolItem { private: /// First-line indent always relative to GetTextLeft() - short m_nFirstLineOffset = 0; + double m_dFirstLineOffset = 0.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; public: - bool IsAutoFirst() const { return m_bAutoFirst; } - void SetAutoFirst(const bool bNew) { ASSERT_CHANGE_REFCOUNTED_ITEM; m_bAutoFirst = bNew; } + bool IsAutoFirst() const; + void SetAutoFirst(const bool bNew); - 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; - m_nUnit = css::util::MeasureUnit::TWIP; - } + void SetPropTextFirstLineOffset(sal_uInt16 nProp); + sal_uInt16 GetPropTextFirstLineOffset() const; + + void SetTextFirstLineOffset(double dValue, sal_Int16 nUnit, sal_uInt16 nProp = 100); + double GetTextFirstLineOffsetValue() const; + sal_Int16 GetTextFirstLineOffsetUnit() const; + double ResolveTextFirstLineOffsetDouble(const SvxFontUnitMetrics& rMetrics) const; + sal_Int32 ResolveTextFirstLineOffset(const SvxFontUnitMetrics& rMetrics) const; explicit SvxFirstLineIndentItem(const sal_uInt16 nId); - SvxFirstLineIndentItem(const short nOffset, const sal_uInt16 nId); + SvxFirstLineIndentItem(double dValue, sal_uInt16 nUnit, const sal_uInt16 nId); SvxFirstLineIndentItem(SvxFirstLineIndentItem const &) = default; // SfxPoolItem copy function dichotomy // "pure virtual Methods" from SfxPoolItem diff --git a/include/editeng/numitem.hxx b/include/editeng/numitem.hxx index 423a0e2aeda3..c6067c53cb40 100644 --- a/include/editeng/numitem.hxx +++ b/include/editeng/numitem.hxx @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,7 @@ private: SvxNumPositionAndSpaceMode mePositionAndSpaceMode; sal_Int32 nFirstLineOffset; // First line indent + sal_Int16 nFirstLineOffsetUnit = css::util::MeasureUnit::TWIP; sal_Int32 nAbsLSpace; // Distance Border<->Number short nCharTextDistance; // Distance Number<->Text @@ -139,6 +141,7 @@ private: tools::Long mnListtabPos; // specifies the first line indent tools::Long mnFirstLineIndent; + sal_Int16 mnFirstLineIndentUnit = css::util::MeasureUnit::TWIP; // specifies the indent before the text, e.g. in L2R-layout the left margin tools::Long mnIndentAt; @@ -210,6 +213,7 @@ public: sal_Int32 GetAbsLSpace() const; void SetFirstLineOffset(sal_Int32 nSet) { nFirstLineOffset = nSet;} sal_Int32 GetFirstLineOffset() const; + sal_Int16 GetFirstLineOffsetUnit() const { return nFirstLineOffsetUnit; } void SetCharTextDistance(short nSet) { nCharTextDistance = nSet; } short GetCharTextDistance() const; @@ -220,6 +224,7 @@ public: tools::Long GetListtabPos() const { return mnListtabPos;} void SetFirstLineIndent( const tools::Long nFirstLineIndent ); tools::Long GetFirstLineIndent() const { return mnFirstLineIndent;} + sal_Int16 GetFirstLineIndentUnit() const { return mnFirstLineIndentUnit; } void SetIndentAt( const tools::Long nIndentAt ); tools::Long GetIndentAt() const { return mnIndentAt;} diff --git a/include/vcl/metric.hxx b/include/vcl/metric.hxx index bc38cb227256..0f9942e3992f 100644 --- a/include/vcl/metric.hxx +++ b/include/vcl/metric.hxx @@ -49,6 +49,10 @@ public: sal_Int32 GetBulletOffset() const { return mnBulletOffset; } sal_Int32 GetHangingBaseline() const { return mnHangingBaseline; } + double GetUnitEm() const { return mdEmSize; } + double GetHorCJKAdvance() const { return mdHorCJKAdvanceSize; } + double GetVertCJKAdvance() const { return mdVertCJKAdvanceSize; } + void SetAscent( sal_Int32 nAscent ) { mnAscent = nAscent; } void SetDescent( sal_Int32 nDescent ) { mnDescent = nDescent; } void SetExternalLeading( sal_Int32 nExtLeading ) { mnExtLeading = nExtLeading; } @@ -58,6 +62,10 @@ public: void SetBulletOffset( sal_Int32 nOffset ) { mnBulletOffset = nOffset; } void SetHangingBaseline( sal_Int32 nBaseline ) { mnHangingBaseline = nBaseline; } + void SetUnitEm(double dValue) { mdEmSize = dValue; } + void SetHorCJKAdvance(double dValue) { mdHorCJKAdvanceSize = dValue; } + void SetVertCJKAdvance(double dValue) { mdVertCJKAdvanceSize = dValue; } + bool IsFullstopCentered() const { return mbFullstopCentered; } void SetFullstopCenteredFlag( bool bCentered ) { mbFullstopCentered = bCentered; } @@ -85,6 +93,9 @@ private: sal_Int32 mnSlant; // Slant sal_Int32 mnBulletOffset; // Offset for non-printing character sal_Int32 mnHangingBaseline; // Offset from Romn baseline to hanging baseline. + double mdEmSize; // Size of an 'em' unit + double mdHorCJKAdvanceSize; // Size of an 'ic' unit in horizontal layout + double mdVertCJKAdvanceSize; // Size of an 'ic' unit in vertical layout bool mbFullstopCentered; }; diff --git a/offapi/com/sun/star/util/MeasureUnit.idl b/offapi/com/sun/star/util/MeasureUnit.idl index 2b9a93a6e12a..ef3f52de9a64 100644 --- a/offapi/com/sun/star/util/MeasureUnit.idl +++ b/offapi/com/sun/star/util/MeasureUnit.idl @@ -84,11 +84,17 @@ published constants MeasureUnit /** all measures for this component are in SYSFONT */ const short SYSFONT = 18; - /** all measures for this component are in em relative to the font */ + /** all measures for this component are in em relative to the font + + @since LibreOffice 25.2 + */ const short FONT_EM = 19; - /** all measures for this component are in ideographic advances relative to the font */ - const short FONT_IC = 20; + /** all measures for this component are in ic, per the CSS definition + + @since LibreOffice 25.2 + */ + const short FONT_CJK_ADVANCE = 20; }; diff --git a/sax/qa/cppunit/test_converter.cxx b/sax/qa/cppunit/test_converter.cxx index 47bd5b9d412d..65eb7f0acfb3 100644 --- a/sax/qa/cppunit/test_converter.cxx +++ b/sax/qa/cppunit/test_converter.cxx @@ -660,7 +660,7 @@ void ConverterTest::testConvertMeasureUnit() fnFromStr("5000%", 5000.0, MeasureUnit::PERCENT, true); fnFromStr("5000cm", 5000.0, MeasureUnit::CM, true); fnFromStr("5000em", 5000.0, MeasureUnit::FONT_EM, true); - fnFromStr("5000ic", 5000.0, MeasureUnit::FONT_IC, true); + fnFromStr("5000ic", 5000.0, MeasureUnit::FONT_CJK_ADVANCE, true); fnFromStr("5000in", 5000.0, MeasureUnit::INCH, true); fnFromStr("5000mm", 5000.0, MeasureUnit::MM, true); fnFromStr("5000pt", 5000.0, MeasureUnit::POINT, true); diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx index 0c1613a32a89..61557575350b 100644 --- a/sax/source/tools/converter.cxx +++ b/sax/source/tools/converter.cxx @@ -76,7 +76,7 @@ const std::map stConvertMeasureUnitStrMap{ { MeasureUnit::INCH, gpsINCH }, { MeasureUnit::POINT, gpsPT }, { MeasureUnit::PICA, gpsPC }, { MeasureUnit::PERCENT, gpsPERCENT }, { MeasureUnit::PIXEL, gpsPX }, { MeasureUnit::FONT_EM, gpsFONT_EM }, - { MeasureUnit::FONT_IC, gpsFONT_IC } + { MeasureUnit::FONT_CJK_ADVANCE, gpsFONT_IC } }; o3tl::Length Measure2O3tlUnit(sal_Int16 nUnit) @@ -159,7 +159,7 @@ template static std::optional lcl_parseMeasureUnit(const V& case u'i': if (wordEndsWith(rString.substr(1), "c")) - return MeasureUnit::FONT_IC; + return MeasureUnit::FONT_CJK_ADVANCE; if (wordEndsWith(rString.substr(1), "n")) return MeasureUnit::INCH; break; diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index c77e91a89371..48d9d287df50 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -43,6 +43,7 @@ class SwNumRule; class SwNodeNum; class SvxFirstLineIndentItem; class SvxTextLeftMarginItem; +struct SvxFontUnitMetrics; class SwXParagraph; namespace utl { @@ -530,13 +531,18 @@ public: Returns the combined first line indent of this text node and its numbering. - @param the first line indent of this text node taking the - numbering into account (return parameter) + @param rFirstOffset + the first line indent of this text node taking the numbering into + account (return parameter) + + @param rMetrics + helper structure containing font metrics, used for resolving font- + relative indentation @retval true this node has SwNodeNum and has numbering rule @retval false else */ - bool GetFirstLineOfsWithNum( short& rFirstOffset ) const; + bool GetFirstLineOfsWithNum( short& rFirstOffset, const SvxFontUnitMetrics& rMetrics ) const; SwTwips GetAdditionalIndentForStartingNewList() const; diff --git a/sw/qa/extras/uiwriter/uiwriter8.cxx b/sw/qa/extras/uiwriter/uiwriter8.cxx index 109970c1cf6e..df3be99f9037 100644 --- a/sw/qa/extras/uiwriter/uiwriter8.cxx +++ b/sw/qa/extras/uiwriter/uiwriter8.cxx @@ -991,8 +991,11 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule()); CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->GetTextLeft(), rNode.GetAttr(RES_MARGIN_TEXTLEFT).GetTextLeft()); - CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffset(), - rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset()); + CPPUNIT_ASSERT_DOUBLES_EQUAL( + pFirstLineIndent->GetTextFirstLineOffsetValue(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffsetValue(), 0.01); + CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffsetUnit(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffsetUnit()); } pWrtShell->FwdPara(); @@ -1017,8 +1020,11 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule()); CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->GetTextLeft(), rNode.GetAttr(RES_MARGIN_TEXTLEFT).GetTextLeft()); - CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffset(), - rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset()); + CPPUNIT_ASSERT_DOUBLES_EQUAL( + pFirstLineIndent->GetTextFirstLineOffsetValue(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffsetValue(), 0.01); + CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffsetUnit(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffsetUnit()); } pWrtShell->FwdPara(); @@ -1043,8 +1049,11 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule()); CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->GetTextLeft(), rNode.GetAttr(RES_MARGIN_TEXTLEFT).GetTextLeft()); - CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffset(), - rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset()); + CPPUNIT_ASSERT_DOUBLES_EQUAL( + pFirstLineIndent->GetTextFirstLineOffsetValue(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffsetValue(), 0.01); + CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffsetUnit(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffsetUnit()); } } diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx index dcdfc4118851..e187159bc7d3 100644 --- a/sw/source/core/crsr/crstrvl.cxx +++ b/sw/source/core/crsr/crstrvl.cxx @@ -2438,7 +2438,7 @@ bool SwCursorShell::SetShadowCursorPos( const Point& rPt, SwFillMode eFillMode ) RES_MARGIN_FIRSTLINE, RES_MARGIN_TEXTLEFT> aSet(GetDoc()->GetAttrPool()); SvxFirstLineIndentItem firstLine(pCNd->GetAttr(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(pCNd->GetAttr(RES_MARGIN_TEXTLEFT)); - firstLine.SetTextFirstLineOffset(0); + firstLine.SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); leftMargin.SetTextLeft(aFPos.nTabCnt); aSet.Put(firstLine); aSet.Put(leftMargin); diff --git a/sw/source/core/doc/DocumentStylePoolManager.cxx b/sw/source/core/doc/DocumentStylePoolManager.cxx index 09e7efe6f09c..7df2dc58ebfd 100644 --- a/sw/source/core/doc/DocumentStylePoolManager.cxx +++ b/sw/source/core/doc/DocumentStylePoolManager.cxx @@ -212,8 +212,8 @@ namespace { SvxFirstLineIndentItem firstLine(pColl->GetFormatAttr(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(pColl->GetFormatAttr(RES_MARGIN_TEXTLEFT)); - firstLine.SetTextFirstLineOffsetValue(rNFormat.GetFirstLineOffset()); - //TODO: overflow + firstLine.SetTextFirstLineOffset(rNFormat.GetFirstLineOffset(), + rNFormat.GetFirstLineOffsetUnit()); leftMargin.SetTextLeft(rNFormat.GetAbsLSpace()); pColl->SetFormatAttr(firstLine); pColl->SetFormatAttr(leftMargin); @@ -232,7 +232,7 @@ namespace bool bHeader, bool bTab ) { sal_uInt16 nLeft = o3tl::convert(5 * nFact, o3tl::Length::mm, o3tl::Length::twip); - SvxFirstLineIndentItem const firstLine(0, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(nLeft, RES_MARGIN_TEXTLEFT); rSet.Put(firstLine); rSet.Put(leftMargin); @@ -257,7 +257,8 @@ namespace sal_uInt16 nNxt, SwTwips nEZ, SwTwips nLeft, SwTwips nUpper, SwTwips nLower ) { - SvxFirstLineIndentItem const firstLine(sal_uInt16(nEZ), RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem firstLine(nEZ, css::util::MeasureUnit::TWIP, RES_MARGIN_FIRSTLINE); + SvxTextLeftMarginItem const leftMargin(sal_uInt16(nLeft), RES_MARGIN_TEXTLEFT); rSet.Put(firstLine); rSet.Put(leftMargin); @@ -710,7 +711,8 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, case RES_POOLCOLL_TEXT_IDENT: // Text body indentation { auto const first(o3tl::convert(5, o3tl::Length::mm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(first, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(first, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(0, RES_MARGIN_TEXTLEFT); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -720,7 +722,8 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, { auto const first(-o3tl::convert(5, o3tl::Length::mm, o3tl::Length::twip)); auto const left(o3tl::convert(1, o3tl::Length::cm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(first, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(first, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(left, RES_MARGIN_TEXTLEFT); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -733,7 +736,7 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, case RES_POOLCOLL_TEXT_MOVE: // Text body move { auto const left(o3tl::convert(5, o3tl::Length::mm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(0, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(left, RES_MARGIN_TEXTLEFT); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -744,7 +747,8 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, { auto const first(-o3tl::convert(45, o3tl::Length::mm, o3tl::Length::twip)); auto const left(o3tl::convert(5, o3tl::Length::cm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(first, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(first, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(left, RES_MARGIN_TEXTLEFT); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -757,7 +761,7 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, case RES_POOLCOLL_MARGINAL: // Text body marginal { auto const left(o3tl::convert(4, o3tl::Length::cm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(0, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(left, RES_MARGIN_TEXTLEFT); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -952,7 +956,8 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, { auto const first(-o3tl::convert(6, o3tl::Length::mm, o3tl::Length::twip)); auto const left(o3tl::convert(6, o3tl::Length::mm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(first, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(first, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(left, RES_MARGIN_TEXTLEFT); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -1025,7 +1030,7 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, aSet.Put(rightMargin); // First line indent - aSet.Put(SvxFirstLineIndentItem(0, RES_MARGIN_FIRSTLINE)); + aSet.Put(SvxFirstLineIndentItem(RES_MARGIN_FIRSTLINE)); // Added as part of tdf#159531 // Top/bottom spacing (i.e. Above/Below paragraph spacing) @@ -1394,7 +1399,7 @@ SwTextFormatColl* DocumentStylePoolManager::GetTextCollFromPool( sal_uInt16 nId, { auto const left(o3tl::convert(1, o3tl::Length::cm, o3tl::Length::twip)); auto const right(o3tl::convert(1, o3tl::Length::cm, o3tl::Length::twip)); - SvxFirstLineIndentItem const firstLine(0, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(left, RES_MARGIN_TEXTLEFT); SvxRightMarginItem const rightMargin(right, RES_MARGIN_RIGHT); aSet.Put(firstLine); diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx index 0c48355c6417..adec26e403c4 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -1706,7 +1706,8 @@ void SwDoc::MoveLeftMargin(const SwPaM& rPam, bool bRight, bool bModulus, } if (indents & ::sw::ListLevelIndents::FirstLine) { - firstLine.SetTextFirstLineOffset(static_cast(rFormat.GetFirstLineIndent())); + firstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit()); } } } diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx index e6c4c16310a4..a7d47a8681fe 100644 --- a/sw/source/core/doc/fmtcol.cxx +++ b/sw/source/core/doc/fmtcol.cxx @@ -251,10 +251,11 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH // We had a relative value -> recalculate if (100 != pOldFirstLineIndent->GetPropTextFirstLineOffset()) { - const short nOld = pOldFirstLineIndent->GetTextFirstLineOffset(); - aNew.SetTextFirstLineOffset(pNewFirstLineIndent->GetTextFirstLineOffset(), + const double dOld = pOldFirstLineIndent->GetTextFirstLineOffsetValue(); + aNew.SetTextFirstLineOffset(pNewFirstLineIndent->GetTextFirstLineOffsetValue(), + pNewFirstLineIndent->GetTextFirstLineOffsetUnit(), pOldFirstLineIndent->GetPropTextFirstLineOffset()); - bChg = nOld != aNew.GetTextFirstLineOffset(); + bChg = dOld != aNew.GetTextFirstLineOffsetValue(); } if( bChg ) { diff --git a/sw/source/core/edit/autofmt.cxx b/sw/source/core/edit/autofmt.cxx index 092fa86fa4f3..d875b161fa67 100644 --- a/sw/source/core/edit/autofmt.cxx +++ b/sw/source/core/edit/autofmt.cxx @@ -1482,7 +1482,14 @@ void SwAutoFormat::BuildEnum( sal_uInt16 nLvl, sal_uInt16 nDigitLevel ) SwTextFrameInfo aInfo( m_pCurTextFrame ); nLeftTextPos = aInfo.GetCharPos(nPos); - nLeftTextPos -= m_pCurTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().GetTextLeftMargin().GetLeft(m_pCurTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent()); + + nLeftTextPos -= m_pCurTextFrame->GetTextNodeForParaProps() + ->GetSwAttrSet() + .GetTextLeftMargin() + .GetLeft(m_pCurTextFrame->GetTextNodeForParaProps() + ->GetSwAttrSet() + .GetFirstLineIndent(), + /*metrics*/ {}); } if( m_bMoreLines ) @@ -2505,9 +2512,14 @@ SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFormatFlags aFlags, SvxTextLeftMarginItem const*const pTextLeftMargin( m_pCurTextFrame->GetTextNodeForParaProps() ->GetSwAttrSet().GetItemIfSet(RES_MARGIN_TEXTLEFT)); - short nSz(pFirstLineIndent ? pFirstLineIndent->GetTextFirstLineOffset() : 0); - if (0 != nSz || - (pTextLeftMargin && 0 != pTextLeftMargin->GetTextLeft())) + + // Unit conversion is not needed here: check the sign only + double dIndentValue = 0.0; + if (pFirstLineIndent) + dIndentValue = pFirstLineIndent->GetTextFirstLineOffsetValue(); + + if (0.0 != dIndentValue + || (pTextLeftMargin && 0 != pTextLeftMargin->GetTextLeft())) { // exception: numbering/enumeration can have an indentation if (IsEnumericChar(*m_pCurTextFrame)) @@ -2526,9 +2538,9 @@ SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFormatFlags aFlags, if( bReplaceStyles ) { // then use one of our templates - if( 0 < nSz ) // positive 1st line indentation + if (0.0 < dIndentValue) // positive 1st line indentation BuildIndent(); - else if( 0 > nSz ) // negative 1st line indentation + else if (0.0 > dIndentValue) // negative 1st line indentation BuildNegIndent( aFInfo.GetLineStart() ); else if (pTextLeftMargin && pTextLeftMargin->GetTextLeft() != 0) // is indentation BuildTextIndent(); @@ -2744,15 +2756,20 @@ SwAutoFormat::SwAutoFormat( SwEditShell* pEdShell, SvxSwAutoFormatFlags aFlags, SvxTextLeftMarginItem const*const pTextLeftMargin( m_pCurTextFrame->GetTextNodeForParaProps() ->GetSwAttrSet().GetItemIfSet(RES_MARGIN_TEXTLEFT, false)); - short nSz(pFirstLineIndent ? pFirstLineIndent->GetTextFirstLineOffset() : 0); - if( bReplaceStyles && - (0 != nSz || - (pTextLeftMargin && 0 != pTextLeftMargin->GetTextLeft()))) + + // Unit conversino is not needed here: check the sign only + double dIndentValue = 0.0; + if (pFirstLineIndent) + dIndentValue = pFirstLineIndent->GetTextFirstLineOffsetValue(); + + if (bReplaceStyles + && (0.0 != dIndentValue + || (pTextLeftMargin && 0 != pTextLeftMargin->GetTextLeft()))) { // then use one of our templates - if( 0 < nSz ) // positive 1st line indentation + if (0.0 < dIndentValue) // positive 1st line indentation BuildIndent(); - else if( 0 > nSz ) // negative 1st line indentation + else if (0.0 > dIndentValue) // negative 1st line indentation { BuildNegIndent( aFInfo.GetLineStart() ); } diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx index 6e4aafef7cc9..87f6492754ac 100644 --- a/sw/source/core/inc/swfont.hxx +++ b/sw/source/core/inc/swfont.hxx @@ -28,6 +28,7 @@ #include #include "drawfont.hxx" #include +#include #include #include @@ -427,6 +428,9 @@ public: const SvxShadowItemSide nShadow, const bool bVertLayout, const bool bVertLayoutLRBT, const bool bSkipLeft, const bool bSkipRight ) const; + // Extract metrics for font-relative unit conversion + SvxFontUnitMetrics GetFontUnitMetrics() const; + void dumpAsXml( xmlTextWriterPtr writer ) const; }; diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index e33617ef8f31..9a91f98d75a1 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -3021,8 +3021,9 @@ static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame ) SvxRightMarginItem const& rRightMargin(rParaSet.GetRightMargin()); if (!static_cast(pFrame)->IsLocked()) { + // tdf#36709: TODO: Handle font-relative first-line indent nMin += rRightMargin.GetRight() + rLeftMargin.GetTextLeft() - + rFirstLine.GetTextFirstLineOffset(); + + rFirstLine.ResolveTextFirstLineOffset({}); } } else if ( pFrame->IsTabFrame() ) diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index 3f6afd46e5ef..1cf9fac80564 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -2353,7 +2353,8 @@ tools::Long SwBorderAttrs::CalcRight( const SwFrame* pCaller ) const { if (pCaller->IsRightToLeft()) { - nRight += m_pTextLeftMargin->GetLeft(*m_pFirstLineIndent); + // tdf#36709: TODO: Handle font-relative units + nRight += m_pTextLeftMargin->GetLeft(*m_pFirstLineIndent, /*metrics*/ {}); } else { @@ -2408,7 +2409,8 @@ tools::Long SwBorderAttrs::CalcLeft( const SwFrame *pCaller ) const { if (pCaller->IsTextFrame()) { - nLeft += m_pTextLeftMargin->GetLeft(*m_pFirstLineIndent); + // tdf#36709: TODO: Handle font-relative units + nLeft += m_pTextLeftMargin->GetLeft(*m_pFirstLineIndent, /*metrics*/ {}); } else nLeft += m_xLR->GetLeft(); diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx index 81173d209c3e..ee221ccb66bf 100644 --- a/sw/source/core/text/EnhancedPDFExportHelper.cxx +++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx @@ -832,7 +832,7 @@ void SwTaggedPDFHelper::SetAttributes( vcl::PDFWriter::StructElement eType ) OSL_ENSURE( pFrame->IsTextFrame(), "Frame type <-> tag attribute mismatch" ); const SvxFirstLineIndentItem& rFirstLine( static_cast(pFrame)->GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent()); - nVal = rFirstLine.GetTextFirstLineOffset(); + nVal = rFirstLine.ResolveTextFirstLineOffset({}); if ( 0 != nVal ) mpPDFExtOutDevData->SetStructureAttributeNumerical( vcl::PDFWriter::TextIndent, nVal ); } diff --git a/sw/source/core/text/frmcrsr.cxx b/sw/source/core/text/frmcrsr.cxx index 882573f7cb96..0c845b0150a7 100644 --- a/sw/source/core/text/frmcrsr.cxx +++ b/sw/source/core/text/frmcrsr.cxx @@ -216,7 +216,8 @@ bool SwTextFrame::GetCharRect( SwRect& rOrig, const SwPosition &rPos, Point aPnt1 = pFrame->getFrameArea().Pos() + pFrame->getFramePrintArea().Pos(); SwTextNode const*const pTextNd(GetTextNodeForParaProps()); short nFirstOffset; - pTextNd->GetFirstLineOfsWithNum( nFirstOffset ); + // tdf#36709: TODO: Handle font-relative units + pTextNd->GetFirstLineOfsWithNum(nFirstOffset, {}); Point aPnt2; if ( aRectFnSet.IsVert() ) @@ -1482,8 +1483,10 @@ void SwTextFrame::FillCursorPos( SwFillData& rFill ) const if( nFirst && nDiff > -1 ) rRect.Top( rRect.Top() + nFirst ); rRect.Height( nLineHeight ); - SwTwips nLeft = rFill.Left() + rTextLeftMargin.GetLeft(rFirstLine) + - GetTextNodeForParaProps()->GetLeftMarginWithNum(); + + // tdf#36709: TODO: Handle font-relative units + SwTwips nLeft = rFill.Left() + rTextLeftMargin.GetLeft(rFirstLine, /*metrics*/ {}) + + GetTextNodeForParaProps()->GetLeftMarginWithNum(); SwTwips nRight = rFill.Right() - rRightMargin.GetRight(); SwTwips nCenter = ( nLeft + nRight ) / 2; rRect.Left( nLeft ); diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx index 85d4bb03828e..c39ea7b7395f 100644 --- a/sw/source/core/text/frmpaint.cxx +++ b/sw/source/core/text/frmpaint.cxx @@ -575,9 +575,10 @@ bool SwTextFrame::PaintEmpty( const SwRect &rRect, bool bCheck ) const const SvxFirstLineIndentItem& rFirstLine( GetTextNodeForParaProps()->GetSwAttrSet().GetFirstLineIndent()); - if (0 < rFirstLine.GetTextFirstLineOffset()) + // tdf#36709: TODO: Handle font-relative first-line indentation + if (0.0 < rFirstLine.GetTextFirstLineOffsetValue()) { - aPos.AdjustX(rFirstLine.GetTextFirstLineOffset()); + aPos.AdjustX(rFirstLine.ResolveTextFirstLineOffset({})); } std::unique_ptr> xClip; diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx index ae38bda0bab3..c7d03b80b9f9 100644 --- a/sw/source/core/text/itratr.cxx +++ b/sw/source/core/text/itratr.cxx @@ -1085,7 +1085,8 @@ void SwTextNode::GetMinMaxSize( SwNodeOffset nIndex, sal_uLong& rMin, sal_uLong tools::Long nLROffset = rTextLeftMargin.GetTextLeft() + GetLeftMarginWithNum( true ); short nFLOffs; // For enumerations a negative first line indentation is probably filled already - if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset ) + // tdf#36709: TODO: Handle font-relative units + if (!GetFirstLineOfsWithNum(nFLOffs, {}) || nFLOffs > nLROffset) nLROffset = nFLOffs; SwMinMaxNodeArgs aNodeArgs; diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx index c393154777a0..6da4d23ce54d 100644 --- a/sw/source/core/text/itrcrsr.cxx +++ b/sw/source/core/text/itrcrsr.cxx @@ -161,6 +161,8 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame *pNewFrame, SwTextSizeInfo *p GetInfo().SetFont( GetFnt() ); const SwTextNode *const pNode = m_pFrame->GetTextNodeForParaProps(); + auto stMetrics = GetFnt()->GetFontUnitMetrics(); + SvxFirstLineIndentItem const& rFirstLine(pNode->GetSwAttrSet().GetFirstLineIndent()); SvxTextLeftMarginItem const& rTextLeftMargin(pNode->GetSwAttrSet().GetTextLeftMargin()); // #i95907# @@ -192,7 +194,7 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame *pNewFrame, SwTextSizeInfo *p // #i95907# // #i111284# // rSpace.GetLeft() + rSpace.GetTextLeft(); - (rTextLeftMargin.GetLeft(rFirstLine) - rTextLeftMargin.GetTextLeft()); + (rTextLeftMargin.GetLeft(rFirstLine, stMetrics) - rTextLeftMargin.GetTextLeft()); } else { @@ -208,7 +210,7 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame *pNewFrame, SwTextSizeInfo *p pNode->GetLeftMarginWithNum() - // #i95907# // #i111284# - (rTextLeftMargin.GetLeft(rFirstLine) - rTextLeftMargin.GetTextLeft()); + (rTextLeftMargin.GetLeft(rFirstLine, stMetrics) - rTextLeftMargin.GetTextLeft()); } else { @@ -239,8 +241,7 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame *pNewFrame, SwTextSizeInfo *p { short nFLOfst = 0; tools::Long nFirstLineOfs = 0; - if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) && - rFirstLine.IsAutoFirst()) + if (!pNode->GetFirstLineOfsWithNum(nFLOfst, stMetrics) && rFirstLine.IsAutoFirst()) { nFirstLineOfs = GetFnt()->GetSize( GetFnt()->GetActual() ).Height(); LanguageType const aLang = m_pFrame->GetLangOfChar( @@ -299,26 +300,6 @@ 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(static_cast(nFntHeight) - * rFirstLine.GetTextFirstLineOffsetDouble()); - break; - - default: - nFirstLineOfs = 0; - break; - } - } else nFirstLineOfs = nFLOfst; diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx index a955d3d72b65..36cbdbce162d 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -604,11 +604,14 @@ bool SwNumberPortion::Format( SwTextFormatInfo &rInf ) (IsFootnoteNumPortion() && rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER))) { + // tdf#36709: TODO: Handle font-relative first line indentation nDiff = rInf.Left() - + rInf.GetTextFrame()->GetTextNodeForParaProps()-> - GetSwAttrSet().GetFirstLineIndent().GetTextFirstLineOffset() - - rInf.First() - + rInf.ForcedLeftMargin(); + + rInf.GetTextFrame() + ->GetTextNodeForParaProps() + ->GetSwAttrSet() + .GetFirstLineIndent() + .ResolveTextFirstLineOffset({}) + - rInf.First() + rInf.ForcedLeftMargin(); } else { diff --git a/sw/source/core/tox/ToxTabStopTokenHandler.cxx b/sw/source/core/tox/ToxTabStopTokenHandler.cxx index 2cdcc358c971..3ebedfec05a3 100644 --- a/sw/source/core/tox/ToxTabStopTokenHandler.cxx +++ b/sw/source/core/tox/ToxTabStopTokenHandler.cxx @@ -114,8 +114,10 @@ auto DefaultToxTabStopTokenHandler::CalcEndStop(SwTextNode const& rNode, rNode.GetTextColl()->GetFirstLineIndent()); SvxTextLeftMarginItem const& rTextLeftMargin( rNode.GetTextColl()->GetTextLeftMargin()); - nRightMargin -= rTextLeftMargin.GetLeft(rFirstLine); - nRightMargin -= rFirstLine.GetTextFirstLineOffset(); + + // tdf#36709: TODO: Handle font-relative units + nRightMargin -= rTextLeftMargin.GetLeft(rFirstLine, /*metrics*/ {}); + nRightMargin -= rFirstLine.ResolveTextFirstLineOffset(/*metrics*/ {}); } return nRightMargin - 1; // subtract 1 twip to avoid equal for TabOverMargin } diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index bc965b3ad7fc..edb760a33ba9 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -3311,7 +3311,8 @@ tools::Long SwTextNode::GetLeftMarginWithNum( bool bTextLeft ) const if( pRule->IsAbsSpaces() ) { SvxFirstLineIndentItem const& rFirst(GetSwAttrSet().GetFirstLineIndent()); - nRet = nRet - GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst); + // tdf#36709: TODO: Handle font-relative units + nRet = nRet - GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst, /*metrics*/ {}); } } else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) @@ -3324,27 +3325,29 @@ tools::Long SwTextNode::GetLeftMarginWithNum( bool bTextLeft ) const // list/paragraph items. (this is rather inelegant) SvxFirstLineIndentItem firstLine(GetSwAttrSet().GetFirstLineIndent()); SvxTextLeftMarginItem leftMargin(GetSwAttrSet().GetTextLeftMargin()); - nRet = bTextLeft - ? - leftMargin.GetTextLeft() - : - leftMargin.GetLeft(firstLine); + // tdf#36709: TODO: Handle font-relative units + nRet = bTextLeft ? -leftMargin.GetTextLeft() + : -leftMargin.GetLeft(firstLine, /*metrics*/ {}); if (indents & ::sw::ListLevelIndents::LeftMargin) { leftMargin.SetTextLeft(rFormat.GetIndentAt()); } if (indents & ::sw::ListLevelIndents::FirstLine) { - firstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent()); + firstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit()); } - nRet += bTextLeft - ? leftMargin.GetTextLeft() - : leftMargin.GetLeft(firstLine); + // tdf#36709: TODO: Handle font-relative units + nRet += bTextLeft ? leftMargin.GetTextLeft() + : leftMargin.GetLeft(firstLine, /*metrics*/ {}); } } return nRet; } -bool SwTextNode::GetFirstLineOfsWithNum( short& rFLOffset ) const +bool SwTextNode::GetFirstLineOfsWithNum(short& rFLOffset, + const SvxFontUnitMetrics& rMetrics) const { // #i95907# rFLOffset = 0; @@ -3363,7 +3366,7 @@ bool SwTextNode::GetFirstLineOfsWithNum( short& rFLOffset ) const if (!getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING)) { SvxFirstLineIndentItem const aItem(GetSwAttrSet().GetFirstLineIndent()); - rFLOffset = rFLOffset + aItem.GetTextFirstLineOffset(); + rFLOffset = rFLOffset + aItem.ResolveTextFirstLineOffset(rMetrics); } } else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) @@ -3375,7 +3378,7 @@ bool SwTextNode::GetFirstLineOfsWithNum( short& rFLOffset ) const else if (!getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING)) { SvxFirstLineIndentItem const aItem(GetSwAttrSet().GetFirstLineIndent()); - rFLOffset = aItem.GetTextFirstLineOffset(); + rFLOffset = aItem.ResolveTextFirstLineOffset(rMetrics); } } } @@ -3383,7 +3386,7 @@ bool SwTextNode::GetFirstLineOfsWithNum( short& rFLOffset ) const return true; } - rFLOffset = GetSwAttrSet().GetFirstLineIndent().GetTextFirstLineOffset(); + rFLOffset = GetSwAttrSet().GetFirstLineIndent().ResolveTextFirstLineOffset(rMetrics); return false; } @@ -3398,12 +3401,16 @@ SwTwips SwTextNode::GetAdditionalIndentForStartingNewList() const if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) { SvxFirstLineIndentItem const& rFirst(GetSwAttrSet().GetFirstLineIndent()); - nAdditionalIndent = GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst); + + // tdf#36709: TODO: Handle font-relative indentation + nAdditionalIndent = GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst, /*metrics*/ {}); if (getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING)) { - nAdditionalIndent = nAdditionalIndent - - GetSwAttrSet().GetFirstLineIndent().GetTextFirstLineOffset(); + // tdf#36709: TODO: Handle font-relative indentation + nAdditionalIndent + = nAdditionalIndent + - GetSwAttrSet().GetFirstLineIndent().ResolveTextFirstLineOffset({}); } } else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) @@ -3414,26 +3421,30 @@ SwTwips SwTextNode::GetAdditionalIndentForStartingNewList() const ::sw::ListLevelIndents const indents(AreListLevelIndentsApplicable()); SvxFirstLineIndentItem const aFirst( indents & ::sw::ListLevelIndents::FirstLine - ? SvxFirstLineIndentItem(rFormat.GetFirstLineIndent(), RES_MARGIN_FIRSTLINE) + ? SvxFirstLineIndentItem(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit(), RES_MARGIN_FIRSTLINE) : GetSwAttrSet().GetFirstLineIndent()); SvxTextLeftMarginItem const aLeft( indents & ::sw::ListLevelIndents::LeftMargin ? SvxTextLeftMarginItem(rFormat.GetIndentAt(), RES_MARGIN_TEXTLEFT) : GetSwAttrSet().GetTextLeftMargin()); - nAdditionalIndent = aLeft.GetLeft(aFirst); + // tdf#36709: TODO: Handle font-relative indentation + nAdditionalIndent = aLeft.GetLeft(aFirst, /*metrics*/ {}); if (!(indents & ::sw::ListLevelIndents::FirstLine)) { if (getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING)) { - nAdditionalIndent = nAdditionalIndent - aFirst.GetTextFirstLineOffset(); + // tdf#36709: TODO: Handle font-relative first line indentation + nAdditionalIndent = nAdditionalIndent - aFirst.ResolveTextFirstLineOffset({}); } } } } else { + // tdf#36709: TODO: Handle font-relative first line indentation SvxFirstLineIndentItem const& rFirst(GetSwAttrSet().GetFirstLineIndent()); - nAdditionalIndent = GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst); + nAdditionalIndent = GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst, /*metrics*/ {}); } return nAdditionalIndent; diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx index 5499c8b84421..864d3c99ecfb 100644 --- a/sw/source/core/txtnode/swfont.cxx +++ b/sw/source/core/txtnode/swfont.cxx @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -340,6 +341,17 @@ sal_uInt16 SwFont::CalcShadowSpace(const SvxShadowItemSide nShadow, const bool b return nSpace; } +SvxFontUnitMetrics SwFont::GetFontUnitMetrics() const +{ + // tdf#36709: Metrics conversion should use em and ic values from the bound fonts. + // Unfortunately, this currently poses a problem due to font substitution: tests + // abort when a missing font is set on a device. + // In the interim, use height for all metrics. This is technically not correct, but + // should be close enough for common fonts. + return { /*em*/ static_cast(GetHeight(GetActual())), + /*ic*/ static_cast(GetHeight(SwFontScript::CJK)) }; +} + void SwFont::dumpAsXml(xmlTextWriterPtr writer) const { (void)xmlTextWriterStartElement(writer, BAD_CAST("SwFont")); diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx index a8001e2cdf94..4dab2b5ee23d 100644 --- a/sw/source/core/txtnode/thints.cxx +++ b/sw/source/core/txtnode/thints.cxx @@ -2135,7 +2135,9 @@ static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTextNode& rTextNode, { if (indents & ::sw::ListLevelIndents::FirstLine) { - SvxFirstLineIndentItem const firstLine(static_cast(rFormat.GetFirstLineIndent()), RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit(), + RES_MARGIN_FIRSTLINE); rSet.Put(firstLine); } if (indents & ::sw::ListLevelIndents::LeftMargin) diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index 20a47b5a842c..de2c160f3330 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -2794,8 +2794,9 @@ static SwHTMLWriter& OutCSS1_SvxFirstLineIndent(SwHTMLWriter & rWrt, SfxPoolItem // match that of the current template // The LineIndent of the first line might contain the room for numbering - tools::Long nFirstLineIndent = static_cast(rFirstLine.GetTextFirstLineOffset()) - - rWrt.m_nFirstLineIndent; + tools::Long nFirstLineIndent + = static_cast(rFirstLine.ResolveTextFirstLineOffset({})) + - rWrt.m_nFirstLineIndent; if (rWrt.m_nDfltFirstLineIndent != nFirstLineIndent) { rWrt.OutCSS1_UnitProperty(sCSS1_P_text_indent, nFirstLineIndent); diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx index 38bee88aaa93..a3e1c8817728 100644 --- a/sw/source/filter/html/htmlatr.cxx +++ b/sw/source/filter/html/htmlatr.cxx @@ -377,7 +377,7 @@ SwHTMLFormatInfo::SwHTMLFormatInfo( const SwFormat *pF, SwDoc *pDoc, SwDoc *pTem (pReferenceFormat ? pReferenceFormat : pFormat)->GetRightMargin()); nLeftMargin = rTextLeftMargin.GetTextLeft(); nRightMargin = rRightMargin.GetRight(); - nFirstLineIndent = rFirstLine.GetTextFirstLineOffset(); + nFirstLineIndent = rFirstLine.ResolveTextFirstLineOffset({}); const SvxULSpaceItem &rULSpace = (pReferenceFormat ? pReferenceFormat : pFormat)->GetULSpace(); @@ -717,7 +717,7 @@ static void OutHTML_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat, rWrt.m_nDfltLeftMargin = rTextLeftMargin.GetTextLeft(); // In numbered lists, don't output a first line indent. - rWrt.m_nFirstLineIndent = rFirstLine.GetTextFirstLineOffset(); + rWrt.m_nFirstLineIndent = rFirstLine.ResolveTextFirstLineOffset({}); } if( rInfo.bInNumberBulletList && bNumbered && bPara && !rWrt.m_bCfgOutStyles ) @@ -2086,7 +2086,7 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode SvxFirstLineIndentItem const& rFirstLine(pItemSet->Get(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem const& rTextLeftMargin(pItemSet->Get(RES_MARGIN_TEXTLEFT)); SvxRightMarginItem const& rRightMargin(pItemSet->Get(RES_MARGIN_RIGHT)); - sal_Int32 const nLeft(rTextLeftMargin.GetLeft(rFirstLine)); + sal_Int32 const nLeft(rTextLeftMargin.GetLeft(rFirstLine, /*metrics*/ {})); sal_Int32 const nRight(rRightMargin.GetRight()); if( nLeft || nRight ) { diff --git a/sw/source/filter/html/htmlctxt.cxx b/sw/source/filter/html/htmlctxt.cxx index 7dad6a6065d4..bb0a1d58c734 100644 --- a/sw/source/filter/html/htmlctxt.cxx +++ b/sw/source/filter/html/htmlctxt.cxx @@ -638,13 +638,14 @@ void SwHTMLParser::InsertAttrs( SfxItemSet &rItemSet, nRight = nOldRight + static_cast< sal_uInt16 >(rPropInfo.m_nRightMargin); } if (rPropInfo.m_bTextIndent && pFirstLineItem) - nIndent = pFirstLineItem->GetTextFirstLineOffset(); + nIndent = pFirstLineItem->ResolveTextFirstLineOffset({}); // Remember the value for the following paragraphs pContext->SetMargins( nLeft, nRight, nIndent ); // Set the attribute on the current paragraph - SvxFirstLineIndentItem const firstLine(nIndent, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem firstLine(nIndent, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); NewAttr(m_xAttrTab, &m_xAttrTab->pFirstLineIndent, firstLine); EndAttr(m_xAttrTab->pFirstLineIndent, false); SvxTextLeftMarginItem const leftMargin(nLeft, RES_MARGIN_TEXTLEFT); diff --git a/sw/source/filter/html/htmlnumreader.cxx b/sw/source/filter/html/htmlnumreader.cxx index d9ecc21f3d3b..64d4d89fa259 100644 --- a/sw/source/filter/html/htmlnumreader.cxx +++ b/sw/source/filter/html/htmlnumreader.cxx @@ -277,8 +277,8 @@ void SwHTMLParser::NewNumberBulletList( HtmlTokenId nToken ) } if( aPropInfo.m_bTextIndent ) { - short nTextIndent = - aItemSet.Get(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset(); + short nTextIndent + = aItemSet.Get(RES_MARGIN_FIRSTLINE).ResolveTextFirstLineOffset({}); aNumFormat.SetFirstLineOffset( nTextIndent ); bChangeNumFormat = true; } diff --git a/sw/source/filter/html/svxcss1.cxx b/sw/source/filter/html/svxcss1.cxx index f93ff5387c97..8350dff92c7d 100644 --- a/sw/source/filter/html/svxcss1.cxx +++ b/sw/source/filter/html/svxcss1.cxx @@ -1987,7 +1987,8 @@ static void ParseCSS1_text_indent( const CSS1Expression *pExpr, if( !bSet ) return; - SvxFirstLineIndentItem const firstLine(nIndent, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(nIndent, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); rItemSet.Put(firstLine); rPropInfo.m_bTextIndent = true; } diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx index e35749be234e..5f8236f97217 100644 --- a/sw/source/filter/html/swhtml.cxx +++ b/sw/source/filter/html/swhtml.cxx @@ -4772,7 +4772,7 @@ void SwHTMLParser::SetTextCollAttrs( HTMLAttrContext *pContext ) { sal_Int32 nLeft = rItemSet.Get(RES_MARGIN_TEXTLEFT).GetTextLeft(); sal_Int32 nRight = rItemSet.Get(RES_MARGIN_RIGHT).GetRight(); - nFirstLineIndent = rItemSet.Get(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset(); + nFirstLineIndent = rItemSet.Get(RES_MARGIN_FIRSTLINE).ResolveTextFirstLineOffset({}); // In Definition lists the margins also contain the margins from the previous levels if( RES_POOLCOLL_HTML_DD == nTopColl ) @@ -4814,7 +4814,7 @@ void SwHTMLParser::SetTextCollAttrs( HTMLAttrContext *pContext ) } if( !nFirstLineIndent ) { - nFirstLineIndent = pCollToSet->GetFirstLineIndent().GetTextFirstLineOffset(); + nFirstLineIndent = pCollToSet->GetFirstLineIndent().ResolveTextFirstLineOffset({}); } } @@ -4837,16 +4837,16 @@ void SwHTMLParser::SetTextCollAttrs( HTMLAttrContext *pContext ) const SvxFirstLineIndentItem & rFirstLine = pCollToSet->GetFirstLineIndent(); const SvxTextLeftMarginItem & rTextLeftMargin = pCollToSet->GetTextLeftMargin(); const SvxRightMarginItem & rRightMargin = pCollToSet->GetRightMargin(); - bool bSetLRSpace = nLeftMargin != rTextLeftMargin.GetTextLeft() || - nFirstLineIndent != rFirstLine.GetTextFirstLineOffset() || - nRightMargin != rRightMargin.GetRight(); + bool bSetLRSpace = nLeftMargin != rTextLeftMargin.GetTextLeft() + || nFirstLineIndent != rFirstLine.ResolveTextFirstLineOffset({}) + || nRightMargin != rRightMargin.GetRight(); if( bSetLRSpace ) { SvxFirstLineIndentItem firstLine(rFirstLine); SvxTextLeftMarginItem leftMargin(rTextLeftMargin); SvxRightMarginItem rightMargin(rRightMargin); - firstLine.SetTextFirstLineOffset(nFirstLineIndent); + firstLine.SetTextFirstLineOffset(nFirstLineIndent, css::util::MeasureUnit::TWIP); leftMargin.SetTextLeft(nLeftMargin); rightMargin.SetRight(nRightMargin); if( pItemSet ) @@ -5081,7 +5081,8 @@ void SwHTMLParser::InsertSpacer() GetMarginsFromContextWithNumberBullet( nLeft, nRight, nIndent ); nIndent = nIndent + static_cast(nSize); - SvxFirstLineIndentItem const firstLine(nIndent, RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(nIndent, css::util::MeasureUnit::TWIP, + RES_MARGIN_FIRSTLINE); SvxTextLeftMarginItem const leftMargin(nLeft, RES_MARGIN_TEXTLEFT); SvxRightMarginItem const rightMargin(nRight, RES_MARGIN_RIGHT); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index e02477836c9c..c36fc02f633a 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -9276,7 +9276,8 @@ void DocxAttributeOutput::FormatPaperBin(const SvxPaperBinItem& rPaperBin) void DocxAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) { - sal_Int32 const nFirstLineAdjustment(rFirstLine.GetTextFirstLineOffset()); + // tdf#83844: TODO: export FONT_CJK_ADVANCE first line indent as HangingChars/FirstLineChars + sal_Int32 const nFirstLineAdjustment(rFirstLine.ResolveTextFirstLineOffset({})); if (nFirstLineAdjustment > 0) { AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, XML_firstLine), diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index dd0d581257fa..bea6f6940c6e 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -3253,7 +3253,9 @@ void RtfAttributeOutput::ParaNumRule_Impl(const SwTextNode* pTextNd, sal_Int32 n SvxFirstLineIndentItem firstLine(rNdSet.Get(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(rNdSet.Get(RES_MARGIN_TEXTLEFT)); leftMargin.SetTextLeft(leftMargin.GetTextLeft() + pFormat->GetIndentAt()); - firstLine.SetTextFirstLineOffset(pFormat->GetFirstLineOffset()); //TODO: overflow + + firstLine.SetTextFirstLineOffset(pFormat->GetFirstLineOffset(), + pFormat->GetFirstLineOffsetUnit()); sal_uInt16 nStyle = m_rExport.GetId(pFormat->GetCharFormat()); OString* pString = m_rExport.GetStyle(nStyle); @@ -3380,7 +3382,7 @@ void RtfAttributeOutput::FormatPaperBin(const SvxPaperBinItem& rItem) void RtfAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) { m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FI); - m_aStyles.append(static_cast(rFirstLine.GetTextFirstLineOffset())); + m_aStyles.append(rFirstLine.ResolveTextFirstLineOffset({})); } void RtfAttributeOutput::FormatTextLeftMargin(SvxTextLeftMarginItem const& rTextLeftMargin) diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 260bd38fc6ad..5f113a231ea0 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -2757,7 +2757,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) { const SvxFirstLineIndentItem *const pFirstLine(aSet.GetItem(RES_MARGIN_FIRSTLINE)); if (pFirstLine) - nFirstLineIndent = pFirstLine->GetTextFirstLineOffset(); + nFirstLineIndent = pFirstLine->ResolveTextFirstLineOffset({}); } // Insert tab for aesthetic purposes #i24762# @@ -3062,11 +3062,17 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) { if (bParaRTL) { - firstLine.SetTextFirstLineOffsetValue(firstLine.GetTextFirstLineOffset() + pFormat->GetAbsLSpace() - pFormat->GetFirstLineOffset()); //TODO: overflow + firstLine.SetTextFirstLineOffset( + firstLine.ResolveTextFirstLineOffset({}) + pFormat->GetAbsLSpace() + - pFormat->GetFirstLineOffset(), + css::util::MeasureUnit::TWIP); } else { - firstLine.SetTextFirstLineOffset(firstLine.GetTextFirstLineOffset() + GetWordFirstLineOffset(*pFormat)); + firstLine.SetTextFirstLineOffset( + firstLine.ResolveTextFirstLineOffset({}) + + GetWordFirstLineOffset(*pFormat), + css::util::MeasureUnit::TWIP); } } @@ -3165,7 +3171,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) const SvxTextLeftMarginItem *const pTextLeftMargin(oTmpSet->GetItemIfSet(RES_MARGIN_TEXTLEFT)); SvxFirstLineIndentItem firstLine(pFirstLineIndent ? *pFirstLineIndent - : SvxFirstLineIndentItem(0, RES_MARGIN_FIRSTLINE)); + : SvxFirstLineIndentItem(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(pTextLeftMargin ? *pTextLeftMargin : SvxTextLeftMarginItem(0, RES_MARGIN_TEXTLEFT)); @@ -3186,18 +3192,20 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) if ( rNumFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) { - leftMargin.SetTextLeft(leftMargin.GetLeft(firstLine) + rNumFormat.GetAbsLSpace()); + leftMargin.SetTextLeft(leftMargin.GetLeft(firstLine, /*metrics*/ {}) + + rNumFormat.GetAbsLSpace()); } else { - leftMargin.SetTextLeft(leftMargin.GetLeft(firstLine) + rNumFormat.GetIndentAt()); + leftMargin.SetTextLeft(leftMargin.GetLeft(firstLine, /*metrics*/ {}) + + rNumFormat.GetIndentAt()); } // new first line indent = 0 // (first line indent is ignored) if (!bParaRTL) { - firstLine.SetTextFirstLineOffset(0); + firstLine.SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); } // put back the new item diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index 9a2eee82747c..50b35698c620 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -927,7 +927,8 @@ void MSWordExportBase::OutputFormat( const SwFormat& rFormat, bool bPapFormat, b SvxTextLeftMarginItem leftMargin(aSet.Get(RES_MARGIN_TEXTLEFT)); leftMargin.SetTextLeft(leftMargin.GetTextLeft() + rNFormat.GetAbsLSpace()); - firstLine.SetTextFirstLineOffset(GetWordFirstLineOffset(rNFormat)); + firstLine.SetTextFirstLineOffset(GetWordFirstLineOffset(rNFormat), + css::util::MeasureUnit::TWIP); aSet.Put(firstLine); aSet.Put(leftMargin); @@ -4348,9 +4349,10 @@ void WW8AttributeOutput::FormatPaperBin( const SvxPaperBinItem& rPaperBin ) void WW8AttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) { + // tdf#80596: TODO export sprmPDxcLeft1 for first line indents in ICs // sprmPDxaLeft1 m_rWW8Export.InsUInt16( 0x8460 ); //asian version ? - m_rWW8Export.InsUInt16( rFirstLine.GetTextFirstLineOffset() ); + m_rWW8Export.InsUInt16(rFirstLine.ResolveTextFirstLineOffset({})); } void WW8AttributeOutput::FormatTextLeftMargin(SvxTextLeftMarginItem const& rTextLeftMargin) diff --git a/sw/source/filter/ww8/ww8graf.cxx b/sw/source/filter/ww8/ww8graf.cxx index d0ad7521ee6b..d3e8cd0bc20e 100644 --- a/sw/source/filter/ww8/ww8graf.cxx +++ b/sw/source/filter/ww8/ww8graf.cxx @@ -526,7 +526,7 @@ void SwWW8ImplReader::InsertTxbxStyAttrs(SfxItemSet& rS, sal_uInt16 nColl, ManTy SvxLRSpaceItem aLR(rS.Get(EE_PARA_LRSPACE)); aLR.SetTextFirstLineOffset( - pStyInf->m_pFormat->GetFirstLineIndent().GetTextFirstLineOffset()); + pStyInf->m_pFormat->GetFirstLineIndent().ResolveTextFirstLineOffset({})); aLR.SetTextLeft(pStyInf->m_pFormat->GetTextLeftMargin().GetTextLeft()); aLR.SetRight(pStyInf->m_pFormat->GetRightMargin().GetRight()); rS.Put(aLR); @@ -773,7 +773,7 @@ void SwWW8ImplReader::InsertAttrsAsDrawingAttrs(WW8_CP nStartCp, WW8_CP nEndCp, { aLR.SetTextFirstLineOffset( static_cast(pItem) - ->GetTextFirstLineOffset()); + ->ResolveTextFirstLineOffset({})); } else if (nWhich == RES_MARGIN_TEXTLEFT) { diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx index 31f8f8f0f340..397d1b9c7ae9 100644 --- a/sw/source/filter/ww8/ww8par.cxx +++ b/sw/source/filter/ww8/ww8par.cxx @@ -1226,7 +1226,7 @@ static tools::Long lcl_GetTrueMargin(SvxFirstLineIndentItem const& rFirstLine, " - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" ); const tools::Long nBodyIndent = rLeftMargin.GetTextLeft(); - const tools::Long nFirstLineDiff = rFirstLine.GetTextFirstLineOffset(); + const tools::Long nFirstLineDiff = rFirstLine.ResolveTextFirstLineOffset({}); rFirstLinePos = nBodyIndent + nFirstLineDiff; const auto nPseudoListBodyIndent = rFormat.GetAbsLSpace(); @@ -1249,14 +1249,15 @@ void SyncIndentWithList( SvxFirstLineIndentItem & rFirstLine, tools::Long nWantedFirstLinePos; tools::Long nExtraListIndent = lcl_GetTrueMargin(rFirstLine, rLeftMargin, rFormat, nWantedFirstLinePos); rLeftMargin.SetTextLeft(nWantedFirstLinePos - nExtraListIndent); - rFirstLine.SetTextFirstLineOffset(0); + rFirstLine.SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); } else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) { if ( !bFirstLineOfstSet && bLeftIndentSet && rFormat.GetFirstLineIndent() != 0 ) { - rFirstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent()); + rFirstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit()); } else if ( bFirstLineOfstSet && !bLeftIndentSet && rFormat.GetIndentAt() != 0 ) @@ -1267,7 +1268,8 @@ void SyncIndentWithList( SvxFirstLineIndentItem & rFirstLine, { if ( rFormat.GetFirstLineIndent() != 0 ) { - rFirstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent()); + rFirstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit()); } if ( rFormat.GetIndentAt() != 0 ) { @@ -1355,7 +1357,10 @@ void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos, if (rEntry.m_pAttr->Which() == RES_MARGIN_FIRSTLINE) { SvxFirstLineIndentItem const firstLineEntry(*static_cast(rEntry.m_pAttr.get())); - firstLineNew.SetTextFirstLineOffset(firstLineEntry.GetTextFirstLineOffset(), firstLineEntry.GetPropTextFirstLineOffset()); + firstLineNew.SetTextFirstLineOffset( + firstLineEntry.GetTextFirstLineOffsetValue(), + firstLineEntry.GetTextFirstLineOffsetUnit(), + firstLineEntry.GetPropTextFirstLineOffset()); firstLineNew.SetAutoFirst(firstLineEntry.IsAutoFirst()); } else @@ -1380,7 +1385,10 @@ void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos, } else { - firstLineNew.SetTextFirstLineOffset(firstLineOld.GetTextFirstLineOffset(), firstLineOld.GetPropTextFirstLineOffset()); + firstLineNew.SetTextFirstLineOffset( + firstLineOld.GetTextFirstLineOffsetValue(), + firstLineOld.GetTextFirstLineOffsetUnit(), + firstLineOld.GetPropTextFirstLineOffset()); firstLineNew.SetAutoFirst(firstLineOld.IsAutoFirst()); } diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx index 78f6ee19ac85..0f5e7129b5f0 100644 --- a/sw/source/filter/ww8/ww8par2.cxx +++ b/sw/source/filter/ww8/ww8par2.cxx @@ -292,7 +292,7 @@ sal_uInt16 SwWW8ImplReader::End_Footnote() const SvxFirstLineIndentItem *const pFirstLine(aSet.GetItem(RES_MARGIN_FIRSTLINE)); if (pFirstLine) { - nFirstLineIndent = pFirstLine->GetTextFirstLineOffset(); + nFirstLineIndent = pFirstLine->ResolveTextFirstLineOffset({}); } } diff --git a/sw/source/filter/ww8/ww8par3.cxx b/sw/source/filter/ww8/ww8par3.cxx index f5ee3a1dc5fa..adf1a5e31f31 100644 --- a/sw/source/filter/ww8/ww8par3.cxx +++ b/sw/source/filter/ww8/ww8par3.cxx @@ -1680,7 +1680,8 @@ void UseListIndent(SwWW8StyInf &rStyle, const SwNumFormat &rFormat) SvxFirstLineIndentItem firstLine(rStyle.m_pFormat->GetFormatAttr(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(rStyle.m_pFormat->GetFormatAttr(RES_MARGIN_TEXTLEFT)); leftMargin.SetTextLeft(nAbsLSpace); - firstLine.SetTextFirstLineOffset(writer_cast(nListFirstLineIndent)); + firstLine.SetTextFirstLineOffset(writer_cast(nListFirstLineIndent), + css::util::MeasureUnit::TWIP); rStyle.m_pFormat->SetFormatAttr(firstLine); rStyle.m_pFormat->SetFormatAttr(leftMargin); rStyle.m_bListRelevantIndentSet = true; @@ -1702,7 +1703,7 @@ void SetStyleIndent(SwWW8StyInf &rStyle, const SwNumFormat &rFormat) else { leftMargin.SetTextLeft(0); - firstLine.SetTextFirstLineOffset(0); + firstLine.SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); } rStyle.m_pFormat->SetFormatAttr(firstLine); rStyle.m_pFormat->SetFormatAttr(leftMargin); @@ -2020,7 +2021,7 @@ void SwWW8ImplReader::Read_LFOPosition(sal_uInt16, const sal_uInt8* pData, pFirstLine.reset(pItem->Clone()); // reset/blank the left indent (and only the left) - pFirstLine->SetTextFirstLineOffset(0); + pFirstLine->SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); SvxTextLeftMarginItem leftMargin(0, RES_MARGIN_TEXTLEFT); // apply the modified SvxLRSpaceItem to the current paragraph diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx index 08d02b772a4c..a81ab545e38a 100644 --- a/sw/source/filter/ww8/ww8par6.cxx +++ b/sw/source/filter/ww8/ww8par6.cxx @@ -4306,7 +4306,8 @@ void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLe if ( pFormat && pFormat->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) { pLeftMargin->SetTextLeft(pFormat->GetIndentAt()); - pFirstLine->SetTextFirstLineOffset(static_cast(pFormat->GetFirstLineIndent())); + pFirstLine->SetTextFirstLineOffset(pFormat->GetFirstLineIndent(), + pFormat->GetFirstLineIndentUnit()); // make paragraph have hard-set indent attributes pTextNode->SetAttr(*pLeftMargin); pTextNode->SetAttr(*pFirstLine); @@ -4378,11 +4379,13 @@ void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLe { const SvxFirstLineIndentItem & rFirstLine = m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(RES_MARGIN_FIRSTLINE); - nPara = nPara - rFirstLine.GetTextFirstLineOffset(); + // tdf#80596: TODO handle sprmPDxcLeft1 + nPara = nPara - rFirstLine.ResolveTextFirstLineOffset({}); } } - pFirstLine->SetTextFirstLineOffset(nPara); + // tdf#80596: TODO handle sprmPDxcLeft1 + pFirstLine->SetTextFirstLineOffset(nPara, css::util::MeasureUnit::TWIP); if (!m_pCurrentColl) { diff --git a/sw/source/uibase/app/docstyle.cxx b/sw/source/uibase/app/docstyle.cxx index 5644990236f3..02236edde471 100644 --- a/sw/source/uibase/app/docstyle.cxx +++ b/sw/source/uibase/app/docstyle.cxx @@ -215,7 +215,9 @@ public: if (!oLRSpaceItem) oLRSpaceItem.emplace(EE_PARA_LRSPACE); auto pFirstLineItem = static_cast(pItem); - (*oLRSpaceItem).SetTextFirstLineOffsetValue(pFirstLineItem->GetTextFirstLineOffset()); + // tdf#36709: TODO: Handle font-relative first-line indentation + (*oLRSpaceItem) + .SetTextFirstLineOffsetValue(pFirstLineItem->ResolveTextFirstLineOffset({})); (*oLRSpaceItem).SetAutoFirst(pFirstLineItem->IsAutoFirst()); } else if (nWhich == RES_MARGIN_TEXTLEFT) @@ -1603,7 +1605,9 @@ void SwDocStyleSheet::MergeIndentAttrsOfListStyle( SfxItemSet& rSet ) { if (indents & ::sw::ListLevelIndents::FirstLine) { - SvxFirstLineIndentItem const firstLine(static_cast(rFormat.GetFirstLineIndent()), RES_MARGIN_FIRSTLINE); + SvxFirstLineIndentItem const firstLine(rFormat.GetFirstLineIndent(), + rFormat.GetFirstLineIndentUnit(), + RES_MARGIN_FIRSTLINE); rSet.Put(firstLine); } if (indents & ::sw::ListLevelIndents::LeftMargin) diff --git a/sw/source/uibase/shells/txtattr.cxx b/sw/source/uibase/shells/txtattr.cxx index d1749af5f859..c8ac640ad940 100644 --- a/sw/source/uibase/shells/txtattr.cxx +++ b/sw/source/uibase/shells/txtattr.cxx @@ -771,7 +771,10 @@ void SwTextShell::GetAttrState(SfxItemSet &rSet) SvxFirstLineIndentItem const& rFirstLine(aCoreSet.Get(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem const& rLeftMargin(aCoreSet.Get(RES_MARGIN_TEXTLEFT)); SvxRightMarginItem const& rRightMargin(aCoreSet.Get(RES_MARGIN_RIGHT)); - aLR.SetTextFirstLineOffset(rFirstLine.GetTextFirstLineOffset(), rFirstLine.GetPropTextFirstLineOffset()); + + // tdf#36709: TODO: Handle font-relative units + aLR.SetTextFirstLineOffset(rFirstLine.ResolveTextFirstLineOffset({}), + rFirstLine.GetPropTextFirstLineOffset()); aLR.SetAutoFirst(rFirstLine.IsAutoFirst()); aLR.SetTextLeft(rLeftMargin.GetTextLeft(), rLeftMargin.GetPropLeft()); aLR.SetRight(rRightMargin.GetRight(), rRightMargin.GetPropRight()); diff --git a/sw/source/uibase/uiview/viewtab.cxx b/sw/source/uibase/uiview/viewtab.cxx index 66927459d019..9386cccb6638 100644 --- a/sw/source/uibase/uiview/viewtab.cxx +++ b/sw/source/uibase/uiview/viewtab.cxx @@ -630,7 +630,7 @@ void SwView::ExecTabWin( SfxRequest const & rReq ) rSh.GetCurAttr( aSet ); const SvxFirstLineIndentItem & rFirstLine(aSet.Get(RES_MARGIN_FIRSTLINE)); - if (rFirstLine.GetTextFirstLineOffset() < 0) + if (rFirstLine.GetTextFirstLineOffsetValue() < 0.0) { SvxTabStop aSwTabStop( 0, SvxTabAdjust::Default ); aTabStops.Insert( aSwTabStop ); @@ -705,7 +705,8 @@ void SwView::ExecTabWin( SfxRequest const & rReq ) { SvxFirstLineIndentItem firstLine(aLRSpaceSet.Get(RES_MARGIN_FIRSTLINE)); const OUString ratio = fLineIndent->GetValue(); - firstLine.SetTextFirstLineOffset(nPageWidth * ratio.toFloat()); + firstLine.SetTextFirstLineOffset(nPageWidth * ratio.toFloat(), + css::util::MeasureUnit::TWIP); rSh.SetAttrItem(firstLine); } else if (const SfxStringItem *pLeftIndent = pReqArgs->GetItemIfSet(SID_PARAGRAPH_LEFT_INDENT)) @@ -733,7 +734,8 @@ void SwView::ExecTabWin( SfxRequest const & rReq ) SvxFirstLineIndentItem firstLine(aLRSpaceSet.Get(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(aLRSpaceSet.Get(RES_MARGIN_TEXTLEFT)); - tools::Long nIndentDist = firstLine.GetTextFirstLineOffset(); + // tdf#36709: TODO: Handle font-relative hanging indent + tools::Long nIndentDist = firstLine.ResolveTextFirstLineOffset({}); if (nIndentDist == 0) { @@ -742,7 +744,7 @@ void SwView::ExecTabWin( SfxRequest const & rReq ) } leftMargin.SetTextLeft(leftMargin.GetTextLeft() + nIndentDist); - firstLine.SetTextFirstLineOffset(nIndentDist * -1); + firstLine.SetTextFirstLineOffset(nIndentDist * -1, css::util::MeasureUnit::TWIP); firstLine.SetAutoFirst(false); // old code would do this, is it wanted? rSh.SetAttrItem(firstLine); @@ -1670,7 +1672,10 @@ void SwView::StateTabWin(SfxItemSet& rSet) SvxFirstLineIndentItem const& rFirstLine(aCoreSet.Get(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem const& rLeftMargin(aCoreSet.Get(RES_MARGIN_TEXTLEFT)); SvxRightMarginItem const& rRightMargin(aCoreSet.Get(RES_MARGIN_RIGHT)); - aLR->SetTextFirstLineOffset(rFirstLine.GetTextFirstLineOffset(), rFirstLine.GetPropTextFirstLineOffset()); + + // tdf#36709: TODO: Handle font-relative first-line indentation + aLR->SetTextFirstLineOffset(rFirstLine.ResolveTextFirstLineOffset({}), + rFirstLine.GetPropTextFirstLineOffset()); aLR->SetAutoFirst(rFirstLine.IsAutoFirst()); aLR->SetTextLeft(rLeftMargin.GetTextLeft(), rLeftMargin.GetPropLeft()); aLR->SetRight(rRightMargin.GetRight(), rRightMargin.GetPropRight()); @@ -1684,7 +1689,9 @@ void SwView::StateTabWin(SfxItemSet& rSet) m_pNumRuleNodeFromDoc->GetLeftMarginWithNum( true ) ); short nFLOffset; - m_pNumRuleNodeFromDoc->GetFirstLineOfsWithNum( nFLOffset ); + + // tdf#36709: TODO: Handle font-relative units + m_pNumRuleNodeFromDoc->GetFirstLineOfsWithNum(nFLOffset, {}); aLR->SetLeft( nOffset + nFLOffset ); } diff --git a/sw/source/uibase/wrtsh/delete.cxx b/sw/source/uibase/wrtsh/delete.cxx index 2cb0e2ed6d72..79172e8a6819 100644 --- a/sw/source/uibase/wrtsh/delete.cxx +++ b/sw/source/uibase/wrtsh/delete.cxx @@ -70,17 +70,17 @@ bool SwWrtShell::TryRemoveIndent() SvxFirstLineIndentItem firstLine(aAttrSet.Get(RES_MARGIN_FIRSTLINE)); SvxTextLeftMarginItem leftMargin(aAttrSet.Get(RES_MARGIN_TEXTLEFT)); - short aOldFirstLineOfst = firstLine.GetTextFirstLineOffset(); + short aOldFirstLineOfst = firstLine.ResolveTextFirstLineOffset({}); if (aOldFirstLineOfst > 0) { - firstLine.SetTextFirstLineOffset(0); + firstLine.SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); bResult = true; } else if (aOldFirstLineOfst < 0) { // this used to call SetLeft() but this should be the same result - firstLine.SetTextFirstLineOffset(0); + firstLine.SetTextFirstLineOffset(0.0, css::util::MeasureUnit::TWIP); leftMargin.SetTextLeft(leftMargin.GetTextLeft() + aOldFirstLineOfst); bResult = true; } diff --git a/vcl/inc/font/FontMetricData.hxx b/vcl/inc/font/FontMetricData.hxx index 636d2f3f718d..b82b9947ceb9 100644 --- a/vcl/inc/font/FontMetricData.hxx +++ b/vcl/inc/font/FontMetricData.hxx @@ -57,6 +57,9 @@ public: int GetSlant() const { return mnSlant; } double GetMinKashida() const { return mnMinKashida; } tools::Long GetHangingBaseline() const { return mnHangingBaseline; } + double GetUnitEm() const { return mdEmSize; } + double GetHorCJKAdvance() const { return mdHorCJKAdvanceSize; } + double GetVertCJKAdvance() const { return mdVertCJKAdvanceSize; } void SetSlant(int nSlant) { mnSlant=nSlant; } void SetMinKashida(double nMinKashida ) { mnMinKashida=nMinKashida; } @@ -118,6 +121,9 @@ private: int mnSlant; // Slant (Italic/Oblique) double mnMinKashida; // Minimal width of kashida (Arabic) tools::Long mnHangingBaseline; // Offset of hanging baseline to Romn baseline + double mdEmSize; // Size of an 'em' + double mdHorCJKAdvanceSize; // Size of an 'ic' in horizontal text + double mdVertCJKAdvanceSize; // Size of an 'ic' in vertical text // font attributes queried from the font instance bool mbFullstopCentered; diff --git a/vcl/source/font/fontmetric.cxx b/vcl/source/font/fontmetric.cxx index 6ce4b1309e43..d2008484f6cc 100644 --- a/vcl/source/font/fontmetric.cxx +++ b/vcl/source/font/fontmetric.cxx @@ -42,15 +42,18 @@ using namespace ::com::sun::star::uno; using namespace ::rtl; FontMetric::FontMetric() -: mnAscent( 0 ), - mnDescent( 0 ), - mnIntLeading( 0 ), - mnExtLeading( 0 ), - mnLineHeight( 0 ), - mnSlant( 0 ), - mnBulletOffset( 0 ), - mnHangingBaseline( 0 ), - mbFullstopCentered( false ) + : mnAscent(0) + , mnDescent(0) + , mnIntLeading(0) + , mnExtLeading(0) + , mnLineHeight(0) + , mnSlant(0) + , mnBulletOffset(0) + , mnHangingBaseline(0) + , mdEmSize(0.0) + , mdHorCJKAdvanceSize(0.0) + , mdVertCJKAdvanceSize(0.0) + , mbFullstopCentered(false) {} FontMetric::FontMetric( const FontMetric& rFontMetric ) = default; @@ -141,6 +144,9 @@ FontMetricData::FontMetricData( const vcl::font::FontSelectPattern& rFontSelData , mnSlant( 0 ) , mnMinKashida( 0 ) , mnHangingBaseline( 0 ) + , mdEmSize(0.0) + , mdHorCJKAdvanceSize(0.0) + , mdVertCJKAdvanceSize(0.0) , mbFullstopCentered( false ) , mnBulletOffset( 0 ) , mnUnderlineSize( 0 ) @@ -535,6 +541,24 @@ void FontMetricData::ImplCalcLineSpacing(LogicalFontInstance* pFontInstance) if (mnAscent || mnDescent) mnIntLeading = mnAscent + mnDescent - mnHeight; + + // tdf#36709: Additional font metrics are needed for font-relative indentation + mdEmSize = static_cast(mnHeight); + + // The ic is defined as the advance of CJK UNIFIED IDEOGRAPH-6C34 (水). + // If this character does not exist, it defaults to em. + mdHorCJKAdvanceSize = mdEmSize; + mdVertCJKAdvanceSize = mdEmSize; + + hb_codepoint_t nIcGlyph; + if (hb_font_get_glyph(pHbFont, 0x6C34, /*variation selector*/ 0, &nIcGlyph)) + { + auto nIcHAdvance = hb_font_get_glyph_h_advance(pHbFont, nIcGlyph); + mdHorCJKAdvanceSize = static_cast(nIcHAdvance) * fScale; + + auto nIcVAdvance = hb_font_get_glyph_v_advance(pHbFont, nIcGlyph); + mdVertCJKAdvanceSize = static_cast(nIcVAdvance) * fScale; + } } void FontMetricData::ImplInitBaselines(LogicalFontInstance *pFontInstance) diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx index 45b773a20c01..3d143938038b 100644 --- a/vcl/source/outdev/font.cxx +++ b/vcl/source/outdev/font.cxx @@ -211,6 +211,10 @@ FontMetric OutputDevice::GetFontMetric() const aMetric.SetSlant( ImplDevicePixelToLogicHeight( xFontMetric->GetSlant() ) ); aMetric.SetHangingBaseline( ImplDevicePixelToLogicHeight( xFontMetric->GetHangingBaseline() ) ); + aMetric.SetUnitEm(ImplDevicePixelToLogicWidth(xFontMetric->GetUnitEm())); + aMetric.SetHorCJKAdvance(ImplDevicePixelToLogicWidth(xFontMetric->GetHorCJKAdvance())); + aMetric.SetVertCJKAdvance(ImplDevicePixelToLogicHeight(xFontMetric->GetVertCJKAdvance())); + // get miscellaneous data aMetric.SetQuality( xFontMetric->GetQuality() ); diff --git a/xmloff/source/style/xmlbahdl.cxx b/xmloff/source/style/xmlbahdl.cxx index 02c271ad6a2e..a59abbdeed04 100644 --- a/xmloff/source/style/xmlbahdl.cxx +++ b/xmloff/source/style/xmlbahdl.cxx @@ -220,7 +220,7 @@ bool XMLUnitMeasurePropHdl::importXML( const OUString& rStrImpValue, Any& rValue // 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) + && css::util::MeasureUnit::FONT_CJK_ADVANCE != nValueUnit) { return false; } @@ -244,7 +244,7 @@ bool XMLUnitMeasurePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue // 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) + && css::util::MeasureUnit::FONT_CJK_ADVANCE != nValueUnit) { return false; }