i18npool/inc/cclass_unicode.hxx | 26 - i18npool/source/characterclassification/cclass_unicode_parser.cxx | 137 +++++----- include/oox/mathml/import.hxx | 11 oox/inc/drawingml/textparagraph.hxx | 13 oox/source/core/xmlfilterbase.cxx | 4 oox/source/drawingml/shape.cxx | 51 +++ oox/source/drawingml/textbodycontext.cxx | 5 oox/source/drawingml/textparagraph.cxx | 10 oox/source/mathml/import.cxx | 92 ++++++ sd/qa/unit/data/pptx/Math.pptx |binary sd/qa/unit/export-tests.cxx | 54 +++ starmath/qa/cppunit/test_nodetotextvisitors.cxx | 26 + starmath/source/ooxmlexport.cxx | 6 writerfilter/source/dmapper/DomainMapper_Impl.cxx | 1 14 files changed, 348 insertions(+), 88 deletions(-)
New commits: commit 9486dd0692e08b3770bee8f3be2292263c6e5d26 Author: Michael Stahl <[email protected]> Date: Thu Jan 21 19:00:26 2016 +0100 i18npool: why not document the state transitions Change-Id: Ica5789dab22a49efb9e2da3a795e13aa7e2c4339 diff --git a/i18npool/inc/cclass_unicode.hxx b/i18npool/inc/cclass_unicode.hxx index e88530a..cbcb6f9 100644 --- a/i18npool/inc/cclass_unicode.hxx +++ b/i18npool/inc/cclass_unicode.hxx @@ -75,16 +75,16 @@ private: enum ScanState { - ssGetChar, - ssGetValue, - ssGetWord, - ssGetWordFirstChar, - ssGetString, - ssGetBool, - ssRewindFromValue, - ssIgnoreLeadingInRewind, - ssStopBack, - ssBounce, + ssGetChar, // initial state; -> ssBounce, ssGetValue, ssRewindFromValue, ssGetWord, ssGetWordFirstChar, ssGetString, ssGetBool, ssStop + ssGetValue, // -> ssBounce, ssRewindFromValue, ssStopBack, ssGetWord + ssGetWord, // -> ssBounce, ssStop, ssStopBack + ssGetWordFirstChar, // -> ssBounce, ssGetWord, ssStop, ssStopBack + ssGetString, // -> ssBounce, ssStop + ssGetBool, // -> ssBounce, ssStop, ssStopBack + ssRewindFromValue, // -> ssBounce, ssGetValue, ssGetWord, ssGetWordFirstChar, ssGetString, ssGetBool, ssStop, ssIgnoreLeadingInRewind + ssIgnoreLeadingInRewind, // -> ssBounce, ssGetValue, ssRewindFromValue, ssGetWord, ssGetWordFirstChar, ssGetString, ssGetBool, ssStop + ssStopBack, // -> ssStop + ssBounce, // -> ssStopBack ssStop }; commit 331a0a347e2ed238ff41c8cd7815b946cc95ac0f Author: Michael Stahl <[email protected]> Date: Thu Jan 21 18:20:12 2016 +0100 starmath: fix OOXML export of non-BMP Unicode Change-Id: Iafaeb9ea2e96ee6d8cc96174731ba3845c230b5e diff --git a/sd/qa/unit/data/pptx/Math.pptx b/sd/qa/unit/data/pptx/Math.pptx new file mode 100644 index 0000000..fef2067 Binary files /dev/null and b/sd/qa/unit/data/pptx/Math.pptx differ diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index 2f9550a..211cff2 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -142,6 +142,7 @@ public: void testTdf91378(); void testBnc822341(); void testMathObject(); + void testMathObjectPPT2010(); void testTdf80224(); void testTdf92527(); @@ -182,6 +183,7 @@ public: CPPUNIT_TEST(testBnc822341); CPPUNIT_TEST(testMathObject); + CPPUNIT_TEST(testMathObjectPPT2010); CPPUNIT_TEST(testTdf80224); CPPUNIT_TEST(testExportTransitionsPPTX); @@ -1202,6 +1204,33 @@ void SdExportTest::testMathObject() xDocShRef->DoClose(); } +void SdExportTest::testMathObjectPPT2010() +{ + // Check import / export of math object + ::sd::DrawDocShellRef xDocShRef = loadURL(getURLFromSrc("sd/qa/unit/data/pptx/Math.pptx"), PPTX); + utl::TempFile tempFile1; + xDocShRef = saveAndReload(xDocShRef, PPTX, &tempFile1); + + // Export an MS specific ole object (imported from a PPTX document) + { + xmlDocPtr pXmlDocContent = parseExport(tempFile1, "ppt/slides/slide1.xml"); + assertXPath(pXmlDocContent, + "/p:sld/p:cSld/p:spTree/mc:AlternateContent/mc:Choice", + "Requires", + "a14"); + assertXPathContent(pXmlDocContent, + "/p:sld/p:cSld/p:spTree/mc:AlternateContent/mc:Choice/p:sp/p:txBody/a:p/a14:m/m:oMath/m:sSup/m:e/m:r[1]/m:t", + OUString::fromUtf8("\xf0\x9d\x91\x8e")); // non-BMP char + + const SdrPage *pPage = GetPage(1, xDocShRef); + const SdrObject* pObj = dynamic_cast<SdrObject*>(pPage->GetObj(0)); + CPPUNIT_ASSERT_MESSAGE("no object", pObj != nullptr); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(OBJ_OLE2), pObj->GetObjIdentifier()); + } + + xDocShRef->DoClose(); +} + void SdExportTest::testBulletMarginAndIndentation() { ::sd::DrawDocShellRef xDocShRef = loadURL( getURLFromSrc("/sd/qa/unit/data/pptx/bulletMarginAndIndent.pptx"), PPTX ); diff --git a/starmath/source/ooxmlexport.cxx b/starmath/source/ooxmlexport.cxx index 277fb25..63f7cd4 100644 --- a/starmath/source/ooxmlexport.cxx +++ b/starmath/source/ooxmlexport.cxx @@ -75,6 +75,7 @@ void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/) m_pSerializer->startElementNS( XML_m, XML_t, FSNS( XML_xml, XML_space ), "preserve", FSEND ); const SmTextNode* pTemp = static_cast<const SmTextNode* >(pNode); SAL_INFO( "starmath.ooxml", "Text:" << OUStringToOString( pTemp->GetText(), RTL_TEXTENCODING_UTF8 ).getStr()); + OUStringBuffer buf(pTemp->GetText()); for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++) { #if 0 @@ -94,9 +95,7 @@ void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/) nFace = 0x7; *pS << sal_uInt8(nFace+128); //typeface #endif - sal_uInt16 nChar = pTemp->GetText()[i]; - m_pSerializer->writeEscaped( OUString( SmTextNode::ConvertSymbolToUnicode(nChar))); - + buf[i] = SmTextNode::ConvertSymbolToUnicode(buf[i]); #if 0 //Mathtype can only have these sort of character //attributes on a single character, starmath can put them @@ -127,6 +126,7 @@ void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/) } #endif } + m_pSerializer->writeEscaped(buf.makeStringAndClear()); m_pSerializer->endElementNS( XML_m, XML_t ); m_pSerializer->endElementNS( XML_m, XML_r ); } commit fefd1221be844a033e409a18e05e8c6e98f6d1a7 Author: Michael Stahl <[email protected]> Date: Thu Jan 21 18:11:12 2016 +0100 i18npool: handle non-BMP Unicode in cclass_Unicode::parseText() The UTF-16 code unit limitation was mangling starmath import. Change-Id: I087e5c5b7954799fdb73e7ee1a8d3d02669f8831 diff --git a/i18npool/inc/cclass_unicode.hxx b/i18npool/inc/cclass_unicode.hxx index eb449e4..e88530a 100644 --- a/i18npool/inc/cclass_unicode.hxx +++ b/i18npool/inc/cclass_unicode.hxx @@ -135,13 +135,13 @@ private: sal_Unicode cDecimalSep; /// Get corresponding KParseTokens flag for a character - static sal_Int32 getParseTokensType( const sal_Unicode* aStr, sal_Int32 nPos ); + static sal_Int32 getParseTokensType(sal_uInt32 c, bool isFirst); /// Access parser table flags. - UPT_FLAG_TYPE getFlags( const sal_Unicode* aStr, sal_Int32 nPos ); + UPT_FLAG_TYPE getFlags(sal_uInt32 c); /// Access parser flags via International and special definitions. - UPT_FLAG_TYPE getFlagsExtended( const sal_Unicode* aStr, sal_Int32 nPos ); + UPT_FLAG_TYPE getFlagsExtended(sal_uInt32 c); /// Access parser table flags for user defined start characters. UPT_FLAG_TYPE getStartCharsFlags( sal_Unicode c ); diff --git a/i18npool/source/characterclassification/cclass_unicode_parser.cxx b/i18npool/source/characterclassification/cclass_unicode_parser.cxx index 7321a7e..c003959 100644 --- a/i18npool/source/characterclassification/cclass_unicode_parser.cxx +++ b/i18npool/source/characterclassification/cclass_unicode_parser.cxx @@ -351,16 +351,15 @@ const sal_Unicode* cclass_Unicode::StrChr( const sal_Unicode* pStr, sal_Unicode } -sal_Int32 cclass_Unicode::getParseTokensType( const sal_Unicode* aStr, sal_Int32 nPos ) +sal_Int32 cclass_Unicode::getParseTokensType(sal_uInt32 const c, bool const isFirst) { - sal_Unicode c = aStr[nPos]; if ( c < nDefCnt ) return pParseTokensType[ sal_uInt8(c) ]; else { //! all KParseTokens::UNI_... must be matched - switch ( u_charType( (sal_uInt32) c ) ) + switch (u_charType(c)) { case U_UPPERCASE_LETTER : return KParseTokens::UNI_UPALPHA; @@ -372,7 +371,7 @@ sal_Int32 cclass_Unicode::getParseTokensType( const sal_Unicode* aStr, sal_Int32 return KParseTokens::UNI_MODIFIER_LETTER; case U_OTHER_LETTER : // Non_Spacing_Mark could not be as leading character - if (nPos == 0) break; + if (isFirst) break; // fall through, treat it as Other_Letter. case U_NON_SPACING_MARK : return KParseTokens::UNI_OTHER_LETTER; @@ -571,14 +570,13 @@ void cclass_Unicode::destroyParserTable() } -UPT_FLAG_TYPE cclass_Unicode::getFlags( const sal_Unicode* aStr, sal_Int32 nPos ) +UPT_FLAG_TYPE cclass_Unicode::getFlags(sal_uInt32 const c) { UPT_FLAG_TYPE nMask; - sal_Unicode c = aStr[nPos]; if ( c < nDefCnt ) nMask = pTable[ sal_uInt8(c) ]; else - nMask = getFlagsExtended( aStr, nPos ); + nMask = getFlagsExtended(c); switch ( eState ) { case ssGetChar : @@ -608,9 +606,8 @@ UPT_FLAG_TYPE cclass_Unicode::getFlags( const sal_Unicode* aStr, sal_Int32 nPos } -UPT_FLAG_TYPE cclass_Unicode::getFlagsExtended( const sal_Unicode* aStr, sal_Int32 nPos ) +UPT_FLAG_TYPE cclass_Unicode::getFlagsExtended(sal_uInt32 const c) { - sal_Unicode c = aStr[nPos]; if ( c == cGroupSep ) return TOKEN_VALUE; else if ( c == cDecimalSep ) @@ -621,7 +618,7 @@ UPT_FLAG_TYPE cclass_Unicode::getFlagsExtended( const sal_Unicode* aStr, sal_Int sal_Int32 nTypes = (bStart ? nStartTypes : nContTypes); //! all KParseTokens::UNI_... must be matched - switch ( u_charType( (sal_uInt32) c ) ) + switch (u_charType(c)) { case U_UPPERCASE_LETTER : return (nTypes & KParseTokens::UNI_UPALPHA) ? @@ -712,25 +709,29 @@ UPT_FLAG_TYPE cclass_Unicode::getContCharsFlags( sal_Unicode c ) void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 nPos, sal_Int32 nTokenType ) { + assert(r.LeadingWhiteSpace == 0); using namespace i18n; - const sal_Unicode* const pTextStart = rText.getStr() + nPos; eState = ssGetChar; //! All the variables below (plus ParseResult) have to be resetted on ssRewindFromValue! - const sal_Unicode* pSym = pTextStart; - const sal_Unicode* pSrc = pSym; OUString aSymbol; - sal_Unicode c = *pSrc; - sal_Unicode cLast = 0; + bool isFirst(true); + sal_Int32 index(nPos); // index of next code point after current + sal_Int32 postSymbolIndex(index); // index of code point following last quote + sal_uInt32 current((index < rText.getLength()) ? rText.iterateCodePoints(&index) : 0); + sal_uInt32 cLast = 0; + sal_Int32 nCodePoints(0); int nDecSeps = 0; bool bQuote = false; bool bMightBeWord = true; bool bMightBeWordLast = true; //! All the variables above (plus ParseResult) have to be resetted on ssRewindFromValue! + sal_Int32 nextCharIndex(0); // == index of nextChar - while ( (c != 0) && (eState != ssStop) ) + while ((current != 0) && (eState != ssStop)) { - UPT_FLAG_TYPE nMask = getFlags( pTextStart, pSrc - pTextStart ); + ++nCodePoints; + UPT_FLAG_TYPE nMask = getFlags(current); if ( nMask & TOKEN_EXCLUDED ) eState = ssBounce; if ( bMightBeWord ) @@ -741,8 +742,11 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 else bMightBeWord = ((nMask & TOKEN_WORD) != 0); } - sal_Int32 nParseTokensType = getParseTokensType( pTextStart, pSrc - pTextStart ); - pSrc++; + sal_Int32 nParseTokensType = getParseTokensType(current, isFirst); + isFirst = false; + sal_Int32 const nextIndex(nextCharIndex); // == index of char following current + nextCharIndex = index; // == index of nextChar + sal_uInt32 nextChar((index < rText.getLength()) ? rText.iterateCodePoints(&index) : 0); switch (eState) { case ssGetChar : @@ -755,14 +759,14 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 eState = ssGetValue; if ( nMask & TOKEN_VALUE_DIGIT ) { - if ( 128 <= c ) + if (128 <= current) r.TokenType = KParseType::UNI_NUMBER; else r.TokenType = KParseType::ASC_NUMBER; } - else if ( c == cDecimalSep ) + else if (current == cDecimalSep) { - if ( *pSrc ) + if (nextChar) ++nDecSeps; else eState = ssRewindFromValue; @@ -778,14 +782,14 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 { eState = ssGetWordFirstChar; bQuote = true; - pSym++; + postSymbolIndex = nextCharIndex; nParseTokensType = 0; // will be taken of first real character r.TokenType = KParseType::SINGLE_QUOTE_NAME; } else if ( nMask & TOKEN_CHAR_STRING ) { eState = ssGetString; - pSym++; + postSymbolIndex = nextCharIndex; nParseTokensType = 0; // will be taken of first real character r.TokenType = KParseType::DOUBLE_QUOTE_STRING; } @@ -795,8 +799,9 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 { if (eState == ssRewindFromValue) eState = ssIgnoreLeadingInRewind; - r.LeadingWhiteSpace++; - pSym++; + r.LeadingWhiteSpace = nextCharIndex - nPos; + nCodePoints--; // exclude leading whitespace + postSymbolIndex = nextCharIndex; nParseTokensType = 0; // wait until real character bMightBeWord = true; } @@ -821,16 +826,16 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 { if ( nMask & TOKEN_VALUE_DIGIT ) { - if ( 128 <= c ) + if (128 <= current) r.TokenType = KParseType::UNI_NUMBER; else if ( r.TokenType != KParseType::UNI_NUMBER ) r.TokenType = KParseType::ASC_NUMBER; } if ( nMask & TOKEN_VALUE ) { - if ( c == cDecimalSep && ++nDecSeps > 1 ) + if (current == cDecimalSep && ++nDecSeps > 1) { - if ( pSrc - pTextStart == 2 ) + if (nCodePoints == 2) eState = ssRewindFromValue; // consecutive separators else @@ -838,12 +843,12 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 } // else keep it going } - else if ( c == 'E' || c == 'e' ) + else if (current == 'E' || current == 'e') { - UPT_FLAG_TYPE nNext = getFlags( pTextStart, pSrc - pTextStart ); + UPT_FLAG_TYPE nNext = getFlags(nextChar); if ( nNext & TOKEN_VALUE_EXP ) ; // keep it going - else if ( bMightBeWord && ((nNext & TOKEN_WORD) || !*pSrc) ) + else if (bMightBeWord && ((nNext & TOKEN_WORD) || !nextChar)) { // might be a numerical name (1.2efg) eState = ssGetWord; r.TokenType = KParseType::IDENTNAME; @@ -855,10 +860,10 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 { if ( (cLast == 'E') || (cLast == 'e') ) { - UPT_FLAG_TYPE nNext = getFlags( pTextStart, pSrc - pTextStart ); + UPT_FLAG_TYPE nNext = getFlags(nextChar); if ( nNext & TOKEN_VALUE_EXP_VALUE ) ; // keep it going - else if ( bMightBeWord && ((nNext & TOKEN_WORD) || !*pSrc) ) + else if (bMightBeWord && ((nNext & TOKEN_WORD) || !nextChar)) { // might be a numerical name (1.2e+fg) eState = ssGetWord; r.TokenType = KParseType::IDENTNAME; @@ -896,15 +901,15 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 { if ( cLast == '\\' ) { // escaped - aSymbol += OUString( pSym, pSrc - pSym - 2 ); - aSymbol += OUString( &c, 1); + aSymbol += rText.copy(postSymbolIndex, nextCharIndex - postSymbolIndex - 2); + aSymbol += OUString(¤t, 1); } else { eState = ssStop; - aSymbol += OUString( pSym, pSrc - pSym - 1 ); + aSymbol += rText.copy(postSymbolIndex, nextCharIndex - postSymbolIndex - 1); } - pSym = pSrc; + postSymbolIndex = nextCharIndex; } else eState = ssStopBack; @@ -921,21 +926,23 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 { if ( cLast == '\\' ) { // escaped - aSymbol += OUString( pSym, pSrc - pSym - 2 ); - aSymbol += OUString( &c, 1); + aSymbol += rText.copy(postSymbolIndex, nextCharIndex - postSymbolIndex - 2); + aSymbol += OUString(¤t, 1); } - else if ( c == *pSrc && + else if (current == nextChar && !(nContTypes & KParseTokens::TWO_DOUBLE_QUOTES_BREAK_STRING) ) { // "" => literal " escaped - aSymbol += OUString( pSym, pSrc - pSym ); - pSrc++; + aSymbol += rText.copy(postSymbolIndex, nextCharIndex - postSymbolIndex); + nextCharIndex = index; + if (index < rText.getLength()) { ++nCodePoints; } + nextChar = (index < rText.getLength()) ? rText.iterateCodePoints(&index) : 0; } else { eState = ssStop; - aSymbol += OUString( pSym, pSrc - pSym - 1 ); + aSymbol += rText.copy(postSymbolIndex, nextCharIndex - postSymbolIndex - 1); } - pSym = pSrc; + postSymbolIndex = nextCharIndex; } } break; @@ -956,10 +963,13 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 if ( eState == ssRewindFromValue ) { r = ParseResult(); - pSym = pTextStart; - pSrc = pSym; + index = nPos; + postSymbolIndex = nPos; + nextCharIndex = 0; aSymbol.clear(); - c = *pSrc; + current = (index < rText.getLength()) ? rText.iterateCodePoints(&index) : 0; + nCodePoints = (nPos < rText.getLength()) ? 1 : 0; + isFirst = true; cLast = 0; nDecSeps = 0; bQuote = false; @@ -973,7 +983,7 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 if ( (r.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER)) && (nTokenType & KParseType::IDENTNAME) && bMightBeWord ) ; // keep a number that might be a word - else if ( r.LeadingWhiteSpace == (pSrc - pTextStart) ) + else if (r.LeadingWhiteSpace == (nextCharIndex - nPos)) ; // keep ignored white space else if ( !r.TokenType && eState == ssGetValue && (nMask & TOKEN_VALUE_SEP) ) ; // keep uncertain value @@ -987,7 +997,9 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 } if ( eState == ssStopBack ) { // put back - pSrc--; + nextChar = rText.iterateCodePoints(&index, -1); + nextCharIndex = nextIndex; + --nCodePoints; bMightBeWord = bMightBeWordLast; eState = ssStop; } @@ -999,19 +1011,18 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 r.ContFlags |= nParseTokensType; } bMightBeWordLast = bMightBeWord; - cLast = c; - c = *pSrc; + cLast = current; + current = nextChar; } } - // r.CharLen is the length in characters (not code points) of the parsed - // token not including any leading white space, change this calculation if - // multi-code-point Unicode characters are to be supported. - r.CharLen = pSrc - pTextStart - r.LeadingWhiteSpace; - r.EndPos = nPos + (pSrc - pTextStart); + // r.CharLen is the length in characters (not code units) of the parsed + // token not including any leading white space. + r.CharLen = nCodePoints; + r.EndPos = nextCharIndex; if ( r.TokenType & KParseType::ASC_NUMBER ) { - r.Value = rtl_math_uStringToDouble( pTextStart + r.LeadingWhiteSpace, - pTextStart + r.EndPos, cDecimalSep, cGroupSep, nullptr, nullptr ); + r.Value = rtl_math_uStringToDouble(rText.getStr() + nPos + r.LeadingWhiteSpace, + rText.getStr() + r.EndPos, cDecimalSep, cGroupSep, nullptr, nullptr); if ( bMightBeWord ) r.TokenType |= KParseType::IDENTNAME; } @@ -1024,8 +1035,8 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 xNatNumSup = NativeNumberSupplier::create( m_xContext ); } } - OUString aTmp( pTextStart + r.LeadingWhiteSpace, r.EndPos - nPos + - r.LeadingWhiteSpace ); + OUString aTmp(rText.getStr() + nPos + r.LeadingWhiteSpace, + r.EndPos - nPos - r.LeadingWhiteSpace); // transliterate to ASCII aTmp = xNatNumSup->getNativeNumberString( aTmp, aParserLocale, NativeNumberMode::NATNUM0 ); @@ -1035,9 +1046,9 @@ void cclass_Unicode::parseText( ParseResult& r, const OUString& rText, sal_Int32 } else if ( r.TokenType & (KParseType::SINGLE_QUOTE_NAME | KParseType::DOUBLE_QUOTE_STRING) ) { - if ( pSym < pSrc ) + if (postSymbolIndex < nextCharIndex) { //! open quote - aSymbol += OUString( pSym, pSrc - pSym ); + aSymbol += rText.copy(postSymbolIndex, nextCharIndex - postSymbolIndex - 1); r.TokenType |= KParseType::MISSING_QUOTE; } r.DequotedNameOrString = aSymbol; diff --git a/starmath/qa/cppunit/test_nodetotextvisitors.cxx b/starmath/qa/cppunit/test_nodetotextvisitors.cxx index a539761..91d7203 100644 --- a/starmath/qa/cppunit/test_nodetotextvisitors.cxx +++ b/starmath/qa/cppunit/test_nodetotextvisitors.cxx @@ -26,7 +26,6 @@ typedef tools::SvRef<SmDocShell> SmDocShellRef; using namespace ::com::sun::star; -namespace { class Test : public test::BootstrapFixture { @@ -53,6 +52,7 @@ public: void testBinHorInSubSup(); void testUnaryInMixedNumberAsNumerator(); void testMiscEquivalent(); + void testParser(); CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(SimpleUnaryOp); @@ -72,6 +72,7 @@ public: CPPUNIT_TEST(testBinHorInSubSup); CPPUNIT_TEST(testUnaryInMixedNumberAsNumerator); CPPUNIT_TEST(testMiscEquivalent); + CPPUNIT_TEST(testParser); CPPUNIT_TEST_SUITE_END(); private: @@ -486,13 +487,13 @@ void Test::ParseAndCompare(const char *formula1, const char *formula2, const cha SmNode *pNode1, *pNode2; // parse formula1 - OUString sInput1 = OUString::createFromAscii(formula1); + OUString sInput1 = OUString(formula1, strlen(formula1), RTL_TEXTENCODING_UTF8); pNode1 = SmParser().ParseExpression(sInput1); pNode1->Prepare(xDocShRef->GetFormat(), *xDocShRef); SmNodeToTextVisitor(pNode1, sOutput1); // parse formula2 - OUString sInput2 = OUString::createFromAscii(formula2); + OUString sInput2 = OUString(formula2, strlen(formula2), RTL_TEXTENCODING_UTF8); pNode2 = SmParser().ParseExpression(sInput2); pNode2->Prepare(xDocShRef->GetFormat(), *xDocShRef); SmNodeToTextVisitor(pNode2, sOutput2); @@ -652,10 +653,27 @@ void Test::testMiscEquivalent() // fdo#66081 ParseAndCompare("{x}", "x", "Variable in brace"); ParseAndCompare("{{x+{{y}}}}", "x+y", "Nested braces"); + + // check non-BMP Unicode char + ParseAndCompare("{\xf0\x9d\x91\x8e}", "\xf0\x9d\x91\x8e", "non-BMP variable in brace"); + ParseAndCompare("{ \xf0\x9d\x91\x8e }", "\xf0\x9d\x91\x8e", "non-BMP variable in brace"); } -CPPUNIT_TEST_SUITE_REGISTRATION(Test); +void Test::testParser() +{ + char const* formula = "{ \xf0\x9d\x91\x8e }"; // non-BMP Unicode + char const* expected = "\xf0\x9d\x91\x8e"; + OUString sOutput; + OUString sInput = OUString(formula, strlen(formula), RTL_TEXTENCODING_UTF8); + OUString sExpected = OUString(expected, strlen(expected), RTL_TEXTENCODING_UTF8); + std::unique_ptr<SmNode> pNode(SmParser().ParseExpression(sInput)); + pNode->Prepare(xDocShRef->GetFormat(), *xDocShRef); + SmNodeToTextVisitor(pNode.get(), sOutput); + CPPUNIT_ASSERT_EQUAL(sExpected, sOutput); } +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 332a796366b7cb91dff41de4b9ffb17843112a3e Author: Michael Stahl <[email protected]> Date: Thu Jan 21 17:39:26 2016 +0100 oox: import Math objects from PPTX files This is quite hacky and limited: in OOXML these are not OLE objects but occur inside text boxes, and PPT 2010 allows inserting multiple Math objects into one text box but Impress does not have as-character anchored objects, so we can't import that properly; for now only import Math if there is nothing else in the text box. Also for now only import them as children of TextParagraphContext (a:p); it's not clear what the possible parent elements could be since the OOXML standard only lists WordProcessingML parent elements :( Change-Id: I847f810084c9ddae4b60f93896fb73a742683cc2 diff --git a/include/oox/mathml/import.hxx b/include/oox/mathml/import.hxx index 2617ff5..b2ed99b 100644 --- a/include/oox/mathml/import.hxx +++ b/include/oox/mathml/import.hxx @@ -9,10 +9,11 @@ #ifndef INCLUDED_OOX_MATHML_IMPORT_HXX #define INCLUDED_OOX_MATHML_IMPORT_HXX -#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <oox/dllapi.h> + #include <tools/gen.hxx> -#include <oox/dllapi.h> +#include <rtl/ref.hxx> namespace oox { @@ -39,6 +40,12 @@ protected: ~FormulaImportBase() {} }; +namespace core { class ContextHandler; } +namespace drawingml { class TextParagraph; } + +::rtl::Reference<core::ContextHandler> CreateLazyMathBufferingContext( + core::ContextHandler const& rParent, drawingml::TextParagraph & rPara); + } // namespace #endif diff --git a/oox/inc/drawingml/textparagraph.hxx b/oox/inc/drawingml/textparagraph.hxx index f96989c..43bf51a 100644 --- a/oox/inc/drawingml/textparagraph.hxx +++ b/oox/inc/drawingml/textparagraph.hxx @@ -28,6 +28,11 @@ #include <drawingml/textliststyle.hxx> #include <drawingml/textparagraphproperties.hxx> + +namespace oox { namespace formulaimport { + class XmlStreamBuilder; +} } + namespace oox { namespace drawingml { typedef RefVector< TextRun > TextRunVector; @@ -57,10 +62,18 @@ public: bool bFirst = false, float nDefaultCharHeight = 0) const; + bool HasMathXml() const + { + return m_pMathXml != nullptr; + } + formulaimport::XmlStreamBuilder & GetMathXml(); + private: TextParagraphProperties maProperties; TextCharacterProperties maEndProperties; TextRunVector maRuns; + // temporarily store this here + std::unique_ptr<formulaimport::XmlStreamBuilder> m_pMathXml; }; } } diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index ea1721d..062a600 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -129,11 +129,15 @@ struct NamespaceIds: public rtl::StaticWithInit< NMSP_mce}, {"http://schemas.openxmlformats.org/spreadsheetml/2006/main/v2", NMSP_mceTest}, + {"http://schemas.openxmlformats.org/officeDocument/2006/math", + NMSP_officeMath}, {"http://schemas.microsoft.com/office/drawing/2008/diagram", NMSP_dsp}, {"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main", NMSP_xls14Lst}, {"http://schemas.libreoffice.org/", NMSP_loext}, + {"http://schemas.microsoft.com/office/drawing/2010/main", + NMSP_a14}, {"http://schemas.microsoft.com/office/powerpoint/2010/main", NMSP_p14}, {"http://schemas.microsoft.com/office/powerpoint/2012/main", diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index b744bb1..9d12b50 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -27,6 +27,7 @@ #include "effectproperties.hxx" #include "oox/drawingml/shapepropertymap.hxx" #include "drawingml/textbody.hxx" +#include <drawingml/textparagraph.hxx> #include <drawingml/ThemeOverrideFragmentHandler.hxx> #include "drawingml/table/tableproperties.hxx" #include "oox/drawingml/chart/chartconverter.hxx" @@ -40,8 +41,12 @@ #include "oox/helper/graphichelper.hxx" #include "oox/helper/propertyset.hxx" #include "oox/helper/modelobjecthelper.hxx" +#include <oox/mathml/importutils.hxx> +#include <oox/mathml/import.hxx> +#include <comphelper/classids.hxx> #include <tools/gen.hxx> +#include <tools/globname.hxx> #include <tools/mapunit.hxx> #include <editeng/unoprnms.hxx> #include <com/sun/star/awt/Size.hpp> @@ -55,6 +60,7 @@ #include <com/sun/star/drawing/HomogenMatrix3.hpp> #include <com/sun/star/drawing/TextVerticalAdjust.hpp> #include <com/sun/star/drawing/GraphicExportFilter.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> #include <com/sun/star/text/XText.hpp> #include <com/sun/star/table/BorderLine2.hpp> #include <com/sun/star/table/ShadowFormat.hpp> @@ -407,6 +413,25 @@ Reference< XShape > Shape::createAndInsert( bool bIsEmbMedia = false; SAL_INFO("oox.drawingml", OSL_THIS_FUNC << " id: " << msId); + formulaimport::XmlStreamBuilder * pMathXml(nullptr); + if (mpTextBody.get()) + { + for (auto const& it : mpTextBody->getParagraphs()) + { + if (it->HasMathXml()) + { + if (!mpTextBody->isEmpty() || pMathXml != nullptr) + { + SAL_WARN("oox.drawingml", "losing a Math object..."); + } + else + { + pMathXml = &it->GetMathXml(); + } + } + } + } + // tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height if ( mpTablePropertiesPtr.get() && rServiceName == "com.sun.star.drawing.TableShape" ) { @@ -427,7 +452,15 @@ Reference< XShape > Shape::createAndInsert( awt::Rectangle aShapeRectHmm( maPosition.X / EMU_PER_HMM, maPosition.Y / EMU_PER_HMM, maSize.Width / EMU_PER_HMM, maSize.Height / EMU_PER_HMM ); OUString aServiceName; - if( rServiceName == "com.sun.star.drawing.GraphicObjectShape" && + if (pMathXml) + { + // convert this shape to OLE + aServiceName = "com.sun.star.drawing.OLE2Shape"; + msServiceName = aServiceName; + meFrameType = FRAMETYPE_GENERIC; // not OLEOBJECT, no stream in package + mnSubType = 0; + } + else if (rServiceName == "com.sun.star.drawing.GraphicObjectShape" && mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty()) { aServiceName = finalizeServiceName( rFilterBase, "com.sun.star.presentation.MediaShape", aShapeRectHmm ); @@ -605,6 +638,22 @@ Reference< XShape > Shape::createAndInsert( } } + if (pMathXml) + { + // the "EmbeddedObject" property is read-only, so we have to create + // the shape first, and it can be read only after the shape is + // inserted into the document, so delay the actual import until here + SvGlobalName name(SO3_SM_CLASSID); + xSet->setPropertyValue("CLSID", uno::makeAny(name.GetHexName())); + uno::Reference<embed::XEmbeddedObject> const xObj( + xSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY); + uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent()); + oox::FormulaImportBase *const pMagic( + dynamic_cast<oox::FormulaImportBase*>(xMathModel.get())); + assert(pMagic); + pMagic->readFormulaOoxml(*pMathXml); + } + const GraphicHelper& rGraphicHelper = rFilterBase.getGraphicHelper(); LineProperties aLineProperties; diff --git a/oox/source/drawingml/textbodycontext.cxx b/oox/source/drawingml/textbodycontext.cxx index 20d3b26..84fc769 100644 --- a/oox/source/drawingml/textbodycontext.cxx +++ b/oox/source/drawingml/textbodycontext.cxx @@ -26,6 +26,8 @@ #include "drawingml/textfield.hxx" #include "drawingml/textfieldcontext.hxx" +#include <oox/mathml/import.hxx> + using namespace ::oox::core; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::text; @@ -90,6 +92,9 @@ ContextHandlerRef TextParagraphContext::onCreateContext( sal_Int32 aElementToken case W_TOKEN( ins ): return this; break; + case OOX_TOKEN(a14, m): + return CreateLazyMathBufferingContext(*this, mrParagraph); + break; default: SAL_WARN("oox", "TextParagraphContext::onCreateContext: unhandled element: " << getBaseToken(aElementToken)); } diff --git a/oox/source/drawingml/textparagraph.cxx b/oox/source/drawingml/textparagraph.cxx index 76d299a..5d49659 100644 --- a/oox/source/drawingml/textparagraph.cxx +++ b/oox/source/drawingml/textparagraph.cxx @@ -22,6 +22,7 @@ #include "drawingml/textcharacterproperties.hxx" #include <rtl/ustring.hxx> +#include <oox/mathml/importutils.hxx> #include "oox/helper/propertyset.hxx" #include <com/sun/star/text/XText.hpp> #include <com/sun/star/text/XTextCursor.hpp> @@ -138,6 +139,15 @@ void TextParagraph::insertAt( } } +formulaimport::XmlStreamBuilder & TextParagraph::GetMathXml() +{ + if (!m_pMathXml) + { + m_pMathXml.reset(new formulaimport::XmlStreamBuilder); + } + return *m_pMathXml; +} + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/mathml/import.cxx b/oox/source/mathml/import.cxx index bf49de2..5b80dc4 100644 --- a/oox/source/mathml/import.cxx +++ b/oox/source/mathml/import.cxx @@ -9,6 +9,14 @@ #include "oox/mathml/import.hxx" +#include <oox/mathml/importutils.hxx> +#include <oox/core/contexthandler.hxx> + +#include <drawingml/textparagraph.hxx> + + +using namespace ::com::sun::star; + namespace oox { @@ -16,6 +24,88 @@ FormulaImportBase::FormulaImportBase() { } -} // namespace +namespace formulaimport { + +class LazyMathBufferingContext : public core::ContextHandler +{ +private: + XmlStreamBuilder & m_rBuilder; + long m_Counter; + +public: + LazyMathBufferingContext(core::ContextHandler const& rParent, + drawingml::TextParagraph & rPara); + + // com.sun.star.xml.sax.XFastContextHandler interface --------------------- + + virtual void SAL_CALL startFastElement(::sal_Int32 Element, const uno::Reference<xml::sax::XFastAttributeList>& xAttribs) throw (xml::sax::SAXException, uno::RuntimeException, std::exception) override; + virtual void SAL_CALL endFastElement(::sal_Int32 Element) throw (xml::sax::SAXException, uno::RuntimeException, std::exception) override; + virtual uno::Reference< xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(::sal_Int32 Element, const uno::Reference<xml::sax::XFastAttributeList >& xAttribs) throw (xml::sax::SAXException, uno::RuntimeException, std::exception) override; + virtual void SAL_CALL characters(const OUString& rChars) throw (xml::sax::SAXException, uno::RuntimeException, std::exception) override; + +}; + +LazyMathBufferingContext::LazyMathBufferingContext( + core::ContextHandler const& rParent, drawingml::TextParagraph & rPara) + : core::ContextHandler(rParent) + , m_rBuilder(rPara.GetMathXml()) + , m_Counter(0) +{ +} + +void SAL_CALL LazyMathBufferingContext::startFastElement( + sal_Int32 const nElement, + uno::Reference<xml::sax::XFastAttributeList> const& xAttrs) + throw (xml::sax::SAXException, uno::RuntimeException, std::exception) +{ + if (0 < m_Counter) // ignore a14:m + { // ignore outer oMathPara + if (1 != m_Counter || OOX_TOKEN(officeMath, oMathPara) != nElement) + { + m_rBuilder.appendOpeningTag(nElement, xAttrs); + } + } + ++m_Counter; +} + +void SAL_CALL LazyMathBufferingContext::endFastElement(sal_Int32 const nElement) + throw (xml::sax::SAXException, uno::RuntimeException, std::exception) +{ + --m_Counter; + if (0 < m_Counter) // ignore a14:m + { // ignore outer oMathPara + if (1 != m_Counter || OOX_TOKEN(officeMath, oMathPara) != nElement) + { + m_rBuilder.appendClosingTag(nElement); + } + } +} + +uno::Reference<xml::sax::XFastContextHandler> SAL_CALL +LazyMathBufferingContext::createFastChildContext(sal_Int32 const, + uno::Reference<xml::sax::XFastAttributeList> const&) + throw (xml::sax::SAXException, uno::RuntimeException, std::exception) +{ + return this; +} + +void SAL_CALL LazyMathBufferingContext::characters(OUString const& rChars) + throw (xml::sax::SAXException, uno::RuntimeException, std::exception) +{ + if (0 < m_Counter) // ignore a14:m + { + m_rBuilder.appendCharacters(rChars); + } +} + +} // namespace formulaimport + +core::ContextHandlerRef CreateLazyMathBufferingContext( + core::ContextHandler const& rParent, drawingml::TextParagraph & rPara) +{ + return new formulaimport::LazyMathBufferingContext(rParent, rPara); +} + +} // namespace oox /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index 818ea21..2f9550a 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -1173,7 +1173,30 @@ void SdExportTest::testMathObject() "/p:sld/p:cSld/p:spTree/mc:AlternateContent/mc:Choice/p:sp/p:txBody/a:p/a14:m/m:oMath/m:r[1]/m:t", "a"); - // TODO can't import yet + const SdrPage *pPage = GetPage(1, xDocShRef); + const SdrObject* pObj = dynamic_cast<SdrObject*>(pPage->GetObj(0)); + CPPUNIT_ASSERT_MESSAGE("no object", pObj != nullptr); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(OBJ_OLE2), pObj->GetObjIdentifier()); + } + + utl::TempFile tempFile2; + xDocShRef = saveAndReload( xDocShRef, PPTX, &tempFile2 ); + + // Export an MS specific ole object (imported from a PPTX document) + { + xmlDocPtr pXmlDocContent = parseExport(tempFile1, "ppt/slides/slide1.xml"); + assertXPath(pXmlDocContent, + "/p:sld/p:cSld/p:spTree/mc:AlternateContent/mc:Choice", + "Requires", + "a14"); + assertXPathContent(pXmlDocContent, + "/p:sld/p:cSld/p:spTree/mc:AlternateContent/mc:Choice/p:sp/p:txBody/a:p/a14:m/m:oMath/m:r[1]/m:t", + "a"); + + const SdrPage *pPage = GetPage(1, xDocShRef); + const SdrObject* pObj = dynamic_cast<SdrObject*>(pPage->GetObj(0)); + CPPUNIT_ASSERT_MESSAGE("no object", pObj != nullptr); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(OBJ_OLE2), pObj->GetObjIdentifier()); } xDocShRef->DoClose(); diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 4cdd7c0..eeb11a0 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -32,6 +32,7 @@ #include <com/sun/star/document/PrinterIndependentLayout.hpp> #include <com/sun/star/document/IndexedPropertyValues.hpp> #include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> #include <com/sun/star/style/LineNumberPosition.hpp> _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
