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:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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*/)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user