docx: export symbol characters correctly

Previously we had:
after save: <w:t></w:t>
original content: <w:sym w:font="Wingdings" w:char="F0E0"/>

This patch checks if paragraph has symbol font used and exports
content using w:sym mark in that case

Change-Id: I74f4bb0d249cbf5dfc930e931f7d91bd0d2e9821
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143455
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144949
Tested-by: Jenkins
Reviewed-by: Szymon Kłos <szymon.klos@collabora.com>
This commit is contained in:
Szymon Kłos
2023-01-03 15:01:05 +00:00
parent 8a96d90a89
commit 87e82f80e8
9 changed files with 89 additions and 19 deletions
+30
View File
@@ -9,6 +9,7 @@
#include <swmodeltestbase.hxx>
#include <com/sun/star/awt/CharSet.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <docsh.hxx>
@@ -159,6 +160,35 @@ CPPUNIT_TEST_FIXTURE(Test, testDocxContentControlDropdownEmptyDisplayText)
// i.e. we wrote an empty attribute instead of omitting it.
assertXPathNoAttribute(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem", "displayText");
}
CPPUNIT_TEST_FIXTURE(Test, testDocxSymbolFontExport)
{
// Create document with symbol character and font Wingdings
mxComponent = loadFromDesktop("private:factory/swriter");
uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XText> xText = xTextDocument->getText();
uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
xText->insertString(xCursor, u"", true);
uno::Reference<text::XTextRange> xRange = xCursor;
uno::Reference<beans::XPropertySet> xTextProps(xRange, uno::UNO_QUERY);
xTextProps->setPropertyValue("CharFontName", uno::Any(OUString("Wingdings")));
xTextProps->setPropertyValue("CharFontNameAsian", uno::Any(OUString("Wingdings")));
xTextProps->setPropertyValue("CharFontNameComplex", uno::Any(OUString("Wingdings")));
xTextProps->setPropertyValue("CharFontCharSet", uno::Any(awt::CharSet::SYMBOL));
// When exporting to DOCX:
save("Office Open XML Text");
// Then make sure the expected markup is used:
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
assertXPath(pXmlDoc, "//w:p/w:r/w:sym", 1);
assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "font", "Wingdings");
assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "char", "f0e0");
}
}
CPPUNIT_PLUGIN_IMPLEMENT();
+1 -1
View File
@@ -191,7 +191,7 @@ public:
virtual void WritePostitFieldReference() {};
/// Output text (inside a run).
virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ) = 0;
virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) = 0;
/// Output text (without markup).
virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) = 0;
+23 -10
View File
@@ -3478,7 +3478,8 @@ bool DocxAttributeOutput::FootnoteEndnoteRefTag()
the switch in DocxAttributeOutput::RunText() nicer ;-)
*/
static bool impl_WriteRunText( FSHelperPtr const & pSerializer, sal_Int32 nTextToken,
const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true )
const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true,
const OUString& rSymbolFont = OUString() )
{
const sal_Unicode *pBegin = rBegin;
@@ -3489,22 +3490,34 @@ static bool impl_WriteRunText( FSHelperPtr const & pSerializer, sal_Int32 nTextT
if ( pBegin >= pEnd )
return false; // we want to write at least one character
// we have to add 'preserve' when starting/ending with space
if ( *pBegin == ' ' || *( pEnd - 1 ) == ' ' )
bool bIsSymbol = !rSymbolFont.isEmpty();
std::u16string_view aView( pBegin, pEnd - pBegin );
if (bIsSymbol)
{
pSerializer->startElementNS(XML_w, nTextToken, FSNS(XML_xml, XML_space), "preserve");
for (char16_t aChar : aView)
{
pSerializer->singleElementNS(XML_w, XML_sym,
FSNS(XML_w, XML_font), rSymbolFont,
FSNS(XML_w, XML_char), OString::number(aChar, 16));
}
}
else
pSerializer->startElementNS(XML_w, nTextToken);
{
// we have to add 'preserve' when starting/ending with space
if ( *pBegin == ' ' || *( pEnd - 1 ) == ' ' )
pSerializer->startElementNS(XML_w, nTextToken, FSNS(XML_xml, XML_space), "preserve");
else
pSerializer->startElementNS(XML_w, nTextToken);
pSerializer->writeEscaped( std::u16string_view( pBegin, pEnd - pBegin ) );
pSerializer->endElementNS( XML_w, nTextToken );
pSerializer->writeEscaped( aView );
pSerializer->endElementNS( XML_w, nTextToken );
}
return true;
}
void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding /*eCharSet*/ )
void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding /*eCharSet*/, const OUString& rSymbolFont )
{
if( m_closeHyperlinkInThisRun )
{
@@ -3569,7 +3582,7 @@ void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding /*eCh
}
}
impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false );
impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false, rSymbolFont );
}
void DocxAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
+1 -1
View File
@@ -207,7 +207,7 @@ public:
virtual void WritePostitFieldReference() override;
/// Output text (inside a run).
virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ) override;
virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) override;
/// Output text (without markup).
virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) override;
+2 -1
View File
@@ -515,7 +515,8 @@ OString RtfAttributeOutput::MoveCharacterProperties(bool aAutoWriteRtlLtr)
return aBuf.makeStringAndClear();
}
void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/,
const OUString& /*rSymbolFont*/)
{
SAL_INFO("sw.rtf", __func__ << ", rText: " << rText);
RawText(rText, m_rExport.GetCurrentEncoding());
+2 -1
View File
@@ -85,7 +85,8 @@ public:
void EndRunProperties(const SwRedlineData* pRedlineData) override;
/// Output text (inside a run).
void RunText(const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8) override;
void RunText(const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8,
const OUString& rSymbolFont = OUString()) override;
// Access to (anyway) private buffers, used by the sdr exporter
OStringBuffer& RunText();
+28 -3
View File
@@ -2224,6 +2224,25 @@ bool MSWordExportBase::NeedTextNodeSplit( const SwTextNode& rNd, SwSoftPageBreak
return pList.size() > 2 && NeedSectionBreak( rNd );
}
namespace {
OUString lcl_GetSymbolFont(SwAttrPool& rPool, const SwTextNode* pTextNode, int nStart, int nEnd)
{
SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet( rPool );
if ( pTextNode && pTextNode->GetParaAttr(aSet, nStart, nEnd) )
{
SfxPoolItem const* pPoolItem = aSet.GetItem(RES_CHRATR_FONT);
if (pPoolItem)
{
const SvxFontItem* pFontItem = static_cast<const SvxFontItem*>(pPoolItem);
if (pFontItem->GetCharSet() == RTL_TEXTENCODING_SYMBOL)
return pFontItem->GetFamilyName();
}
}
return OUString();
}
}
void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
{
SAL_INFO( "sw.ww8", "<OutWW8_SwTextNode>" );
@@ -2447,6 +2466,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nCurrentPos );
OUString aSymbolFont;
sal_Int32 nLen = nNextAttr - nCurrentPos;
if ( !bTextAtr && nLen )
{
@@ -2613,12 +2633,13 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
assert(0 <= nLen);
OUString aSnippet( aAttrIter.GetSnippet( aStr, nCurrentPos + ofs, nLen ) );
const SwTextNode* pTextNode( rNode.GetTextNode() );
if ( ( m_nTextTyp == TXT_EDN || m_nTextTyp == TXT_FTN ) && nCurrentPos == 0 && nLen > 0 )
{
// Allow MSO to emulate LO footnote text starting at left margin - only meaningful with hanging indent
sal_Int32 nFirstLineIndent=0;
SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aSet( m_rDoc.GetAttrPool() );
const SwTextNode* pTextNode( rNode.GetTextNode() );
if ( pTextNode && pTextNode->GetAttr(aSet) )
{
const SvxLRSpaceItem* pLRSpace = aSet.GetItem<SvxLRSpaceItem>(RES_LR_SPACE);
@@ -2632,6 +2653,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
m_bAddFootnoteTab = false;
}
aSymbolFont = lcl_GetSymbolFont(m_rDoc.GetAttrPool(), pTextNode, nCurrentPos + ofs, nCurrentPos + ofs + nLen);
if ( bPostponeWritingText && ( FLY_POSTPONED != nStateOfFlyFrame ) )
{
aSavedSnippet = aSnippet ;
@@ -2639,7 +2662,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
else
{
bPostponeWritingText = false ;
AttrOutput().RunText( aSnippet, eChrSet );
AttrOutput().RunText( aSnippet, eChrSet, aSymbolFont );
}
if (ofs == 1 && nNextAttr == nEnd)
@@ -2764,6 +2787,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
AttrOutput().WritePostitFieldReference();
aSymbolFont = lcl_GetSymbolFont(m_rDoc.GetAttrPool(), &rNode, nCurrentPos, nCurrentPos + nLen);
if (bPostponeWritingText)
{
if (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == nStateOfFlyFrame)
@@ -2785,7 +2810,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
// OutAttr may have introduced new comments, so write them out now
AttrOutput().WritePostitFieldReference();
}
AttrOutput().RunText( aSavedSnippet, eChrSet );
AttrOutput().RunText( aSavedSnippet, eChrSet, aSymbolFont );
AttrOutput().EndRun(&rNode, nCurrentPos, nLen, nNextAttr == nEnd);
}
else
+1 -1
View File
@@ -1136,7 +1136,7 @@ void WW8AttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData )
m_rWW8Export.m_pO->clear();
}
void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet )
void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet, const OUString& /*rSymbolFont*/ )
{
RawText(rText, eCharSet);
}
+1 -1
View File
@@ -67,7 +67,7 @@ public:
virtual void EndRunProperties( const SwRedlineData* pRedlineData ) override;
/// Output text.
virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ) override;
virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) override;
/// Output text (without markup).
virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) override;