/src/libreoffice/starmath/source/ooxmlexport.cxx
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #include "ooxmlexport.hxx" |
11 | | |
12 | | #include <oox/token/tokens.hxx> |
13 | | #include <rtl/ustring.hxx> |
14 | | #include <sal/log.hxx> |
15 | | #include <oox/mathml/imexport.hxx> |
16 | | |
17 | | using namespace oox; |
18 | | using namespace oox::core; |
19 | | |
20 | | SmOoxmlExport::SmOoxmlExport(const SmNode *const pIn, OoxmlVersion const v, |
21 | | drawingml::DocumentType const documentType) |
22 | 0 | : SmWordExportBase( pIn ) |
23 | 0 | , version( v ) |
24 | 0 | , m_DocumentType(documentType) |
25 | 0 | { |
26 | 0 | } |
27 | | |
28 | | void SmOoxmlExport::ConvertFromStarMath( const ::sax_fastparser::FSHelperPtr& serializer, const sal_Int8 nAlign ) |
29 | 0 | { |
30 | 0 | if( GetTree() == nullptr ) |
31 | 0 | return; |
32 | 0 | m_pSerializer = serializer; |
33 | | |
34 | | //Formula alignment situations: |
35 | | // |
36 | | // 1)Inline(as before): |
37 | | // |
38 | | // <m:oMath> |
39 | | // <m:r> ... </m:r> |
40 | | // </m:oMath> |
41 | | // |
42 | | // 2)Aligned: |
43 | | // |
44 | | // <m:oMathPara> |
45 | | // <m:oMathParaPr> |
46 | | // <m:jc m:val="left|right|center"> |
47 | | // </m:oMathParaPr> |
48 | | // <m:oMath> |
49 | | // <m:r> ... </m:r> |
50 | | // </m:oMath> |
51 | | // </m:oMathPara> |
52 | |
|
53 | 0 | if (nAlign != FormulaImExportBase::eFormulaAlign::INLINE) |
54 | 0 | { |
55 | 0 | m_pSerializer->startElementNS(XML_m, XML_oMathPara, |
56 | 0 | FSNS(XML_xmlns, XML_m), "http://schemas.openxmlformats.org/officeDocument/2006/math"); |
57 | 0 | m_pSerializer->startElementNS(XML_m, XML_oMathParaPr); |
58 | 0 | if (nAlign == FormulaImExportBase::eFormulaAlign::CENTER) |
59 | 0 | m_pSerializer->singleElementNS(XML_m, XML_jc, FSNS(XML_m, XML_val), "center"); |
60 | 0 | if (nAlign == FormulaImExportBase::eFormulaAlign::LEFT) |
61 | 0 | m_pSerializer->singleElementNS(XML_m, XML_jc, FSNS(XML_m, XML_val), "left"); |
62 | 0 | if (nAlign == FormulaImExportBase::eFormulaAlign::RIGHT) |
63 | 0 | m_pSerializer->singleElementNS(XML_m, XML_jc, FSNS(XML_m, XML_val), "right"); |
64 | 0 | m_pSerializer->endElementNS(XML_m, XML_oMathParaPr); |
65 | 0 | m_pSerializer->startElementNS(XML_m, XML_oMath); |
66 | 0 | HandleNode(GetTree(), 0); |
67 | 0 | m_pSerializer->endElementNS(XML_m, XML_oMath); |
68 | 0 | m_pSerializer->endElementNS(XML_m, XML_oMathPara); |
69 | 0 | } |
70 | 0 | else //else, inline as was before |
71 | 0 | { |
72 | 0 | m_pSerializer->startElementNS(XML_m, XML_oMath, |
73 | 0 | FSNS(XML_xmlns, XML_m), "http://schemas.openxmlformats.org/officeDocument/2006/math"); |
74 | 0 | HandleNode( GetTree(), 0 ); |
75 | 0 | m_pSerializer->endElementNS( XML_m, XML_oMath ); |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | | // NOTE: This is still work in progress and unfinished, but it already covers a good |
80 | | // part of the ooxml math stuff. |
81 | | |
82 | | void SmOoxmlExport::HandleVerticalStack( const SmNode* pNode, int nLevel ) |
83 | 0 | { |
84 | 0 | m_pSerializer->startElementNS(XML_m, XML_eqArr); |
85 | 0 | int size = pNode->GetNumSubNodes(); |
86 | 0 | for( int i = 0; |
87 | 0 | i < size; |
88 | 0 | ++i ) |
89 | 0 | { |
90 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
91 | 0 | HandleNode( pNode->GetSubNode( i ), nLevel + 1 ); |
92 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
93 | 0 | } |
94 | 0 | m_pSerializer->endElementNS( XML_m, XML_eqArr ); |
95 | 0 | } |
96 | | |
97 | | void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/) |
98 | 0 | { |
99 | 0 | m_pSerializer->startElementNS(XML_m, XML_r); |
100 | |
|
101 | 0 | if( pNode->GetToken().eType == TTEXT ) // literal text (in quotes) |
102 | 0 | { |
103 | 0 | m_pSerializer->startElementNS(XML_m, XML_rPr); |
104 | 0 | m_pSerializer->singleElementNS(XML_m, XML_lit); |
105 | 0 | m_pSerializer->singleElementNS(XML_m, XML_nor); |
106 | 0 | m_pSerializer->endElementNS( XML_m, XML_rPr ); |
107 | 0 | } |
108 | 0 | if (drawingml::DOCUMENT_DOCX == m_DocumentType && ECMA_376_1ST_EDITION == version) |
109 | 0 | { // HACK: MSOffice2007 does not import characters properly unless this font is explicitly given |
110 | 0 | m_pSerializer->startElementNS(XML_w, XML_rPr); |
111 | 0 | m_pSerializer->singleElementNS( XML_w, XML_rFonts, FSNS( XML_w, XML_ascii ), "Cambria Math", |
112 | 0 | FSNS( XML_w, XML_hAnsi ), "Cambria Math" ); |
113 | 0 | m_pSerializer->endElementNS( XML_w, XML_rPr ); |
114 | 0 | } |
115 | 0 | m_pSerializer->startElementNS(XML_m, XML_t, FSNS(XML_xml, XML_space), "preserve"); |
116 | 0 | const SmTextNode* pTemp = static_cast<const SmTextNode* >(pNode); |
117 | 0 | SAL_INFO( "starmath.ooxml", "Text:" << pTemp->GetText()); |
118 | 0 | OUStringBuffer buf(pTemp->GetText()); |
119 | 0 | for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++) |
120 | 0 | { |
121 | | #if 0 |
122 | | if ((nPendingAttributes) && |
123 | | (i == ((pTemp->GetText().getLength()+1)/2)-1)) |
124 | | { |
125 | | *pS << sal_uInt8(0x22); //char, with attributes right |
126 | | //after the character |
127 | | } |
128 | | else |
129 | | *pS << sal_uInt8(CHAR); |
130 | | |
131 | | sal_uInt8 nFace = 0x1; |
132 | | if (pNode->GetFont().GetItalic() == ITALIC_NORMAL) |
133 | | nFace = 0x3; |
134 | | else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD) |
135 | | nFace = 0x7; |
136 | | *pS << sal_uInt8(nFace+128); //typeface |
137 | | #endif |
138 | 0 | buf[i] = SmTextNode::ConvertSymbolToUnicode(buf[i]); |
139 | | #if 0 |
140 | | //Mathtype can only have these sort of character |
141 | | //attributes on a single character, starmath can put them |
142 | | //anywhere, when the entity involved is a text run this is |
143 | | //a large effort to place the character attribute on the |
144 | | //central mathtype character so that it does pretty much |
145 | | //what the user probably has in mind. The attributes |
146 | | //filled in here are dummy ones which are replaced in the |
147 | | //ATTRIBUTE handler if a suitable location for the |
148 | | //attributes was found here. Unfortunately it is |
149 | | //possible for starmath to place character attributes on |
150 | | //entities which cannot occur in mathtype e.g. a Summation |
151 | | //symbol so these attributes may be lost |
152 | | if ((nPendingAttributes) && |
153 | | (i == ((pTemp->GetText().getLength()+1)/2)-1)) |
154 | | { |
155 | | *pS << sal_uInt8(EMBEL); |
156 | | while (nPendingAttributes) |
157 | | { |
158 | | *pS << sal_uInt8(2); |
159 | | //wedge the attributes in here and clear |
160 | | //the pending stack |
161 | | nPendingAttributes--; |
162 | | } |
163 | | nInsertion=pS->Tell(); |
164 | | *pS << sal_uInt8(END); //end embel |
165 | | *pS << sal_uInt8(END); //end embel |
166 | | } |
167 | | #endif |
168 | 0 | } |
169 | 0 | m_pSerializer->writeEscaped(buf); |
170 | 0 | m_pSerializer->endElementNS( XML_m, XML_t ); |
171 | 0 | m_pSerializer->endElementNS( XML_m, XML_r ); |
172 | 0 | } |
173 | | |
174 | | void SmOoxmlExport::HandleFractions( const SmNode* pNode, int nLevel, const char* type ) |
175 | 0 | { |
176 | 0 | m_pSerializer->startElementNS(XML_m, XML_f); |
177 | 0 | if( type != nullptr ) |
178 | 0 | { |
179 | 0 | m_pSerializer->startElementNS(XML_m, XML_fPr); |
180 | 0 | m_pSerializer->singleElementNS(XML_m, XML_type, FSNS(XML_m, XML_val), type); |
181 | 0 | m_pSerializer->endElementNS( XML_m, XML_fPr ); |
182 | 0 | } |
183 | 0 | assert( pNode->GetNumSubNodes() == 3 ); |
184 | 0 | m_pSerializer->startElementNS(XML_m, XML_num); |
185 | 0 | HandleNode( pNode->GetSubNode( 0 ), nLevel + 1 ); |
186 | 0 | m_pSerializer->endElementNS( XML_m, XML_num ); |
187 | 0 | m_pSerializer->startElementNS(XML_m, XML_den); |
188 | 0 | HandleNode( pNode->GetSubNode( 2 ), nLevel + 1 ); |
189 | 0 | m_pSerializer->endElementNS( XML_m, XML_den ); |
190 | 0 | m_pSerializer->endElementNS( XML_m, XML_f ); |
191 | 0 | } |
192 | | |
193 | | void SmOoxmlExport::HandleAttribute( const SmAttributeNode* pNode, int nLevel ) |
194 | 0 | { |
195 | 0 | switch( pNode->Attribute()->GetToken().eType ) |
196 | 0 | { |
197 | 0 | case TCHECK: |
198 | 0 | case TACUTE: |
199 | 0 | case TGRAVE: |
200 | 0 | case TBREVE: |
201 | 0 | case TCIRCLE: |
202 | 0 | case TVEC: |
203 | 0 | case TTILDE: |
204 | 0 | case THAT: |
205 | 0 | case TDOT: |
206 | 0 | case TDDOT: |
207 | 0 | case TDDDOT: |
208 | 0 | case TWIDETILDE: |
209 | 0 | case TWIDEHAT: |
210 | 0 | case TWIDEHARPOON: |
211 | 0 | case TWIDEVEC: |
212 | 0 | case TBAR: |
213 | 0 | { |
214 | 0 | m_pSerializer->startElementNS(XML_m, XML_acc); |
215 | 0 | m_pSerializer->startElementNS(XML_m, XML_accPr); |
216 | 0 | OString value = OUStringToOString(pNode->Attribute()->GetToken().cMathChar, RTL_TEXTENCODING_UTF8 ); |
217 | 0 | m_pSerializer->singleElementNS(XML_m, XML_chr, FSNS(XML_m, XML_val), value); |
218 | 0 | m_pSerializer->endElementNS( XML_m, XML_accPr ); |
219 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
220 | 0 | HandleNode( pNode->Body(), nLevel + 1 ); |
221 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
222 | 0 | m_pSerializer->endElementNS( XML_m, XML_acc ); |
223 | 0 | break; |
224 | 0 | } |
225 | 0 | case TOVERLINE: |
226 | 0 | case TUNDERLINE: |
227 | 0 | m_pSerializer->startElementNS(XML_m, XML_bar); |
228 | 0 | m_pSerializer->startElementNS(XML_m, XML_barPr); |
229 | 0 | m_pSerializer->singleElementNS( XML_m, XML_pos, FSNS( XML_m, XML_val ), |
230 | 0 | ( pNode->Attribute()->GetToken().eType == TUNDERLINE ) ? "bot" : "top" ); |
231 | 0 | m_pSerializer->endElementNS( XML_m, XML_barPr ); |
232 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
233 | 0 | HandleNode( pNode->Body(), nLevel + 1 ); |
234 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
235 | 0 | m_pSerializer->endElementNS( XML_m, XML_bar ); |
236 | 0 | break; |
237 | 0 | case TOVERSTRIKE: |
238 | 0 | m_pSerializer->startElementNS(XML_m, XML_borderBox); |
239 | 0 | m_pSerializer->startElementNS(XML_m, XML_borderBoxPr); |
240 | 0 | m_pSerializer->singleElementNS(XML_m, XML_hideTop, FSNS(XML_m, XML_val), "1"); |
241 | 0 | m_pSerializer->singleElementNS(XML_m, XML_hideBot, FSNS(XML_m, XML_val), "1"); |
242 | 0 | m_pSerializer->singleElementNS(XML_m, XML_hideLeft, FSNS(XML_m, XML_val), "1"); |
243 | 0 | m_pSerializer->singleElementNS(XML_m, XML_hideRight, FSNS(XML_m, XML_val), "1"); |
244 | 0 | m_pSerializer->singleElementNS(XML_m, XML_strikeH, FSNS(XML_m, XML_val), "1"); |
245 | 0 | m_pSerializer->endElementNS( XML_m, XML_borderBoxPr ); |
246 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
247 | 0 | HandleNode( pNode->Body(), nLevel + 1 ); |
248 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
249 | 0 | m_pSerializer->endElementNS( XML_m, XML_borderBox ); |
250 | 0 | break; |
251 | 0 | default: |
252 | 0 | HandleAllSubNodes( pNode, nLevel ); |
253 | 0 | break; |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | | void SmOoxmlExport::HandleRoot( const SmRootNode* pNode, int nLevel ) |
258 | 0 | { |
259 | 0 | m_pSerializer->startElementNS(XML_m, XML_rad); |
260 | 0 | if( const SmNode* argument = pNode->Argument()) |
261 | 0 | { |
262 | 0 | m_pSerializer->startElementNS(XML_m, XML_deg); |
263 | 0 | HandleNode( argument, nLevel + 1 ); |
264 | 0 | m_pSerializer->endElementNS( XML_m, XML_deg ); |
265 | 0 | } |
266 | 0 | else |
267 | 0 | { |
268 | 0 | m_pSerializer->startElementNS(XML_m, XML_radPr); |
269 | 0 | m_pSerializer->singleElementNS(XML_m, XML_degHide, FSNS(XML_m, XML_val), "1"); |
270 | 0 | m_pSerializer->endElementNS( XML_m, XML_radPr ); |
271 | 0 | m_pSerializer->singleElementNS(XML_m, XML_deg); // empty but present |
272 | 0 | } |
273 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
274 | 0 | HandleNode( pNode->Body(), nLevel + 1 ); |
275 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
276 | 0 | m_pSerializer->endElementNS( XML_m, XML_rad ); |
277 | 0 | } |
278 | | |
279 | | static OString mathSymbolToString( const SmNode* node ) |
280 | 0 | { |
281 | 0 | assert( node->GetType() == SmNodeType::Math || node->GetType() == SmNodeType::MathIdent ); |
282 | 0 | const SmTextNode* txtnode = static_cast< const SmTextNode* >( node ); |
283 | 0 | assert( txtnode->GetText().getLength() == 1 ); |
284 | 0 | sal_Unicode chr = SmTextNode::ConvertSymbolToUnicode( txtnode->GetText()[0] ); |
285 | 0 | return OUStringToOString( OUStringChar( chr ), RTL_TEXTENCODING_UTF8 ); |
286 | 0 | } |
287 | | |
288 | | void SmOoxmlExport::HandleOperator( const SmOperNode* pNode, int nLevel ) |
289 | 0 | { |
290 | 0 | SAL_INFO( "starmath.ooxml", "Operator: " << int( pNode->GetToken().eType )); |
291 | 0 | switch( pNode->GetToken().eType ) |
292 | 0 | { |
293 | 0 | case TINT: |
294 | 0 | case TINTD: |
295 | 0 | case TIINT: |
296 | 0 | case TIIINT: |
297 | 0 | case TLINT: |
298 | 0 | case TLLINT: |
299 | 0 | case TLLLINT: |
300 | 0 | case TPROD: |
301 | 0 | case TCOPROD: |
302 | 0 | case TSUM: |
303 | 0 | { |
304 | 0 | const SmSubSupNode* subsup = pNode->GetSubNode( 0 )->GetType() == SmNodeType::SubSup |
305 | 0 | ? static_cast< const SmSubSupNode* >( pNode->GetSubNode( 0 )) : nullptr; |
306 | 0 | const SmNode* operation = subsup != nullptr ? subsup->GetBody() : pNode->GetSubNode( 0 ); |
307 | 0 | m_pSerializer->startElementNS(XML_m, XML_nary); |
308 | 0 | m_pSerializer->startElementNS(XML_m, XML_naryPr); |
309 | 0 | m_pSerializer->singleElementNS( XML_m, XML_chr, |
310 | 0 | FSNS( XML_m, XML_val ), mathSymbolToString(operation) ); |
311 | 0 | if( subsup == nullptr || subsup->GetSubSup( CSUB ) == nullptr ) |
312 | 0 | m_pSerializer->singleElementNS(XML_m, XML_subHide, FSNS(XML_m, XML_val), "1"); |
313 | 0 | if( subsup == nullptr || subsup->GetSubSup( CSUP ) == nullptr ) |
314 | 0 | m_pSerializer->singleElementNS(XML_m, XML_supHide, FSNS(XML_m, XML_val), "1"); |
315 | 0 | m_pSerializer->endElementNS( XML_m, XML_naryPr ); |
316 | 0 | if( subsup == nullptr || subsup->GetSubSup( CSUB ) == nullptr ) |
317 | 0 | m_pSerializer->singleElementNS(XML_m, XML_sub); |
318 | 0 | else |
319 | 0 | { |
320 | 0 | m_pSerializer->startElementNS(XML_m, XML_sub); |
321 | 0 | HandleNode( subsup->GetSubSup( CSUB ), nLevel + 1 ); |
322 | 0 | m_pSerializer->endElementNS( XML_m, XML_sub ); |
323 | 0 | } |
324 | 0 | if( subsup == nullptr || subsup->GetSubSup( CSUP ) == nullptr ) |
325 | 0 | m_pSerializer->singleElementNS(XML_m, XML_sup); |
326 | 0 | else |
327 | 0 | { |
328 | 0 | m_pSerializer->startElementNS(XML_m, XML_sup); |
329 | 0 | HandleNode( subsup->GetSubSup( CSUP ), nLevel + 1 ); |
330 | 0 | m_pSerializer->endElementNS( XML_m, XML_sup ); |
331 | 0 | } |
332 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
333 | 0 | HandleNode( pNode->GetSubNode( 1 ), nLevel + 1 ); // body |
334 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
335 | 0 | m_pSerializer->endElementNS( XML_m, XML_nary ); |
336 | 0 | break; |
337 | 0 | } |
338 | 0 | case TLIM: |
339 | 0 | m_pSerializer->startElementNS(XML_m, XML_func); |
340 | 0 | m_pSerializer->startElementNS(XML_m, XML_fName); |
341 | 0 | m_pSerializer->startElementNS(XML_m, XML_limLow); |
342 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
343 | 0 | HandleNode( pNode->GetSymbol(), nLevel + 1 ); |
344 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
345 | 0 | m_pSerializer->startElementNS(XML_m, XML_lim); |
346 | 0 | if( const SmSubSupNode* subsup = pNode->GetSubNode( 0 )->GetType() == SmNodeType::SubSup |
347 | 0 | ? static_cast< const SmSubSupNode* >( pNode->GetSubNode( 0 )) : nullptr ) |
348 | 0 | { |
349 | 0 | if( subsup->GetSubSup( CSUB ) != nullptr ) |
350 | 0 | HandleNode( subsup->GetSubSup( CSUB ), nLevel + 1 ); |
351 | 0 | } |
352 | 0 | m_pSerializer->endElementNS( XML_m, XML_lim ); |
353 | 0 | m_pSerializer->endElementNS( XML_m, XML_limLow ); |
354 | 0 | m_pSerializer->endElementNS( XML_m, XML_fName ); |
355 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
356 | 0 | HandleNode( pNode->GetSubNode( 1 ), nLevel + 1 ); // body |
357 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
358 | 0 | m_pSerializer->endElementNS( XML_m, XML_func ); |
359 | 0 | break; |
360 | 0 | default: |
361 | 0 | SAL_WARN("starmath.ooxml", "Unhandled operation"); |
362 | 0 | HandleAllSubNodes( pNode, nLevel ); |
363 | 0 | break; |
364 | 0 | } |
365 | 0 | } |
366 | | |
367 | | void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int nLevel, int flags ) |
368 | 0 | { |
369 | | // docx supports only a certain combination of sub/super scripts, but LO can have any, |
370 | | // so try to merge it using several tags if necessary |
371 | 0 | if( flags == 0 ) // none |
372 | 0 | return; |
373 | 0 | if(( flags & ( 1 << RSUP | 1 << RSUB )) == ( 1 << RSUP | 1 << RSUB )) |
374 | 0 | { // m:sSubSup |
375 | 0 | m_pSerializer->startElementNS(XML_m, XML_sSubSup); |
376 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
377 | 0 | flags &= ~( 1 << RSUP | 1 << RSUB ); |
378 | 0 | if( flags == 0 ) |
379 | 0 | HandleNode( pNode->GetBody(), nLevel + 1 ); |
380 | 0 | else |
381 | 0 | HandleSubSupScriptInternal( pNode, nLevel, flags ); |
382 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
383 | 0 | m_pSerializer->startElementNS(XML_m, XML_sub); |
384 | 0 | HandleNode( pNode->GetSubSup( RSUB ), nLevel + 1 ); |
385 | 0 | m_pSerializer->endElementNS( XML_m, XML_sub ); |
386 | 0 | m_pSerializer->startElementNS(XML_m, XML_sup); |
387 | 0 | HandleNode( pNode->GetSubSup( RSUP ), nLevel + 1 ); |
388 | 0 | m_pSerializer->endElementNS( XML_m, XML_sup ); |
389 | 0 | m_pSerializer->endElementNS( XML_m, XML_sSubSup ); |
390 | 0 | } |
391 | 0 | else if(( flags & ( 1 << RSUB )) == 1 << RSUB ) |
392 | 0 | { // m:sSub |
393 | 0 | m_pSerializer->startElementNS(XML_m, XML_sSub); |
394 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
395 | 0 | flags &= ~( 1 << RSUB ); |
396 | 0 | if( flags == 0 ) |
397 | 0 | HandleNode( pNode->GetBody(), nLevel + 1 ); |
398 | 0 | else |
399 | 0 | HandleSubSupScriptInternal( pNode, nLevel, flags ); |
400 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
401 | 0 | m_pSerializer->startElementNS(XML_m, XML_sub); |
402 | 0 | HandleNode( pNode->GetSubSup( RSUB ), nLevel + 1 ); |
403 | 0 | m_pSerializer->endElementNS( XML_m, XML_sub ); |
404 | 0 | m_pSerializer->endElementNS( XML_m, XML_sSub ); |
405 | 0 | } |
406 | 0 | else if(( flags & ( 1 << RSUP )) == 1 << RSUP ) |
407 | 0 | { // m:sSup |
408 | 0 | m_pSerializer->startElementNS(XML_m, XML_sSup); |
409 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
410 | 0 | flags &= ~( 1 << RSUP ); |
411 | 0 | if( flags == 0 ) |
412 | 0 | HandleNode( pNode->GetBody(), nLevel + 1 ); |
413 | 0 | else |
414 | 0 | HandleSubSupScriptInternal( pNode, nLevel, flags ); |
415 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
416 | 0 | m_pSerializer->startElementNS(XML_m, XML_sup); |
417 | 0 | HandleNode( pNode->GetSubSup( RSUP ), nLevel + 1 ); |
418 | 0 | m_pSerializer->endElementNS( XML_m, XML_sup ); |
419 | 0 | m_pSerializer->endElementNS( XML_m, XML_sSup ); |
420 | 0 | } |
421 | 0 | else if(( flags & ( 1 << LSUP | 1 << LSUB )) == ( 1 << LSUP | 1 << LSUB )) |
422 | 0 | { // m:sPre |
423 | 0 | m_pSerializer->startElementNS(XML_m, XML_sPre); |
424 | 0 | m_pSerializer->startElementNS(XML_m, XML_sub); |
425 | 0 | HandleNode( pNode->GetSubSup( LSUB ), nLevel + 1 ); |
426 | 0 | m_pSerializer->endElementNS( XML_m, XML_sub ); |
427 | 0 | m_pSerializer->startElementNS(XML_m, XML_sup); |
428 | 0 | HandleNode( pNode->GetSubSup( LSUP ), nLevel + 1 ); |
429 | 0 | m_pSerializer->endElementNS( XML_m, XML_sup ); |
430 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
431 | 0 | flags &= ~( 1 << LSUP | 1 << LSUB ); |
432 | 0 | if( flags == 0 ) |
433 | 0 | HandleNode( pNode->GetBody(), nLevel + 1 ); |
434 | 0 | else |
435 | 0 | HandleSubSupScriptInternal( pNode, nLevel, flags ); |
436 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
437 | 0 | m_pSerializer->endElementNS( XML_m, XML_sPre ); |
438 | 0 | } |
439 | 0 | else if(( flags & ( 1 << CSUB )) == ( 1 << CSUB )) |
440 | 0 | { // m:limLow looks like a good element for central superscript |
441 | 0 | m_pSerializer->startElementNS(XML_m, XML_limLow); |
442 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
443 | 0 | flags &= ~( 1 << CSUB ); |
444 | 0 | if( flags == 0 ) |
445 | 0 | HandleNode( pNode->GetBody(), nLevel + 1 ); |
446 | 0 | else |
447 | 0 | HandleSubSupScriptInternal( pNode, nLevel, flags ); |
448 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
449 | 0 | m_pSerializer->startElementNS(XML_m, XML_lim); |
450 | 0 | HandleNode( pNode->GetSubSup( CSUB ), nLevel + 1 ); |
451 | 0 | m_pSerializer->endElementNS( XML_m, XML_lim ); |
452 | 0 | m_pSerializer->endElementNS( XML_m, XML_limLow ); |
453 | 0 | } |
454 | 0 | else if(( flags & ( 1 << CSUP )) == ( 1 << CSUP )) |
455 | 0 | { // m:limUpp looks like a good element for central superscript |
456 | 0 | m_pSerializer->startElementNS(XML_m, XML_limUpp); |
457 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
458 | 0 | flags &= ~( 1 << CSUP ); |
459 | 0 | if( flags == 0 ) |
460 | 0 | HandleNode( pNode->GetBody(), nLevel + 1 ); |
461 | 0 | else |
462 | 0 | HandleSubSupScriptInternal( pNode, nLevel, flags ); |
463 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
464 | 0 | m_pSerializer->startElementNS(XML_m, XML_lim); |
465 | 0 | HandleNode( pNode->GetSubSup( CSUP ), nLevel + 1 ); |
466 | 0 | m_pSerializer->endElementNS( XML_m, XML_lim ); |
467 | 0 | m_pSerializer->endElementNS( XML_m, XML_limUpp ); |
468 | 0 | } |
469 | 0 | else |
470 | 0 | { |
471 | 0 | SAL_WARN("starmath.ooxml", "Unhandled sub/sup combination"); |
472 | | // TODO do not do anything, this should be probably an assert() |
473 | | // HandleAllSubNodes( pNode, nLevel ); |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | | void SmOoxmlExport::HandleMatrix( const SmMatrixNode* pNode, int nLevel ) |
478 | 0 | { |
479 | 0 | m_pSerializer->startElementNS(XML_m, XML_m); |
480 | 0 | for (size_t row = 0; row < pNode->GetNumRows(); ++row) |
481 | 0 | { |
482 | 0 | m_pSerializer->startElementNS(XML_m, XML_mr); |
483 | 0 | for (size_t col = 0; col < pNode->GetNumCols(); ++col) |
484 | 0 | { |
485 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
486 | 0 | if( const SmNode* node = pNode->GetSubNode( row * pNode->GetNumCols() + col )) |
487 | 0 | HandleNode( node, nLevel + 1 ); |
488 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
489 | 0 | } |
490 | 0 | m_pSerializer->endElementNS( XML_m, XML_mr ); |
491 | 0 | } |
492 | 0 | m_pSerializer->endElementNS( XML_m, XML_m ); |
493 | 0 | } |
494 | | |
495 | | void SmOoxmlExport::HandleBrace( const SmBraceNode* pNode, int nLevel ) |
496 | 0 | { |
497 | 0 | m_pSerializer->startElementNS(XML_m, XML_d); |
498 | 0 | m_pSerializer->startElementNS(XML_m, XML_dPr); |
499 | | |
500 | | //check if the node has an opening brace |
501 | 0 | if( TNONE == pNode->OpeningBrace()->GetToken().eType ) |
502 | 0 | m_pSerializer->singleElementNS(XML_m, XML_begChr, FSNS(XML_m, XML_val), ""); |
503 | 0 | else |
504 | 0 | m_pSerializer->singleElementNS( XML_m, XML_begChr, |
505 | 0 | FSNS( XML_m, XML_val ), mathSymbolToString( pNode->OpeningBrace()) ); |
506 | |
|
507 | 0 | std::vector< const SmNode* > subnodes; |
508 | 0 | if( pNode->Body()->GetType() == SmNodeType::Bracebody ) |
509 | 0 | { |
510 | 0 | const SmBracebodyNode* body = static_cast< const SmBracebodyNode* >( pNode->Body()); |
511 | 0 | bool separatorWritten = false; // assume all separators are the same |
512 | 0 | for (size_t i = 0; i < body->GetNumSubNodes(); ++i) |
513 | 0 | { |
514 | 0 | const SmNode* subnode = body->GetSubNode( i ); |
515 | 0 | if (subnode->GetType() == SmNodeType::Math || subnode->GetType() == SmNodeType::MathIdent) |
516 | 0 | { // do not write, but write what separator it is |
517 | 0 | const SmMathSymbolNode* math = static_cast< const SmMathSymbolNode* >( subnode ); |
518 | 0 | if( !separatorWritten ) |
519 | 0 | { |
520 | 0 | m_pSerializer->singleElementNS( XML_m, XML_sepChr, |
521 | 0 | FSNS( XML_m, XML_val ), mathSymbolToString(math) ); |
522 | 0 | separatorWritten = true; |
523 | 0 | } |
524 | 0 | } |
525 | 0 | else |
526 | 0 | subnodes.push_back( subnode ); |
527 | 0 | } |
528 | 0 | } |
529 | 0 | else |
530 | 0 | subnodes.push_back( pNode->Body()); |
531 | |
|
532 | 0 | if( TNONE == pNode->ClosingBrace()->GetToken().eType ) |
533 | 0 | m_pSerializer->singleElementNS(XML_m, XML_endChr, FSNS(XML_m, XML_val), ""); |
534 | 0 | else |
535 | 0 | m_pSerializer->singleElementNS( XML_m, XML_endChr, |
536 | 0 | FSNS( XML_m, XML_val ), mathSymbolToString(pNode->ClosingBrace()) ); |
537 | |
|
538 | 0 | m_pSerializer->endElementNS( XML_m, XML_dPr ); |
539 | 0 | for(const SmNode* subnode : subnodes) |
540 | 0 | { |
541 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
542 | 0 | HandleNode( subnode, nLevel + 1 ); |
543 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
544 | 0 | } |
545 | 0 | m_pSerializer->endElementNS( XML_m, XML_d ); |
546 | 0 | } |
547 | | |
548 | | void SmOoxmlExport::HandleVerticalBrace( const SmVerticalBraceNode* pNode, int nLevel ) |
549 | 0 | { |
550 | 0 | SAL_INFO( "starmath.ooxml", "Vertical: " << int( pNode->GetToken().eType )); |
551 | 0 | switch( pNode->GetToken().eType ) |
552 | 0 | { |
553 | 0 | case TOVERBRACE: |
554 | 0 | case TUNDERBRACE: |
555 | 0 | { |
556 | 0 | bool top = ( pNode->GetToken().eType == TOVERBRACE ); |
557 | 0 | m_pSerializer->startElementNS(XML_m, top ? XML_limUpp : XML_limLow); |
558 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
559 | 0 | m_pSerializer->startElementNS(XML_m, XML_groupChr); |
560 | 0 | m_pSerializer->startElementNS(XML_m, XML_groupChrPr); |
561 | 0 | m_pSerializer->singleElementNS( XML_m, XML_chr, |
562 | 0 | FSNS( XML_m, XML_val ), mathSymbolToString(pNode->Brace()) ); |
563 | | // TODO not sure if pos and vertJc are correct |
564 | 0 | m_pSerializer->singleElementNS( XML_m, XML_pos, |
565 | 0 | FSNS( XML_m, XML_val ), top ? "top" : "bot" ); |
566 | 0 | m_pSerializer->singleElementNS(XML_m, XML_vertJc, FSNS(XML_m, XML_val), |
567 | 0 | top ? "bot" : "top"); |
568 | 0 | m_pSerializer->endElementNS( XML_m, XML_groupChrPr ); |
569 | 0 | m_pSerializer->startElementNS(XML_m, XML_e); |
570 | 0 | HandleNode( pNode->Body(), nLevel + 1 ); |
571 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
572 | 0 | m_pSerializer->endElementNS( XML_m, XML_groupChr ); |
573 | 0 | m_pSerializer->endElementNS( XML_m, XML_e ); |
574 | 0 | m_pSerializer->startElementNS(XML_m, XML_lim); |
575 | 0 | HandleNode( pNode->Script(), nLevel + 1 ); |
576 | 0 | m_pSerializer->endElementNS( XML_m, XML_lim ); |
577 | 0 | m_pSerializer->endElementNS( XML_m, top ? XML_limUpp : XML_limLow ); |
578 | 0 | break; |
579 | 0 | } |
580 | 0 | default: |
581 | 0 | SAL_WARN("starmath.ooxml", "Unhandled vertical brace"); |
582 | 0 | HandleAllSubNodes( pNode, nLevel ); |
583 | 0 | break; |
584 | 0 | } |
585 | 0 | } |
586 | | |
587 | | void SmOoxmlExport::HandleBlank() |
588 | 0 | { |
589 | 0 | m_pSerializer->startElementNS(XML_m, XML_r); |
590 | 0 | m_pSerializer->startElementNS(XML_m, XML_t, FSNS(XML_xml, XML_space), "preserve"); |
591 | 0 | m_pSerializer->write( " " ); |
592 | 0 | m_pSerializer->endElementNS( XML_m, XML_t ); |
593 | 0 | m_pSerializer->endElementNS( XML_m, XML_r ); |
594 | 0 | } |
595 | | |
596 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |