Line data Source code
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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "node.hxx"
22 : #include "rect.hxx"
23 : #include "symbol.hxx"
24 : #include "smmod.hxx"
25 : #include "document.hxx"
26 : #include "view.hxx"
27 : #include "mathtype.hxx"
28 : #include "tmpdevice.hxx"
29 : #include "visitors.hxx"
30 :
31 : #include <comphelper/string.hxx>
32 : #include <tools/color.hxx>
33 : #include <tools/fract.hxx>
34 : #include <tools/gen.hxx>
35 : #include <vcl/outdev.hxx>
36 :
37 : #include <math.h>
38 : #include <float.h>
39 :
40 :
41 :
42 30918 : SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken)
43 : : aNodeToken( rNodeToken )
44 : , eType( eNodeType )
45 : , eScaleMode( SCALE_NONE )
46 : , eRectHorAlign( RHA_LEFT )
47 : , nFlags( 0 )
48 : , nAttributes( 0 )
49 : , bIsPhantom( false )
50 : , bIsDebug( false )
51 : , bIsSelected( false )
52 : , nAccIndex( -1 )
53 30918 : , aParentNode( NULL )
54 : {
55 30918 : }
56 :
57 :
58 30882 : SmNode::~SmNode()
59 : {
60 30882 : }
61 :
62 :
63 0 : bool SmNode::IsVisible() const
64 : {
65 0 : return false;
66 : }
67 :
68 :
69 0 : sal_uInt16 SmNode::GetNumSubNodes() const
70 : {
71 0 : return 0;
72 : }
73 :
74 :
75 0 : SmNode * SmNode::GetSubNode(sal_uInt16 /*nIndex*/)
76 : {
77 0 : return NULL;
78 : }
79 :
80 :
81 11422 : SmNode * SmNode::GetLeftMost()
82 : // returns leftmost node of current subtree.
83 : //! (this assumes the one with index 0 is always the leftmost subnode
84 : //! for the current node).
85 : {
86 11422 : SmNode *pNode = GetNumSubNodes() > 0 ?
87 11422 : GetSubNode(0) : NULL;
88 :
89 11422 : return pNode ? pNode->GetLeftMost() : this;
90 : }
91 :
92 :
93 0 : void SmNode::SetPhantom(bool bIsPhantomP)
94 : {
95 0 : if (! (Flags() & FLG_VISIBLE))
96 0 : bIsPhantom = bIsPhantomP;
97 :
98 : SmNode *pNode;
99 0 : sal_uInt16 nSize = GetNumSubNodes();
100 0 : for (sal_uInt16 i = 0; i < nSize; i++)
101 0 : if (NULL != (pNode = GetSubNode(i)))
102 0 : pNode->SetPhantom(bIsPhantom);
103 0 : }
104 :
105 :
106 0 : void SmNode::SetColor(const Color& rColor)
107 : {
108 0 : if (! (Flags() & FLG_COLOR))
109 0 : GetFont().SetColor(rColor);
110 :
111 : SmNode *pNode;
112 0 : sal_uInt16 nSize = GetNumSubNodes();
113 0 : for (sal_uInt16 i = 0; i < nSize; i++)
114 0 : if (NULL != (pNode = GetSubNode(i)))
115 0 : pNode->SetColor(rColor);
116 0 : }
117 :
118 :
119 2 : void SmNode::SetAttribut(sal_uInt16 nAttrib)
120 : {
121 2 : if (
122 4 : (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
123 2 : (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
124 : )
125 : {
126 2 : nAttributes |= nAttrib;
127 : }
128 :
129 : SmNode *pNode;
130 2 : sal_uInt16 nSize = GetNumSubNodes();
131 2 : for (sal_uInt16 i = 0; i < nSize; i++)
132 0 : if (NULL != (pNode = GetSubNode(i)))
133 0 : pNode->SetAttribut(nAttrib);
134 2 : }
135 :
136 :
137 0 : void SmNode::ClearAttribut(sal_uInt16 nAttrib)
138 : {
139 0 : if (
140 0 : (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
141 0 : (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
142 : )
143 : {
144 0 : nAttributes &= ~nAttrib;
145 : }
146 :
147 : SmNode *pNode;
148 0 : sal_uInt16 nSize = GetNumSubNodes();
149 0 : for (sal_uInt16 i = 0; i < nSize; i++)
150 0 : if (NULL != (pNode = GetSubNode(i)))
151 0 : pNode->ClearAttribut(nAttrib);
152 0 : }
153 :
154 :
155 24 : void SmNode::SetFont(const SmFace &rFace)
156 : {
157 24 : if (!(Flags() & FLG_FONT))
158 24 : GetFont() = rFace;
159 :
160 : SmNode *pNode;
161 24 : sal_uInt16 nSize = GetNumSubNodes();
162 48 : for (sal_uInt16 i = 0; i < nSize; i++)
163 24 : if (NULL != (pNode = GetSubNode(i)))
164 12 : pNode->SetFont(rFace);
165 24 : }
166 :
167 :
168 372 : void SmNode::SetFontSize(const Fraction &rSize, sal_uInt16 nType)
169 : //! 'rSize' is in units of pts
170 : {
171 372 : Size aFntSize;
172 :
173 372 : if (!(Flags() & FLG_SIZE))
174 : {
175 : Fraction aVal (SmPtsTo100th_mm(rSize.GetNumerator()),
176 372 : rSize.GetDenominator());
177 372 : long nHeight = (long)aVal;
178 :
179 372 : aFntSize = GetFont().GetSize();
180 372 : aFntSize.Width() = 0;
181 372 : switch(nType)
182 : {
183 : case FNTSIZ_ABSOLUT:
184 372 : aFntSize.Height() = nHeight;
185 372 : break;
186 :
187 : case FNTSIZ_PLUS:
188 0 : aFntSize.Height() += nHeight;
189 0 : break;
190 :
191 : case FNTSIZ_MINUS:
192 0 : aFntSize.Height() -= nHeight;
193 0 : break;
194 :
195 : case FNTSIZ_MULTIPLY:
196 0 : aFntSize.Height() = (long) (Fraction(aFntSize.Height()) * rSize);
197 0 : break;
198 :
199 : case FNTSIZ_DIVIDE:
200 0 : if (rSize != Fraction(0L))
201 0 : aFntSize.Height() = (long) (Fraction(aFntSize.Height()) / rSize);
202 0 : break;
203 : default:
204 0 : break;
205 : }
206 :
207 : // check the requested size against maximum value
208 372 : static int const nMaxVal = SmPtsTo100th_mm(128);
209 372 : if (aFntSize.Height() > nMaxVal)
210 0 : aFntSize.Height() = nMaxVal;
211 :
212 372 : GetFont().SetSize(aFntSize);
213 : }
214 :
215 : SmNode *pNode;
216 372 : sal_uInt16 nSize = GetNumSubNodes();
217 984 : for (sal_uInt16 i = 0; i < nSize; i++)
218 612 : if (NULL != (pNode = GetSubNode(i)))
219 252 : pNode->SetFontSize(rSize, nType);
220 372 : }
221 :
222 :
223 7496 : void SmNode::SetSize(const Fraction &rSize)
224 : {
225 7496 : GetFont() *= rSize;
226 :
227 : SmNode *pNode;
228 7496 : sal_uInt16 nSize = GetNumSubNodes();
229 10256 : for (sal_uInt16 i = 0; i < nSize; i++)
230 2760 : if (NULL != (pNode = GetSubNode(i)))
231 2524 : pNode->SetSize(rSize);
232 7496 : }
233 :
234 :
235 1876 : void SmNode::SetRectHorAlign(RectHorAlign eHorAlign, bool bApplyToSubTree )
236 : {
237 1876 : if (!(Flags() & FLG_HORALIGN))
238 1876 : eRectHorAlign = eHorAlign;
239 :
240 1876 : if (bApplyToSubTree)
241 : {
242 : SmNode *pNode;
243 156 : sal_uInt16 nSize = GetNumSubNodes();
244 156 : for (sal_uInt16 i = 0; i < nSize; i++)
245 0 : if (NULL != (pNode = GetSubNode(i)))
246 0 : pNode->SetRectHorAlign(eHorAlign);
247 : }
248 1876 : }
249 :
250 :
251 14442 : void SmNode::PrepareAttributes()
252 : {
253 14442 : GetFont().SetWeight((Attributes() & ATTR_BOLD) ? WEIGHT_BOLD : WEIGHT_NORMAL);
254 14442 : GetFont().SetItalic((Attributes() & ATTR_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE);
255 14442 : }
256 :
257 :
258 31702 : void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
259 : {
260 : #if OSL_DEBUG_LEVEL > 1
261 : bIsDebug = true;
262 : #else
263 31702 : bIsDebug = false;
264 : #endif
265 31702 : bIsPhantom = false;
266 31702 : nFlags = 0;
267 31702 : nAttributes = 0;
268 :
269 31702 : switch (rFormat.GetHorAlign())
270 0 : { case AlignLeft: eRectHorAlign = RHA_LEFT; break;
271 31372 : case AlignCenter: eRectHorAlign = RHA_CENTER; break;
272 330 : case AlignRight: eRectHorAlign = RHA_RIGHT; break;
273 : }
274 :
275 31702 : GetFont() = rFormat.GetFont(FNT_MATH);
276 : OSL_ENSURE( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
277 : "unexpected CharSet" );
278 31702 : GetFont().SetWeight(WEIGHT_NORMAL);
279 31702 : GetFont().SetItalic(ITALIC_NONE);
280 :
281 : SmNode *pNode;
282 31702 : sal_uInt16 nSize = GetNumSubNodes();
283 67044 : for (sal_uInt16 i = 0; i < nSize; i++)
284 35342 : if (NULL != (pNode = GetSubNode(i)))
285 27864 : pNode->Prepare(rFormat, rDocShell);
286 31702 : }
287 :
288 0 : sal_uInt16 SmNode::FindIndex() const
289 : {
290 0 : const SmStructureNode* pParent = GetParent();
291 0 : if (!pParent) { return 0; }
292 :
293 0 : for (sal_uInt16 i = 0; i < pParent->GetNumSubNodes(); ++i) {
294 0 : if (pParent->GetSubNode(i) == this) {
295 0 : return i;
296 : }
297 : }
298 :
299 : DBG_ASSERT(false, "Connection between parent and child is inconsistent.");
300 0 : return 0;
301 : }
302 :
303 :
304 : #if OSL_DEBUG_LEVEL > 1
305 : void SmNode::ToggleDebug() const
306 : // toggle 'bIsDebug' in current subtree
307 : {
308 : SmNode *pThis = (SmNode *) this;
309 :
310 : pThis->bIsDebug = bIsDebug ? false : true;
311 :
312 : SmNode *pNode;
313 : sal_uInt16 nSize = GetNumSubNodes();
314 : for (sal_uInt16 i = 0; i < nSize; i++)
315 : if (NULL != (pNode = pThis->GetSubNode(i)))
316 : pNode->ToggleDebug();
317 : }
318 : #endif
319 :
320 :
321 60576 : void SmNode::Move(const Point& rPosition)
322 : {
323 60576 : if (rPosition.X() == 0 && rPosition.Y() == 0)
324 60588 : return;
325 :
326 60564 : SmRect::Move(rPosition);
327 :
328 : SmNode *pNode;
329 60564 : sal_uInt16 nSize = GetNumSubNodes();
330 124394 : for (sal_uInt16 i = 0; i < nSize; i++)
331 63830 : if (NULL != (pNode = GetSubNode(i)))
332 45248 : pNode->Move(rPosition);
333 : }
334 :
335 :
336 0 : void SmNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
337 : {
338 : SmNode *pNode;
339 0 : sal_uInt16 nSize = GetNumSubNodes();
340 0 : for (sal_uInt16 i = 0; i < nSize; i++)
341 0 : if (NULL != (pNode = GetSubNode(i)))
342 0 : pNode->Arrange(rDev, rFormat);
343 0 : }
344 :
345 0 : void SmNode::CreateTextFromNode(OUString &rText)
346 : {
347 : SmNode *pNode;
348 0 : sal_uInt16 nSize = GetNumSubNodes();
349 0 : if (nSize > 1)
350 0 : rText += "{";
351 0 : for (sal_uInt16 i = 0; i < nSize; i++)
352 0 : if (NULL != (pNode = GetSubNode(i)))
353 0 : pNode->CreateTextFromNode(rText);
354 0 : if (nSize > 1)
355 : {
356 0 : rText = comphelper::string::stripEnd(rText, ' ');
357 0 : rText += "} ";
358 : }
359 0 : }
360 :
361 :
362 0 : void SmNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong /*nWidth*/)
363 : {
364 0 : }
365 :
366 :
367 0 : void SmNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong /*nHeight*/)
368 : {
369 0 : }
370 :
371 :
372 44 : const SmNode * SmNode::FindTokenAt(sal_uInt16 nRow, sal_uInt16 nCol) const
373 : // returns (first) ** visible ** (sub)node with the tokens text at
374 : // position 'nRow', 'nCol'.
375 : //! (there should be exactly one such node if any)
376 : {
377 88 : if ( IsVisible()
378 8 : && nRow == GetToken().nRow
379 52 : && nCol >= GetToken().nCol && nCol < GetToken().nCol + GetToken().aText.getLength())
380 8 : return this;
381 : else
382 : {
383 36 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
384 44 : for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
385 32 : { const SmNode *pNode = GetSubNode(i);
386 :
387 32 : if (!pNode)
388 0 : continue;
389 :
390 32 : const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
391 32 : if (pResult)
392 24 : return pResult;
393 : }
394 : }
395 :
396 12 : return 0;
397 : }
398 :
399 :
400 0 : const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
401 : {
402 0 : long nDist = LONG_MAX;
403 0 : const SmNode *pResult = 0;
404 :
405 0 : if (IsVisible())
406 0 : pResult = this;
407 : else
408 : {
409 0 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
410 0 : for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
411 0 : { const SmNode *pNode = GetSubNode(i);
412 :
413 0 : if (!pNode)
414 0 : continue;
415 :
416 : long nTmp;
417 0 : const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
418 0 : if (pFound && (nTmp = pFound->OrientedDist(rPoint)) < nDist)
419 0 : { nDist = nTmp;
420 0 : pResult = pFound;
421 :
422 : // quit immediately if 'rPoint' is inside the *should not
423 : // overlap with other rectangles* part.
424 : // This (partly) serves for getting the attributes in eg
425 : // "bar overstrike a".
426 : // ('nDist < 0' is used as *quick shot* to avoid evaluation of
427 : // the following expression, where the result is already determined)
428 0 : if (nDist < 0 && pFound->IsInsideRect(rPoint))
429 0 : break;
430 : }
431 : }
432 : }
433 :
434 0 : return pResult;
435 : }
436 :
437 0 : void SmNode::GetAccessibleText( OUStringBuffer &/*rText*/ ) const
438 : {
439 : SAL_WARN("starmath", "SmNode: GetAccessibleText not overloaded");
440 0 : }
441 :
442 0 : const SmNode * SmNode::FindNodeWithAccessibleIndex(sal_Int32 nAccIdx) const
443 : {
444 0 : const SmNode *pResult = 0;
445 :
446 0 : sal_Int32 nIdx = GetAccessibleIndex();
447 0 : OUStringBuffer aTxt;
448 0 : if (nIdx >= 0)
449 0 : GetAccessibleText( aTxt ); // get text if used in following 'if' statement
450 :
451 0 : if (nIdx >= 0
452 0 : && nIdx <= nAccIdx && nAccIdx < nIdx + aTxt.getLength())
453 0 : pResult = this;
454 : else
455 : {
456 0 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
457 0 : for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
458 : {
459 0 : const SmNode *pNode = GetSubNode(i);
460 0 : if (!pNode)
461 0 : continue;
462 :
463 0 : pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
464 0 : if (pResult)
465 0 : return pResult;
466 : }
467 : }
468 :
469 0 : return pResult;
470 : }
471 :
472 : #ifdef DEBUG_ENABLE_DUMPASDOT
473 : void SmNode::DumpAsDot(std::ostream &out, OUString* label, int number, int& id, int parent) const
474 : {
475 : //If this is the root start the file
476 : if(number == -1){
477 : out<<"digraph {"<<std::endl;
478 : if(label){
479 : out<<"labelloc = \"t\";"<<std::endl;
480 : OUString eq(*label);
481 : //CreateTextFromNode(eq);
482 : eq = eq.replaceAll("\n", " ");
483 : eq = eq.replaceAll("\\", "\\\\");
484 : eq = eq.replaceAll("\"", "\\\"");
485 : out<<"label= \"Equation: \\\"";
486 : out<< OUStringToOString(eq, RTL_TEXTENCODING_UTF8).getStr();
487 : out<<"\\\"\";"<<std::endl;
488 : }
489 : }
490 :
491 : //Some how out<<(int)this; doesn't work... So we do this nasty workaround...
492 : char strid[100];
493 : sprintf(strid, "%i", id);
494 :
495 : char strnr[100];
496 : sprintf(strnr, "%i", number);
497 :
498 : //Dump connection to this node
499 : if( parent != -1 ){
500 : char pid[100];
501 : sprintf(pid, "%i", parent);
502 : out<<"n"<<pid<<" -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
503 : //If doesn't have parent and isn't a rootnode:
504 : } else if(number != -1) {
505 : out<<"orphaned -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
506 : }
507 :
508 : //Dump this node
509 : out<<"n"<< strid<<" [label=\"";
510 : switch( GetType() ) {
511 : case NTABLE: out<<"SmTableNode"; break;
512 : case NBRACE: out<<"SmBraceNode"; break;
513 : case NBRACEBODY: out<<"SmBracebodyNode"; break;
514 : case NOPER: out<<"SmOperNode"; break;
515 : case NALIGN: out<<"SmAlignNode"; break;
516 : case NATTRIBUT: out<<"SmAttributNode"; break;
517 : case NFONT: out<<"SmFontNode"; break;
518 : case NUNHOR: out<<"SmUnHorNode"; break;
519 : case NBINHOR: out<<"SmBinHorNode"; break;
520 : case NBINVER: out<<"SmBinVerNode"; break;
521 : case NBINDIAGONAL: out<<"SmBinDiagonalNode"; break;
522 : case NSUBSUP: out<<"SmSubSupNode"; break;
523 : case NMATRIX: out<<"SmMatrixNode"; break;
524 : case NPLACE: out<<"SmPlaceNode"; break;
525 : case NTEXT:
526 : out<<"SmTextNode: ";
527 : out<< OUStringToOString(((SmTextNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).getStr();
528 : break;
529 : case NSPECIAL: out<<"SmSpecialNode"; break;
530 : case NGLYPH_SPECIAL: out<<"SmGlyphSpecialNode"; break;
531 : case NMATH:
532 : out<<"SmMathSymbolNode: ";
533 : out<< OUStringToOString(((SmMathSymbolNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).getStr();
534 : break;
535 : case NBLANK: out<<"SmBlankNode"; break;
536 : case NERROR: out<<"SmErrorNode"; break;
537 : case NLINE: out<<"SmLineNode"; break;
538 : case NEXPRESSION: out<<"SmExpressionNode"; break;
539 : case NPOLYLINE: out<<"SmPolyLineNode"; break;
540 : case NROOT: out<<"SmRootNode"; break;
541 : case NROOTSYMBOL: out<<"SmRootSymbolNode"; break;
542 : case NRECTANGLE: out<<"SmRectangleNode"; break;
543 : case NVERTICAL_BRACE: out<<"SmVerticalBraceNode"; break;
544 : case NMATHIDENT: out<<"SmMathIdentifierNode"; break;
545 : case NINTDYNSYMBOL: out<<"SmDynIntegralSymbolNode"; break;
546 : case NINTDYN: out<<"SmDynIntegralNode"; break;
547 : default:
548 : out<<"Unknown Node";
549 : }
550 : out<<"\"";
551 : if(IsSelected())
552 : out<<", style=dashed";
553 : out<<"];"<<std::endl;
554 :
555 : //Dump subnodes
556 : int myid = id;
557 : const SmNode *pNode;
558 : sal_uInt16 nSize = GetNumSubNodes();
559 : for (sal_uInt16 i = 0; i < nSize; i++)
560 : if (NULL != (pNode = GetSubNode(i)))
561 : pNode->DumpAsDot(out, NULL, i, ++id, myid);
562 :
563 : //If this is the root end the file
564 : if( number == -1 )
565 : out<<"}"<<std::endl;
566 : }
567 : #endif /* DEBUG_ENABLE_DUMPASDOT */
568 :
569 0 : long SmNode::GetFormulaBaseline() const
570 : {
571 : SAL_WARN("starmath", "This dummy implementation should not have been called.");
572 0 : return 0;
573 : }
574 :
575 :
576 :
577 0 : SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
578 0 : SmNode( rNode.GetType(), rNode.GetToken() )
579 : {
580 : sal_uLong i;
581 0 : for (i = 0; i < aSubNodes.size(); i++)
582 0 : delete aSubNodes[i];
583 0 : aSubNodes.resize(0);
584 :
585 0 : sal_uLong nSize = rNode.aSubNodes.size();
586 0 : aSubNodes.resize( nSize );
587 0 : for (i = 0; i < nSize; ++i)
588 : {
589 0 : SmNode *pNode = rNode.aSubNodes[i];
590 0 : aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
591 : }
592 0 : ClaimPaternity();
593 0 : }
594 :
595 :
596 26468 : SmStructureNode::~SmStructureNode()
597 : {
598 : SmNode *pNode;
599 :
600 48182 : for (sal_uInt16 i = 0; i < GetNumSubNodes(); i++)
601 34948 : if (NULL != (pNode = GetSubNode(i)))
602 27362 : delete pNode;
603 13234 : }
604 :
605 :
606 0 : SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
607 : {
608 0 : SmNode::operator = ( rNode );
609 :
610 : sal_uLong i;
611 0 : for (i = 0; i < aSubNodes.size(); i++)
612 0 : delete aSubNodes[i];
613 0 : aSubNodes.resize(0);
614 :
615 0 : sal_uLong nSize = rNode.aSubNodes.size();
616 0 : aSubNodes.resize( nSize );
617 0 : for (i = 0; i < nSize; ++i)
618 : {
619 0 : SmNode *pNode = rNode.aSubNodes[i];
620 0 : aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
621 : }
622 :
623 0 : ClaimPaternity();
624 :
625 0 : return *this;
626 : }
627 :
628 :
629 5914 : void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThird)
630 : {
631 5914 : size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0));
632 5914 : aSubNodes.resize( nSize );
633 5914 : if (pFirst)
634 4950 : aSubNodes[0] = pFirst;
635 5914 : if (pSecond)
636 5188 : aSubNodes[1] = pSecond;
637 5914 : if (pThird)
638 3698 : aSubNodes[2] = pThird;
639 :
640 5914 : ClaimPaternity();
641 5914 : }
642 :
643 :
644 7916 : void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
645 : {
646 7916 : aSubNodes = rNodeArray;
647 7916 : ClaimPaternity();
648 7916 : }
649 :
650 :
651 36 : bool SmStructureNode::IsVisible() const
652 : {
653 36 : return false;
654 : }
655 :
656 :
657 179888 : sal_uInt16 SmStructureNode::GetNumSubNodes() const
658 : {
659 179888 : return (sal_uInt16) aSubNodes.size();
660 : }
661 :
662 :
663 423425 : SmNode * SmStructureNode::GetSubNode(sal_uInt16 nIndex)
664 : {
665 423425 : return aSubNodes[nIndex];
666 : }
667 :
668 :
669 0 : void SmStructureNode::GetAccessibleText( OUStringBuffer &rText ) const
670 : {
671 0 : sal_uInt16 nNodes = GetNumSubNodes();
672 0 : for (sal_uInt16 i = 0; i < nNodes; ++i)
673 : {
674 0 : const SmNode *pNode = ((SmStructureNode *) this)->GetSubNode(i);
675 0 : if (pNode)
676 : {
677 0 : if (pNode->IsVisible())
678 0 : ((SmStructureNode *) pNode)->nAccIndex = rText.getLength();
679 0 : pNode->GetAccessibleText( rText );
680 : }
681 : }
682 0 : }
683 :
684 :
685 :
686 :
687 8 : bool SmVisibleNode::IsVisible() const
688 : {
689 8 : return true;
690 : }
691 :
692 :
693 69220 : sal_uInt16 SmVisibleNode::GetNumSubNodes() const
694 : {
695 69220 : return 0;
696 : }
697 :
698 :
699 0 : SmNode * SmVisibleNode::GetSubNode(sal_uInt16 /*nIndex*/)
700 : {
701 0 : return NULL;
702 : }
703 :
704 :
705 :
706 :
707 0 : void SmGraphicNode::GetAccessibleText( OUStringBuffer &rText ) const
708 : {
709 0 : rText.append(GetToken().aText);
710 0 : }
711 :
712 :
713 :
714 :
715 0 : void SmExpressionNode::CreateTextFromNode(OUString &rText)
716 : {
717 : SmNode *pNode;
718 0 : sal_uInt16 nSize = GetNumSubNodes();
719 0 : if (nSize > 1)
720 0 : rText += "{";
721 0 : for (sal_uInt16 i = 0; i < nSize; i++)
722 0 : if (NULL != (pNode = GetSubNode(i)))
723 : {
724 0 : pNode->CreateTextFromNode(rText);
725 : //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
726 0 : if (pNode->GetType() == NMATH)
727 0 : if ((nSize != 2) ||
728 0 : ( !rText.endsWith("+") && !rText.endsWith("-") ))
729 0 : rText += " ";
730 : }
731 :
732 0 : if (nSize > 1)
733 : {
734 0 : rText = comphelper::string::stripEnd(rText, ' ');
735 0 : rText += "} ";
736 : }
737 0 : }
738 :
739 :
740 :
741 :
742 2292 : void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
743 : // arranges all subnodes in one column
744 : {
745 : SmNode *pNode;
746 2292 : sal_uInt16 nSize = GetNumSubNodes();
747 :
748 : // make distance depend on font size
749 2292 : long nDist = +(rFormat.GetDistance(DIS_VERTICAL)
750 2292 : * GetFont().GetSize().Height()) / 100L;
751 :
752 2292 : if (nSize < 1)
753 2292 : return;
754 :
755 : // arrange subnodes and get maximum width of them
756 2292 : long nMaxWidth = 0,
757 : nTmp;
758 : sal_uInt16 i;
759 4776 : for (i = 0; i < nSize; i++)
760 2484 : if (NULL != (pNode = GetSubNode(i)))
761 2484 : { pNode->Arrange(rDev, rFormat);
762 2484 : if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
763 2376 : nMaxWidth = nTmp;
764 : }
765 :
766 2292 : Point aPos;
767 2292 : SmRect::operator = (SmRect(nMaxWidth, 1));
768 4776 : for (i = 0; i < nSize; i++)
769 2484 : { if (NULL != (pNode = GetSubNode(i)))
770 2484 : { const SmRect &rNodeRect = pNode->GetRect();
771 2484 : const SmNode *pCoNode = pNode->GetLeftMost();
772 2484 : RectHorAlign eHorAlign = pCoNode->GetRectHorAlign();
773 :
774 : aPos = rNodeRect.AlignTo(*this, RP_BOTTOM,
775 2484 : eHorAlign, RVA_BASELINE);
776 2484 : if (i)
777 192 : aPos.Y() += nDist;
778 2484 : pNode->MoveTo(aPos);
779 2484 : ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG);
780 : }
781 : }
782 : // #i972#
783 2292 : if (HasBaseline())
784 1966 : nFormulaBaseline = GetBaseline();
785 : else
786 : {
787 326 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
788 326 : aTmpDev.SetFont(GetFont());
789 :
790 : SmRect aRect = (SmRect(aTmpDev, &rFormat, OUString("a"),
791 326 : GetFont().GetBorderWidth()));
792 326 : nFormulaBaseline = GetAlignM();
793 : // move from middle position by constant - distance
794 : // between middle and baseline for single letter
795 326 : nFormulaBaseline += aRect.GetBaseline() - aRect.GetAlignM();
796 : }
797 : }
798 :
799 :
800 90 : SmNode * SmTableNode::GetLeftMost()
801 : {
802 90 : return this;
803 : }
804 :
805 :
806 1118 : long SmTableNode::GetFormulaBaseline() const
807 : {
808 1118 : return nFormulaBaseline;
809 : }
810 :
811 :
812 : /**************************************************************************/
813 :
814 :
815 3998 : void SmLineNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
816 : {
817 3998 : SmNode::Prepare(rFormat, rDocShell);
818 :
819 : // Here we use the 'FNT_VARIABLE' font since it's ascent and descent in general fit better
820 : // to the rest of the formula compared to the 'FNT_MATH' font.
821 3998 : GetFont() = rFormat.GetFont(FNT_VARIABLE);
822 3998 : Flags() |= FLG_FONT;
823 3998 : }
824 :
825 :
826 : /**************************************************************************/
827 :
828 :
829 3832 : void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
830 : // arranges all subnodes in one row with some extra space between
831 : {
832 : SmNode *pNode;
833 3832 : sal_uInt16 nSize = GetNumSubNodes();
834 : sal_uInt16 i;
835 10138 : for (i = 0; i < nSize; i++)
836 6306 : if (NULL != (pNode = GetSubNode(i)))
837 6306 : pNode->Arrange(rDev, rFormat);
838 :
839 3832 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
840 3832 : aTmpDev.SetFont(GetFont());
841 :
842 3832 : if (nSize < 1)
843 : {
844 : // provide an empty rectangle with alignment parameters for the "current"
845 : // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
846 : // same sub-/supscript positions.)
847 : //! be sure to use a character that has explicitly defined HiAttribut
848 : //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
849 : //! 'vec {a}'.
850 : SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString("a"),
851 422 : GetFont().GetBorderWidth()));
852 : // make sure that the rectangle occupies (almost) no space
853 422 : SetWidth(1);
854 422 : SetItalicSpaces(0, 0);
855 4254 : return;
856 : }
857 :
858 : // make distance depend on font size
859 3410 : long nDist = (rFormat.GetDistance(DIS_HORIZONTAL) * GetFont().GetSize().Height()) / 100L;
860 3410 : if (!IsUseExtraSpaces())
861 0 : nDist = 0;
862 :
863 3410 : Point aPos;
864 : // copy the first node into LineNode and extend by the others
865 3410 : if (NULL != (pNode = GetSubNode(0)))
866 3410 : SmRect::operator = (pNode->GetRect());
867 :
868 6306 : for (i = 1; i < nSize; i++)
869 2896 : if (NULL != (pNode = GetSubNode(i)))
870 : {
871 2896 : aPos = pNode->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
872 :
873 : // add horizontal space to the left for each but the first sub node
874 2896 : aPos.X() += nDist;
875 :
876 2896 : pNode->MoveTo(aPos);
877 2896 : ExtendBy( *pNode, RCP_XOR );
878 3410 : }
879 : }
880 :
881 :
882 : /**************************************************************************/
883 :
884 :
885 1720 : void SmExpressionNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
886 : // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
887 : {
888 1720 : SmLineNode::Arrange(rDev, rFormat);
889 :
890 : // copy alignment of leftmost subnode if any
891 1720 : SmNode *pNode = GetLeftMost();
892 1720 : if (pNode)
893 1720 : SetRectHorAlign(pNode->GetRectHorAlign(), false);
894 1720 : }
895 :
896 :
897 : /**************************************************************************/
898 :
899 :
900 278 : void SmUnHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
901 : {
902 278 : bool bIsPostfix = GetToken().eType == TFACT;
903 :
904 278 : SmNode *pOper = GetSubNode(bIsPostfix ? 1 : 0),
905 278 : *pBody = GetSubNode(bIsPostfix ? 0 : 1);
906 : OSL_ENSURE(pOper, "Sm: NULL pointer");
907 : OSL_ENSURE(pBody, "Sm: NULL pointer");
908 :
909 278 : pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
910 278 : pOper->Arrange(rDev, rFormat);
911 278 : pBody->Arrange(rDev, rFormat);
912 :
913 : Point aPos = pOper->AlignTo(*pBody, bIsPostfix ? RP_RIGHT : RP_LEFT,
914 278 : RHA_CENTER, RVA_BASELINE);
915 : // add a bit space between operator and argument
916 : // (worst case -{1 over 2} where - and over have almost no space inbetween)
917 278 : long nDelta = pOper->GetFont().GetSize().Height() / 20;
918 278 : if (bIsPostfix)
919 0 : aPos.X() += nDelta;
920 : else
921 278 : aPos.X() -= nDelta;
922 278 : pOper->MoveTo(aPos);
923 :
924 278 : SmRect::operator = (*pBody);
925 278 : long nOldBot = GetBottom();
926 :
927 278 : ExtendBy(*pOper, RCP_XOR);
928 :
929 : // workaround for Bug 50865: "a^2 a^+2" have different baselines
930 : // for exponents (if size of exponent is large enough)
931 278 : SetBottom(nOldBot);
932 278 : }
933 :
934 :
935 : /**************************************************************************/
936 :
937 :
938 156 : void SmRootNode::GetHeightVerOffset(const SmRect &rRect,
939 : long &rHeight, long &rVerOffset) const
940 : // calculate height and vertical offset of root sign suitable for 'rRect'
941 : {
942 156 : rVerOffset = (rRect.GetBottom() - rRect.GetAlignB()) / 2;
943 156 : rHeight = rRect.GetHeight() - rVerOffset;
944 :
945 : OSL_ENSURE(rHeight >= 0, "Sm : Ooops...");
946 : OSL_ENSURE(rVerOffset >= 0, "Sm : Ooops...");
947 156 : }
948 :
949 :
950 30 : Point SmRootNode::GetExtraPos(const SmRect &rRootSymbol,
951 : const SmRect &rExtra) const
952 : {
953 30 : const Size &rSymSize = rRootSymbol.GetSize();
954 :
955 30 : Point aPos = rRootSymbol.GetTopLeft()
956 30 : + Point((rSymSize.Width() * 70) / 100,
957 90 : (rSymSize.Height() * 52) / 100);
958 :
959 : // from this calculate topleft edge of 'rExtra'
960 30 : aPos.X() -= rExtra.GetWidth() + rExtra.GetItalicRightSpace();
961 30 : aPos.Y() -= rExtra.GetHeight();
962 : // if there's enough space move a bit less to the right
963 : // examples: "nroot i a", "nroot j a"
964 : // (it looks better if we don't use italic-spaces here)
965 30 : long nX = rRootSymbol.GetLeft() + (rSymSize.Width() * 30) / 100;
966 30 : if (aPos.X() > nX)
967 0 : aPos.X() = nX;
968 :
969 30 : return aPos;
970 : }
971 :
972 :
973 156 : void SmRootNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
974 : {
975 : //! pExtra needs to have the smaller index than pRootSym in order to
976 : //! not to get the root symbol but the pExtra when clicking on it in the
977 : //! GraphicWindow. (That is because of the simplicity of the algorithm
978 : //! that finds the node corresponding to a mouseclick in the window.)
979 156 : SmNode *pExtra = GetSubNode(0),
980 156 : *pRootSym = GetSubNode(1),
981 156 : *pBody = GetSubNode(2);
982 : OSL_ENSURE(pRootSym, "Sm: NULL pointer");
983 : OSL_ENSURE(pBody, "Sm: NULL pointer");
984 :
985 156 : pBody->Arrange(rDev, rFormat);
986 :
987 : long nHeight,
988 : nVerOffset;
989 156 : GetHeightVerOffset(*pBody, nHeight, nVerOffset);
990 156 : nHeight += rFormat.GetDistance(DIS_ROOT)
991 156 : * GetFont().GetSize().Height() / 100L;
992 :
993 : // font specialist advised to change the width first
994 156 : pRootSym->AdaptToY(rDev, nHeight);
995 156 : pRootSym->AdaptToX(rDev, pBody->GetItalicWidth());
996 :
997 156 : pRootSym->Arrange(rDev, rFormat);
998 :
999 156 : Point aPos = pRootSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
1000 : //! override calculated vertical position
1001 156 : aPos.Y() = pRootSym->GetTop() + pBody->GetBottom() - pRootSym->GetBottom();
1002 156 : aPos.Y() -= nVerOffset;
1003 156 : pRootSym->MoveTo(aPos);
1004 :
1005 156 : if (pExtra)
1006 30 : { pExtra->SetSize(Fraction(rFormat.GetRelSize(SIZ_INDEX), 100));
1007 30 : pExtra->Arrange(rDev, rFormat);
1008 :
1009 30 : aPos = GetExtraPos(*pRootSym, *pExtra);
1010 30 : pExtra->MoveTo(aPos);
1011 : }
1012 :
1013 156 : SmRect::operator = (*pBody);
1014 156 : ExtendBy(*pRootSym, RCP_THIS);
1015 156 : if (pExtra)
1016 30 : ExtendBy(*pExtra, RCP_THIS, true);
1017 156 : }
1018 :
1019 :
1020 0 : void SmRootNode::CreateTextFromNode(OUString &rText)
1021 : {
1022 0 : SmNode *pExtra = GetSubNode(0);
1023 0 : if (pExtra)
1024 : {
1025 0 : rText += "nroot ";
1026 0 : pExtra->CreateTextFromNode(rText);
1027 : }
1028 : else
1029 0 : rText += "sqrt ";
1030 :
1031 0 : if (!pExtra && GetSubNode(2)->GetNumSubNodes() > 1)
1032 0 : rText += "{ ";
1033 :
1034 0 : GetSubNode(2)->CreateTextFromNode(rText);
1035 :
1036 0 : if (!pExtra && GetSubNode(2)->GetNumSubNodes() > 1)
1037 0 : rText += "} ";
1038 0 : }
1039 :
1040 : /**************************************************************************/
1041 :
1042 :
1043 0 : void SmDynIntegralNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1044 : {
1045 0 : SmNode *pDynIntegralSym = Symbol(),
1046 0 : *pBody = Body();
1047 : OSL_ENSURE(pDynIntegralSym, "Sm: NULL pointer");
1048 : OSL_ENSURE(pBody, "Sm: NULL pointer");
1049 :
1050 0 : pBody->Arrange(rDev, rFormat);
1051 :
1052 0 : long nHeight = pBody->GetHeight();
1053 0 : pDynIntegralSym->AdaptToY(rDev, nHeight);
1054 :
1055 0 : pDynIntegralSym->Arrange(rDev, rFormat);
1056 :
1057 0 : Point aPos = pDynIntegralSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
1058 : //! override calculated vertical position
1059 0 : aPos.Y() = pDynIntegralSym->GetTop() + pBody->GetBottom() - pDynIntegralSym->GetBottom();
1060 0 : pDynIntegralSym->MoveTo(aPos);
1061 :
1062 :
1063 : // override its own rectangle with pBody's
1064 0 : SmRect::operator = (*pBody);
1065 : // extends this rectangle with the symbol's one
1066 0 : ExtendBy(*pDynIntegralSym, RCP_THIS);
1067 :
1068 0 : }
1069 :
1070 :
1071 0 : void SmDynIntegralNode::CreateTextFromNode(OUString &rText)
1072 : {
1073 :
1074 0 : rText += "intd ";
1075 0 : SmNode *pBody = GetSubNode(1);
1076 :
1077 0 : if (pBody->GetNumSubNodes() > 1)
1078 0 : rText += "{ ";
1079 :
1080 0 : pBody->CreateTextFromNode(rText);
1081 :
1082 0 : if (pBody->GetNumSubNodes() > 1)
1083 0 : rText += "} ";
1084 0 : }
1085 :
1086 :
1087 :
1088 : /**************************************************************************/
1089 :
1090 :
1091 1608 : void SmBinHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1092 : {
1093 1608 : SmNode *pLeft = GetSubNode(0),
1094 1608 : *pOper = GetSubNode(1),
1095 1608 : *pRight = GetSubNode(2);
1096 : OSL_ENSURE(pLeft != NULL, "Sm: NULL pointer");
1097 : OSL_ENSURE(pOper != NULL, "Sm: NULL pointer");
1098 : OSL_ENSURE(pRight != NULL, "Sm: NULL pointer");
1099 :
1100 1608 : pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
1101 :
1102 1608 : pLeft ->Arrange(rDev, rFormat);
1103 1608 : pOper ->Arrange(rDev, rFormat);
1104 1608 : pRight->Arrange(rDev, rFormat);
1105 :
1106 1608 : const SmRect &rOpRect = pOper->GetRect();
1107 :
1108 3216 : long nDist = (rOpRect.GetWidth() *
1109 3216 : rFormat.GetDistance(DIS_HORIZONTAL)) / 100L;
1110 :
1111 1608 : SmRect::operator = (*pLeft);
1112 :
1113 1608 : Point aPos;
1114 1608 : aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1115 1608 : aPos.X() += nDist;
1116 1608 : pOper->MoveTo(aPos);
1117 1608 : ExtendBy(*pOper, RCP_XOR);
1118 :
1119 1608 : aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1120 1608 : aPos.X() += nDist;
1121 :
1122 1608 : pRight->MoveTo(aPos);
1123 1608 : ExtendBy(*pRight, RCP_XOR);
1124 1608 : }
1125 :
1126 :
1127 : /**************************************************************************/
1128 :
1129 :
1130 462 : void SmBinVerNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1131 : {
1132 462 : SmNode *pNum = GetSubNode(0),
1133 462 : *pLine = GetSubNode(1),
1134 462 : *pDenom = GetSubNode(2);
1135 : OSL_ENSURE(pNum, "Sm : NULL pointer");
1136 : OSL_ENSURE(pLine, "Sm : NULL pointer");
1137 : OSL_ENSURE(pDenom, "Sm : NULL pointer");
1138 :
1139 462 : bool bIsTextmode = rFormat.IsTextmode();
1140 462 : if (bIsTextmode)
1141 : {
1142 0 : Fraction aFraction(rFormat.GetRelSize(SIZ_INDEX), 100);
1143 0 : pNum ->SetSize(aFraction);
1144 0 : pLine ->SetSize(aFraction);
1145 0 : pDenom->SetSize(aFraction);
1146 : }
1147 :
1148 462 : pNum ->Arrange(rDev, rFormat);
1149 462 : pDenom->Arrange(rDev, rFormat);
1150 :
1151 462 : long nFontHeight = GetFont().GetSize().Height(),
1152 462 : nExtLen = nFontHeight * rFormat.GetDistance(DIS_FRACTION) / 100L,
1153 462 : nThick = nFontHeight * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L,
1154 462 : nWidth = std::max(pNum->GetItalicWidth(), pDenom->GetItalicWidth()),
1155 : nNumDist = bIsTextmode ? 0 :
1156 462 : nFontHeight * rFormat.GetDistance(DIS_NUMERATOR) / 100L,
1157 : nDenomDist = bIsTextmode ? 0 :
1158 462 : nFontHeight * rFormat.GetDistance(DIS_DENOMINATOR) / 100L;
1159 :
1160 : // font specialist advised to change the width first
1161 462 : pLine->AdaptToY(rDev, nThick);
1162 462 : pLine->AdaptToX(rDev, nWidth + 2 * nExtLen);
1163 462 : pLine->Arrange(rDev, rFormat);
1164 :
1165 : // get horizontal alignment for numerator
1166 462 : const SmNode *pLM = pNum->GetLeftMost();
1167 462 : RectHorAlign eHorAlign = pLM->GetRectHorAlign();
1168 :
1169 : // move numerator to its position
1170 462 : Point aPos = pNum->AlignTo(*pLine, RP_TOP, eHorAlign, RVA_BASELINE);
1171 462 : aPos.Y() -= nNumDist;
1172 462 : pNum->MoveTo(aPos);
1173 :
1174 : // get horizontal alignment for denominator
1175 462 : pLM = pDenom->GetLeftMost();
1176 462 : eHorAlign = pLM->GetRectHorAlign();
1177 :
1178 : // move denominator to its position
1179 462 : aPos = pDenom->AlignTo(*pLine, RP_BOTTOM, eHorAlign, RVA_BASELINE);
1180 462 : aPos.Y() += nDenomDist;
1181 462 : pDenom->MoveTo(aPos);
1182 :
1183 462 : SmRect::operator = (*pNum);
1184 462 : ExtendBy(*pDenom, RCP_NONE).ExtendBy(*pLine, RCP_NONE, pLine->GetCenterY());
1185 462 : }
1186 :
1187 0 : void SmBinVerNode::CreateTextFromNode(OUString &rText)
1188 : {
1189 0 : SmNode *pNum = GetSubNode(0),
1190 0 : *pDenom = GetSubNode(2);
1191 0 : pNum->CreateTextFromNode(rText);
1192 0 : rText += "over ";
1193 0 : pDenom->CreateTextFromNode(rText);
1194 0 : }
1195 :
1196 :
1197 80 : SmNode * SmBinVerNode::GetLeftMost()
1198 : {
1199 80 : return this;
1200 : }
1201 :
1202 :
1203 : /**************************************************************************/
1204 :
1205 :
1206 : /// @return value of the determinant formed by the two points
1207 136 : double Det(const Point &rHeading1, const Point &rHeading2)
1208 : {
1209 136 : return rHeading1.X() * rHeading2.Y() - rHeading1.Y() * rHeading2.X();
1210 : }
1211 :
1212 :
1213 : /// Is true iff the point 'rPoint1' belongs to the straight line through 'rPoint2'
1214 : /// and has the direction vector 'rHeading2'
1215 0 : bool IsPointInLine(const Point &rPoint1,
1216 : const Point &rPoint2, const Point &rHeading2)
1217 : {
1218 : OSL_ENSURE(rHeading2 != Point(), "Sm : 0 vector");
1219 :
1220 0 : bool bRes = false;
1221 0 : const double eps = 5.0 * DBL_EPSILON;
1222 :
1223 : double fLambda;
1224 0 : if (labs(rHeading2.X()) > labs(rHeading2.Y()))
1225 : {
1226 0 : fLambda = (rPoint1.X() - rPoint2.X()) / (double) rHeading2.X();
1227 0 : bRes = fabs(rPoint1.Y() - (rPoint2.Y() + fLambda * rHeading2.Y())) < eps;
1228 : }
1229 : else
1230 : {
1231 0 : fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y();
1232 0 : bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
1233 : }
1234 :
1235 0 : return bRes;
1236 : }
1237 :
1238 :
1239 136 : sal_uInt16 GetLineIntersectionPoint(Point &rResult,
1240 : const Point& rPoint1, const Point &rHeading1,
1241 : const Point& rPoint2, const Point &rHeading2)
1242 : {
1243 : OSL_ENSURE(rHeading1 != Point(), "Sm : 0 vector");
1244 : OSL_ENSURE(rHeading2 != Point(), "Sm : 0 vector");
1245 :
1246 136 : sal_uInt16 nRes = 1;
1247 136 : const double eps = 5.0 * DBL_EPSILON;
1248 :
1249 : // are the direction vectors linearly dependent?
1250 136 : double fDet = Det(rHeading1, rHeading2);
1251 136 : if (fabs(fDet) < eps)
1252 : {
1253 0 : nRes = IsPointInLine(rPoint1, rPoint2, rHeading2) ? USHRT_MAX : 0;
1254 0 : rResult = nRes ? rPoint1 : Point();
1255 : }
1256 : else
1257 : {
1258 : // here we do not pay attention to the computational accurancy
1259 : // (that would be more complicated and is not really worth it in this case)
1260 136 : double fLambda = ( (rPoint1.Y() - rPoint2.Y()) * rHeading2.X()
1261 136 : - (rPoint1.X() - rPoint2.X()) * rHeading2.Y())
1262 136 : / fDet;
1263 136 : rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()),
1264 272 : rPoint1.Y() + (long) (fLambda * rHeading1.Y()));
1265 : }
1266 :
1267 136 : return nRes;
1268 : }
1269 :
1270 :
1271 :
1272 68 : SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken)
1273 68 : : SmStructureNode(NBINDIAGONAL, rNodeToken)
1274 : {
1275 68 : bAscending = false;
1276 68 : SetNumSubNodes(3);
1277 68 : }
1278 :
1279 :
1280 : /// @return position and size of the diagonal line
1281 : /// premise: SmRect of the node defines the limitation(!) consequently it has to be known upfront
1282 68 : void SmBinDiagonalNode::GetOperPosSize(Point &rPos, Size &rSize,
1283 : const Point &rDiagPoint, double fAngleDeg) const
1284 :
1285 : {
1286 68 : const double fPi = 3.1415926535897932384626433;
1287 68 : double fAngleRad = fAngleDeg / 180.0 * fPi;
1288 68 : long nRectLeft = GetItalicLeft(),
1289 68 : nRectRight = GetItalicRight(),
1290 68 : nRectTop = GetTop(),
1291 68 : nRectBottom = GetBottom();
1292 68 : Point aRightHdg (100, 0),
1293 68 : aDownHdg (0, 100),
1294 68 : aDiagHdg ( (long)(100.0 * cos(fAngleRad)),
1295 136 : (long)(-100.0 * sin(fAngleRad)) );
1296 :
1297 : long nLeft, nRight, nTop, nBottom; // margins of the rectangle for the diagonal
1298 68 : Point aPoint;
1299 68 : if (IsAscending())
1300 : {
1301 : // determine top right corner
1302 : GetLineIntersectionPoint(aPoint,
1303 : Point(nRectLeft, nRectTop), aRightHdg,
1304 34 : rDiagPoint, aDiagHdg);
1305 : // is there a point of intersection with the top border?
1306 34 : if (aPoint.X() <= nRectRight)
1307 : {
1308 34 : nRight = aPoint.X();
1309 34 : nTop = nRectTop;
1310 : }
1311 : else
1312 : {
1313 : // there has to be a point of intersection with the right border!
1314 : GetLineIntersectionPoint(aPoint,
1315 : Point(nRectRight, nRectTop), aDownHdg,
1316 0 : rDiagPoint, aDiagHdg);
1317 :
1318 0 : nRight = nRectRight;
1319 0 : nTop = aPoint.Y();
1320 : }
1321 :
1322 : // determine bottom left corner
1323 : GetLineIntersectionPoint(aPoint,
1324 : Point(nRectLeft, nRectBottom), aRightHdg,
1325 34 : rDiagPoint, aDiagHdg);
1326 : // is there a point of intersection with the bottom border?
1327 34 : if (aPoint.X() >= nRectLeft)
1328 : {
1329 34 : nLeft = aPoint.X();
1330 34 : nBottom = nRectBottom;
1331 : }
1332 : else
1333 : {
1334 : // there has to be a point of intersection with the left border!
1335 : GetLineIntersectionPoint(aPoint,
1336 : Point(nRectLeft, nRectTop), aDownHdg,
1337 0 : rDiagPoint, aDiagHdg);
1338 :
1339 0 : nLeft = nRectLeft;
1340 0 : nBottom = aPoint.Y();
1341 : }
1342 : }
1343 : else
1344 : {
1345 : // determine top left corner
1346 : GetLineIntersectionPoint(aPoint,
1347 : Point(nRectLeft, nRectTop), aRightHdg,
1348 34 : rDiagPoint, aDiagHdg);
1349 : // is there a point of intersection with the top border?
1350 34 : if (aPoint.X() >= nRectLeft)
1351 : {
1352 34 : nLeft = aPoint.X();
1353 34 : nTop = nRectTop;
1354 : }
1355 : else
1356 : {
1357 : // there has to be a point of intersection with the left border!
1358 : GetLineIntersectionPoint(aPoint,
1359 : Point(nRectLeft, nRectTop), aDownHdg,
1360 0 : rDiagPoint, aDiagHdg);
1361 :
1362 0 : nLeft = nRectLeft;
1363 0 : nTop = aPoint.Y();
1364 : }
1365 :
1366 : // determine bottom right corner
1367 : GetLineIntersectionPoint(aPoint,
1368 : Point(nRectLeft, nRectBottom), aRightHdg,
1369 34 : rDiagPoint, aDiagHdg);
1370 : // is there a point of intersection with the bottom border?
1371 34 : if (aPoint.X() <= nRectRight)
1372 : {
1373 34 : nRight = aPoint.X();
1374 34 : nBottom = nRectBottom;
1375 : }
1376 : else
1377 : {
1378 : // there has to be a point of intersection with the right border!
1379 : GetLineIntersectionPoint(aPoint,
1380 : Point(nRectRight, nRectTop), aDownHdg,
1381 0 : rDiagPoint, aDiagHdg);
1382 :
1383 0 : nRight = nRectRight;
1384 0 : nBottom = aPoint.Y();
1385 : }
1386 : }
1387 :
1388 68 : rSize = Size(nRight - nLeft + 1, nBottom - nTop + 1);
1389 68 : rPos.X() = nLeft;
1390 68 : rPos.Y() = nTop;
1391 68 : }
1392 :
1393 :
1394 68 : void SmBinDiagonalNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1395 : {
1396 : // Both arguments have to get into the SubNodes before the Operator so that clicking
1397 : // within the GraphicWindow sets the FormulaCursor correctly (cf. SmRootNode)
1398 68 : SmNode *pLeft = GetSubNode(0),
1399 68 : *pRight = GetSubNode(1);
1400 : OSL_ENSURE(pLeft, "Sm : NULL pointer");
1401 : OSL_ENSURE(pRight, "Sm : NULL pointer");
1402 :
1403 : OSL_ENSURE(GetSubNode(2)->GetType() == NPOLYLINE, "Sm : wrong node type");
1404 68 : SmPolyLineNode *pOper = (SmPolyLineNode *) GetSubNode(2);
1405 : OSL_ENSURE(pOper, "Sm : NULL pointer");
1406 :
1407 : //! some routines being called extract some info from the OutputDevice's
1408 : //! font (eg the space to be used for borders OR the font name(!!)).
1409 : //! Thus the font should reflect the needs and has to be set!
1410 68 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
1411 68 : aTmpDev.SetFont(GetFont());
1412 :
1413 68 : pLeft->Arrange(aTmpDev, rFormat);
1414 68 : pRight->Arrange(aTmpDev, rFormat);
1415 :
1416 : // determine implicitly the values (incl. the margin) of the diagonal line
1417 68 : pOper->Arrange(aTmpDev, rFormat);
1418 :
1419 68 : long nDelta = pOper->GetWidth() * 8 / 10;
1420 :
1421 : // determine TopLeft position from the right argument
1422 68 : Point aPos;
1423 68 : aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace();
1424 68 : if (IsAscending())
1425 34 : aPos.Y() = pLeft->GetBottom() + nDelta;
1426 : else
1427 34 : aPos.Y() = pLeft->GetTop() - nDelta - pRight->GetHeight();
1428 :
1429 68 : pRight->MoveTo(aPos);
1430 :
1431 : // determine new baseline
1432 102 : long nTmpBaseline = IsAscending() ? (pLeft->GetBottom() + pRight->GetTop()) / 2
1433 102 : : (pLeft->GetTop() + pRight->GetBottom()) / 2;
1434 68 : Point aLogCenter ((pLeft->GetItalicRight() + pRight->GetItalicLeft()) / 2,
1435 68 : nTmpBaseline);
1436 :
1437 68 : SmRect::operator = (*pLeft);
1438 68 : ExtendBy(*pRight, RCP_NONE);
1439 :
1440 :
1441 : // determine position and size of diagonal line
1442 68 : Size aTmpSize;
1443 68 : GetOperPosSize(aPos, aTmpSize, aLogCenter, IsAscending() ? 60.0 : -60.0);
1444 :
1445 : // font specialist advised to change the width first
1446 68 : pOper->AdaptToY(aTmpDev, aTmpSize.Height());
1447 68 : pOper->AdaptToX(aTmpDev, aTmpSize.Width());
1448 : // and make it active
1449 68 : pOper->Arrange(aTmpDev, rFormat);
1450 :
1451 68 : pOper->MoveTo(aPos);
1452 :
1453 68 : ExtendBy(*pOper, RCP_NONE, nTmpBaseline);
1454 68 : }
1455 :
1456 :
1457 : /**************************************************************************/
1458 :
1459 :
1460 1480 : void SmSubSupNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1461 : {
1462 : OSL_ENSURE(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES,
1463 : "Sm: wrong number of subnodes");
1464 :
1465 1480 : SmNode *pBody = GetBody();
1466 : OSL_ENSURE(pBody, "Sm: NULL pointer");
1467 :
1468 1480 : long nOrigHeight = pBody->GetFont().GetSize().Height();
1469 :
1470 1480 : pBody->Arrange(rDev, rFormat);
1471 :
1472 1480 : const SmRect &rBodyRect = pBody->GetRect();
1473 1480 : SmRect::operator = (rBodyRect);
1474 :
1475 : // line that separates sub- and supscript rectangles
1476 1480 : long nDelimLine = SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1477 :
1478 1480 : Point aPos;
1479 : long nDelta, nDist;
1480 :
1481 : // iterate over all possible sub-/supscripts
1482 1480 : SmRect aTmpRect (rBodyRect);
1483 10360 : for (int i = 0; i < SUBSUP_NUM_ENTRIES; i++)
1484 8880 : { SmSubSup eSubSup = (SmSubSup) i; // cast
1485 8880 : SmNode *pSubSup = GetSubSup(eSubSup);
1486 :
1487 8880 : if (!pSubSup)
1488 6904 : continue;
1489 :
1490 : // switch position of limits if we are in textmode
1491 1976 : if (rFormat.IsTextmode() && (GetToken().nGroup & TGLIMIT))
1492 0 : switch (eSubSup)
1493 0 : { case CSUB: eSubSup = RSUB; break;
1494 0 : case CSUP: eSubSup = RSUP; break;
1495 : default:
1496 0 : break;
1497 : }
1498 :
1499 : // prevent sub-/supscripts from diminishing in size
1500 : // (as would be in "a_{1_{2_{3_4}}}")
1501 1976 : if (GetFont().GetSize().Height() > rFormat.GetBaseSize().Height() / 3)
1502 : {
1503 1652 : sal_uInt16 nIndex = (eSubSup == CSUB || eSubSup == CSUP) ?
1504 2594 : SIZ_LIMITS : SIZ_INDEX;
1505 1976 : Fraction aFraction ( rFormat.GetRelSize(nIndex), 100 );
1506 1976 : pSubSup->SetSize(aFraction);
1507 : }
1508 :
1509 1976 : pSubSup->Arrange(rDev, rFormat);
1510 :
1511 1976 : bool bIsTextmode = rFormat.IsTextmode();
1512 1976 : nDist = 0;
1513 :
1514 : //! be sure that CSUB, CSUP are handled before the other cases!
1515 1976 : switch (eSubSup)
1516 : { case RSUB :
1517 : case LSUB :
1518 472 : if (!bIsTextmode)
1519 : nDist = nOrigHeight
1520 472 : * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L;
1521 472 : aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1522 : eSubSup == LSUB ? RP_LEFT : RP_RIGHT,
1523 944 : RHA_CENTER, RVA_BOTTOM);
1524 472 : aPos.Y() += nDist;
1525 472 : nDelta = nDelimLine - aPos.Y();
1526 472 : if (nDelta > 0)
1527 472 : aPos.Y() += nDelta;
1528 472 : break;
1529 : case RSUP :
1530 : case LSUP :
1531 886 : if (!bIsTextmode)
1532 : nDist = nOrigHeight
1533 886 : * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L;
1534 886 : aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1535 : eSubSup == LSUP ? RP_LEFT : RP_RIGHT,
1536 1772 : RHA_CENTER, RVA_TOP);
1537 886 : aPos.Y() -= nDist;
1538 886 : nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
1539 886 : if (nDelta > 0)
1540 18 : aPos.Y() -= nDelta;
1541 886 : break;
1542 : case CSUB :
1543 324 : if (!bIsTextmode)
1544 : nDist = nOrigHeight
1545 324 : * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L;
1546 324 : aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM,
1547 324 : RHA_CENTER, RVA_BASELINE);
1548 324 : aPos.Y() += nDist;
1549 324 : break;
1550 : case CSUP :
1551 294 : if (!bIsTextmode)
1552 : nDist = nOrigHeight
1553 294 : * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L;
1554 294 : aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP,
1555 294 : RHA_CENTER, RVA_BASELINE);
1556 294 : aPos.Y() -= nDist;
1557 294 : break;
1558 : }
1559 :
1560 1976 : pSubSup->MoveTo(aPos);
1561 1976 : ExtendBy(*pSubSup, RCP_THIS, true);
1562 :
1563 : // update rectangle to which RSUB, RSUP, LSUB, LSUP
1564 : // will be aligned to
1565 1976 : if (eSubSup == CSUB || eSubSup == CSUP)
1566 618 : aTmpRect = *this;
1567 : }
1568 1480 : }
1569 :
1570 0 : void SmSubSupNode::CreateTextFromNode(OUString &rText)
1571 : {
1572 : SmNode *pNode;
1573 0 : GetSubNode(0)->CreateTextFromNode(rText);
1574 :
1575 0 : if (NULL != (pNode = GetSubNode(LSUB+1)))
1576 : {
1577 0 : rText += "lsub ";
1578 0 : pNode->CreateTextFromNode(rText);
1579 : }
1580 0 : if (NULL != (pNode = GetSubNode(LSUP+1)))
1581 : {
1582 0 : rText += "lsup ";
1583 0 : pNode->CreateTextFromNode(rText);
1584 : }
1585 0 : if (NULL != (pNode = GetSubNode(CSUB+1)))
1586 : {
1587 0 : rText += "csub ";
1588 0 : pNode->CreateTextFromNode(rText);
1589 : }
1590 0 : if (NULL != (pNode = GetSubNode(CSUP+1)))
1591 : {
1592 0 : rText += "csup ";
1593 0 : pNode->CreateTextFromNode(rText);
1594 : }
1595 0 : if (NULL != (pNode = GetSubNode(RSUB+1)))
1596 : {
1597 0 : rText = comphelper::string::stripEnd(rText, ' ');
1598 0 : rText += "_";
1599 0 : pNode->CreateTextFromNode(rText);
1600 : }
1601 0 : if (NULL != (pNode = GetSubNode(RSUP+1)))
1602 : {
1603 0 : rText = comphelper::string::stripEnd(rText, ' ');
1604 0 : rText += "^";
1605 0 : pNode->CreateTextFromNode(rText);
1606 : }
1607 0 : }
1608 :
1609 :
1610 : /**************************************************************************/
1611 :
1612 0 : void SmBraceNode::CreateTextFromNode(OUString &rText)
1613 : {
1614 0 : if (GetScaleMode() == SCALE_HEIGHT)
1615 0 : rText += "left ";
1616 : {
1617 0 : OUString aStr;
1618 0 : GetSubNode(0)->CreateTextFromNode(aStr);
1619 0 : aStr = comphelper::string::strip(aStr, ' ');
1620 0 : aStr = comphelper::string::stripStart(aStr, '\\');
1621 0 : if (!aStr.isEmpty())
1622 : {
1623 0 : if (aStr.equalsAscii("divides"))
1624 0 : rText += "lline";
1625 0 : else if (aStr.equalsAscii("parallel"))
1626 0 : rText += "ldline";
1627 0 : else if (aStr.equalsAscii("<"))
1628 0 : rText += "langle";
1629 : else
1630 0 : rText += aStr;
1631 0 : rText += " ";
1632 : }
1633 : else
1634 0 : rText += "none ";
1635 : }
1636 0 : GetSubNode(1)->CreateTextFromNode(rText);
1637 0 : if (GetScaleMode() == SCALE_HEIGHT)
1638 0 : rText += "right ";
1639 : {
1640 0 : OUString aStr;
1641 0 : GetSubNode(2)->CreateTextFromNode(aStr);
1642 0 : aStr = comphelper::string::strip(aStr, ' ');
1643 0 : aStr = comphelper::string::stripStart(aStr, '\\');
1644 0 : if (!aStr.isEmpty())
1645 : {
1646 0 : if (aStr.equalsAscii("divides"))
1647 0 : rText += "rline";
1648 0 : else if (aStr.equalsAscii("parallel"))
1649 0 : rText += "rdline";
1650 0 : else if (aStr.equalsAscii(">"))
1651 0 : rText += "rangle";
1652 : else
1653 0 : rText += aStr;
1654 0 : rText += " ";
1655 : }
1656 : else
1657 0 : rText += "none ";
1658 : }
1659 0 : rText += " ";
1660 :
1661 0 : }
1662 :
1663 876 : void SmBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1664 : {
1665 876 : SmNode *pLeft = GetSubNode(0),
1666 876 : *pBody = GetSubNode(1),
1667 876 : *pRight = GetSubNode(2);
1668 : OSL_ENSURE(pLeft, "Sm: NULL pointer");
1669 : OSL_ENSURE(pBody, "Sm: NULL pointer");
1670 : OSL_ENSURE(pRight, "Sm: NULL pointer");
1671 :
1672 876 : pBody->Arrange(rDev, rFormat);
1673 :
1674 876 : bool bIsScaleNormal = rFormat.IsScaleNormalBrackets(),
1675 2496 : bScale = pBody->GetHeight() > 0 &&
1676 1686 : (GetScaleMode() == SCALE_HEIGHT || bIsScaleNormal),
1677 876 : bIsABS = GetToken().eType == TABS;
1678 :
1679 876 : long nFaceHeight = GetFont().GetSize().Height();
1680 :
1681 : // determine oversize in %
1682 876 : sal_uInt16 nPerc = 0;
1683 876 : if (!bIsABS && bScale)
1684 : { // in case of oversize braces...
1685 810 : sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ?
1686 810 : DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1687 810 : nPerc = rFormat.GetDistance(nIndex);
1688 : }
1689 :
1690 : // determine the height for the braces
1691 : long nBraceHeight;
1692 876 : if (bScale)
1693 : {
1694 810 : nBraceHeight = pBody->GetType() == NBRACEBODY ?
1695 : ((SmBracebodyNode *) pBody)->GetBodyHeight()
1696 810 : : pBody->GetHeight();
1697 810 : nBraceHeight += 2 * (nBraceHeight * nPerc / 100L);
1698 : }
1699 : else
1700 66 : nBraceHeight = nFaceHeight;
1701 :
1702 : // distance to the argument
1703 876 : nPerc = bIsABS ? 0 : rFormat.GetDistance(DIS_BRACKETSPACE);
1704 876 : long nDist = nFaceHeight * nPerc / 100L;
1705 :
1706 : // if wanted, scale the braces to the wanted size
1707 876 : if (bScale)
1708 : {
1709 810 : Size aTmpSize (pLeft->GetFont().GetSize());
1710 : OSL_ENSURE(pRight->GetFont().GetSize() == aTmpSize,
1711 : "Sm : different font sizes");
1712 1620 : aTmpSize.Width() = std::min((long) nBraceHeight * 60L / 100L,
1713 1620 : rFormat.GetBaseSize().Height() * 3L / 2L);
1714 : // correction factor since change from StarMath to OpenSymbol font
1715 : // because of the different font width in the FontMetric
1716 810 : aTmpSize.Width() *= 182;
1717 810 : aTmpSize.Width() /= 267;
1718 :
1719 810 : sal_Unicode cChar = pLeft->GetToken().cMathChar;
1720 810 : if (cChar != MS_LINE && cChar != MS_DLINE &&
1721 774 : cChar != MS_VERTLINE && cChar != MS_DVERTLINE)
1722 738 : pLeft ->GetFont().SetSize(aTmpSize);
1723 :
1724 810 : cChar = pRight->GetToken().cMathChar;
1725 810 : if (cChar != MS_LINE && cChar != MS_DLINE &&
1726 774 : cChar != MS_VERTLINE && cChar != MS_DVERTLINE)
1727 738 : pRight->GetFont().SetSize(aTmpSize);
1728 :
1729 810 : pLeft ->AdaptToY(rDev, nBraceHeight);
1730 810 : pRight->AdaptToY(rDev, nBraceHeight);
1731 : }
1732 :
1733 876 : pLeft ->Arrange(rDev, rFormat);
1734 876 : pRight->Arrange(rDev, rFormat);
1735 :
1736 : // required in order to make "\(a\) - (a) - left ( a right )" look alright
1737 876 : RectVerAlign eVerAlign = bScale ? RVA_CENTERY : RVA_BASELINE;
1738 :
1739 876 : Point aPos;
1740 876 : aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign);
1741 876 : aPos.X() -= nDist;
1742 876 : pLeft->MoveTo(aPos);
1743 :
1744 876 : aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign);
1745 876 : aPos.X() += nDist;
1746 876 : pRight->MoveTo(aPos);
1747 :
1748 876 : SmRect::operator = (*pBody);
1749 876 : ExtendBy(*pLeft, RCP_THIS).ExtendBy(*pRight, RCP_THIS);
1750 876 : }
1751 :
1752 :
1753 : /**************************************************************************/
1754 :
1755 :
1756 876 : void SmBracebodyNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1757 : {
1758 876 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
1759 876 : if (nNumSubNodes == 0)
1760 942 : return;
1761 :
1762 : // arrange arguments
1763 : sal_uInt16 i;
1764 1728 : for (i = 0; i < nNumSubNodes; i += 2)
1765 918 : GetSubNode(i)->Arrange(rDev, rFormat);
1766 :
1767 : // build reference rectangle with necessary info for vertical alignment
1768 810 : SmRect aRefRect (*GetSubNode(0));
1769 1728 : for (i = 0; i < nNumSubNodes; i += 2)
1770 : {
1771 918 : SmRect aTmpRect (*GetSubNode(i));
1772 918 : Point aPos = aTmpRect.AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1773 918 : aTmpRect.MoveTo(aPos);
1774 918 : aRefRect.ExtendBy(aTmpRect, RCP_XOR);
1775 : }
1776 :
1777 810 : nBodyHeight = aRefRect.GetHeight();
1778 :
1779 : // scale separators to required height and arrange them
1780 810 : bool bScale = GetScaleMode() == SCALE_HEIGHT || rFormat.IsScaleNormalBrackets();
1781 810 : long nHeight = bScale ? aRefRect.GetHeight() : GetFont().GetSize().Height();
1782 810 : sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ?
1783 810 : DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1784 810 : sal_uInt16 nPerc = rFormat.GetDistance(nIndex);
1785 810 : if (bScale)
1786 810 : nHeight += 2 * (nHeight * nPerc / 100L);
1787 918 : for (i = 1; i < nNumSubNodes; i += 2)
1788 : {
1789 108 : SmNode *pNode = GetSubNode(i);
1790 108 : pNode->AdaptToY(rDev, nHeight);
1791 108 : pNode->Arrange(rDev, rFormat);
1792 : }
1793 :
1794 : // horizontal distance between argument and brackets or separators
1795 810 : long nDist = GetFont().GetSize().Height()
1796 810 : * rFormat.GetDistance(DIS_BRACKETSPACE) / 100L;
1797 :
1798 810 : SmNode *pLeft = GetSubNode(0);
1799 810 : SmRect::operator = (*pLeft);
1800 1026 : for (i = 1; i < nNumSubNodes; i++)
1801 : {
1802 216 : bool bIsSeparator = i % 2 != 0;
1803 216 : RectVerAlign eVerAlign = bIsSeparator ? RVA_CENTERY : RVA_BASELINE;
1804 :
1805 216 : SmNode *pRight = GetSubNode(i);
1806 216 : Point aPosX = pRight->AlignTo(*pLeft, RP_RIGHT, RHA_CENTER, eVerAlign),
1807 216 : aPosY = pRight->AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, eVerAlign);
1808 216 : aPosX.X() += nDist;
1809 :
1810 216 : pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
1811 216 : ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR);
1812 :
1813 216 : pLeft = pRight;
1814 : }
1815 : }
1816 :
1817 :
1818 : /**************************************************************************/
1819 :
1820 :
1821 72 : void SmVerticalBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1822 : {
1823 72 : SmNode *pBody = GetSubNode(0),
1824 72 : *pBrace = GetSubNode(1),
1825 72 : *pScript = GetSubNode(2);
1826 : OSL_ENSURE(pBody, "Sm: NULL pointer!");
1827 : OSL_ENSURE(pBrace, "Sm: NULL pointer!");
1828 : OSL_ENSURE(pScript, "Sm: NULL pointer!");
1829 :
1830 72 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
1831 72 : aTmpDev.SetFont(GetFont());
1832 :
1833 72 : pBody->Arrange(aTmpDev, rFormat);
1834 :
1835 : // size is the same as for limits for this part
1836 72 : pScript->SetSize( Fraction( rFormat.GetRelSize(SIZ_LIMITS), 100 ) );
1837 : // braces are a bit taller than usually
1838 72 : pBrace ->SetSize( Fraction(3, 2) );
1839 :
1840 72 : long nItalicWidth = pBody->GetItalicWidth();
1841 72 : if (nItalicWidth > 0)
1842 72 : pBrace->AdaptToX(aTmpDev, nItalicWidth);
1843 :
1844 72 : pBrace ->Arrange(aTmpDev, rFormat);
1845 72 : pScript->Arrange(aTmpDev, rFormat);
1846 :
1847 : // determine the relative position and the distances between each other
1848 : RectPos eRectPos;
1849 72 : long nFontHeight = pBody->GetFont().GetSize().Height();
1850 72 : long nDistBody = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
1851 72 : nDistScript = nFontHeight;
1852 72 : if (GetToken().eType == TOVERBRACE)
1853 : {
1854 36 : eRectPos = RP_TOP;
1855 36 : nDistBody = - nDistBody;
1856 36 : nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
1857 : }
1858 : else // TUNDERBRACE
1859 : {
1860 36 : eRectPos = RP_BOTTOM;
1861 36 : nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
1862 : }
1863 72 : nDistBody /= 100L;
1864 72 : nDistScript /= 100L;
1865 :
1866 72 : Point aPos = pBrace->AlignTo(*pBody, eRectPos, RHA_CENTER, RVA_BASELINE);
1867 72 : aPos.Y() += nDistBody;
1868 72 : pBrace->MoveTo(aPos);
1869 :
1870 72 : aPos = pScript->AlignTo(*pBrace, eRectPos, RHA_CENTER, RVA_BASELINE);
1871 72 : aPos.Y() += nDistScript;
1872 72 : pScript->MoveTo(aPos);
1873 :
1874 72 : SmRect::operator = (*pBody);
1875 72 : ExtendBy(*pBrace, RCP_THIS).ExtendBy(*pScript, RCP_THIS);
1876 72 : }
1877 :
1878 :
1879 : /**************************************************************************/
1880 :
1881 :
1882 328 : SmNode * SmOperNode::GetSymbol()
1883 : {
1884 328 : SmNode *pNode = GetSubNode(0);
1885 : OSL_ENSURE(pNode, "Sm: NULL pointer!");
1886 :
1887 328 : if (pNode->GetType() == NSUBSUP)
1888 322 : pNode = ((SmSubSupNode *) pNode)->GetBody();
1889 :
1890 : OSL_ENSURE(pNode, "Sm: NULL pointer!");
1891 328 : return pNode;
1892 : }
1893 :
1894 :
1895 324 : long SmOperNode::CalcSymbolHeight(const SmNode &rSymbol,
1896 : const SmFormat &rFormat) const
1897 : // returns the font height to be used for operator-symbol
1898 : {
1899 324 : long nHeight = GetFont().GetSize().Height();
1900 :
1901 324 : SmTokenType eTmpType = GetToken().eType;
1902 324 : if (eTmpType == TLIM || eTmpType == TLIMINF || eTmpType == TLIMSUP)
1903 30 : return nHeight;
1904 :
1905 294 : if (!rFormat.IsTextmode())
1906 : {
1907 : // set minimum size ()
1908 294 : nHeight += (nHeight * 20L) / 100L;
1909 :
1910 : nHeight += nHeight
1911 294 : * rFormat.GetDistance(DIS_OPERATORSIZE) / 100L;
1912 294 : nHeight = nHeight * 686L / 845L;
1913 : }
1914 :
1915 : // correct user-defined symbols to match height of sum from used font
1916 294 : if (rSymbol.GetToken().eType == TSPECIAL)
1917 0 : nHeight = nHeight * 845L / 686L;
1918 :
1919 294 : return nHeight;
1920 : }
1921 :
1922 :
1923 324 : void SmOperNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1924 : {
1925 324 : SmNode *pOper = GetSubNode(0);
1926 324 : SmNode *pBody = GetSubNode(1);
1927 :
1928 : OSL_ENSURE(pOper, "Sm: missing subnode");
1929 : OSL_ENSURE(pBody, "Sm: missing subnode");
1930 :
1931 324 : SmNode *pSymbol = GetSymbol();
1932 : pSymbol->SetSize(Fraction(CalcSymbolHeight(*pSymbol, rFormat),
1933 324 : pSymbol->GetFont().GetSize().Height()));
1934 :
1935 324 : pBody->Arrange(rDev, rFormat);
1936 324 : pOper->Arrange(rDev, rFormat);
1937 :
1938 324 : long nOrigHeight = GetFont().GetSize().Height(),
1939 : nDist = nOrigHeight
1940 324 : * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L;
1941 :
1942 324 : Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID);
1943 324 : aPos.X() -= nDist;
1944 324 : pOper->MoveTo(aPos);
1945 :
1946 324 : SmRect::operator = (*pBody);
1947 324 : ExtendBy(*pOper, RCP_THIS);
1948 324 : }
1949 :
1950 :
1951 : /**************************************************************************/
1952 :
1953 :
1954 0 : void SmAlignNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1955 : // set alignment within the entire subtree (including current node)
1956 : {
1957 : OSL_ENSURE(GetNumSubNodes() > 0, "Sm: missing subnode");
1958 :
1959 0 : SmNode *pNode = GetSubNode(0);
1960 :
1961 0 : RectHorAlign eHorAlign = RHA_CENTER;
1962 0 : switch (GetToken().eType)
1963 : {
1964 0 : case TALIGNL: eHorAlign = RHA_LEFT; break;
1965 0 : case TALIGNC: eHorAlign = RHA_CENTER; break;
1966 0 : case TALIGNR: eHorAlign = RHA_RIGHT; break;
1967 : default:
1968 0 : break;
1969 : }
1970 0 : SetRectHorAlign(eHorAlign);
1971 :
1972 0 : pNode->Arrange(rDev, rFormat);
1973 :
1974 0 : SmRect::operator = (pNode->GetRect());
1975 0 : }
1976 :
1977 :
1978 : /**************************************************************************/
1979 :
1980 :
1981 508 : void SmAttributNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1982 : {
1983 508 : SmNode *pAttr = GetSubNode(0),
1984 508 : *pBody = GetSubNode(1);
1985 : OSL_ENSURE(pBody, "Sm: body missing");
1986 : OSL_ENSURE(pAttr, "Sm: attribute missing");
1987 :
1988 508 : pBody->Arrange(rDev, rFormat);
1989 :
1990 508 : if (GetScaleMode() == SCALE_WIDTH)
1991 288 : pAttr->AdaptToX(rDev, pBody->GetItalicWidth());
1992 508 : pAttr->Arrange(rDev, rFormat);
1993 :
1994 : // get relative position of attribute
1995 : RectVerAlign eVerAlign;
1996 508 : long nDist = 0;
1997 508 : switch (GetToken().eType)
1998 : { case TUNDERLINE :
1999 36 : eVerAlign = RVA_ATTRIBUT_LO;
2000 36 : break;
2001 : case TOVERSTRIKE :
2002 36 : eVerAlign = RVA_ATTRIBUT_MID;
2003 36 : break;
2004 : default :
2005 436 : eVerAlign = RVA_ATTRIBUT_HI;
2006 436 : if (pBody->GetType() == NATTRIBUT)
2007 0 : nDist = GetFont().GetSize().Height()
2008 0 : * rFormat.GetDistance(DIS_ORNAMENTSPACE) / 100L;
2009 : }
2010 508 : Point aPos = pAttr->AlignTo(*pBody, RP_ATTRIBUT, RHA_CENTER, eVerAlign);
2011 508 : aPos.Y() -= nDist;
2012 508 : pAttr->MoveTo(aPos);
2013 :
2014 508 : SmRect::operator = (*pBody);
2015 508 : ExtendBy(*pAttr, RCP_THIS, true);
2016 508 : }
2017 :
2018 0 : void SmFontNode::CreateTextFromNode(OUString &rText)
2019 : {
2020 0 : switch (GetToken().eType)
2021 : {
2022 : case TBOLD:
2023 0 : rText += "bold ";
2024 0 : break;
2025 : case TNBOLD:
2026 0 : rText += "nbold ";
2027 0 : break;
2028 : case TITALIC:
2029 0 : rText += "italic ";
2030 0 : break;
2031 : case TNITALIC:
2032 0 : rText += "nitalic ";
2033 0 : break;
2034 : case TPHANTOM:
2035 0 : rText += "phantom ";
2036 0 : break;
2037 : case TSIZE:
2038 : {
2039 0 : rText += "size ";
2040 0 : switch (nSizeType)
2041 : {
2042 : case FNTSIZ_PLUS:
2043 0 : rText += "+";
2044 0 : break;
2045 : case FNTSIZ_MINUS:
2046 0 : rText += "-";
2047 0 : break;
2048 : case FNTSIZ_MULTIPLY:
2049 0 : rText += "*'";
2050 0 : break;
2051 : case FNTSIZ_DIVIDE:
2052 0 : rText += "/";
2053 0 : break;
2054 : case FNTSIZ_ABSOLUT:
2055 : default:
2056 0 : break;
2057 : }
2058 0 : rText += ::rtl::math::doubleToUString(
2059 : static_cast<double>(aFontSize),
2060 : rtl_math_StringFormat_Automatic,
2061 0 : rtl_math_DecimalPlaces_Max, '.', true);
2062 0 : rText += " ";
2063 : }
2064 0 : break;
2065 : case TBLACK:
2066 0 : rText += "color black ";
2067 0 : break;
2068 : case TWHITE:
2069 0 : rText += "color white ";
2070 0 : break;
2071 : case TRED:
2072 0 : rText += "color red ";
2073 0 : break;
2074 : case TGREEN:
2075 0 : rText += "color green ";
2076 0 : break;
2077 : case TBLUE:
2078 0 : rText += "color blue ";
2079 0 : break;
2080 : case TCYAN:
2081 0 : rText += "color cyan ";
2082 0 : break;
2083 : case TMAGENTA:
2084 0 : rText += "color magenta ";
2085 0 : break;
2086 : case TYELLOW:
2087 0 : rText += "color yellow ";
2088 0 : break;
2089 : case TTEAL:
2090 0 : rText += "color teal";
2091 0 : break;
2092 : case TSILVER:
2093 0 : rText += "color silver";
2094 0 : break;
2095 : case TGRAY:
2096 0 : rText += "color gray";
2097 0 : break;
2098 : case TMAROON:
2099 0 : rText += "color maroon";
2100 0 : break;
2101 : case TPURPLE:
2102 0 : rText += "color purple";
2103 0 : break;
2104 : case TLIME:
2105 0 : rText += "color lime";
2106 0 : break;
2107 : case TOLIVE:
2108 0 : rText += "color olive";
2109 0 : break;
2110 : case TNAVY:
2111 0 : rText += "color navy";
2112 0 : break;
2113 : case TAQUA:
2114 0 : rText += "color aqua";
2115 0 : break;
2116 : case TFUCHSIA:
2117 0 : rText += "color fuchsia";
2118 0 : break;
2119 : case TSANS:
2120 0 : rText += "font sans ";
2121 0 : break;
2122 : case TSERIF:
2123 0 : rText += "font serif ";
2124 0 : break;
2125 : case TFIXED:
2126 0 : rText += "font fixed ";
2127 0 : break;
2128 : default:
2129 0 : break;
2130 : }
2131 0 : GetSubNode(1)->CreateTextFromNode(rText);
2132 0 : }
2133 :
2134 188 : void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2135 : {
2136 : //! prepare subnodes first
2137 188 : SmNode::Prepare(rFormat, rDocShell);
2138 :
2139 188 : int nFnt = -1;
2140 188 : switch (GetToken().eType)
2141 : {
2142 4 : case TFIXED: nFnt = FNT_FIXED; break;
2143 4 : case TSANS: nFnt = FNT_SANS; break;
2144 4 : case TSERIF: nFnt = FNT_SERIF; break;
2145 : default:
2146 176 : break;
2147 : }
2148 188 : if (nFnt != -1)
2149 12 : { GetFont() = rFormat.GetFont( sal::static_int_cast< sal_uInt16 >(nFnt) );
2150 12 : SetFont(GetFont());
2151 : }
2152 :
2153 : //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
2154 : //! other font nodes (those with lower depth in the tree)
2155 188 : Flags() |= FLG_FONT;
2156 188 : }
2157 :
2158 120 : void SmFontNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2159 : {
2160 120 : SmNode *pNode = GetSubNode(1);
2161 : OSL_ENSURE(pNode, "Sm: missing subnode");
2162 :
2163 120 : switch (GetToken().eType)
2164 : { case TSIZE :
2165 120 : pNode->SetFontSize(aFontSize, nSizeType);
2166 120 : break;
2167 : case TSANS :
2168 : case TSERIF :
2169 : case TFIXED :
2170 0 : pNode->SetFont(GetFont());
2171 0 : break;
2172 0 : case TUNKNOWN : break; // no assertion on "font <?> <?>"
2173 :
2174 0 : case TPHANTOM : SetPhantom(true); break;
2175 0 : case TBOLD : SetAttribut(ATTR_BOLD); break;
2176 0 : case TITALIC : SetAttribut(ATTR_ITALIC); break;
2177 0 : case TNBOLD : ClearAttribut(ATTR_BOLD); break;
2178 0 : case TNITALIC : ClearAttribut(ATTR_ITALIC); break;
2179 :
2180 0 : case TBLACK : SetColor(Color(COL_BLACK)); break;
2181 0 : case TWHITE : SetColor(Color(COL_WHITE)); break;
2182 0 : case TRED : SetColor(Color(COL_LIGHTRED)); break;
2183 0 : case TGREEN : SetColor(Color(COL_GREEN)); break;
2184 0 : case TBLUE : SetColor(Color(COL_LIGHTBLUE)); break;
2185 0 : case TCYAN : SetColor(Color(COL_LIGHTCYAN)); break; // as in Calc
2186 0 : case TMAGENTA : SetColor(Color(COL_LIGHTMAGENTA)); break; // as in Calc
2187 0 : case TYELLOW : SetColor(Color(COL_YELLOW)); break;
2188 0 : case TTEAL : SetColor(Color(COL_CYAN)); break;
2189 0 : case TSILVER : SetColor(Color(COL_LIGHTGRAY)); break;
2190 0 : case TGRAY : SetColor(Color(COL_GRAY)); break;
2191 0 : case TMAROON : SetColor(Color(COL_RED)); break;
2192 0 : case TPURPLE : SetColor(Color(COL_MAGENTA)); break;
2193 0 : case TLIME : SetColor(Color(COL_LIGHTGREEN)); break;
2194 0 : case TOLIVE : SetColor(Color(COL_BROWN)); break;
2195 0 : case TNAVY : SetColor(Color(COL_BLUE)); break;
2196 0 : case TAQUA : SetColor(Color(COL_LIGHTCYAN)); break;
2197 0 : case TFUCHSIA : SetColor(Color(COL_LIGHTMAGENTA)); break;
2198 :
2199 : default:
2200 : SAL_WARN("starmath", "unknown case");
2201 : }
2202 :
2203 120 : pNode->Arrange(rDev, rFormat);
2204 :
2205 120 : SmRect::operator = (pNode->GetRect());
2206 120 : }
2207 :
2208 :
2209 124 : void SmFontNode::SetSizeParameter(const Fraction& rValue, sal_uInt16 Type)
2210 : {
2211 124 : nSizeType = Type;
2212 124 : aFontSize = rValue;
2213 124 : }
2214 :
2215 :
2216 : /**************************************************************************/
2217 :
2218 :
2219 68 : SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
2220 68 : : SmGraphicNode(NPOLYLINE, rNodeToken)
2221 : {
2222 68 : aPoly.SetSize(2);
2223 68 : nWidth = 0;
2224 68 : }
2225 :
2226 :
2227 68 : void SmPolyLineNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nNewWidth)
2228 : {
2229 68 : aToSize.Width() = nNewWidth;
2230 68 : }
2231 :
2232 :
2233 68 : void SmPolyLineNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nNewHeight)
2234 : {
2235 68 : GetFont().FreezeBorderWidth();
2236 68 : aToSize.Height() = nNewHeight;
2237 68 : }
2238 :
2239 :
2240 136 : void SmPolyLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2241 : {
2242 : //! some routines being called extract some info from the OutputDevice's
2243 : //! font (eg the space to be used for borders OR the font name(!!)).
2244 : //! Thus the font should reflect the needs and has to be set!
2245 136 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2246 136 : aTmpDev.SetFont(GetFont());
2247 :
2248 136 : long nBorderwidth = GetFont().GetBorderWidth();
2249 :
2250 : // create polygon using both endpoints
2251 : OSL_ENSURE(aPoly.GetSize() == 2, "Sm : wrong number of points");
2252 136 : Point aPointA, aPointB;
2253 136 : if (GetToken().eType == TWIDESLASH)
2254 : {
2255 68 : aPointA.X() = nBorderwidth;
2256 68 : aPointA.Y() = aToSize.Height() - nBorderwidth;
2257 68 : aPointB.X() = aToSize.Width() - nBorderwidth;
2258 68 : aPointB.Y() = nBorderwidth;
2259 : }
2260 : else
2261 : {
2262 : OSL_ENSURE(GetToken().eType == TWIDEBACKSLASH, "Sm : unexpected token");
2263 68 : aPointA.X() =
2264 68 : aPointA.Y() = nBorderwidth;
2265 68 : aPointB.X() = aToSize.Width() - nBorderwidth;
2266 68 : aPointB.Y() = aToSize.Height() - nBorderwidth;
2267 : }
2268 136 : aPoly.SetPoint(aPointA, 0);
2269 136 : aPoly.SetPoint(aPointB, 1);
2270 :
2271 136 : long nThick = GetFont().GetSize().Height()
2272 136 : * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L;
2273 136 : nWidth = nThick + 2 * nBorderwidth;
2274 :
2275 136 : SmRect::operator = (SmRect(aToSize.Width(), aToSize.Height()));
2276 136 : }
2277 :
2278 :
2279 : /**************************************************************************/
2280 :
2281 156 : void SmRootSymbolNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
2282 : {
2283 156 : nBodyWidth = nWidth;
2284 156 : }
2285 :
2286 :
2287 156 : void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2288 : {
2289 : // some additional length so that the horizontal
2290 : // bar will be positioned above the argument
2291 156 : SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / 10L);
2292 156 : }
2293 :
2294 :
2295 : /**************************************************************************/
2296 :
2297 :
2298 0 : void SmDynIntegralSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2299 : {
2300 0 : long nFactor = 12L;
2301 :
2302 : // The new height equals (1 + nFactor) * oldHeight
2303 : // nFactor was chosen for keeping the integral sign from becoming too "fat".
2304 0 : SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / nFactor);
2305 :
2306 : // keep the ratio
2307 0 : long nCurWidth = GetSize().Width();
2308 0 : SmMathSymbolNode::AdaptToX(rDev, nCurWidth + nCurWidth / nFactor);
2309 0 : }
2310 :
2311 :
2312 : /**************************************************************************/
2313 :
2314 :
2315 534 : void SmRectangleNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
2316 : {
2317 534 : aToSize.Width() = nWidth;
2318 534 : }
2319 :
2320 :
2321 462 : void SmRectangleNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nHeight)
2322 : {
2323 462 : GetFont().FreezeBorderWidth();
2324 462 : aToSize.Height() = nHeight;
2325 462 : }
2326 :
2327 :
2328 534 : void SmRectangleNode::Arrange(const OutputDevice &rDev, const SmFormat &/*rFormat*/)
2329 : {
2330 534 : long nFontHeight = GetFont().GetSize().Height();
2331 534 : long nWidth = aToSize.Width(),
2332 534 : nHeight = aToSize.Height();
2333 534 : if (nHeight == 0)
2334 72 : nHeight = nFontHeight / 30;
2335 534 : if (nWidth == 0)
2336 0 : nWidth = nFontHeight / 3;
2337 :
2338 534 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2339 534 : aTmpDev.SetFont(GetFont());
2340 :
2341 : // add some borderspace
2342 534 : sal_uLong nTmpBorderWidth = GetFont().GetBorderWidth();
2343 534 : nHeight += 2 * nTmpBorderWidth;
2344 :
2345 : //! use this method in order to have 'SmRect::HasAlignInfo() == true'
2346 : //! and thus having the attribute-fences updated in 'SmRect::ExtendBy'
2347 534 : SmRect::operator = (SmRect(nWidth, nHeight));
2348 534 : }
2349 :
2350 :
2351 : /**************************************************************************/
2352 :
2353 :
2354 7240 : SmTextNode::SmTextNode( SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 nFontDescP )
2355 : : SmVisibleNode(eNodeType, rNodeToken)
2356 : , nFontDesc(nFontDescP)
2357 : , nSelectionStart(0)
2358 7240 : , nSelectionEnd(0)
2359 : {
2360 7240 : }
2361 :
2362 9742 : SmTextNode::SmTextNode( const SmToken &rNodeToken, sal_uInt16 nFontDescP )
2363 : : SmVisibleNode(NTEXT, rNodeToken)
2364 : , nFontDesc(nFontDescP)
2365 : , nSelectionStart(0)
2366 9742 : , nSelectionEnd(0)
2367 : {
2368 9742 : }
2369 :
2370 9694 : void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2371 : {
2372 9694 : SmNode::Prepare(rFormat, rDocShell);
2373 :
2374 : // default setting for horizontal alignment of nodes with TTEXT
2375 : // content is as alignl (cannot be done in Arrange since it would
2376 : // override the settings made by an SmAlignNode before)
2377 9694 : if (TTEXT == GetToken().eType)
2378 156 : SetRectHorAlign( RHA_LEFT );
2379 :
2380 9694 : aText = GetToken().aText;
2381 9694 : GetFont() = rFormat.GetFont(GetFontDesc());
2382 :
2383 9694 : if (IsItalic( GetFont() ))
2384 6796 : Attributes() |= ATTR_ITALIC;
2385 9694 : if (IsBold( GetFont() ))
2386 64 : Attributes() |= ATTR_BOLD;
2387 :
2388 : // special handling for ':' where it is a token on it's own and is likely
2389 : // to be used for mathematical notations. (E.g. a:b = 2:3)
2390 : // In that case it should not be displayed in italic.
2391 9694 : if (GetToken().aText.getLength() == 1 && GetToken().aText[0] == ':')
2392 0 : Attributes() &= ~ATTR_ITALIC;
2393 9694 : };
2394 :
2395 :
2396 8410 : void SmTextNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2397 : {
2398 8410 : PrepareAttributes();
2399 :
2400 8410 : sal_uInt16 nSizeDesc = GetFontDesc() == FNT_FUNCTION ?
2401 8410 : SIZ_FUNCTION : SIZ_TEXT;
2402 8410 : GetFont() *= Fraction (rFormat.GetRelSize(nSizeDesc), 100);
2403 :
2404 8410 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2405 8410 : aTmpDev.SetFont(GetFont());
2406 :
2407 8410 : SmRect::operator = (SmRect(aTmpDev, &rFormat, aText, GetFont().GetBorderWidth()));
2408 8410 : }
2409 :
2410 0 : void SmTextNode::CreateTextFromNode(OUString &rText)
2411 : {
2412 0 : bool bQuoted=false;
2413 0 : if (GetToken().eType == TTEXT)
2414 : {
2415 0 : rText += "\"";
2416 0 : bQuoted=true;
2417 : }
2418 : else
2419 : {
2420 0 : SmParser aParseTest;
2421 0 : SmNode *pTable = aParseTest.Parse(GetToken().aText);
2422 0 : bQuoted=true;
2423 0 : if ( (pTable->GetType() == NTABLE) && (pTable->GetNumSubNodes() == 1) )
2424 : {
2425 0 : SmNode *pResult = pTable->GetSubNode(0);
2426 0 : if ( (pResult->GetType() == NLINE) &&
2427 0 : (pResult->GetNumSubNodes() == 1) )
2428 : {
2429 0 : pResult = pResult->GetSubNode(0);
2430 0 : if ( (pResult->GetType() == NEXPRESSION) &&
2431 0 : (pResult->GetNumSubNodes() == 1) )
2432 : {
2433 0 : pResult = pResult->GetSubNode(0);
2434 0 : if (pResult->GetType() == NTEXT)
2435 0 : bQuoted=false;
2436 : }
2437 : }
2438 : }
2439 0 : delete pTable;
2440 :
2441 0 : if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
2442 : {
2443 : //Search for existing functions and remove extraenous keyword
2444 0 : rText += "func ";
2445 : }
2446 0 : else if (bQuoted)
2447 0 : rText += "italic ";
2448 :
2449 0 : if (bQuoted)
2450 0 : rText += "\"";
2451 :
2452 : }
2453 :
2454 0 : rText += GetToken().aText;
2455 :
2456 0 : if (bQuoted)
2457 0 : rText += "\"";
2458 0 : rText += " ";
2459 0 : }
2460 :
2461 :
2462 0 : void SmTextNode::GetAccessibleText( OUStringBuffer &rText ) const
2463 : {
2464 0 : rText.append(aText);
2465 0 : }
2466 :
2467 26 : void SmTextNode::AdjustFontDesc()
2468 : {
2469 26 : if (GetToken().eType == TTEXT)
2470 0 : nFontDesc = FNT_TEXT;
2471 26 : else if(GetToken().eType == TFUNC)
2472 0 : nFontDesc = FNT_FUNCTION;
2473 : else {
2474 : SmTokenType nTok;
2475 26 : const SmTokenTableEntry *pEntry = SmParser::GetTokenTableEntry( aText );
2476 26 : if (pEntry && pEntry->nGroup == TGFUNCTION) {
2477 0 : nTok = pEntry->eType;
2478 0 : nFontDesc = FNT_FUNCTION;
2479 : } else {
2480 26 : sal_Unicode firstChar = aText[0];
2481 26 : if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',') {
2482 12 : nFontDesc = FNT_NUMBER;
2483 12 : nTok = TNUMBER;
2484 14 : } else if (aText.getLength() > 1) {
2485 0 : nFontDesc = FNT_VARIABLE;
2486 0 : nTok = TIDENT;
2487 : } else {
2488 14 : nFontDesc = FNT_VARIABLE;
2489 14 : nTok = TCHARACTER;
2490 : }
2491 : }
2492 26 : SmToken tok = GetToken();
2493 26 : tok.eType = nTok;
2494 26 : SetToken(tok);
2495 : }
2496 26 : }
2497 :
2498 1800 : sal_Unicode SmTextNode::ConvertSymbolToUnicode(sal_Unicode nIn)
2499 : {
2500 : //Find the best match in accepted unicode for our private area symbols
2501 : static const sal_Unicode aStarMathPrivateToUnicode[] =
2502 : {
2503 : 0x2030, 0xF613, 0xF612, 0x002B, 0x003C, 0x003E, 0xE425, 0xE421, 0xE088, 0x2208,
2504 : 0x0192, 0x2026, 0x2192, 0x221A, 0x221A, 0x221A, 0xE090, 0x005E, 0x02C7, 0x02D8,
2505 : 0x00B4, 0x0060, 0x02DC, 0x00AF, 0x0362, 0xE099, 0xE09A, 0x20DB, 0xE09C, 0xE09D,
2506 : 0x0028, 0x0029, 0x2220, 0x22AF, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7,
2507 : 0x002F, 0x005C, 0x274F, 0xE0AB, 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03A0,
2508 : 0x03a3, 0x03a5, 0x03a6, 0x03a8, 0x03A9, 0x03B1, 0x03B2, 0x03b3, 0x03b4, 0x03b5,
2509 : 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
2510 : 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03b5,
2511 : 0x03d1, 0x03d6, 0xE0D2, 0x03db, 0x2118, 0x2202, 0x2129, 0xE0D7, 0xE0D8, 0x22A4,
2512 : 0xE0DA, 0x2190, 0x2191, 0x2193
2513 : };
2514 1800 : if ((nIn >= 0xE080) && (nIn <= 0xE0DD))
2515 0 : nIn = aStarMathPrivateToUnicode[nIn-0xE080];
2516 :
2517 : //For whatever unicode glyph that equation editor doesn't ship with that
2518 : //we have a possible match we can munge it to.
2519 1800 : switch (nIn)
2520 : {
2521 : case 0x2223:
2522 0 : nIn = '|';
2523 0 : break;
2524 : default:
2525 1800 : break;
2526 : }
2527 :
2528 1800 : return nIn;
2529 : }
2530 :
2531 : /**************************************************************************/
2532 :
2533 0 : void SmMatrixNode::CreateTextFromNode(OUString &rText)
2534 : {
2535 0 : rText += "matrix {";
2536 0 : for (sal_uInt16 i = 0; i < nNumRows; i++)
2537 : {
2538 0 : for (sal_uInt16 j = 0; j < nNumCols; j++)
2539 : {
2540 0 : SmNode *pNode = GetSubNode(i * nNumCols + j);
2541 0 : if (pNode)
2542 0 : pNode->CreateTextFromNode(rText);
2543 0 : if (j != nNumCols-1)
2544 0 : rText += "# ";
2545 : }
2546 0 : if (i != nNumRows-1)
2547 0 : rText += "## ";
2548 : }
2549 0 : rText = comphelper::string::stripEnd(rText, ' ');
2550 0 : rText += "} ";
2551 0 : }
2552 :
2553 :
2554 36 : void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2555 : {
2556 : SmNode *pNode;
2557 : sal_uInt16 i, j;
2558 :
2559 : // initialize array that is to hold the maximum widths of all
2560 : // elements (subnodes) in that column.
2561 36 : long *pColWidth = new long[nNumCols];
2562 108 : for (j = 0; j < nNumCols; j++)
2563 72 : pColWidth[j] = 0;
2564 :
2565 : // arrange subnodes and calculate the aboves arrays contents
2566 36 : sal_uInt16 nNodes = GetNumSubNodes();
2567 180 : for (i = 0; i < nNodes; i++)
2568 : {
2569 144 : sal_uInt16 nIdx = nNodes - 1 - i;
2570 144 : if (NULL != (pNode = GetSubNode(nIdx)))
2571 : {
2572 144 : pNode->Arrange(rDev, rFormat);
2573 144 : int nCol = nIdx % nNumCols;
2574 144 : pColWidth[nCol] = std::max(pColWidth[nCol], pNode->GetItalicWidth());
2575 : }
2576 : }
2577 :
2578 : // norm distance from which the following two are calcutated
2579 36 : const long nNormDist = 3 * GetFont().GetSize().Height();
2580 :
2581 : // define horizontal and vertical minimal distances that separate
2582 : // the elements
2583 36 : long nHorDist = nNormDist * rFormat.GetDistance(DIS_MATRIXCOL) / 100L,
2584 36 : nVerDist = nNormDist * rFormat.GetDistance(DIS_MATRIXROW) / 100L;
2585 :
2586 : // build array that holds the leftmost position for each column
2587 36 : long *pColLeft = new long[nNumCols];
2588 36 : long nX = 0;
2589 108 : for (j = 0; j < nNumCols; j++)
2590 72 : { pColLeft[j] = nX;
2591 72 : nX += pColWidth[j] + nHorDist;
2592 : }
2593 :
2594 36 : Point aPos, aDelta;
2595 36 : SmRect aLineRect;
2596 36 : SmRect::operator = (SmRect());
2597 108 : for (i = 0; i < nNumRows; i++)
2598 72 : { aLineRect = SmRect();
2599 216 : for (j = 0; j < nNumCols; j++)
2600 144 : { SmNode *pTmpNode = GetSubNode(i * nNumCols + j);
2601 : OSL_ENSURE(pTmpNode, "Sm: NULL pointer");
2602 :
2603 144 : const SmRect &rNodeRect = pTmpNode->GetRect();
2604 :
2605 : // align all baselines in that row if possible
2606 144 : aPos = rNodeRect.AlignTo(aLineRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
2607 144 : aPos.X() += nHorDist;
2608 :
2609 : // get horizontal alignment
2610 144 : const SmNode *pCoNode = pTmpNode->GetLeftMost();
2611 144 : RectHorAlign eHorAlign = pCoNode->GetRectHorAlign();
2612 :
2613 : // caculate horizontal position of element depending on column
2614 : // and horizontal alignment
2615 144 : switch (eHorAlign)
2616 : { case RHA_LEFT:
2617 0 : aPos.X() = rNodeRect.GetLeft() + pColLeft[j];
2618 0 : break;
2619 : case RHA_CENTER:
2620 144 : aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2621 144 : + pColWidth[j] / 2
2622 144 : - rNodeRect.GetItalicCenterX();
2623 144 : break;
2624 : case RHA_RIGHT:
2625 0 : aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2626 0 : + pColWidth[j] - rNodeRect.GetItalicWidth();
2627 0 : break;
2628 : }
2629 :
2630 144 : pTmpNode->MoveTo(aPos);
2631 144 : aLineRect.ExtendBy(rNodeRect, RCP_XOR);
2632 : }
2633 :
2634 72 : aPos = aLineRect.AlignTo(*this, RP_BOTTOM, RHA_CENTER, RVA_BASELINE);
2635 72 : aPos.Y() += nVerDist;
2636 :
2637 : // move 'aLineRect' and rectangles in that line to final position
2638 72 : aDelta.X() = 0; // since horizontal alignment is already done
2639 72 : aDelta.Y() = aPos.Y() - aLineRect.GetTop();
2640 72 : aLineRect.Move(aDelta);
2641 216 : for (j = 0; j < nNumCols; j++)
2642 144 : if (NULL != (pNode = GetSubNode(i * nNumCols + j)))
2643 144 : pNode->Move(aDelta);
2644 :
2645 72 : ExtendBy(aLineRect, RCP_NONE);
2646 : }
2647 :
2648 36 : delete [] pColLeft;
2649 36 : delete [] pColWidth;
2650 36 : }
2651 :
2652 :
2653 44 : void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
2654 : {
2655 44 : nNumRows = nMatrixRows;
2656 44 : nNumCols = nMatrixCols;
2657 44 : }
2658 :
2659 :
2660 0 : SmNode * SmMatrixNode::GetLeftMost()
2661 : {
2662 0 : return this;
2663 : }
2664 :
2665 :
2666 : /**************************************************************************/
2667 :
2668 :
2669 5456 : SmMathSymbolNode::SmMathSymbolNode(const SmToken &rNodeToken)
2670 5456 : : SmSpecialNode(NMATH, rNodeToken, FNT_MATH)
2671 : {
2672 5456 : sal_Unicode cChar = GetToken().cMathChar;
2673 5456 : if ((sal_Unicode) '\0' != cChar)
2674 5404 : SetText(OUString(cChar));
2675 5456 : }
2676 :
2677 288 : void SmMathSymbolNode::AdaptToX(const OutputDevice &rDev, sal_uLong nWidth)
2678 : {
2679 : // Since there is no function to do this, we try to approximate it:
2680 288 : Size aFntSize (GetFont().GetSize());
2681 :
2682 : //! however the result is a bit better with 'nWidth' as initial font width
2683 288 : aFntSize.Width() = nWidth;
2684 288 : GetFont().SetSize(aFntSize);
2685 :
2686 288 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2687 288 : aTmpDev.SetFont(GetFont());
2688 :
2689 : // get denominator of error factor for width
2690 288 : long nTmpBorderWidth = GetFont().GetBorderWidth();
2691 288 : long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetItalicWidth();
2692 :
2693 : // scale fontwidth with this error factor
2694 288 : aFntSize.Width() *= nWidth;
2695 288 : aFntSize.Width() /= nDenom ? nDenom : 1;
2696 :
2697 288 : GetFont().SetSize(aFntSize);
2698 288 : }
2699 :
2700 1884 : void SmMathSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2701 : {
2702 1884 : GetFont().FreezeBorderWidth();
2703 1884 : Size aFntSize (GetFont().GetSize());
2704 :
2705 : // Since we only want to scale the height, we might have
2706 : // to determine the font width in order to keep it
2707 1884 : if (aFntSize.Width() == 0)
2708 : {
2709 408 : OutputDevice &rDevNC = (OutputDevice &) rDev;
2710 408 : rDevNC.Push(PushFlags::FONT | PushFlags::MAPMODE);
2711 408 : rDevNC.SetFont(GetFont());
2712 408 : aFntSize.Width() = rDev.GetFontMetric().GetSize().Width();
2713 408 : rDevNC.Pop();
2714 : }
2715 : OSL_ENSURE(aFntSize.Width() != 0, "Sm: ");
2716 :
2717 : //! however the result is a bit better with 'nHeight' as initial
2718 : //! font height
2719 1884 : aFntSize.Height() = nHeight;
2720 1884 : GetFont().SetSize(aFntSize);
2721 :
2722 1884 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2723 1884 : aTmpDev.SetFont(GetFont());
2724 :
2725 : // get denominator of error factor for height
2726 1884 : long nTmpBorderWidth = GetFont().GetBorderWidth();
2727 1884 : long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetHeight();
2728 :
2729 : // scale fontwidth with this error factor
2730 1884 : aFntSize.Height() *= nHeight;
2731 1884 : aFntSize.Height() /= nDenom ? nDenom : 1;
2732 :
2733 1884 : GetFont().SetSize(aFntSize);
2734 1884 : }
2735 :
2736 :
2737 5670 : void SmMathSymbolNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2738 : {
2739 5670 : SmNode::Prepare(rFormat, rDocShell);
2740 :
2741 5670 : GetFont() = rFormat.GetFont(GetFontDesc());
2742 : // use same font size as is used for variables
2743 5670 : GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
2744 :
2745 : OSL_ENSURE(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL ||
2746 : GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
2747 : "wrong charset for character from StarMath/OpenSymbol font");
2748 :
2749 5670 : Flags() |= FLG_FONT | FLG_ITALIC;
2750 5670 : };
2751 :
2752 :
2753 4798 : void SmMathSymbolNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2754 : {
2755 4798 : const OUString &rText = GetText();
2756 :
2757 4798 : if (rText.isEmpty() || rText[0] == '\0')
2758 48 : { SmRect::operator = (SmRect());
2759 4846 : return;
2760 : }
2761 :
2762 4750 : PrepareAttributes();
2763 :
2764 4750 : GetFont() *= Fraction (rFormat.GetRelSize(SIZ_TEXT), 100);
2765 :
2766 4750 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2767 4750 : aTmpDev.SetFont(GetFont());
2768 :
2769 4750 : SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
2770 : }
2771 :
2772 0 : void SmMathSymbolNode::CreateTextFromNode(OUString &rText)
2773 : {
2774 0 : OUString sStr;
2775 0 : MathType::LookupChar(GetToken().cMathChar, sStr);
2776 0 : rText += sStr;
2777 0 : }
2778 :
2779 0 : void SmRectangleNode::CreateTextFromNode(OUString &rText)
2780 : {
2781 0 : switch (GetToken().eType)
2782 : {
2783 : case TUNDERLINE:
2784 0 : rText += "underline ";
2785 0 : break;
2786 : case TOVERLINE:
2787 0 : rText += "overline ";
2788 0 : break;
2789 : case TOVERSTRIKE:
2790 0 : rText += "overstrike ";
2791 0 : break;
2792 : default:
2793 0 : break;
2794 : }
2795 0 : }
2796 :
2797 0 : void SmAttributNode::CreateTextFromNode(OUString &rText)
2798 : {
2799 : SmNode *pNode;
2800 0 : sal_uInt16 nSize = GetNumSubNodes();
2801 : OSL_ENSURE(nSize == 2, "Node missing members");
2802 0 : rText += "{";
2803 0 : sal_Unicode nLast=0;
2804 0 : if (NULL != (pNode = GetSubNode(0)))
2805 : {
2806 0 : OUString aStr;
2807 0 : pNode->CreateTextFromNode(aStr);
2808 0 : if (aStr.getLength() > 1)
2809 0 : rText += aStr;
2810 : else
2811 : {
2812 0 : nLast = aStr[0];
2813 0 : switch (nLast)
2814 : {
2815 : case MS_BAR: // MACRON
2816 0 : rText += "overline ";
2817 0 : break;
2818 : case MS_DOT: // DOT ABOVE
2819 0 : rText += "dot ";
2820 0 : break;
2821 : case 0x2dc: // SMALL TILDE
2822 0 : rText += "widetilde ";
2823 0 : break;
2824 : case MS_DDOT: // DIAERESIS
2825 0 : rText += "ddot ";
2826 0 : break;
2827 : case 0xE082:
2828 0 : break;
2829 : case 0xE09B:
2830 : case MS_DDDOT: // COMBINING THREE DOTS ABOVE
2831 0 : rText += "dddot ";
2832 0 : break;
2833 : case MS_ACUTE: // ACUTE ACCENT
2834 : case MS_COMBACUTE: // COMBINING ACUTE ACCENT
2835 0 : rText += "acute ";
2836 0 : break;
2837 : case MS_GRAVE: // GRAVE ACCENT
2838 : case MS_COMBGRAVE: // COMBINING GRAVE ACCENT
2839 0 : rText += "grave ";
2840 0 : break;
2841 : case MS_CHECK: // CARON
2842 : case MS_COMBCHECK: // COMBINING CARON
2843 0 : rText += "check ";
2844 0 : break;
2845 : case MS_BREVE: // BREVE
2846 : case MS_COMBBREVE: // COMBINING BREVE
2847 0 : rText += "breve ";
2848 0 : break;
2849 : case MS_CIRCLE: // RING ABOVE
2850 : case MS_COMBCIRCLE: // COMBINING RING ABOVE
2851 0 : rText += "circle ";
2852 0 : break;
2853 : case MS_RIGHTARROW: // RIGHTWARDS ARROW
2854 : case MS_VEC: // COMBINING RIGHT ARROW ABOVE
2855 0 : rText += "vec ";
2856 0 : break;
2857 : case MS_TILDE: // TILDE
2858 : case MS_COMBTILDE: // COMBINING TILDE
2859 0 : rText += "tilde ";
2860 0 : break;
2861 : case MS_HAT: // CIRCUMFLEX ACCENT
2862 : case MS_COMBHAT: // COMBINING CIRCUMFLEX ACCENT
2863 0 : rText += "hat ";
2864 0 : break;
2865 : case MS_COMBBAR: // COMBINING MACRON
2866 0 : rText += "bar ";
2867 0 : break;
2868 : default:
2869 0 : rText += OUString( nLast );
2870 0 : break;
2871 : }
2872 0 : }
2873 : }
2874 :
2875 0 : if (nSize == 2)
2876 0 : if (NULL != (pNode = GetSubNode(1)))
2877 0 : pNode->CreateTextFromNode(rText);
2878 :
2879 0 : rText = comphelper::string::stripEnd(rText, ' ');
2880 :
2881 0 : if (nLast == 0xE082)
2882 0 : rText += " overbrace {}";
2883 :
2884 0 : rText += "} ";
2885 0 : }
2886 :
2887 : /**************************************************************************/
2888 :
2889 7240 : static bool lcl_IsFromGreekSymbolSet( const OUString &rTokenText )
2890 : {
2891 7240 : bool bRes = false;
2892 :
2893 : // valid symbol name needs to have a '%' at pos 0 and at least an additional char
2894 7240 : if (rTokenText.getLength() > 2 && rTokenText[0] == (sal_Unicode)'%')
2895 : {
2896 262 : OUString aName( rTokenText.copy(1) );
2897 262 : SmSym *pSymbol = SM_MOD()->GetSymbolManager().GetSymbolByName( aName );
2898 262 : if (pSymbol && GetExportSymbolSetName(pSymbol->GetSymbolSetName()) == "Greek")
2899 212 : bRes = true;
2900 : }
2901 :
2902 7240 : return bRes;
2903 : }
2904 :
2905 :
2906 6978 : SmSpecialNode::SmSpecialNode(SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 _nFontDesc) :
2907 6978 : SmTextNode(eNodeType, rNodeToken, _nFontDesc)
2908 : {
2909 6978 : bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText );
2910 6978 : }
2911 :
2912 :
2913 262 : SmSpecialNode::SmSpecialNode(const SmToken &rNodeToken) :
2914 262 : SmTextNode(NSPECIAL, rNodeToken, FNT_MATH) // default Font isn't always correct!
2915 : {
2916 262 : bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText );
2917 262 : }
2918 :
2919 :
2920 262 : void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2921 : {
2922 262 : SmNode::Prepare(rFormat, rDocShell);
2923 :
2924 : const SmSym *pSym;
2925 262 : SmModule *pp = SM_MOD();
2926 :
2927 262 : OUString aName(GetToken().aText.copy(1));
2928 262 : if (NULL != (pSym = pp->GetSymbolManager().GetSymbolByName( aName )))
2929 : {
2930 260 : sal_UCS4 cChar = pSym->GetCharacter();
2931 260 : OUString aTmp( &cChar, 1 );
2932 260 : SetText( aTmp );
2933 260 : GetFont() = pSym->GetFace();
2934 : }
2935 : else
2936 : {
2937 2 : SetText( GetToken().aText );
2938 2 : GetFont() = rFormat.GetFont(FNT_VARIABLE);
2939 : }
2940 : // use same font size as is used for variables
2941 262 : GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
2942 :
2943 : // Actually only WEIGHT_NORMAL and WEIGHT_BOLD should occur... However, the sms-file also
2944 : // contains e.g. 'WEIGHT_ULTRALIGHT'. Consequently, compare here with '>' instead of '!='.
2945 : // (In the long term the necessity for 'PrepareAttribut' and thus also for this here should be dropped)
2946 :
2947 : //! see also SmFontStyles::GetStyleName
2948 262 : if (IsItalic( GetFont() ))
2949 2 : SetAttribut(ATTR_ITALIC);
2950 262 : if (IsBold( GetFont() ))
2951 0 : SetAttribut(ATTR_BOLD);
2952 :
2953 262 : Flags() |= FLG_FONT;
2954 :
2955 262 : if (bIsFromGreekSymbolSet)
2956 : {
2957 : OSL_ENSURE( GetText().getLength() == 1, "a symbol should only consist of 1 char!" );
2958 212 : bool bItalic = false;
2959 212 : sal_Int16 nStyle = rFormat.GetGreekCharStyle();
2960 : OSL_ENSURE( nStyle >= 0 && nStyle <= 2, "unexpected value for GreekCharStyle" );
2961 212 : if (nStyle == 1)
2962 0 : bItalic = true;
2963 212 : else if (nStyle == 2)
2964 : {
2965 0 : const OUString& rTmp(GetText());
2966 0 : if (rTmp.isEmpty())
2967 : {
2968 0 : const sal_Unicode cUppercaseAlpha = 0x0391;
2969 0 : const sal_Unicode cUppercaseOmega = 0x03A9;
2970 0 : sal_Unicode cChar = rTmp[0];
2971 : // uppercase letters should be straight and lowercase letters italic
2972 0 : bItalic = !(cUppercaseAlpha <= cChar && cChar <= cUppercaseOmega);
2973 : }
2974 : }
2975 :
2976 212 : if (bItalic)
2977 0 : Attributes() |= ATTR_ITALIC;
2978 : else
2979 212 : Attributes() &= ~ATTR_ITALIC;
2980 262 : }
2981 262 : };
2982 :
2983 :
2984 0 : void SmSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2985 : {
2986 0 : PrepareAttributes();
2987 :
2988 0 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2989 0 : aTmpDev.SetFont(GetFont());
2990 :
2991 0 : SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
2992 0 : }
2993 :
2994 : /**************************************************************************/
2995 :
2996 :
2997 0 : void SmGlyphSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2998 : {
2999 0 : PrepareAttributes();
3000 :
3001 0 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3002 0 : aTmpDev.SetFont(GetFont());
3003 :
3004 0 : SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(),
3005 0 : GetFont().GetBorderWidth()).AsGlyphRect());
3006 0 : }
3007 :
3008 :
3009 : /**************************************************************************/
3010 :
3011 :
3012 1234 : void SmPlaceNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3013 : {
3014 1234 : SmNode::Prepare(rFormat, rDocShell);
3015 :
3016 1234 : GetFont().SetColor(COL_GRAY);
3017 1234 : Flags() |= FLG_COLOR | FLG_FONT | FLG_ITALIC;
3018 1234 : };
3019 :
3020 :
3021 1234 : void SmPlaceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3022 : {
3023 1234 : PrepareAttributes();
3024 :
3025 1234 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3026 1234 : aTmpDev.SetFont(GetFont());
3027 :
3028 1234 : SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
3029 1234 : }
3030 :
3031 :
3032 : /**************************************************************************/
3033 :
3034 :
3035 48 : void SmErrorNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3036 : {
3037 48 : SmNode::Prepare(rFormat, rDocShell);
3038 :
3039 48 : GetFont().SetColor(COL_RED);
3040 48 : Flags() |= FLG_VISIBLE | FLG_BOLD | FLG_ITALIC
3041 48 : | FLG_COLOR | FLG_FONT | FLG_SIZE;
3042 48 : }
3043 :
3044 :
3045 48 : void SmErrorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3046 : {
3047 48 : PrepareAttributes();
3048 :
3049 48 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3050 48 : aTmpDev.SetFont(GetFont());
3051 :
3052 48 : const OUString &rText = GetText();
3053 48 : SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
3054 48 : }
3055 :
3056 :
3057 : /**************************************************************************/
3058 :
3059 :
3060 8 : void SmBlankNode::IncreaseBy(const SmToken &rToken)
3061 : {
3062 8 : switch(rToken.eType)
3063 : {
3064 4 : case TBLANK: nNum += 4; break;
3065 4 : case TSBLANK: nNum += 1; break;
3066 : default:
3067 0 : break;
3068 : }
3069 8 : }
3070 :
3071 :
3072 8 : void SmBlankNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3073 : {
3074 8 : SmNode::Prepare(rFormat, rDocShell);
3075 :
3076 : // Here it need/should not be the StarMath font, so that for the character
3077 : // used in Arrange a normal (non-clipped) rectangle is generated
3078 8 : GetFont() = rFormat.GetFont(FNT_VARIABLE);
3079 :
3080 8 : Flags() |= FLG_FONT | FLG_BOLD | FLG_ITALIC;
3081 8 : }
3082 :
3083 :
3084 0 : void SmBlankNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3085 : {
3086 0 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3087 0 : aTmpDev.SetFont(GetFont());
3088 :
3089 : // make distance depend on the font height
3090 : // (so that it increases when scaling (e.g. size *2 {a ~ b})
3091 0 : long nDist = GetFont().GetSize().Height() / 10L,
3092 0 : nSpace = nNum * nDist;
3093 :
3094 : // get a SmRect with Baseline and all the bells and whistles
3095 : SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString(' '),
3096 0 : GetFont().GetBorderWidth()));
3097 :
3098 : // and resize it to the requested size
3099 0 : SetItalicSpaces(0, 0);
3100 0 : SetWidth(nSpace);
3101 0 : }
3102 :
3103 : /**************************************************************************/
3104 : //Implementation of all accept methods for SmVisitor
3105 :
3106 0 : void SmNode::Accept(SmVisitor*){
3107 : //This method is only implemented to avoid making SmNode abstract because an
3108 : //obscure copy constructor is used... I can't find it's implementation, and
3109 : //don't want to figure out how to fix it... If you want to, just delete this
3110 : //method, making SmNode abstract, and see where you can an problem with that.
3111 : SAL_WARN("starmath", "SmNode should not be visitable!");
3112 0 : }
3113 :
3114 10176 : void SmTableNode::Accept(SmVisitor* pVisitor) {
3115 10176 : pVisitor->Visit(this);
3116 10176 : }
3117 :
3118 5132 : void SmBraceNode::Accept(SmVisitor* pVisitor) {
3119 5132 : pVisitor->Visit(this);
3120 5132 : }
3121 :
3122 5124 : void SmBracebodyNode::Accept(SmVisitor* pVisitor) {
3123 5124 : pVisitor->Visit(this);
3124 5124 : }
3125 :
3126 1856 : void SmOperNode::Accept(SmVisitor* pVisitor) {
3127 1856 : pVisitor->Visit(this);
3128 1856 : }
3129 :
3130 28 : void SmAlignNode::Accept(SmVisitor* pVisitor) {
3131 28 : pVisitor->Visit(this);
3132 28 : }
3133 :
3134 2932 : void SmAttributNode::Accept(SmVisitor* pVisitor) {
3135 2932 : pVisitor->Visit(this);
3136 2932 : }
3137 :
3138 68 : void SmFontNode::Accept(SmVisitor* pVisitor) {
3139 68 : pVisitor->Visit(this);
3140 68 : }
3141 :
3142 809 : void SmUnHorNode::Accept(SmVisitor* pVisitor) {
3143 809 : pVisitor->Visit(this);
3144 809 : }
3145 :
3146 7713 : void SmBinHorNode::Accept(SmVisitor* pVisitor) {
3147 7713 : pVisitor->Visit(this);
3148 7713 : }
3149 :
3150 2515 : void SmBinVerNode::Accept(SmVisitor* pVisitor) {
3151 2515 : pVisitor->Visit(this);
3152 2515 : }
3153 :
3154 34 : void SmBinDiagonalNode::Accept(SmVisitor* pVisitor) {
3155 34 : pVisitor->Visit(this);
3156 34 : }
3157 :
3158 8004 : void SmSubSupNode::Accept(SmVisitor* pVisitor) {
3159 8004 : pVisitor->Visit(this);
3160 8004 : }
3161 :
3162 212 : void SmMatrixNode::Accept(SmVisitor* pVisitor) {
3163 212 : pVisitor->Visit(this);
3164 212 : }
3165 :
3166 1567 : void SmPlaceNode::Accept(SmVisitor* pVisitor) {
3167 1567 : pVisitor->Visit(this);
3168 1567 : }
3169 :
3170 47574 : void SmTextNode::Accept(SmVisitor* pVisitor) {
3171 47574 : pVisitor->Visit(this);
3172 47574 : }
3173 :
3174 262 : void SmSpecialNode::Accept(SmVisitor* pVisitor) {
3175 262 : pVisitor->Visit(this);
3176 262 : }
3177 :
3178 0 : void SmGlyphSpecialNode::Accept(SmVisitor* pVisitor) {
3179 0 : pVisitor->Visit(this);
3180 0 : }
3181 :
3182 24373 : void SmMathSymbolNode::Accept(SmVisitor* pVisitor) {
3183 24373 : pVisitor->Visit(this);
3184 24373 : }
3185 :
3186 8 : void SmBlankNode::Accept(SmVisitor* pVisitor) {
3187 8 : pVisitor->Visit(this);
3188 8 : }
3189 :
3190 296 : void SmErrorNode::Accept(SmVisitor* pVisitor) {
3191 296 : pVisitor->Visit(this);
3192 296 : }
3193 :
3194 9086 : void SmLineNode::Accept(SmVisitor* pVisitor) {
3195 9086 : pVisitor->Visit(this);
3196 9086 : }
3197 :
3198 7193 : void SmExpressionNode::Accept(SmVisitor* pVisitor) {
3199 7193 : pVisitor->Visit(this);
3200 7193 : }
3201 :
3202 34 : void SmPolyLineNode::Accept(SmVisitor* pVisitor) {
3203 34 : pVisitor->Visit(this);
3204 34 : }
3205 :
3206 892 : void SmRootNode::Accept(SmVisitor* pVisitor) {
3207 892 : pVisitor->Visit(this);
3208 892 : }
3209 :
3210 884 : void SmRootSymbolNode::Accept(SmVisitor* pVisitor) {
3211 884 : pVisitor->Visit(this);
3212 884 : }
3213 :
3214 0 : void SmDynIntegralNode::Accept(SmVisitor* pVisitor) {
3215 0 : pVisitor->Visit(this);
3216 0 : }
3217 :
3218 :
3219 0 : void SmDynIntegralSymbolNode::Accept(SmVisitor* pVisitor) {
3220 0 : pVisitor->Visit(this);
3221 0 : }
3222 :
3223 2853 : void SmRectangleNode::Accept(SmVisitor* pVisitor) {
3224 2853 : pVisitor->Visit(this);
3225 2853 : }
3226 :
3227 416 : void SmVerticalBraceNode::Accept(SmVisitor* pVisitor) {
3228 416 : pVisitor->Visit(this);
3229 488 : }
3230 :
3231 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|