cool#16233 sw: keep a formula's font size across DOCX import and export
An equation's size lives in the w:sz of its math runs. The import ignored it, so every equation came in at the 12pt default of the formula editor, and a file holding equations at three sizes showed all three the same. An equation whose runs name no size takes the size of the text around it, which the styles and the document defaults hold. The export wrote no size at all. It now puts the size on every math run, and in the control properties of each object, which is where the fraction bar, the radical sign and the brackets take theirs from. The size travels in the w namespace, so it goes out for a DOCX only, the way the color of a formula already does. Every formula now carries a size of its own on the way out, including one written in ODF. Such a formula used to leave the size open and took whatever the text around it had in the reading application. It now keeps the size it is drawn at here, so both applications show it the same. Setting the base size means giving each of the fonts that same size. The font size dialog, the BaseFontHeight property of the model and this import each did that on their own, so they now share SmFormat::SetBaseSizeAndFonts. The property used to put the sizes in a copy that a later merge step reads only for a font the same call has named, so a lone BaseFontHeight left the fonts alone. Signed-off-by: Gülşah Köse <gulsah.kose@collabora.com> Change-Id: I18b6c5814a57d8ccb8be5b7bdd357ce76cea024d Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/13297 Reviewed-by: Balázs Varga <balazs.varga@collabora.com> Tested-by: Jenkins CPCI <releng@collaboraoffice.com> (cherry picked from commit 582e3fdb6496d9f511dfefc1f716b4ead6cc3797) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/211600 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
@@ -36,6 +36,12 @@ class OOX_DLLPUBLIC SAL_LOPLUGIN_ANNOTATE("crosscast") FormulaImExportBase
|
||||
public:
|
||||
virtual void readFormulaOoxml( oox::formulaimport::XmlStream& stream ) = 0;
|
||||
virtual Size getFormulaSize() const = 0; // Unit is mm100
|
||||
/** The font size in half points that the OOXML markup gave for the formula. It is 0 when
|
||||
the markup carried no size, and the formula then has whatever size the text around it
|
||||
has. */
|
||||
virtual sal_Int32 getFormulaFontSizeInHalfPoints() const = 0;
|
||||
/** Draw the formula at the given size, in half points. */
|
||||
virtual void setFormulaFontSizeInHalfPoints( sal_Int32 nFontSize ) = 0;
|
||||
|
||||
virtual void writeFormulaOoxml(::sax_fastparser::FSHelperPtr pSerializer,
|
||||
oox::core::OoxmlVersion version,
|
||||
|
||||
@@ -205,6 +205,14 @@ public:
|
||||
Handle the current (unexpected) tag.
|
||||
*/
|
||||
void handleUnexpectedTag();
|
||||
/**
|
||||
Collects an attribute from every opening tag of the given type that sits inside an
|
||||
element of the given enclosing type, anywhere in the stream and however deeply nested.
|
||||
The position in the stream stays where it is.
|
||||
@return the attribute values, in the order the tags carrying them appear
|
||||
*/
|
||||
std::vector<OUString> tagAttributesWithin(int nEnclosingToken, int nTagToken,
|
||||
int nAttributeToken) const;
|
||||
|
||||
protected:
|
||||
Tag checkTag(int token, bool optional);
|
||||
|
||||
@@ -312,6 +312,23 @@ void XmlStream::handleUnexpectedTag()
|
||||
skipElementInternal( currentToken(), false ); // otherwise skip the entire element
|
||||
}
|
||||
|
||||
std::vector<OUString> XmlStream::tagAttributesWithin( int nEnclosingToken, int nTagToken,
|
||||
int nAttributeToken ) const
|
||||
{
|
||||
std::vector<OUString> aValues;
|
||||
int nDepth = 0;
|
||||
for( const Tag& rTag : tags )
|
||||
{
|
||||
if( rTag.token == OPENING( nEnclosingToken ))
|
||||
++nDepth;
|
||||
else if( rTag.token == CLOSING( nEnclosingToken ))
|
||||
--nDepth;
|
||||
else if( nDepth > 0 && rTag.token == OPENING( nTagToken ))
|
||||
aValues.push_back( rTag.attribute( nAttributeToken ));
|
||||
}
|
||||
return aValues;
|
||||
}
|
||||
|
||||
void XmlStreamBuilder::appendOpeningTag( int token, const uno::Reference< xml::sax::XFastAttributeList >& attrs )
|
||||
{
|
||||
tags.emplace_back( OPENING( token ), attrs );
|
||||
|
||||
@@ -93,6 +93,8 @@ class SM_DLLPUBLIC SmDocShell final : public SfxObjectShell, public SfxListener
|
||||
sal_uInt16 mnModifyCount;
|
||||
bool mbFormulaArranged;
|
||||
sal_Int16 mnSmSyntaxVersion;
|
||||
/// Font size in half points that the OOXML markup gave for the formula, 0 when it gave none.
|
||||
sal_Int32 mnOoxmlFontSizeInHalfPoints = 0;
|
||||
std::unique_ptr<AbstractSmParser> maParser;
|
||||
std::unique_ptr<SmCursor> mpCursor;
|
||||
std::set< OUString > maUsedSymbols; // to export used symbols only when saving
|
||||
@@ -215,6 +217,12 @@ public:
|
||||
const sal_Int8 nAlign);
|
||||
void writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding);
|
||||
void readFormulaOoxml( oox::formulaimport::XmlStream& stream );
|
||||
/** The font size in half points that the OOXML markup gave for the formula, or 0 when the
|
||||
markup carried no size of its own. */
|
||||
sal_Int32 GetOoxmlFontSizeInHalfPoints() const { return mnOoxmlFontSizeInHalfPoints; }
|
||||
/** Draw the formula at the given size, in half points. The size becomes the base size and
|
||||
the size of each of the fonts. A size of zero or less leaves the formula as it is. */
|
||||
void SetFontSizeInHalfPoints(sal_Int32 nFontSize);
|
||||
|
||||
void UpdateEditEngineDefaultFonts();
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ public:
|
||||
|
||||
const Size & GetBaseSize() const { return aBaseSize; }
|
||||
void SetBaseSize(const Size &rSize) { aBaseSize = rSize; }
|
||||
/// Sets the base size and gives each of the fonts that same size.
|
||||
void SetBaseSizeAndFonts(const Size &rSize);
|
||||
|
||||
const SmFace & GetFont(sal_uInt16 nIdent) const { return vFont[nIdent]; }
|
||||
void SetFont(sal_uInt16 nIdent, const SmFace &rFont, bool bDefault = false);
|
||||
|
||||
@@ -91,6 +91,8 @@ public:
|
||||
virtual void writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding) override;
|
||||
virtual void readFormulaOoxml( oox::formulaimport::XmlStream& stream ) override;
|
||||
virtual Size getFormulaSize() const override;
|
||||
virtual sal_Int32 getFormulaFontSizeInHalfPoints() const override;
|
||||
virtual void setFormulaFontSizeInHalfPoints(sal_Int32 nFontSize) override;
|
||||
|
||||
private:
|
||||
OUString msOldWindowState; // imported window state
|
||||
|
||||
@@ -521,7 +521,7 @@ void SmFontSizeDialog::ReadFrom(const SmFormat &rFormat)
|
||||
|
||||
void SmFontSizeDialog::WriteTo(SmFormat &rFormat) const
|
||||
{
|
||||
rFormat.SetBaseSize( Size(0, o3tl::convert(m_xBaseSize->get_value(FieldUnit::NONE), o3tl::Length::pt, SmO3tlLengthUnit())) );
|
||||
rFormat.SetBaseSizeAndFonts( Size(0, o3tl::convert(m_xBaseSize->get_value(FieldUnit::NONE), o3tl::Length::pt, SmO3tlLengthUnit())) );
|
||||
|
||||
rFormat.SetRelSize(SIZ_TEXT, sal::static_int_cast<sal_uInt16>(m_xTextSize->get_value(FieldUnit::NONE)));
|
||||
rFormat.SetRelSize(SIZ_INDEX, sal::static_int_cast<sal_uInt16>(m_xIndexSize->get_value(FieldUnit::NONE)));
|
||||
@@ -529,10 +529,6 @@ void SmFontSizeDialog::WriteTo(SmFormat &rFormat) const
|
||||
rFormat.SetRelSize(SIZ_OPERATOR, sal::static_int_cast<sal_uInt16>(m_xOperatorSize->get_value(FieldUnit::NONE)));
|
||||
rFormat.SetRelSize(SIZ_LIMITS, sal::static_int_cast<sal_uInt16>(m_xBorderSize->get_value(FieldUnit::NONE)));
|
||||
|
||||
const Size aTmp (rFormat.GetBaseSize());
|
||||
for (sal_uInt16 i = FNT_BEGIN; i <= FNT_END; i++)
|
||||
rFormat.SetFontSize(i, aTmp);
|
||||
|
||||
rFormat.RequestApplyChanges();
|
||||
}
|
||||
|
||||
|
||||
@@ -835,7 +835,9 @@ void SmDocShell::writeFormulaOoxml(
|
||||
Parse();
|
||||
if( mpTree )
|
||||
ArrangeFormula();
|
||||
SmOoxmlExport aEquation(mpTree.get(), version, documentType);
|
||||
SmOoxmlExport aEquation(mpTree.get(), version, documentType,
|
||||
o3tl::convert(maFormat.GetBaseSize().Height() * 2, SmO3tlLengthUnit(),
|
||||
o3tl::Length::pt));
|
||||
if(documentType == oox::drawingml::DOCUMENT_DOCX)
|
||||
aEquation.ConvertFromStarMath( pSerializer, nAlign);
|
||||
else
|
||||
@@ -856,6 +858,19 @@ void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
|
||||
{
|
||||
SmOoxmlImport aEquation( stream );
|
||||
SetText( aEquation.ConvertToStarMath());
|
||||
mnOoxmlFontSizeInHalfPoints = aEquation.GetFontSizeInHalfPoints();
|
||||
SetFontSizeInHalfPoints(mnOoxmlFontSizeInHalfPoints);
|
||||
}
|
||||
|
||||
void SmDocShell::SetFontSizeInHalfPoints(sal_Int32 nFontSize)
|
||||
{
|
||||
if (nFontSize <= 0)
|
||||
return;
|
||||
SmFormat aFormat(GetFormat());
|
||||
Size aSize(aFormat.GetBaseSize());
|
||||
aSize.setHeight(o3tl::convert(nFontSize, o3tl::Length::pt, SmO3tlLengthUnit()) / 2);
|
||||
aFormat.SetBaseSizeAndFonts(aSize);
|
||||
SetFormat(aFormat);
|
||||
}
|
||||
|
||||
void SmDocShell::Execute(SfxRequest& rReq)
|
||||
|
||||
@@ -89,6 +89,13 @@ SmFormat::SmFormat()
|
||||
}
|
||||
|
||||
|
||||
void SmFormat::SetBaseSizeAndFonts(const Size &rSize)
|
||||
{
|
||||
SetBaseSize(rSize);
|
||||
for (sal_uInt16 nFont = FNT_BEGIN; nFont <= FNT_END; ++nFont)
|
||||
SetFontSize(nFont, rSize);
|
||||
}
|
||||
|
||||
void SmFormat::SetFont(sal_uInt16 nIdent, const SmFace &rFont, bool bDefault )
|
||||
{
|
||||
vFont[nIdent] = rFont;
|
||||
|
||||
@@ -22,10 +22,11 @@ using namespace oox;
|
||||
using namespace oox::core;
|
||||
|
||||
SmOoxmlExport::SmOoxmlExport(const SmNode *const pIn, OoxmlVersion const v,
|
||||
drawingml::DocumentType const documentType)
|
||||
drawingml::DocumentType const documentType, sal_Int32 const nFontSizeInHalfPoints)
|
||||
: SmWordExportBase( pIn )
|
||||
, version( v )
|
||||
, m_DocumentType(documentType)
|
||||
, m_nFontSizeInHalfPoints(nFontSizeInHalfPoints)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -84,27 +85,33 @@ void SmOoxmlExport::ConvertFromStarMath( const ::sax_fastparser::FSHelperPtr& se
|
||||
// part of the ooxml math stuff.
|
||||
|
||||
// The w prefix is bound in a DOCX and nowhere else. A formula in a presentation or a
|
||||
// spreadsheet goes out inside a slide or a sheet, which never declare it, so a color
|
||||
// there would leave the prefix unbound.
|
||||
bool SmOoxmlExport::HasOwnColor( const SmNode* pNode ) const
|
||||
// spreadsheet goes out inside a slide or a sheet, which never declare it, so run
|
||||
// properties there would leave the prefix unbound.
|
||||
bool SmOoxmlExport::WritesRunProperties() const
|
||||
{
|
||||
return drawingml::DOCUMENT_DOCX == m_DocumentType
|
||||
&& pNode->GetFont().GetColor() != COL_AUTO;
|
||||
return drawingml::DOCUMENT_DOCX == m_DocumentType;
|
||||
}
|
||||
|
||||
// Only a bold or italic command around a construct sets these attributes on it.
|
||||
bool SmOoxmlExport::HasCtrlPr( const SmNode* pNode ) const
|
||||
// Only a color command around a node sets a color on it.
|
||||
bool SmOoxmlExport::HasOwnColor( const SmNode* pNode )
|
||||
{
|
||||
return HasOwnColor( pNode )
|
||||
|| ( drawingml::DOCUMENT_DOCX == m_DocumentType
|
||||
&& ( pNode->Attributes() & ( FontAttribute::Bold | FontAttribute::Italic )));
|
||||
return pNode->GetFont().GetColor() != COL_AUTO;
|
||||
}
|
||||
|
||||
// The size belongs on every run and on every control property of the formula, which is
|
||||
// where the markup carries it.
|
||||
void SmOoxmlExport::WriteFontSize()
|
||||
{
|
||||
const OString sFontSize( OString::number( m_nFontSizeInHalfPoints ));
|
||||
m_pSerializer->singleElementNS( XML_w, XML_sz, FSNS( XML_w, XML_val ), sFontSize );
|
||||
m_pSerializer->singleElementNS( XML_w, XML_szCs, FSNS( XML_w, XML_val ), sFontSize );
|
||||
}
|
||||
|
||||
// A construct such as a fraction or a pair of brackets draws part of itself, and the
|
||||
// format of that part travels in the m:ctrlPr of the construct's property element.
|
||||
void SmOoxmlExport::WriteCtrlPr( const SmNode* pNode )
|
||||
{
|
||||
if( !HasCtrlPr( pNode ))
|
||||
if( !WritesRunProperties())
|
||||
return;
|
||||
m_pSerializer->startElementNS( XML_m, XML_ctrlPr );
|
||||
m_pSerializer->startElementNS( XML_w, XML_rPr );
|
||||
@@ -115,10 +122,21 @@ void SmOoxmlExport::WriteCtrlPr( const SmNode* pNode )
|
||||
if( HasOwnColor( pNode ))
|
||||
m_pSerializer->singleElementNS( XML_w, XML_color, FSNS( XML_w, XML_val ),
|
||||
msfilter::util::ConvertColorOU( pNode->GetFont().GetColor()));
|
||||
WriteFontSize();
|
||||
m_pSerializer->endElementNS( XML_w, XML_rPr );
|
||||
m_pSerializer->endElementNS( XML_m, XML_ctrlPr );
|
||||
}
|
||||
|
||||
// A property element that a construct carries only to hold its control properties.
|
||||
void SmOoxmlExport::WritePropertiesElement( sal_Int32 nElement, const SmNode* pNode )
|
||||
{
|
||||
if( !WritesRunProperties())
|
||||
return;
|
||||
m_pSerializer->startElementNS( XML_m, nElement );
|
||||
WriteCtrlPr( pNode );
|
||||
m_pSerializer->endElementNS( XML_m, nElement );
|
||||
}
|
||||
|
||||
static bool lcl_HasLetter( const OUString& rText )
|
||||
{
|
||||
for( sal_Int32 nIndex = 0; nIndex < rText.getLength(); )
|
||||
@@ -145,6 +163,7 @@ static const char* lcl_GetOoxmlStyle( bool bBold, bool bItalic, const OUString&
|
||||
void SmOoxmlExport::HandleVerticalStack( const SmNode* pNode, int nLevel )
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_eqArr);
|
||||
WritePropertiesElement( XML_eqArrPr, pNode );
|
||||
int size = pNode->GetNumSubNodes();
|
||||
for( int i = 0;
|
||||
i < size;
|
||||
@@ -181,32 +200,24 @@ void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/)
|
||||
m_pSerializer->singleElementNS(XML_m, XML_sty, FSNS(XML_m, XML_val), pStyle);
|
||||
m_pSerializer->endElementNS( XML_m, XML_rPr );
|
||||
}
|
||||
const bool bWriteFont
|
||||
= drawingml::DOCUMENT_DOCX == m_DocumentType && ECMA_376_1ST_EDITION == version;
|
||||
const bool bWriteBold
|
||||
= drawingml::DOCUMENT_DOCX == m_DocumentType && bLiteral && bBold;
|
||||
const bool bWriteItalic
|
||||
= drawingml::DOCUMENT_DOCX == m_DocumentType && bLiteral && bItalic;
|
||||
// A surrounding color, bold or italic command has already reached this node.
|
||||
const Color aColor = pNode->GetFont().GetColor();
|
||||
const bool bWriteColor
|
||||
= drawingml::DOCUMENT_DOCX == m_DocumentType && aColor != COL_AUTO;
|
||||
if( bWriteFont || bWriteBold || bWriteItalic || bWriteColor )
|
||||
if( WritesRunProperties())
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_w, XML_rPr);
|
||||
if( bWriteFont )
|
||||
// HACK: MSOffice2007 does not import characters properly unless this font is
|
||||
// explicitly given
|
||||
if( ECMA_376_1ST_EDITION == version )
|
||||
// Readers of the first OOXML edition get the characters wrong unless the font
|
||||
// is named here.
|
||||
m_pSerializer->singleElementNS( XML_w, XML_rFonts,
|
||||
FSNS( XML_w, XML_ascii ), "Cambria Math",
|
||||
FSNS( XML_w, XML_hAnsi ), "Cambria Math" );
|
||||
if( bWriteBold )
|
||||
// A surrounding color, bold or italic command has already reached this node.
|
||||
if( bLiteral && bBold )
|
||||
m_pSerializer->singleElementNS( XML_w, XML_b );
|
||||
if( bWriteItalic )
|
||||
if( bLiteral && bItalic )
|
||||
m_pSerializer->singleElementNS( XML_w, XML_i );
|
||||
if( bWriteColor )
|
||||
if( HasOwnColor( pNode ))
|
||||
m_pSerializer->singleElementNS( XML_w, XML_color, FSNS( XML_w, XML_val ),
|
||||
msfilter::util::ConvertColorOU( aColor ));
|
||||
msfilter::util::ConvertColorOU( pNode->GetFont().GetColor()));
|
||||
WriteFontSize();
|
||||
m_pSerializer->endElementNS( XML_w, XML_rPr );
|
||||
}
|
||||
m_pSerializer->startElementNS(XML_m, XML_t, FSNS(XML_xml, XML_space), "preserve");
|
||||
@@ -270,7 +281,7 @@ void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/)
|
||||
void SmOoxmlExport::HandleFractions( const SmNode* pNode, int nLevel, const char* type )
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_f);
|
||||
if( type != nullptr || HasCtrlPr( pNode ))
|
||||
if( type != nullptr || WritesRunProperties())
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_fPr);
|
||||
if( type != nullptr )
|
||||
@@ -359,27 +370,24 @@ void SmOoxmlExport::HandleAttribute( const SmAttributeNode* pNode, int nLevel )
|
||||
|
||||
void SmOoxmlExport::HandleRoot( const SmRootNode* pNode, int nLevel )
|
||||
{
|
||||
const SmNode* pArgument = pNode->Argument();
|
||||
m_pSerializer->startElementNS(XML_m, XML_rad);
|
||||
if( const SmNode* argument = pNode->Argument())
|
||||
if( pArgument == nullptr || WritesRunProperties())
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_radPr);
|
||||
if( pArgument == nullptr )
|
||||
m_pSerializer->singleElementNS(XML_m, XML_degHide, FSNS(XML_m, XML_val), "1");
|
||||
WriteCtrlPr( pNode );
|
||||
m_pSerializer->endElementNS( XML_m, XML_radPr );
|
||||
}
|
||||
if( pArgument != nullptr )
|
||||
{
|
||||
if( HasCtrlPr( pNode ))
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_radPr);
|
||||
WriteCtrlPr( pNode );
|
||||
m_pSerializer->endElementNS( XML_m, XML_radPr );
|
||||
}
|
||||
m_pSerializer->startElementNS(XML_m, XML_deg);
|
||||
HandleNode( argument, nLevel + 1 );
|
||||
HandleNode( pArgument, nLevel + 1 );
|
||||
m_pSerializer->endElementNS( XML_m, XML_deg );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_radPr);
|
||||
m_pSerializer->singleElementNS(XML_m, XML_degHide, FSNS(XML_m, XML_val), "1");
|
||||
WriteCtrlPr( pNode );
|
||||
m_pSerializer->endElementNS( XML_m, XML_radPr );
|
||||
m_pSerializer->singleElementNS(XML_m, XML_deg); // empty but present
|
||||
}
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
HandleNode( pNode->Body(), nLevel + 1 );
|
||||
m_pSerializer->endElementNS( XML_m, XML_e );
|
||||
@@ -448,8 +456,10 @@ void SmOoxmlExport::HandleOperator( const SmOperNode* pNode, int nLevel )
|
||||
}
|
||||
case TLIM:
|
||||
m_pSerializer->startElementNS(XML_m, XML_func);
|
||||
WritePropertiesElement( XML_funcPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_fName);
|
||||
m_pSerializer->startElementNS(XML_m, XML_limLow);
|
||||
WritePropertiesElement( XML_limLowPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
HandleNode( pNode->GetSymbol(), nLevel + 1 );
|
||||
m_pSerializer->endElementNS( XML_m, XML_e );
|
||||
@@ -484,6 +494,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
if(( flags & ( 1 << RSUP | 1 << RSUB )) == ( 1 << RSUP | 1 << RSUB ))
|
||||
{ // m:sSubSup
|
||||
m_pSerializer->startElementNS(XML_m, XML_sSubSup);
|
||||
WritePropertiesElement( XML_sSubSupPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
flags &= ~( 1 << RSUP | 1 << RSUB );
|
||||
if( flags == 0 )
|
||||
@@ -502,6 +513,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
else if(( flags & ( 1 << RSUB )) == 1 << RSUB )
|
||||
{ // m:sSub
|
||||
m_pSerializer->startElementNS(XML_m, XML_sSub);
|
||||
WritePropertiesElement( XML_sSubPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
flags &= ~( 1 << RSUB );
|
||||
if( flags == 0 )
|
||||
@@ -517,6 +529,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
else if(( flags & ( 1 << RSUP )) == 1 << RSUP )
|
||||
{ // m:sSup
|
||||
m_pSerializer->startElementNS(XML_m, XML_sSup);
|
||||
WritePropertiesElement( XML_sSupPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
flags &= ~( 1 << RSUP );
|
||||
if( flags == 0 )
|
||||
@@ -532,6 +545,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
else if(( flags & ( 1 << LSUP | 1 << LSUB )) == ( 1 << LSUP | 1 << LSUB ))
|
||||
{ // m:sPre
|
||||
m_pSerializer->startElementNS(XML_m, XML_sPre);
|
||||
WritePropertiesElement( XML_sPrePr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_sub);
|
||||
HandleNode( pNode->GetSubSup( LSUB ), nLevel + 1 );
|
||||
m_pSerializer->endElementNS( XML_m, XML_sub );
|
||||
@@ -550,6 +564,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
else if(( flags & ( 1 << CSUB )) == ( 1 << CSUB ))
|
||||
{ // m:limLow looks like a good element for central superscript
|
||||
m_pSerializer->startElementNS(XML_m, XML_limLow);
|
||||
WritePropertiesElement( XML_limLowPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
flags &= ~( 1 << CSUB );
|
||||
if( flags == 0 )
|
||||
@@ -565,6 +580,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
else if(( flags & ( 1 << CSUP )) == ( 1 << CSUP ))
|
||||
{ // m:limUpp looks like a good element for central superscript
|
||||
m_pSerializer->startElementNS(XML_m, XML_limUpp);
|
||||
WritePropertiesElement( XML_limUppPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
flags &= ~( 1 << CSUP );
|
||||
if( flags == 0 )
|
||||
@@ -588,6 +604,7 @@ void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int n
|
||||
void SmOoxmlExport::HandleMatrix( const SmMatrixNode* pNode, int nLevel )
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_m);
|
||||
WritePropertiesElement( XML_mPr, pNode );
|
||||
for (size_t row = 0; row < pNode->GetNumRows(); ++row)
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_mr);
|
||||
@@ -675,6 +692,7 @@ void SmOoxmlExport::HandleVerticalBrace( const SmVerticalBraceNode* pNode, int n
|
||||
{
|
||||
bool top = ( pNode->GetToken().eType == TOVERBRACE );
|
||||
m_pSerializer->startElementNS(XML_m, top ? XML_limUpp : XML_limLow);
|
||||
WritePropertiesElement( top ? XML_limUppPr : XML_limLowPr, pNode );
|
||||
m_pSerializer->startElementNS(XML_m, XML_e);
|
||||
m_pSerializer->startElementNS(XML_m, XML_groupChr);
|
||||
m_pSerializer->startElementNS(XML_m, XML_groupChrPr);
|
||||
@@ -708,6 +726,13 @@ void SmOoxmlExport::HandleVerticalBrace( const SmVerticalBraceNode* pNode, int n
|
||||
void SmOoxmlExport::HandleBlank()
|
||||
{
|
||||
m_pSerializer->startElementNS(XML_m, XML_r);
|
||||
// A blank draws no glyph, so the size is all it carries.
|
||||
if( WritesRunProperties())
|
||||
{
|
||||
m_pSerializer->startElementNS( XML_w, XML_rPr );
|
||||
WriteFontSize();
|
||||
m_pSerializer->endElementNS( XML_w, XML_rPr );
|
||||
}
|
||||
m_pSerializer->startElementNS(XML_m, XML_t, FSNS(XML_xml, XML_space), "preserve");
|
||||
m_pSerializer->write( " " );
|
||||
m_pSerializer->endElementNS( XML_m, XML_t );
|
||||
|
||||
@@ -22,7 +22,7 @@ class SmOoxmlExport : public SmWordExportBase
|
||||
{
|
||||
public:
|
||||
SmOoxmlExport(const SmNode* pIn, oox::core::OoxmlVersion version,
|
||||
oox::drawingml::DocumentType documentType);
|
||||
oox::drawingml::DocumentType documentType, sal_Int32 nFontSizeInHalfPoints);
|
||||
void ConvertFromStarMath(const ::sax_fastparser::FSHelperPtr& m_pSerializer, const sal_Int8);
|
||||
|
||||
private:
|
||||
@@ -37,18 +37,23 @@ private:
|
||||
void HandleBrace(const SmBraceNode* pNode, int nLevel) override;
|
||||
void HandleVerticalBrace(const SmVerticalBraceNode* pNode, int nLevel) override;
|
||||
void HandleBlank() override;
|
||||
/// Writes the m:ctrlPr carrying the color, bold and italic of the parts a construct
|
||||
/// draws itself.
|
||||
/// True when the run properties are written out, which needs a DOCX.
|
||||
bool WritesRunProperties() const;
|
||||
/// True when the node has a color of its own rather than the default one.
|
||||
static bool HasOwnColor(const SmNode* pNode);
|
||||
/// Writes the w:sz and w:szCs carrying the size the formula is drawn at.
|
||||
void WriteFontSize();
|
||||
/// Writes the m:ctrlPr carrying the size, color, bold and italic of the parts a
|
||||
/// construct draws itself.
|
||||
void WriteCtrlPr(const SmNode* pNode);
|
||||
/// True when the node has a color, bold or italic of its own to write in an m:ctrlPr.
|
||||
bool HasCtrlPr(const SmNode* pNode) const;
|
||||
/// True when the color of the node is written out, which needs a color other than
|
||||
/// the default and a DOCX.
|
||||
bool HasOwnColor(const SmNode* pNode) const;
|
||||
/// Writes a property element that a construct carries only to hold its control properties.
|
||||
void WritePropertiesElement(sal_Int32 nElement, const SmNode* pNode);
|
||||
::sax_fastparser::FSHelperPtr m_pSerializer;
|
||||
oox::core::OoxmlVersion version;
|
||||
/// needed to determine markup for nested run properties
|
||||
oox::drawingml::DocumentType const m_DocumentType;
|
||||
/// The size the formula is drawn at, in half points.
|
||||
sal_Int32 const m_nFontSizeInHalfPoints;
|
||||
};
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <sal/config.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
|
||||
#include "ooxmlimport.hxx"
|
||||
@@ -201,6 +202,22 @@ OUString SmOoxmlImport::ConvertToStarMath()
|
||||
return handleStream();
|
||||
}
|
||||
|
||||
sal_Int32 SmOoxmlImport::GetFontSizeInHalfPoints() const
|
||||
{
|
||||
// A formula is drawn at a single size, and the runs of a formula that names a size all
|
||||
// carry it. Where they differ, the largest one is the size of the body: a smaller one
|
||||
// belongs to a part the author shrank, such as a limit or a script. A value that is not
|
||||
// a positive number of half points counts as no size at all, and so does a formula whose
|
||||
// runs name none, which then takes the size of the text around it.
|
||||
sal_Int32 nFontSize = 0;
|
||||
for( const OUString& rValue : m_rStream.tagAttributesWithin(
|
||||
M_TOKEN( r ), W_TOKEN( sz ), W_TOKEN( val )))
|
||||
{
|
||||
nFontSize = std::max( nFontSize, rValue.toInt32());
|
||||
}
|
||||
return nFontSize;
|
||||
}
|
||||
|
||||
// "toplevel" of reading, there will be oMath (if there was oMathPara, that was
|
||||
// up to the parent component to handle)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <sal/types.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -25,6 +26,9 @@ public:
|
||||
explicit SmOoxmlImport( oox::formulaimport::XmlStream& stream );
|
||||
~SmOoxmlImport();
|
||||
OUString ConvertToStarMath();
|
||||
/** The font size the markup gives for the formula, in half points, or 0 when the markup
|
||||
carries no size of its own and the formula takes the size of the text around it. */
|
||||
sal_Int32 GetFontSizeInHalfPoints() const;
|
||||
private:
|
||||
/// The parser that tells whether a run's text stands as an expression of its own.
|
||||
SmParser5& getParser();
|
||||
|
||||
@@ -480,12 +480,12 @@ void SmModel::_setPropertyValues(const PropertyMapEntry** ppEntries, const Any*
|
||||
throw IllegalArgumentException();
|
||||
Size aSize = aFormat.GetBaseSize();
|
||||
aSize.setHeight(o3tl::convert(nVal, o3tl::Length::pt, SmO3tlLengthUnit()));
|
||||
aFormat.SetBaseSize(aSize);
|
||||
aFormat.SetBaseSizeAndFonts(aSize);
|
||||
|
||||
// apply base size to fonts
|
||||
const Size aTmp( aFormat.GetBaseSize() );
|
||||
for (sal_uInt16 i = FNT_BEGIN; i <= FNT_END; i++)
|
||||
maFonts[i].SetSize(aTmp);
|
||||
// A font that this same call names is merged in below, from a copy that
|
||||
// needs the new size too.
|
||||
for (sal_uInt16 nFont = FNT_BEGIN; nFont <= FNT_END; nFont++)
|
||||
maFonts[nFont].SetSize(aSize);
|
||||
}
|
||||
break;
|
||||
case HANDLE_RELATIVE_FONT_HEIGHT_TEXT :
|
||||
@@ -1112,6 +1112,16 @@ void SmModel::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
|
||||
GetSmDocShell()->readFormulaOoxml(stream);
|
||||
}
|
||||
|
||||
sal_Int32 SmModel::getFormulaFontSizeInHalfPoints() const
|
||||
{
|
||||
return GetSmDocShell()->GetOoxmlFontSizeInHalfPoints();
|
||||
}
|
||||
|
||||
void SmModel::setFormulaFontSizeInHalfPoints( sal_Int32 nFontSize )
|
||||
{
|
||||
GetSmDocShell()->SetFontSizeInHalfPoints(nFontSize);
|
||||
}
|
||||
|
||||
Size SmModel::getFormulaSize() const
|
||||
{
|
||||
return o3tl::convert(GetSmDocShell()->GetSize(), SmO3tlLengthUnit(), o3tl::Length::mm100);
|
||||
|
||||
Binary file not shown.
@@ -434,7 +434,14 @@ CPPUNIT_TEST_FIXTURE(Test, testMathBoldItalic)
|
||||
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:num/m:r/m:rPr/m:sty", "val", u"bi");
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:den/m:r/m:rPr", 0);
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:fPr", 0);
|
||||
// The fraction's control properties carry the size it is drawn at and nothing else: a
|
||||
// bold or italic there belongs to the bar alone, and a command around the fraction would
|
||||
// reach the terms as well. The size comes first, so the three counts below are taken on
|
||||
// a path that is there.
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:fPr/m:ctrlPr/w:rPr/w:sz", 1);
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:fPr/m:ctrlPr/w:rPr/w:b", 0);
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:fPr/m:ctrlPr/w:rPr/w:i", 0);
|
||||
assertXPath(pXmlDoc, "//w:p[1]//m:f/m:fPr/m:ctrlPr/w:rPr/w:color", 0);
|
||||
assertXPath(pXmlDoc, "//w:p[2]//m:oMath/m:r[1]/w:rPr/w:b", 0);
|
||||
assertXPath(pXmlDoc, "(//w:p[3]//m:sSub)[1]/m:sub/m:r/m:rPr/m:sty", "val", u"b");
|
||||
assertXPath(pXmlDoc, "(//w:p[3]//m:f)[1]/m:num/m:r/m:rPr/m:sty", "val", u"bi");
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <com/sun/star/beans/XPropertyState.hpp>
|
||||
#include <com/sun/star/beans/XPropertySet.hpp>
|
||||
#include <com/sun/star/container/XEnumerationAccess.hpp>
|
||||
#include <com/sun/star/document/XEmbeddedObjectSupplier2.hpp>
|
||||
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
||||
#include <com/sun/star/style/DropCapFormat.hpp>
|
||||
#include <com/sun/star/text/HoriOrientation.hpp>
|
||||
@@ -419,6 +420,37 @@ CPPUNIT_TEST_FIXTURE(Test, testTableAlignmentFromTableStyle)
|
||||
verify();
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testEquationFontSize)
|
||||
{
|
||||
// Each equation is drawn at the size its run properties give it, and an equation whose runs
|
||||
// give none takes the 11pt of the text around it. Without the fix all three came out at the
|
||||
// 12pt default of the formula editor.
|
||||
createSwDoc("math-font-size.docx");
|
||||
|
||||
const sal_Int16 aExpectedSizes[] = { 8, 11, 20 };
|
||||
for (size_t i = 0; i < std::size(aExpectedSizes); ++i)
|
||||
{
|
||||
uno::Reference<document::XEmbeddedObjectSupplier2> xFormula(getShape(i + 1),
|
||||
uno::UNO_QUERY);
|
||||
CPPUNIT_ASSERT(xFormula.is());
|
||||
CPPUNIT_ASSERT_EQUAL(
|
||||
aExpectedSizes[i],
|
||||
getProperty<sal_Int16>(xFormula->getEmbeddedObject(), u"BaseFontHeight"_ustr));
|
||||
}
|
||||
|
||||
save(TestFilter::DOCX);
|
||||
|
||||
xmlDocUniquePtr pXmlDoc = parseExport(u"word/document.xml"_ustr);
|
||||
// The size goes back out on the equation's runs, in half points, so the sizes survive a
|
||||
// round trip. Without the fix the export wrote no size at all.
|
||||
assertXPath(pXmlDoc, "//w:p[1]/m:oMath/m:r/w:rPr/w:sz", "val", u"16");
|
||||
assertXPath(pXmlDoc, "//w:p[2]/m:oMath/m:r/w:rPr/w:sz", "val", u"22");
|
||||
assertXPath(pXmlDoc, "//w:p[3]/m:oMath/m:f/m:num/m:r/w:rPr/w:sz", "val", u"40");
|
||||
// The fraction bar is drawn by the fraction itself, and takes its size from the control
|
||||
// properties rather than from the runs above and below it.
|
||||
assertXPath(pXmlDoc, "//w:p[3]/m:oMath/m:f/m:fPr/m:ctrlPr/w:rPr/w:sz", "val", u"40");
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ class tdf157569(UITestCase):
|
||||
nHeight = xShape.getSize().Height
|
||||
nWidth = xShape.getSize().Width
|
||||
|
||||
# Without the fix in place, this test would have failed with
|
||||
# AssertionError: 1663 != 944
|
||||
self.assertEqual(1663, nHeight)
|
||||
# The formula takes the 11pt of the text around it, which the document defaults
|
||||
# hold, rather than the 12pt default of the formula editor.
|
||||
self.assertEqual(1529, nHeight)
|
||||
if platform.system() == "Windows":
|
||||
self.assertEqual(2157, nWidth) # no idea why it's different on Windows
|
||||
self.assertEqual(1976, nWidth) # no idea why it's different on Windows
|
||||
else:
|
||||
self.assertEqual(2118, nWidth)
|
||||
self.assertEqual(1940, nWidth)
|
||||
|
||||
xDoc = self.xUITest.getTopFocusWindow()
|
||||
xEditWin = xDoc.getChild("writer_edit")
|
||||
|
||||
@@ -3844,9 +3844,21 @@ void DomainMapper_Impl::appendStarMath( const Value& val )
|
||||
uno::Any(sal_Int32(0)));
|
||||
xComponentProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
|
||||
uno::Any(sal_Int32(0)));
|
||||
|
||||
auto* pFormula = dynamic_cast<oox::FormulaImExportBase*>(xInterface.get());
|
||||
// A formula whose own markup carries no font size is drawn at the size of the text
|
||||
// around it, which the styles and the document defaults hold.
|
||||
double fCharHeight = 0;
|
||||
if (pFormula && pFormula->getFormulaFontSizeInHalfPoints() == 0
|
||||
&& (GetAnyProperty(PROP_CHAR_HEIGHT, GetTopContextOfType(CONTEXT_CHARACTER))
|
||||
>>= fCharHeight))
|
||||
{
|
||||
pFormula->setFormulaFontSizeInHalfPoints(std::lround(fCharHeight * 2));
|
||||
}
|
||||
|
||||
Size size( 1000, 1000 );
|
||||
if( oox::FormulaImExportBase* formulaimport = dynamic_cast< oox::FormulaImExportBase* >( xInterface.get()))
|
||||
size = formulaimport->getFormulaSize();
|
||||
if( pFormula )
|
||||
size = pFormula->getFormulaSize();
|
||||
xStarMath->setPropertyValue(getPropertyName( PROP_WIDTH ),
|
||||
uno::Any( sal_Int32(size.Width())));
|
||||
xStarMath->setPropertyValue(getPropertyName( PROP_HEIGHT ),
|
||||
|
||||
Reference in New Issue
Block a user