fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / starmath / source / node.cxx
blob469eee1b64ef2d6bc9932c0b940d26317a02c267
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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 "visitors.hxx"
30 #include <comphelper/string.hxx>
31 #include <tools/gen.hxx>
32 #include <tools/fract.hxx>
33 #include <rtl/math.hxx>
34 #include <tools/color.hxx>
35 #include <vcl/metric.hxx>
36 #include <vcl/lineinfo.hxx>
37 #include <vcl/outdev.hxx>
38 #include <sfx2/module.hxx>
40 #include <math.h>
41 #include <float.h>
44 ////////////////////////////////////////
45 // SmTmpDevice
46 // Allows for font and color changes. The original settings will be restored
47 // in the destructor.
48 // It's main purpose is to allow for the "const" in the 'OutputDevice'
49 // argument in the 'Arrange' functions and restore changes made in the 'Draw'
50 // functions.
51 // Usually a MapMode of 1/100th mm will be used.
54 class SmTmpDevice
56 OutputDevice &rOutDev;
58 // disallow use of copy-constructor and assignment-operator
59 SmTmpDevice(const SmTmpDevice &rTmpDev);
60 SmTmpDevice & operator = (const SmTmpDevice &rTmpDev);
62 Color Impl_GetColor( const Color& rColor );
64 public:
65 SmTmpDevice(OutputDevice &rTheDev, bool bUseMap100th_mm);
66 ~SmTmpDevice() { rOutDev.Pop(); }
68 void SetFont(const Font &rNewFont);
70 void SetLineColor( const Color& rColor ) { rOutDev.SetLineColor( Impl_GetColor(rColor) ); }
71 void SetFillColor( const Color& rColor ) { rOutDev.SetFillColor( Impl_GetColor(rColor) ); }
72 void SetTextColor( const Color& rColor ) { rOutDev.SetTextColor( Impl_GetColor(rColor) ); }
74 operator OutputDevice & () { return rOutDev; }
78 SmTmpDevice::SmTmpDevice(OutputDevice &rTheDev, bool bUseMap100th_mm) :
79 rOutDev(rTheDev)
81 rOutDev.Push( PUSH_FONT | PUSH_MAPMODE |
82 PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
83 if (bUseMap100th_mm && MAP_100TH_MM != rOutDev.GetMapMode().GetMapUnit())
85 OSL_FAIL( "incorrect MapMode?" );
86 rOutDev.SetMapMode( MAP_100TH_MM ); //Immer fuer 100% fomatieren
91 Color SmTmpDevice::Impl_GetColor( const Color& rColor )
93 ColorData nNewCol = rColor.GetColor();
94 if (COL_AUTO == nNewCol)
96 if (OUTDEV_PRINTER == rOutDev.GetOutDevType())
97 nNewCol = COL_BLACK;
98 else
100 Color aBgCol( rOutDev.GetBackground().GetColor() );
101 if (OUTDEV_WINDOW == rOutDev.GetOutDevType())
102 aBgCol = ((Window &) rOutDev).GetDisplayBackground().GetColor();
104 nNewCol = SM_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
106 Color aTmpColor( nNewCol );
107 if (aBgCol.IsDark() && aTmpColor.IsDark())
108 nNewCol = COL_WHITE;
109 else if (aBgCol.IsBright() && aTmpColor.IsBright())
110 nNewCol = COL_BLACK;
113 return Color( nNewCol );
117 void SmTmpDevice::SetFont(const Font &rNewFont)
119 rOutDev.SetFont( rNewFont );
120 rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor() ) );
124 ///////////////////////////////////////////////////////////////////////////
127 SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken)
129 eType = eNodeType;
130 eScaleMode = SCALE_NONE;
131 aNodeToken = rNodeToken;
132 nAccIndex = -1;
133 SetSelected(false);
134 aParentNode = NULL;
138 SmNode::~SmNode()
143 bool SmNode::IsVisible() const
145 return false;
149 sal_uInt16 SmNode::GetNumSubNodes() const
151 return 0;
155 SmNode * SmNode::GetSubNode(sal_uInt16 /*nIndex*/)
157 return NULL;
161 SmNode * SmNode::GetLeftMost()
162 // returns leftmost node of current subtree.
163 //! (this assumes the one with index 0 is always the leftmost subnode
164 //! for the current node).
166 SmNode *pNode = GetNumSubNodes() > 0 ?
167 GetSubNode(0) : NULL;
169 return pNode ? pNode->GetLeftMost() : this;
173 void SmNode::SetPhantom(bool bIsPhantomP)
175 if (! (Flags() & FLG_VISIBLE))
176 bIsPhantom = bIsPhantomP;
178 SmNode *pNode;
179 sal_uInt16 nSize = GetNumSubNodes();
180 for (sal_uInt16 i = 0; i < nSize; i++)
181 if (NULL != (pNode = GetSubNode(i)))
182 pNode->SetPhantom(bIsPhantom);
186 void SmNode::SetColor(const Color& rColor)
188 if (! (Flags() & FLG_COLOR))
189 GetFont().SetColor(rColor);
191 SmNode *pNode;
192 sal_uInt16 nSize = GetNumSubNodes();
193 for (sal_uInt16 i = 0; i < nSize; i++)
194 if (NULL != (pNode = GetSubNode(i)))
195 pNode->SetColor(rColor);
199 void SmNode::SetAttribut(sal_uInt16 nAttrib)
201 if (
202 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
203 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
206 nAttributes |= nAttrib;
209 SmNode *pNode;
210 sal_uInt16 nSize = GetNumSubNodes();
211 for (sal_uInt16 i = 0; i < nSize; i++)
212 if (NULL != (pNode = GetSubNode(i)))
213 pNode->SetAttribut(nAttrib);
217 void SmNode::ClearAttribut(sal_uInt16 nAttrib)
219 if (
220 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
221 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
224 nAttributes &= ~nAttrib;
227 SmNode *pNode;
228 sal_uInt16 nSize = GetNumSubNodes();
229 for (sal_uInt16 i = 0; i < nSize; i++)
230 if (NULL != (pNode = GetSubNode(i)))
231 pNode->ClearAttribut(nAttrib);
235 void SmNode::SetFont(const SmFace &rFace)
237 if (!(Flags() & FLG_FONT))
238 GetFont() = rFace;
240 SmNode *pNode;
241 sal_uInt16 nSize = GetNumSubNodes();
242 for (sal_uInt16 i = 0; i < nSize; i++)
243 if (NULL != (pNode = GetSubNode(i)))
244 pNode->SetFont(rFace);
248 void SmNode::SetFontSize(const Fraction &rSize, sal_uInt16 nType)
249 //! 'rSize' is in units of pts
251 Size aFntSize;
253 if (!(Flags() & FLG_SIZE))
255 Fraction aVal (SmPtsTo100th_mm(rSize.GetNumerator()),
256 rSize.GetDenominator());
257 long nHeight = (long)aVal;
259 aFntSize = GetFont().GetSize();
260 aFntSize.Width() = 0;
261 switch(nType)
263 case FNTSIZ_ABSOLUT:
264 aFntSize.Height() = nHeight;
265 break;
267 case FNTSIZ_PLUS:
268 aFntSize.Height() += nHeight;
269 break;
271 case FNTSIZ_MINUS:
272 aFntSize.Height() -= nHeight;
273 break;
275 case FNTSIZ_MULTIPLY:
276 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) * rSize);
277 break;
279 case FNTSIZ_DIVIDE:
280 if (rSize != Fraction(0L))
281 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) / rSize);
282 break;
283 default:
284 break;
287 // check the requested size against maximum value
288 static int const nMaxVal = SmPtsTo100th_mm(128);
289 if (aFntSize.Height() > nMaxVal)
290 aFntSize.Height() = nMaxVal;
292 GetFont().SetSize(aFntSize);
295 SmNode *pNode;
296 sal_uInt16 nSize = GetNumSubNodes();
297 for (sal_uInt16 i = 0; i < nSize; i++)
298 if (NULL != (pNode = GetSubNode(i)))
299 pNode->SetFontSize(rSize, nType);
303 void SmNode::SetSize(const Fraction &rSize)
305 GetFont() *= rSize;
307 SmNode *pNode;
308 sal_uInt16 nSize = GetNumSubNodes();
309 for (sal_uInt16 i = 0; i < nSize; i++)
310 if (NULL != (pNode = GetSubNode(i)))
311 pNode->SetSize(rSize);
315 void SmNode::SetRectHorAlign(RectHorAlign eHorAlign, bool bApplyToSubTree )
317 if (!(Flags() & FLG_HORALIGN))
318 eRectHorAlign = eHorAlign;
320 if (bApplyToSubTree)
322 SmNode *pNode;
323 sal_uInt16 nSize = GetNumSubNodes();
324 for (sal_uInt16 i = 0; i < nSize; i++)
325 if (NULL != (pNode = GetSubNode(i)))
326 pNode->SetRectHorAlign(eHorAlign);
331 void SmNode::PrepareAttributes()
333 GetFont().SetWeight((Attributes() & ATTR_BOLD) ? WEIGHT_BOLD : WEIGHT_NORMAL);
334 GetFont().SetItalic((Attributes() & ATTR_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE);
338 void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
340 #if OSL_DEBUG_LEVEL > 1
341 bIsDebug = true;
342 #else
343 bIsDebug = false;
344 #endif
345 bIsPhantom = false;
346 nFlags = 0;
347 nAttributes = 0;
349 switch (rFormat.GetHorAlign())
350 { case AlignLeft: eRectHorAlign = RHA_LEFT; break;
351 case AlignCenter: eRectHorAlign = RHA_CENTER; break;
352 case AlignRight: eRectHorAlign = RHA_RIGHT; break;
355 GetFont() = rFormat.GetFont(FNT_MATH);
356 OSL_ENSURE( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
357 "unexpected CharSet" );
358 GetFont().SetWeight(WEIGHT_NORMAL);
359 GetFont().SetItalic(ITALIC_NONE);
361 SmNode *pNode;
362 sal_uInt16 nSize = GetNumSubNodes();
363 for (sal_uInt16 i = 0; i < nSize; i++)
364 if (NULL != (pNode = GetSubNode(i)))
365 pNode->Prepare(rFormat, rDocShell);
368 sal_uInt16 SmNode::FindIndex() const
370 const SmStructureNode* pParent = GetParent();
371 if (!pParent) { return 0; }
373 for (sal_uInt16 i = 0; i < pParent->GetNumSubNodes(); ++i) {
374 if (pParent->GetSubNode(i) == this) {
375 return i;
379 DBG_ASSERT(false, "Connection between parent and child is inconsistent.");
380 return 0;
384 #if OSL_DEBUG_LEVEL > 1
385 void SmNode::ToggleDebug() const
386 // toggle 'bIsDebug' in current subtree
388 SmNode *pThis = (SmNode *) this;
390 pThis->bIsDebug = bIsDebug ? false : true;
392 SmNode *pNode;
393 sal_uInt16 nSize = GetNumSubNodes();
394 for (sal_uInt16 i = 0; i < nSize; i++)
395 if (NULL != (pNode = pThis->GetSubNode(i)))
396 pNode->ToggleDebug();
398 #endif
401 void SmNode::Move(const Point& rPosition)
403 if (rPosition.X() == 0 && rPosition.Y() == 0)
404 return;
406 SmRect::Move(rPosition);
408 SmNode *pNode;
409 sal_uInt16 nSize = GetNumSubNodes();
410 for (sal_uInt16 i = 0; i < nSize; i++)
411 if (NULL != (pNode = GetSubNode(i)))
412 pNode->Move(rPosition);
416 void SmNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
418 SmNode *pNode;
419 sal_uInt16 nSize = GetNumSubNodes();
420 for (sal_uInt16 i = 0; i < nSize; i++)
421 if (NULL != (pNode = GetSubNode(i)))
422 pNode->Arrange(rDev, rFormat);
425 void SmNode::CreateTextFromNode(String &rText)
427 SmNode *pNode;
428 sal_uInt16 nSize = GetNumSubNodes();
429 if (nSize > 1)
430 rText.Append('{');
431 for (sal_uInt16 i = 0; i < nSize; i++)
432 if (NULL != (pNode = GetSubNode(i)))
433 pNode->CreateTextFromNode(rText);
434 if (nSize > 1)
436 rText = comphelper::string::stripEnd(rText, ' ');
437 rText += "} ";
442 void SmNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong /*nWidth*/)
447 void SmNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong /*nHeight*/)
452 const SmNode * SmNode::FindTokenAt(sal_uInt16 nRow, sal_uInt16 nCol) const
453 // returns (first) ** visible ** (sub)node with the tokens text at
454 // position 'nRow', 'nCol'.
455 //! (there should be exactly one such node if any)
457 if ( IsVisible()
458 && nRow == GetToken().nRow
459 && nCol >= GetToken().nCol && nCol < GetToken().nCol + GetToken().aText.getLength())
460 return this;
461 else
463 sal_uInt16 nNumSubNodes = GetNumSubNodes();
464 for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
465 { const SmNode *pNode = GetSubNode(i);
467 if (!pNode)
468 continue;
470 const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
471 if (pResult)
472 return pResult;
476 return 0;
480 const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
482 long nDist = LONG_MAX;
483 const SmNode *pResult = 0;
485 if (IsVisible())
486 pResult = this;
487 else
489 sal_uInt16 nNumSubNodes = GetNumSubNodes();
490 for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
491 { const SmNode *pNode = GetSubNode(i);
493 if (!pNode)
494 continue;
496 long nTmp;
497 const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
498 if (pFound && (nTmp = pFound->OrientedDist(rPoint)) < nDist)
499 { nDist = nTmp;
500 pResult = pFound;
502 // quit immediately if 'rPoint' is inside the *should not
503 // overlap with other rectangles* part.
504 // This (partly) serves for getting the attributes in eg
505 // "bar overstrike a".
506 // ('nDist < 0' is used as *quick shot* to avoid evaluation of
507 // the following expression, where the result is already determined)
508 if (nDist < 0 && pFound->IsInsideRect(rPoint))
509 break;
514 return pResult;
517 void SmNode::GetAccessibleText( OUStringBuffer &/*rText*/ ) const
519 OSL_FAIL( "SmNode: GetAccessibleText not overloaded" );
522 const SmNode * SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx) const
524 const SmNode *pResult = 0;
526 sal_Int32 nIdx = GetAccessibleIndex();
527 OUStringBuffer aTxt;
528 if (nIdx >= 0)
529 GetAccessibleText( aTxt ); // get text if used in following 'if' statement
531 if (nIdx >= 0
532 && nIdx <= nAccIdx && nAccIdx < nIdx + aTxt.getLength())
533 pResult = this;
534 else
536 sal_uInt16 nNumSubNodes = GetNumSubNodes();
537 for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
539 const SmNode *pNode = GetSubNode(i);
540 if (!pNode)
541 continue;
543 pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
544 if (pResult)
545 return pResult;
549 return pResult;
552 #ifdef DEBUG_ENABLE_DUMPASDOT
553 void SmNode::DumpAsDot(std::ostream &out, OUString* label, int number, int& id, int parent) const
555 //If this is the root start the file
556 if(number == -1){
557 out<<"digraph {"<<std::endl;
558 if(label){
559 out<<"labelloc = \"t\";"<<std::endl;
560 OUString eq(*label);
561 //CreateTextFromNode(eq);
562 eq = eq.replaceAll("\n", " ");
563 eq = eq.replaceAll("\\", "\\\\");
564 eq = eq.replaceAll("\"", "\\\"");
565 out<<"label= \"Equation: \\\"";
566 out<< OUStringToOString(eq, RTL_TEXTENCODING_UTF8).getStr();
567 out<<"\\\"\";"<<std::endl;
571 //Some how out<<(int)this; doesn't work... So we do this nasty workaround...
572 char strid[100];
573 sprintf(strid, "%i", id);
575 char strnr[100];
576 sprintf(strnr, "%i", number);
578 //Dump connection to this node
579 if( parent != -1 ){
580 char pid[100];
581 sprintf(pid, "%i", parent);
582 out<<"n"<<pid<<" -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
583 //If doesn't have parent and isn't a rootnode:
584 } else if(number != -1) {
585 out<<"orphaned -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
588 //Dump this node
589 out<<"n"<< strid<<" [label=\"";
590 switch( GetType() ) {
591 case NTABLE: out<<"SmTableNode"; break;
592 case NBRACE: out<<"SmBraceNode"; break;
593 case NBRACEBODY: out<<"SmBracebodyNode"; break;
594 case NOPER: out<<"SmOperNode"; break;
595 case NALIGN: out<<"SmAlignNode"; break;
596 case NATTRIBUT: out<<"SmAttributNode"; break;
597 case NFONT: out<<"SmFontNode"; break;
598 case NUNHOR: out<<"SmUnHorNode"; break;
599 case NBINHOR: out<<"SmBinHorNode"; break;
600 case NBINVER: out<<"SmBinVerNode"; break;
601 case NBINDIAGONAL: out<<"SmBinDiagonalNode"; break;
602 case NSUBSUP: out<<"SmSubSupNode"; break;
603 case NMATRIX: out<<"SmMatrixNode"; break;
604 case NPLACE: out<<"SmPlaceNode"; break;
605 case NTEXT:
606 out<<"SmTextNode: ";
607 out<< OUStringToOString(((SmTextNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).getStr();
608 break;
609 case NSPECIAL: out<<"SmSpecialNode"; break;
610 case NGLYPH_SPECIAL: out<<"SmGlyphSpecialNode"; break;
611 case NMATH:
612 out<<"SmMathSymbolNode: ";
613 out<< OUStringToOString(((SmMathSymbolNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).getStr();
614 break;
615 case NBLANK: out<<"SmBlankNode"; break;
616 case NERROR: out<<"SmErrorNode"; break;
617 case NLINE: out<<"SmLineNode"; break;
618 case NEXPRESSION: out<<"SmExpressionNode"; break;
619 case NPOLYLINE: out<<"SmPolyLineNode"; break;
620 case NROOT: out<<"SmRootNode"; break;
621 case NROOTSYMBOL: out<<"SmRootSymbolNode"; break;
622 case NRECTANGLE: out<<"SmRectangleNode"; break;
623 case NVERTICAL_BRACE: out<<"SmVerticalBraceNode"; break;
624 default:
625 out<<"Unknown Node";
627 out<<"\"";
628 if(IsSelected())
629 out<<", style=dashed";
630 out<<"];"<<std::endl;
632 //Dump subnodes
633 int myid = id;
634 const SmNode *pNode;
635 sal_uInt16 nSize = GetNumSubNodes();
636 for (sal_uInt16 i = 0; i < nSize; i++)
637 if (NULL != (pNode = GetSubNode(i)))
638 pNode->DumpAsDot(out, NULL, i, ++id, myid);
640 //If this is the root end the file
641 if( number == -1 )
642 out<<"}"<<std::endl;
644 #endif /* DEBUG_ENABLE_DUMPASDOT */
646 long SmNode::GetFormulaBaseline() const
648 OSL_FAIL( "This dummy implementation should not have been called." );
649 return 0;
652 ///////////////////////////////////////////////////////////////////////////
654 SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
655 SmNode( rNode.GetType(), rNode.GetToken() )
657 sal_uLong i;
658 for (i = 0; i < aSubNodes.size(); i++)
659 delete aSubNodes[i];
660 aSubNodes.resize(0);
662 sal_uLong nSize = rNode.aSubNodes.size();
663 aSubNodes.resize( nSize );
664 for (i = 0; i < nSize; ++i)
666 SmNode *pNode = rNode.aSubNodes[i];
667 aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
669 ClaimPaternity();
673 SmStructureNode::~SmStructureNode()
675 SmNode *pNode;
677 for (sal_uInt16 i = 0; i < GetNumSubNodes(); i++)
678 if (NULL != (pNode = GetSubNode(i)))
679 delete pNode;
683 SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
685 SmNode::operator = ( rNode );
687 sal_uLong i;
688 for (i = 0; i < aSubNodes.size(); i++)
689 delete aSubNodes[i];
690 aSubNodes.resize(0);
692 sal_uLong nSize = rNode.aSubNodes.size();
693 aSubNodes.resize( nSize );
694 for (i = 0; i < nSize; ++i)
696 SmNode *pNode = rNode.aSubNodes[i];
697 aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
700 ClaimPaternity();
702 return *this;
706 void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThird)
708 size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0));
709 aSubNodes.resize( nSize );
710 if (pFirst)
711 aSubNodes[0] = pFirst;
712 if (pSecond)
713 aSubNodes[1] = pSecond;
714 if (pThird)
715 aSubNodes[2] = pThird;
717 ClaimPaternity();
721 void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
723 aSubNodes = rNodeArray;
724 ClaimPaternity();
728 bool SmStructureNode::IsVisible() const
730 return false;
734 sal_uInt16 SmStructureNode::GetNumSubNodes() const
736 return (sal_uInt16) aSubNodes.size();
740 SmNode * SmStructureNode::GetSubNode(sal_uInt16 nIndex)
742 return aSubNodes[nIndex];
746 void SmStructureNode::GetAccessibleText( OUStringBuffer &rText ) const
748 sal_uInt16 nNodes = GetNumSubNodes();
749 for (sal_uInt16 i = 0; i < nNodes; ++i)
751 const SmNode *pNode = ((SmStructureNode *) this)->GetSubNode(i);
752 if (pNode)
754 if (pNode->IsVisible())
755 ((SmStructureNode *) pNode)->nAccIndex = rText.getLength();
756 pNode->GetAccessibleText( rText );
761 ///////////////////////////////////////////////////////////////////////////
764 bool SmVisibleNode::IsVisible() const
766 return true;
770 sal_uInt16 SmVisibleNode::GetNumSubNodes() const
772 return 0;
776 SmNode * SmVisibleNode::GetSubNode(sal_uInt16 /*nIndex*/)
778 return NULL;
782 ///////////////////////////////////////////////////////////////////////////
784 void SmGraphicNode::GetAccessibleText( OUStringBuffer &rText ) const
786 rText.append(GetToken().aText);
789 ///////////////////////////////////////////////////////////////////////////
792 void SmExpressionNode::CreateTextFromNode(String &rText)
794 SmNode *pNode;
795 sal_uInt16 nSize = GetNumSubNodes();
796 if (nSize > 1)
797 rText.Append('{');
798 for (sal_uInt16 i = 0; i < nSize; i++)
799 if (NULL != (pNode = GetSubNode(i)))
801 pNode->CreateTextFromNode(rText);
802 //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
803 if (pNode->GetType() == NMATH)
804 if ((nSize != 2) || ((rText.GetChar(rText.Len()-1) != '+') &&
805 (rText.GetChar(rText.Len()-1) != '-')))
806 rText.Append(' ');
809 if (nSize > 1)
811 rText = comphelper::string::stripEnd(rText, ' ');
812 rText += "} ";
817 ///////////////////////////////////////////////////////////////////////////
819 void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
820 // arranges all subnodes in one column
822 SmNode *pNode;
823 sal_uInt16 nSize = GetNumSubNodes();
825 // make distance depend on font size
826 long nDist = +(rFormat.GetDistance(DIS_VERTICAL)
827 * GetFont().GetSize().Height()) / 100L;
829 if (nSize < 1)
830 return;
832 // arrange subnodes and get maximum width of them
833 long nMaxWidth = 0,
834 nTmp;
835 sal_uInt16 i;
836 for (i = 0; i < nSize; i++)
837 if (NULL != (pNode = GetSubNode(i)))
838 { pNode->Arrange(rDev, rFormat);
839 if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
840 nMaxWidth = nTmp;
843 Point aPos;
844 SmRect::operator = (SmRect(nMaxWidth, 1));
845 for (i = 0; i < nSize; i++)
846 { if (NULL != (pNode = GetSubNode(i)))
847 { const SmRect &rNodeRect = pNode->GetRect();
848 const SmNode *pCoNode = pNode->GetLeftMost();
849 RectHorAlign eHorAlign = pCoNode->GetRectHorAlign();
851 aPos = rNodeRect.AlignTo(*this, RP_BOTTOM,
852 eHorAlign, RVA_BASELINE);
853 if (i)
854 aPos.Y() += nDist;
855 pNode->MoveTo(aPos);
856 ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG);
859 // #i972#
860 if (HasBaseline())
861 nFormulaBaseline = GetBaseline();
862 else
864 SmTmpDevice aTmpDev ((OutputDevice &) rDev, sal_True);
865 aTmpDev.SetFont(GetFont());
867 SmRect aRect = (SmRect(aTmpDev, &rFormat, OUString("a"),
868 GetFont().GetBorderWidth()));
869 nFormulaBaseline = GetAlignM();
870 // move from middle position by constant - distance
871 // between middle and baseline for single letter
872 nFormulaBaseline += aRect.GetBaseline() - aRect.GetAlignM();
877 SmNode * SmTableNode::GetLeftMost()
879 return this;
883 long SmTableNode::GetFormulaBaseline() const
885 return nFormulaBaseline;
889 /**************************************************************************/
892 void SmLineNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
894 SmNode::Prepare(rFormat, rDocShell);
896 // Here we use the 'FNT_VARIABLE' font since it's ascent and descent in general fit better
897 // to the rest of the formula compared to the 'FNT_MATH' font.
898 GetFont() = rFormat.GetFont(FNT_VARIABLE);
899 Flags() |= FLG_FONT;
903 /**************************************************************************/
906 void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
907 // arranges all subnodes in one row with some extra space between
909 SmNode *pNode;
910 sal_uInt16 nSize = GetNumSubNodes();
911 sal_uInt16 i;
912 for (i = 0; i < nSize; i++)
913 if (NULL != (pNode = GetSubNode(i)))
914 pNode->Arrange(rDev, rFormat);
916 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
917 aTmpDev.SetFont(GetFont());
919 if (nSize < 1)
921 // provide an empty rectangle with alignment parameters for the "current"
922 // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
923 // same sub-/supscript positions.)
924 //! be sure to use a character that has explicitly defined HiAttribut
925 //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
926 //! 'vec {a}'.
927 SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString("a"),
928 GetFont().GetBorderWidth()));
929 // make sure that the rectangle occupies (almost) no space
930 SetWidth(1);
931 SetItalicSpaces(0, 0);
932 return;
935 // make distance depend on font size
936 long nDist = (rFormat.GetDistance(DIS_HORIZONTAL) * GetFont().GetSize().Height()) / 100L;
937 if (!IsUseExtraSpaces())
938 nDist = 0;
940 Point aPos;
941 // copy the first node into LineNode and extend by the others
942 if (NULL != (pNode = GetSubNode(0)))
943 SmRect::operator = (pNode->GetRect());
945 for (i = 1; i < nSize; i++)
946 if (NULL != (pNode = GetSubNode(i)))
948 aPos = pNode->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
950 // add horizontal space to the left for each but the first sub node
951 aPos.X() += nDist;
953 pNode->MoveTo(aPos);
954 ExtendBy( *pNode, RCP_XOR );
959 /**************************************************************************/
962 void SmExpressionNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
963 // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
965 SmLineNode::Arrange(rDev, rFormat);
967 // copy alignment of leftmost subnode if any
968 SmNode *pNode = GetLeftMost();
969 if (pNode)
970 SetRectHorAlign(pNode->GetRectHorAlign(), false);
974 /**************************************************************************/
977 void SmUnHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
979 bool bIsPostfix = GetToken().eType == TFACT;
981 SmNode *pOper = GetSubNode(bIsPostfix ? 1 : 0),
982 *pBody = GetSubNode(bIsPostfix ? 0 : 1);
983 OSL_ENSURE(pOper, "Sm: NULL pointer");
984 OSL_ENSURE(pBody, "Sm: NULL pointer");
986 pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
987 pOper->Arrange(rDev, rFormat);
988 pBody->Arrange(rDev, rFormat);
990 Point aPos = pOper->AlignTo(*pBody, bIsPostfix ? RP_RIGHT : RP_LEFT,
991 RHA_CENTER, RVA_BASELINE);
992 // add a bit space between operator and argument
993 // (worst case -{1 over 2} where - and over have almost no space inbetween)
994 long nDelta = pOper->GetFont().GetSize().Height() / 20;
995 if (bIsPostfix)
996 aPos.X() += nDelta;
997 else
998 aPos.X() -= nDelta;
999 pOper->MoveTo(aPos);
1001 SmRect::operator = (*pBody);
1002 long nOldBot = GetBottom();
1004 ExtendBy(*pOper, RCP_XOR);
1006 // workaround for Bug 50865: "a^2 a^+2" have different baselines
1007 // for exponents (if size of exponent is large enough)
1008 SetBottom(nOldBot);
1012 /**************************************************************************/
1015 void SmRootNode::GetHeightVerOffset(const SmRect &rRect,
1016 long &rHeight, long &rVerOffset) const
1017 // calculate height and vertical offset of root sign suitable for 'rRect'
1019 rVerOffset = (rRect.GetBottom() - rRect.GetAlignB()) / 2;
1020 rHeight = rRect.GetHeight() - rVerOffset;
1022 OSL_ENSURE(rHeight >= 0, "Sm : Ooops...");
1023 OSL_ENSURE(rVerOffset >= 0, "Sm : Ooops...");
1027 Point SmRootNode::GetExtraPos(const SmRect &rRootSymbol,
1028 const SmRect &rExtra) const
1030 const Size &rSymSize = rRootSymbol.GetSize();
1032 Point aPos = rRootSymbol.GetTopLeft()
1033 + Point((rSymSize.Width() * 70) / 100,
1034 (rSymSize.Height() * 52) / 100);
1036 // from this calculate topleft edge of 'rExtra'
1037 aPos.X() -= rExtra.GetWidth() + rExtra.GetItalicRightSpace();
1038 aPos.Y() -= rExtra.GetHeight();
1039 // if there's enough space move a bit less to the right
1040 // examples: "nroot i a", "nroot j a"
1041 // (it looks better if we don't use italic-spaces here)
1042 long nX = rRootSymbol.GetLeft() + (rSymSize.Width() * 30) / 100;
1043 if (aPos.X() > nX)
1044 aPos.X() = nX;
1046 return aPos;
1050 void SmRootNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1052 //! pExtra needs to have the smaller index than pRootSym in order to
1053 //! not to get the root symbol but the pExtra when clicking on it in the
1054 //! GraphicWindow. (That is because of the simplicity of the algorithm
1055 //! that finds the node corresponding to a mouseclick in the window.)
1056 SmNode *pExtra = GetSubNode(0),
1057 *pRootSym = GetSubNode(1),
1058 *pBody = GetSubNode(2);
1059 OSL_ENSURE(pRootSym, "Sm: NULL pointer");
1060 OSL_ENSURE(pBody, "Sm: NULL pointer");
1062 pBody->Arrange(rDev, rFormat);
1064 long nHeight,
1065 nVerOffset;
1066 GetHeightVerOffset(*pBody, nHeight, nVerOffset);
1067 nHeight += rFormat.GetDistance(DIS_ROOT)
1068 * GetFont().GetSize().Height() / 100L;
1070 // font specialist advised to change the width first
1071 pRootSym->AdaptToY(rDev, nHeight);
1072 pRootSym->AdaptToX(rDev, pBody->GetItalicWidth());
1074 pRootSym->Arrange(rDev, rFormat);
1076 Point aPos = pRootSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
1077 //! overrride calculated vertical position
1078 aPos.Y() = pRootSym->GetTop() + pBody->GetBottom() - pRootSym->GetBottom();
1079 aPos.Y() -= nVerOffset;
1080 pRootSym->MoveTo(aPos);
1082 if (pExtra)
1083 { pExtra->SetSize(Fraction(rFormat.GetRelSize(SIZ_INDEX), 100));
1084 pExtra->Arrange(rDev, rFormat);
1086 aPos = GetExtraPos(*pRootSym, *pExtra);
1087 pExtra->MoveTo(aPos);
1090 SmRect::operator = (*pBody);
1091 ExtendBy(*pRootSym, RCP_THIS);
1092 if (pExtra)
1093 ExtendBy(*pExtra, RCP_THIS, true);
1097 void SmRootNode::CreateTextFromNode(String &rText)
1099 SmNode *pExtra = GetSubNode(0);
1100 if (pExtra)
1102 rText += "nroot ";
1103 pExtra->CreateTextFromNode(rText);
1105 else
1106 rText += "sqrt ";
1107 GetSubNode(2)->CreateTextFromNode(rText);
1111 /**************************************************************************/
1114 void SmBinHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1116 SmNode *pLeft = GetSubNode(0),
1117 *pOper = GetSubNode(1),
1118 *pRight = GetSubNode(2);
1119 OSL_ENSURE(pLeft != NULL, "Sm: NULL pointer");
1120 OSL_ENSURE(pOper != NULL, "Sm: NULL pointer");
1121 OSL_ENSURE(pRight != NULL, "Sm: NULL pointer");
1123 pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
1125 pLeft ->Arrange(rDev, rFormat);
1126 pOper ->Arrange(rDev, rFormat);
1127 pRight->Arrange(rDev, rFormat);
1129 const SmRect &rOpRect = pOper->GetRect();
1131 long nDist = (rOpRect.GetWidth() *
1132 rFormat.GetDistance(DIS_HORIZONTAL)) / 100L;
1134 SmRect::operator = (*pLeft);
1136 Point aPos;
1137 aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1138 aPos.X() += nDist;
1139 pOper->MoveTo(aPos);
1140 ExtendBy(*pOper, RCP_XOR);
1142 aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1143 aPos.X() += nDist;
1145 pRight->MoveTo(aPos);
1146 ExtendBy(*pRight, RCP_XOR);
1150 /**************************************************************************/
1153 void SmBinVerNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1155 SmNode *pNum = GetSubNode(0),
1156 *pLine = GetSubNode(1),
1157 *pDenom = GetSubNode(2);
1158 OSL_ENSURE(pNum, "Sm : NULL pointer");
1159 OSL_ENSURE(pLine, "Sm : NULL pointer");
1160 OSL_ENSURE(pDenom, "Sm : NULL pointer");
1162 bool bIsTextmode = rFormat.IsTextmode();
1163 if (bIsTextmode)
1165 Fraction aFraction(rFormat.GetRelSize(SIZ_INDEX), 100);
1166 pNum ->SetSize(aFraction);
1167 pLine ->SetSize(aFraction);
1168 pDenom->SetSize(aFraction);
1171 pNum ->Arrange(rDev, rFormat);
1172 pDenom->Arrange(rDev, rFormat);
1174 long nFontHeight = GetFont().GetSize().Height(),
1175 nExtLen = nFontHeight * rFormat.GetDistance(DIS_FRACTION) / 100L,
1176 nThick = nFontHeight * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L,
1177 nWidth = std::max(pNum->GetItalicWidth(), pDenom->GetItalicWidth()),
1178 nNumDist = bIsTextmode ? 0 :
1179 nFontHeight * rFormat.GetDistance(DIS_NUMERATOR) / 100L,
1180 nDenomDist = bIsTextmode ? 0 :
1181 nFontHeight * rFormat.GetDistance(DIS_DENOMINATOR) / 100L;
1183 // font specialist advised to change the width first
1184 pLine->AdaptToY(rDev, nThick);
1185 pLine->AdaptToX(rDev, nWidth + 2 * nExtLen);
1186 pLine->Arrange(rDev, rFormat);
1188 // get horizontal alignment for numerator
1189 const SmNode *pLM = pNum->GetLeftMost();
1190 RectHorAlign eHorAlign = pLM->GetRectHorAlign();
1192 // move numerator to its position
1193 Point aPos = pNum->AlignTo(*pLine, RP_TOP, eHorAlign, RVA_BASELINE);
1194 aPos.Y() -= nNumDist;
1195 pNum->MoveTo(aPos);
1197 // get horizontal alignment for denominator
1198 pLM = pDenom->GetLeftMost();
1199 eHorAlign = pLM->GetRectHorAlign();
1201 // move denominator to its position
1202 aPos = pDenom->AlignTo(*pLine, RP_BOTTOM, eHorAlign, RVA_BASELINE);
1203 aPos.Y() += nDenomDist;
1204 pDenom->MoveTo(aPos);
1206 SmRect::operator = (*pNum);
1207 ExtendBy(*pDenom, RCP_NONE).ExtendBy(*pLine, RCP_NONE, pLine->GetCenterY());
1210 void SmBinVerNode::CreateTextFromNode(String &rText)
1212 SmNode *pNum = GetSubNode(0),
1213 *pDenom = GetSubNode(2);
1214 pNum->CreateTextFromNode(rText);
1215 rText += "over ";
1216 pDenom->CreateTextFromNode(rText);
1220 SmNode * SmBinVerNode::GetLeftMost()
1222 return this;
1226 /**************************************************************************/
1229 /// @return value of the determinant formed by the two points
1230 double Det(const Point &rHeading1, const Point &rHeading2)
1232 return rHeading1.X() * rHeading2.Y() - rHeading1.Y() * rHeading2.X();
1236 /// Is true iff the point 'rPoint1' belongs to the straight line through 'rPoint2'
1237 /// and has the direction vector 'rHeading2'
1238 bool IsPointInLine(const Point &rPoint1,
1239 const Point &rPoint2, const Point &rHeading2)
1241 OSL_ENSURE(rHeading2 != Point(), "Sm : 0 vector");
1243 bool bRes = false;
1244 const double eps = 5.0 * DBL_EPSILON;
1246 double fLambda;
1247 if (labs(rHeading2.X()) > labs(rHeading2.Y()))
1249 fLambda = (rPoint1.X() - rPoint2.X()) / (double) rHeading2.X();
1250 bRes = fabs(rPoint1.Y() - (rPoint2.Y() + fLambda * rHeading2.Y())) < eps;
1252 else
1254 fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y();
1255 bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
1258 return bRes;
1262 sal_uInt16 GetLineIntersectionPoint(Point &rResult,
1263 const Point& rPoint1, const Point &rHeading1,
1264 const Point& rPoint2, const Point &rHeading2)
1266 OSL_ENSURE(rHeading1 != Point(), "Sm : 0 vector");
1267 OSL_ENSURE(rHeading2 != Point(), "Sm : 0 vector");
1269 sal_uInt16 nRes = 1;
1270 const double eps = 5.0 * DBL_EPSILON;
1272 // are the direction vectors linearly dependent?
1273 double fDet = Det(rHeading1, rHeading2);
1274 if (fabs(fDet) < eps)
1276 nRes = IsPointInLine(rPoint1, rPoint2, rHeading2) ? USHRT_MAX : 0;
1277 rResult = nRes ? rPoint1 : Point();
1279 else
1281 // here we do not pay attention to the computational accurancy
1282 // (that would be more complicated and is not really worth it in this case)
1283 double fLambda = ( (rPoint1.Y() - rPoint2.Y()) * rHeading2.X()
1284 - (rPoint1.X() - rPoint2.X()) * rHeading2.Y())
1285 / fDet;
1286 rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()),
1287 rPoint1.Y() + (long) (fLambda * rHeading1.Y()));
1290 return nRes;
1295 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken)
1296 : SmStructureNode(NBINDIAGONAL, rNodeToken)
1298 bAscending = false;
1299 SetNumSubNodes(3);
1303 /// @return position and size of the diagonal line
1304 /// premise: SmRect of the node defines the limitation(!) consequently it has to be known upfront
1305 void SmBinDiagonalNode::GetOperPosSize(Point &rPos, Size &rSize,
1306 const Point &rDiagPoint, double fAngleDeg) const
1309 const double fPi = 3.1415926535897932384626433;
1310 double fAngleRad = fAngleDeg / 180.0 * fPi;
1311 long nRectLeft = GetItalicLeft(),
1312 nRectRight = GetItalicRight(),
1313 nRectTop = GetTop(),
1314 nRectBottom = GetBottom();
1315 Point aRightHdg (100, 0),
1316 aDownHdg (0, 100),
1317 aDiagHdg ( (long)(100.0 * cos(fAngleRad)),
1318 (long)(-100.0 * sin(fAngleRad)) );
1320 long nLeft, nRight, nTop, nBottom; // margins of the rectangle for the diagonal
1321 Point aPoint;
1322 if (IsAscending())
1324 // determine top right corner
1325 GetLineIntersectionPoint(aPoint,
1326 Point(nRectLeft, nRectTop), aRightHdg,
1327 rDiagPoint, aDiagHdg);
1328 // is there a point of intersection with the top border?
1329 if (aPoint.X() <= nRectRight)
1331 nRight = aPoint.X();
1332 nTop = nRectTop;
1334 else
1336 // there has to be a point of intersection with the right border!
1337 GetLineIntersectionPoint(aPoint,
1338 Point(nRectRight, nRectTop), aDownHdg,
1339 rDiagPoint, aDiagHdg);
1341 nRight = nRectRight;
1342 nTop = aPoint.Y();
1345 // determine bottom left corner
1346 GetLineIntersectionPoint(aPoint,
1347 Point(nRectLeft, nRectBottom), aRightHdg,
1348 rDiagPoint, aDiagHdg);
1349 // is there a point of intersection with the bottom border?
1350 if (aPoint.X() >= nRectLeft)
1352 nLeft = aPoint.X();
1353 nBottom = nRectBottom;
1355 else
1357 // there has to be a point of intersection with the left border!
1358 GetLineIntersectionPoint(aPoint,
1359 Point(nRectLeft, nRectTop), aDownHdg,
1360 rDiagPoint, aDiagHdg);
1362 nLeft = nRectLeft;
1363 nBottom = aPoint.Y();
1366 else
1368 // determine top left corner
1369 GetLineIntersectionPoint(aPoint,
1370 Point(nRectLeft, nRectTop), aRightHdg,
1371 rDiagPoint, aDiagHdg);
1372 // is there a point of intersection with the top border?
1373 if (aPoint.X() >= nRectLeft)
1375 nLeft = aPoint.X();
1376 nTop = nRectTop;
1378 else
1380 // there has to be a point of intersection with the left border!
1381 GetLineIntersectionPoint(aPoint,
1382 Point(nRectLeft, nRectTop), aDownHdg,
1383 rDiagPoint, aDiagHdg);
1385 nLeft = nRectLeft;
1386 nTop = aPoint.Y();
1389 // determine bottom right corner
1390 GetLineIntersectionPoint(aPoint,
1391 Point(nRectLeft, nRectBottom), aRightHdg,
1392 rDiagPoint, aDiagHdg);
1393 // is there a point of intersection with the bottom border?
1394 if (aPoint.X() <= nRectRight)
1396 nRight = aPoint.X();
1397 nBottom = nRectBottom;
1399 else
1401 // there has to be a point of intersection with the right border!
1402 GetLineIntersectionPoint(aPoint,
1403 Point(nRectRight, nRectTop), aDownHdg,
1404 rDiagPoint, aDiagHdg);
1406 nRight = nRectRight;
1407 nBottom = aPoint.Y();
1411 rSize = Size(nRight - nLeft + 1, nBottom - nTop + 1);
1412 rPos.X() = nLeft;
1413 rPos.Y() = nTop;
1417 void SmBinDiagonalNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1419 // Both arguments have to get into the SubNodes before the Operator so that clicking
1420 // within the GraphicWindow sets the FormulaCursor correctly (cf. SmRootNode)
1421 SmNode *pLeft = GetSubNode(0),
1422 *pRight = GetSubNode(1);
1423 OSL_ENSURE(pLeft, "Sm : NULL pointer");
1424 OSL_ENSURE(pRight, "Sm : NULL pointer");
1426 OSL_ENSURE(GetSubNode(2)->GetType() == NPOLYLINE, "Sm : wrong node type");
1427 SmPolyLineNode *pOper = (SmPolyLineNode *) GetSubNode(2);
1428 OSL_ENSURE(pOper, "Sm : NULL pointer");
1430 //! some routines being called extract some info from the OutputDevice's
1431 //! font (eg the space to be used for borders OR the font name(!!)).
1432 //! Thus the font should reflect the needs and has to be set!
1433 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
1434 aTmpDev.SetFont(GetFont());
1436 pLeft->Arrange(aTmpDev, rFormat);
1437 pRight->Arrange(aTmpDev, rFormat);
1439 // determine implicitely the values (incl. the margin) of the diagonal line
1440 pOper->Arrange(aTmpDev, rFormat);
1442 long nDelta = pOper->GetWidth() * 8 / 10;
1444 // determine TopLeft position from the right argument
1445 Point aPos;
1446 aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace();
1447 if (IsAscending())
1448 aPos.Y() = pLeft->GetBottom() + nDelta;
1449 else
1450 aPos.Y() = pLeft->GetTop() - nDelta - pRight->GetHeight();
1452 pRight->MoveTo(aPos);
1454 // determine new baseline
1455 long nTmpBaseline = IsAscending() ? (pLeft->GetBottom() + pRight->GetTop()) / 2
1456 : (pLeft->GetTop() + pRight->GetBottom()) / 2;
1457 Point aLogCenter ((pLeft->GetItalicRight() + pRight->GetItalicLeft()) / 2,
1458 nTmpBaseline);
1460 SmRect::operator = (*pLeft);
1461 ExtendBy(*pRight, RCP_NONE);
1464 // determine position and size of diagonal line
1465 Size aTmpSize;
1466 GetOperPosSize(aPos, aTmpSize, aLogCenter, IsAscending() ? 60.0 : -60.0);
1468 // font specialist advised to change the width first
1469 pOper->AdaptToY(aTmpDev, aTmpSize.Height());
1470 pOper->AdaptToX(aTmpDev, aTmpSize.Width());
1471 // and make it active
1472 pOper->Arrange(aTmpDev, rFormat);
1474 pOper->MoveTo(aPos);
1476 ExtendBy(*pOper, RCP_NONE, nTmpBaseline);
1480 /**************************************************************************/
1483 void SmSubSupNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1485 OSL_ENSURE(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES,
1486 "Sm: wrong number of subnodes");
1488 SmNode *pBody = GetBody();
1489 OSL_ENSURE(pBody, "Sm: NULL pointer");
1491 long nOrigHeight = pBody->GetFont().GetSize().Height();
1493 pBody->Arrange(rDev, rFormat);
1495 const SmRect &rBodyRect = pBody->GetRect();
1496 SmRect::operator = (rBodyRect);
1498 // line that separates sub- and supscript rectangles
1499 long nDelimLine = SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1501 Point aPos;
1502 long nDelta, nDist;
1504 // iterate over all possible sub-/supscripts
1505 SmRect aTmpRect (rBodyRect);
1506 for (int i = 0; i < SUBSUP_NUM_ENTRIES; i++)
1507 { SmSubSup eSubSup = (SmSubSup) i; // cast
1508 SmNode *pSubSup = GetSubSup(eSubSup);
1510 if (!pSubSup)
1511 continue;
1513 // switch position of limits if we are in textmode
1514 if (rFormat.IsTextmode() && (GetToken().nGroup & TGLIMIT))
1515 switch (eSubSup)
1516 { case CSUB: eSubSup = RSUB; break;
1517 case CSUP: eSubSup = RSUP; break;
1518 default:
1519 break;
1522 // prevent sub-/supscripts from diminishing in size
1523 // (as would be in "a_{1_{2_{3_4}}}")
1524 if (GetFont().GetSize().Height() > rFormat.GetBaseSize().Height() / 3)
1526 sal_uInt16 nIndex = (eSubSup == CSUB || eSubSup == CSUP) ?
1527 SIZ_LIMITS : SIZ_INDEX;
1528 Fraction aFraction ( rFormat.GetRelSize(nIndex), 100 );
1529 pSubSup->SetSize(aFraction);
1532 pSubSup->Arrange(rDev, rFormat);
1534 bool bIsTextmode = rFormat.IsTextmode();
1535 nDist = 0;
1537 //! be sure that CSUB, CSUP are handled before the other cases!
1538 switch (eSubSup)
1539 { case RSUB :
1540 case LSUB :
1541 if (!bIsTextmode)
1542 nDist = nOrigHeight
1543 * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L;
1544 aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1545 eSubSup == LSUB ? RP_LEFT : RP_RIGHT,
1546 RHA_CENTER, RVA_BOTTOM);
1547 aPos.Y() += nDist;
1548 nDelta = nDelimLine - aPos.Y();
1549 if (nDelta > 0)
1550 aPos.Y() += nDelta;
1551 break;
1552 case RSUP :
1553 case LSUP :
1554 if (!bIsTextmode)
1555 nDist = nOrigHeight
1556 * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L;
1557 aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1558 eSubSup == LSUP ? RP_LEFT : RP_RIGHT,
1559 RHA_CENTER, RVA_TOP);
1560 aPos.Y() -= nDist;
1561 nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
1562 if (nDelta > 0)
1563 aPos.Y() -= nDelta;
1564 break;
1565 case CSUB :
1566 if (!bIsTextmode)
1567 nDist = nOrigHeight
1568 * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L;
1569 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM,
1570 RHA_CENTER, RVA_BASELINE);
1571 aPos.Y() += nDist;
1572 break;
1573 case CSUP :
1574 if (!bIsTextmode)
1575 nDist = nOrigHeight
1576 * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L;
1577 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP,
1578 RHA_CENTER, RVA_BASELINE);
1579 aPos.Y() -= nDist;
1580 break;
1581 default :
1582 OSL_FAIL("Sm: unknown case");
1583 break;
1586 pSubSup->MoveTo(aPos);
1587 ExtendBy(*pSubSup, RCP_THIS, true);
1589 // update rectangle to which RSUB, RSUP, LSUB, LSUP
1590 // will be aligned to
1591 if (eSubSup == CSUB || eSubSup == CSUP)
1592 aTmpRect = *this;
1596 void SmSubSupNode::CreateTextFromNode(String &rText)
1598 SmNode *pNode;
1599 GetSubNode(0)->CreateTextFromNode(rText);
1601 if (NULL != (pNode = GetSubNode(LSUB+1)))
1603 rText += "lsub ";
1604 pNode->CreateTextFromNode(rText);
1606 if (NULL != (pNode = GetSubNode(LSUP+1)))
1608 rText += "lsup ";
1609 pNode->CreateTextFromNode(rText);
1611 if (NULL != (pNode = GetSubNode(CSUB+1)))
1613 rText += "csub ";
1614 pNode->CreateTextFromNode(rText);
1616 if (NULL != (pNode = GetSubNode(CSUP+1)))
1618 rText += "csup ";
1619 pNode->CreateTextFromNode(rText);
1621 if (NULL != (pNode = GetSubNode(RSUB+1)))
1623 rText = comphelper::string::stripEnd(rText, ' ');
1624 rText.Append('_');
1625 pNode->CreateTextFromNode(rText);
1627 if (NULL != (pNode = GetSubNode(RSUP+1)))
1629 rText = comphelper::string::stripEnd(rText, ' ');
1630 rText.Append('^');
1631 pNode->CreateTextFromNode(rText);
1636 /**************************************************************************/
1638 void SmBraceNode::CreateTextFromNode(String &rText)
1640 if (GetScaleMode() == SCALE_HEIGHT)
1641 rText += "left ";
1643 String aStr;
1644 GetSubNode(0)->CreateTextFromNode(aStr);
1645 aStr = comphelper::string::strip(aStr, ' ');
1646 aStr = comphelper::string::stripStart(aStr, '\\');
1647 if (aStr.Len())
1649 if (aStr.EqualsAscii("divides"))
1650 rText += "lline";
1651 else if (aStr.EqualsAscii("parallel"))
1652 rText += "ldline";
1653 else if (aStr.EqualsAscii("<"))
1654 rText += "langle";
1655 else
1656 rText.Append(aStr);
1657 rText.Append(' ');
1659 else
1660 rText += "none ";
1662 GetSubNode(1)->CreateTextFromNode(rText);
1663 if (GetScaleMode() == SCALE_HEIGHT)
1664 rText += "right ";
1666 String aStr;
1667 GetSubNode(2)->CreateTextFromNode(aStr);
1668 aStr = comphelper::string::strip(aStr, ' ');
1669 aStr = comphelper::string::stripStart(aStr, '\\');
1670 if (aStr.Len())
1672 if (aStr.EqualsAscii("divides"))
1673 rText += "rline";
1674 else if (aStr.EqualsAscii("parallel"))
1675 rText += "rdline";
1676 else if (aStr.EqualsAscii(">"))
1677 rText += "rangle";
1678 else
1679 rText.Append(aStr);
1680 rText.Append(' ');
1682 else
1683 rText += "none ";
1685 rText.Append(' ');
1689 void SmBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1691 SmNode *pLeft = GetSubNode(0),
1692 *pBody = GetSubNode(1),
1693 *pRight = GetSubNode(2);
1694 OSL_ENSURE(pLeft, "Sm: NULL pointer");
1695 OSL_ENSURE(pBody, "Sm: NULL pointer");
1696 OSL_ENSURE(pRight, "Sm: NULL pointer");
1698 pBody->Arrange(rDev, rFormat);
1700 bool bIsScaleNormal = rFormat.IsScaleNormalBrackets(),
1701 bScale = pBody->GetHeight() > 0 &&
1702 (GetScaleMode() == SCALE_HEIGHT || bIsScaleNormal),
1703 bIsABS = GetToken().eType == TABS;
1705 long nFaceHeight = GetFont().GetSize().Height();
1707 // determine oversize in %
1708 sal_uInt16 nPerc = 0;
1709 if (!bIsABS && bScale)
1710 { // in case of oversize braces...
1711 sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ?
1712 DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1713 nPerc = rFormat.GetDistance(nIndex);
1716 // determine the height for the braces
1717 long nBraceHeight;
1718 if (bScale)
1720 nBraceHeight = pBody->GetType() == NBRACEBODY ?
1721 ((SmBracebodyNode *) pBody)->GetBodyHeight()
1722 : pBody->GetHeight();
1723 nBraceHeight += 2 * (nBraceHeight * nPerc / 100L);
1725 else
1726 nBraceHeight = nFaceHeight;
1728 // distance to the argument
1729 nPerc = bIsABS ? 0 : rFormat.GetDistance(DIS_BRACKETSPACE);
1730 long nDist = nFaceHeight * nPerc / 100L;
1732 // if wanted, scale the braces to the wanted size
1733 if (bScale)
1735 Size aTmpSize (pLeft->GetFont().GetSize());
1736 OSL_ENSURE(pRight->GetFont().GetSize() == aTmpSize,
1737 "Sm : different font sizes");
1738 aTmpSize.Width() = std::min((long) nBraceHeight * 60L / 100L,
1739 rFormat.GetBaseSize().Height() * 3L / 2L);
1740 // correction factor since change from StarMath to OpenSymbol font
1741 // because of the different font width in the FontMetric
1742 aTmpSize.Width() *= 182;
1743 aTmpSize.Width() /= 267;
1745 sal_Unicode cChar = pLeft->GetToken().cMathChar;
1746 if (cChar != MS_LINE && cChar != MS_DLINE)
1747 pLeft ->GetFont().SetSize(aTmpSize);
1749 cChar = pRight->GetToken().cMathChar;
1750 if (cChar != MS_LINE && cChar != MS_DLINE)
1751 pRight->GetFont().SetSize(aTmpSize);
1753 pLeft ->AdaptToY(rDev, nBraceHeight);
1754 pRight->AdaptToY(rDev, nBraceHeight);
1757 pLeft ->Arrange(rDev, rFormat);
1758 pRight->Arrange(rDev, rFormat);
1760 // required in order to make "\(a\) - (a) - left ( a right )" look alright
1761 RectVerAlign eVerAlign = bScale ? RVA_CENTERY : RVA_BASELINE;
1763 Point aPos;
1764 aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign);
1765 aPos.X() -= nDist;
1766 pLeft->MoveTo(aPos);
1768 aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign);
1769 aPos.X() += nDist;
1770 pRight->MoveTo(aPos);
1772 SmRect::operator = (*pBody);
1773 ExtendBy(*pLeft, RCP_THIS).ExtendBy(*pRight, RCP_THIS);
1777 /**************************************************************************/
1780 void SmBracebodyNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1782 sal_uInt16 nNumSubNodes = GetNumSubNodes();
1783 if (nNumSubNodes == 0)
1784 return;
1786 // arrange arguments
1787 sal_uInt16 i;
1788 for (i = 0; i < nNumSubNodes; i += 2)
1789 GetSubNode(i)->Arrange(rDev, rFormat);
1791 // build reference rectangle with necessary info for vertical alignment
1792 SmRect aRefRect (*GetSubNode(0));
1793 for (i = 0; i < nNumSubNodes; i += 2)
1795 SmRect aTmpRect (*GetSubNode(i));
1796 Point aPos = aTmpRect.AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1797 aTmpRect.MoveTo(aPos);
1798 aRefRect.ExtendBy(aTmpRect, RCP_XOR);
1801 nBodyHeight = aRefRect.GetHeight();
1803 // scale separators to required height and arrange them
1804 bool bScale = GetScaleMode() == SCALE_HEIGHT || rFormat.IsScaleNormalBrackets();
1805 long nHeight = bScale ? aRefRect.GetHeight() : GetFont().GetSize().Height();
1806 sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ?
1807 DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1808 sal_uInt16 nPerc = rFormat.GetDistance(nIndex);
1809 if (bScale)
1810 nHeight += 2 * (nHeight * nPerc / 100L);
1811 for (i = 1; i < nNumSubNodes; i += 2)
1813 SmNode *pNode = GetSubNode(i);
1814 pNode->AdaptToY(rDev, nHeight);
1815 pNode->Arrange(rDev, rFormat);
1818 // horizontal distance between argument and brackets or separators
1819 long nDist = GetFont().GetSize().Height()
1820 * rFormat.GetDistance(DIS_BRACKETSPACE) / 100L;
1822 SmNode *pLeft = GetSubNode(0);
1823 SmRect::operator = (*pLeft);
1824 for (i = 1; i < nNumSubNodes; i++)
1826 bool bIsSeparator = i % 2 != 0;
1827 RectVerAlign eVerAlign = bIsSeparator ? RVA_CENTERY : RVA_BASELINE;
1829 SmNode *pRight = GetSubNode(i);
1830 Point aPosX = pRight->AlignTo(*pLeft, RP_RIGHT, RHA_CENTER, eVerAlign),
1831 aPosY = pRight->AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, eVerAlign);
1832 aPosX.X() += nDist;
1834 pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
1835 ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR);
1837 pLeft = pRight;
1842 /**************************************************************************/
1845 void SmVerticalBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1847 SmNode *pBody = GetSubNode(0),
1848 *pBrace = GetSubNode(1),
1849 *pScript = GetSubNode(2);
1850 OSL_ENSURE(pBody, "Sm: NULL pointer!");
1851 OSL_ENSURE(pBrace, "Sm: NULL pointer!");
1852 OSL_ENSURE(pScript, "Sm: NULL pointer!");
1854 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
1855 aTmpDev.SetFont(GetFont());
1857 pBody->Arrange(aTmpDev, rFormat);
1859 // size is the same as for limits for this part
1860 pScript->SetSize( Fraction( rFormat.GetRelSize(SIZ_LIMITS), 100 ) );
1861 // braces are a bit taller than usually
1862 pBrace ->SetSize( Fraction(3, 2) );
1864 long nItalicWidth = pBody->GetItalicWidth();
1865 if (nItalicWidth > 0)
1866 pBrace->AdaptToX(aTmpDev, nItalicWidth);
1868 pBrace ->Arrange(aTmpDev, rFormat);
1869 pScript->Arrange(aTmpDev, rFormat);
1871 // determine the relative position and the distances between each other
1872 RectPos eRectPos;
1873 long nFontHeight = pBody->GetFont().GetSize().Height();
1874 long nDistBody = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
1875 nDistScript = nFontHeight;
1876 if (GetToken().eType == TOVERBRACE)
1878 eRectPos = RP_TOP;
1879 nDistBody = - nDistBody;
1880 nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
1882 else // TUNDERBRACE
1884 eRectPos = RP_BOTTOM;
1885 nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
1887 nDistBody /= 100L;
1888 nDistScript /= 100L;
1890 Point aPos = pBrace->AlignTo(*pBody, eRectPos, RHA_CENTER, RVA_BASELINE);
1891 aPos.Y() += nDistBody;
1892 pBrace->MoveTo(aPos);
1894 aPos = pScript->AlignTo(*pBrace, eRectPos, RHA_CENTER, RVA_BASELINE);
1895 aPos.Y() += nDistScript;
1896 pScript->MoveTo(aPos);
1898 SmRect::operator = (*pBody);
1899 ExtendBy(*pBrace, RCP_THIS).ExtendBy(*pScript, RCP_THIS);
1903 /**************************************************************************/
1906 SmNode * SmOperNode::GetSymbol()
1908 SmNode *pNode = GetSubNode(0);
1909 OSL_ENSURE(pNode, "Sm: NULL pointer!");
1911 if (pNode->GetType() == NSUBSUP)
1912 pNode = ((SmSubSupNode *) pNode)->GetBody();
1914 OSL_ENSURE(pNode, "Sm: NULL pointer!");
1915 return pNode;
1919 long SmOperNode::CalcSymbolHeight(const SmNode &rSymbol,
1920 const SmFormat &rFormat) const
1921 // returns the font height to be used for operator-symbol
1923 long nHeight = GetFont().GetSize().Height();
1925 SmTokenType eTmpType = GetToken().eType;
1926 if (eTmpType == TLIM || eTmpType == TLIMINF || eTmpType == TLIMSUP)
1927 return nHeight;
1929 if (!rFormat.IsTextmode())
1931 // set minimum size ()
1932 nHeight += (nHeight * 20L) / 100L;
1934 nHeight += nHeight
1935 * rFormat.GetDistance(DIS_OPERATORSIZE) / 100L;
1936 nHeight = nHeight * 686L / 845L;
1939 // correct user-defined symbols to match height of sum from used font
1940 if (rSymbol.GetToken().eType == TSPECIAL)
1941 nHeight = nHeight * 845L / 686L;
1943 return nHeight;
1947 void SmOperNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1949 SmNode *pOper = GetSubNode(0);
1950 SmNode *pBody = GetSubNode(1);
1952 OSL_ENSURE(pOper, "Sm: missing subnode");
1953 OSL_ENSURE(pBody, "Sm: missing subnode");
1955 SmNode *pSymbol = GetSymbol();
1956 pSymbol->SetSize(Fraction(CalcSymbolHeight(*pSymbol, rFormat),
1957 pSymbol->GetFont().GetSize().Height()));
1959 pBody->Arrange(rDev, rFormat);
1960 pOper->Arrange(rDev, rFormat);
1962 long nOrigHeight = GetFont().GetSize().Height(),
1963 nDist = nOrigHeight
1964 * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L;
1966 Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID);
1967 aPos.X() -= nDist;
1968 pOper->MoveTo(aPos);
1970 SmRect::operator = (*pBody);
1971 ExtendBy(*pOper, RCP_THIS);
1975 /**************************************************************************/
1978 void SmAlignNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1979 // set alignment within the entire subtree (including current node)
1981 OSL_ENSURE(GetNumSubNodes() > 0, "Sm: missing subnode");
1983 SmNode *pNode = GetSubNode(0);
1985 RectHorAlign eHorAlign = RHA_CENTER;
1986 switch (GetToken().eType)
1988 case TALIGNL: eHorAlign = RHA_LEFT; break;
1989 case TALIGNC: eHorAlign = RHA_CENTER; break;
1990 case TALIGNR: eHorAlign = RHA_RIGHT; break;
1991 default:
1992 break;
1994 SetRectHorAlign(eHorAlign);
1996 pNode->Arrange(rDev, rFormat);
1998 SmRect::operator = (pNode->GetRect());
2002 /**************************************************************************/
2005 void SmAttributNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2007 SmNode *pAttr = GetSubNode(0),
2008 *pBody = GetSubNode(1);
2009 OSL_ENSURE(pBody, "Sm: body missing");
2010 OSL_ENSURE(pAttr, "Sm: attribute missing");
2012 pBody->Arrange(rDev, rFormat);
2014 if (GetScaleMode() == SCALE_WIDTH)
2015 pAttr->AdaptToX(rDev, pBody->GetItalicWidth());
2016 pAttr->Arrange(rDev, rFormat);
2018 // get relative position of attribute
2019 RectVerAlign eVerAlign;
2020 long nDist = 0;
2021 switch (GetToken().eType)
2022 { case TUNDERLINE :
2023 eVerAlign = RVA_ATTRIBUT_LO;
2024 break;
2025 case TOVERSTRIKE :
2026 eVerAlign = RVA_ATTRIBUT_MID;
2027 break;
2028 default :
2029 eVerAlign = RVA_ATTRIBUT_HI;
2030 if (pBody->GetType() == NATTRIBUT)
2031 nDist = GetFont().GetSize().Height()
2032 * rFormat.GetDistance(DIS_ORNAMENTSPACE) / 100L;
2034 Point aPos = pAttr->AlignTo(*pBody, RP_ATTRIBUT, RHA_CENTER, eVerAlign);
2035 aPos.Y() -= nDist;
2036 pAttr->MoveTo(aPos);
2038 SmRect::operator = (*pBody);
2039 ExtendBy(*pAttr, RCP_THIS, true);
2043 /**************************************************************************/
2048 void SmFontNode::CreateTextFromNode(String &rText)
2050 switch (GetToken().eType)
2052 case TBOLD:
2053 rText += "bold ";
2054 break;
2055 case TNBOLD:
2056 rText += "nbold ";
2057 break;
2058 case TITALIC:
2059 rText += "italic ";
2060 break;
2061 case TNITALIC:
2062 rText += "nitalic ";
2063 break;
2064 case TPHANTOM:
2065 rText += "phantom ";
2066 break;
2067 case TSIZE:
2069 rText += "size ";
2070 switch (nSizeType)
2072 case FNTSIZ_PLUS:
2073 rText.Append('+');
2074 break;
2075 case FNTSIZ_MINUS:
2076 rText.Append('-');
2077 break;
2078 case FNTSIZ_MULTIPLY:
2079 rText.Append('*');
2080 break;
2081 case FNTSIZ_DIVIDE:
2082 rText.Append('/');
2083 break;
2084 case FNTSIZ_ABSOLUT:
2085 default:
2086 break;
2088 rText += String( ::rtl::math::doubleToUString(
2089 static_cast<double>(aFontSize),
2090 rtl_math_StringFormat_Automatic,
2091 rtl_math_DecimalPlaces_Max, '.', sal_True));
2092 rText.Append(' ');
2094 break;
2095 case TBLACK:
2096 rText += "color black ";
2097 break;
2098 case TWHITE:
2099 rText += "color white ";
2100 break;
2101 case TRED:
2102 rText += "color red ";
2103 break;
2104 case TGREEN:
2105 rText += "color green ";
2106 break;
2107 case TBLUE:
2108 rText += "color blue ";
2109 break;
2110 case TCYAN:
2111 rText += "color cyan ";
2112 break;
2113 case TMAGENTA:
2114 rText += "color magenta ";
2115 break;
2116 case TYELLOW:
2117 rText += "color yellow ";
2118 break;
2119 case TSANS:
2120 rText += "font sans ";
2121 break;
2122 case TSERIF:
2123 rText += "font serif ";
2124 break;
2125 case TFIXED:
2126 rText += "font fixed ";
2127 break;
2128 default:
2129 break;
2131 GetSubNode(1)->CreateTextFromNode(rText);
2135 void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2137 //! prepare subnodes first
2138 SmNode::Prepare(rFormat, rDocShell);
2140 int nFnt = -1;
2141 switch (GetToken().eType)
2143 case TFIXED: nFnt = FNT_FIXED; break;
2144 case TSANS: nFnt = FNT_SANS; break;
2145 case TSERIF: nFnt = FNT_SERIF; break;
2146 default:
2147 break;
2149 if (nFnt != -1)
2150 { GetFont() = rFormat.GetFont( sal::static_int_cast< sal_uInt16 >(nFnt) );
2151 SetFont(GetFont());
2154 //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
2155 //! other font nodes (those with lower depth in the tree)
2156 Flags() |= FLG_FONT;
2160 void SmFontNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2162 SmNode *pNode = GetSubNode(1);
2163 OSL_ENSURE(pNode, "Sm: missing subnode");
2165 switch (GetToken().eType)
2166 { case TSIZE :
2167 pNode->SetFontSize(aFontSize, nSizeType);
2168 break;
2169 case TSANS :
2170 case TSERIF :
2171 case TFIXED :
2172 pNode->SetFont(GetFont());
2173 break;
2174 case TUNKNOWN : break; // no assertion on "font <?> <?>"
2176 case TPHANTOM : SetPhantom(true); break;
2177 case TBOLD : SetAttribut(ATTR_BOLD); break;
2178 case TITALIC : SetAttribut(ATTR_ITALIC); break;
2179 case TNBOLD : ClearAttribut(ATTR_BOLD); break;
2180 case TNITALIC : ClearAttribut(ATTR_ITALIC); break;
2182 case TBLACK : SetColor(Color(COL_BLACK)); break;
2183 case TWHITE : SetColor(Color(COL_WHITE)); break;
2184 case TRED : SetColor(Color(COL_RED)); break;
2185 case TGREEN : SetColor(Color(COL_GREEN)); break;
2186 case TBLUE : SetColor(Color(COL_BLUE)); break;
2187 case TCYAN : SetColor(Color(COL_CYAN)); break;
2188 case TMAGENTA : SetColor(Color(COL_MAGENTA)); break;
2189 case TYELLOW : SetColor(Color(COL_YELLOW)); break;
2191 default:
2192 OSL_FAIL("Sm: unknown case");
2195 pNode->Arrange(rDev, rFormat);
2197 SmRect::operator = (pNode->GetRect());
2201 void SmFontNode::SetSizeParameter(const Fraction& rValue, sal_uInt16 Type)
2203 nSizeType = Type;
2204 aFontSize = rValue;
2208 /**************************************************************************/
2211 SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
2212 : SmGraphicNode(NPOLYLINE, rNodeToken)
2214 aPoly.SetSize(2);
2215 nWidth = 0;
2219 void SmPolyLineNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nNewWidth)
2221 aToSize.Width() = nNewWidth;
2225 void SmPolyLineNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nNewHeight)
2227 GetFont().FreezeBorderWidth();
2228 aToSize.Height() = nNewHeight;
2232 void SmPolyLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2234 //! some routines being called extract some info from the OutputDevice's
2235 //! font (eg the space to be used for borders OR the font name(!!)).
2236 //! Thus the font should reflect the needs and has to be set!
2237 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2238 aTmpDev.SetFont(GetFont());
2240 long nBorderwidth = GetFont().GetBorderWidth();
2242 // create polygon using both endpoints
2243 OSL_ENSURE(aPoly.GetSize() == 2, "Sm : wrong number of points");
2244 Point aPointA, aPointB;
2245 if (GetToken().eType == TWIDESLASH)
2247 aPointA.X() = nBorderwidth;
2248 aPointA.Y() = aToSize.Height() - nBorderwidth;
2249 aPointB.X() = aToSize.Width() - nBorderwidth;
2250 aPointB.Y() = nBorderwidth;
2252 else
2254 OSL_ENSURE(GetToken().eType == TWIDEBACKSLASH, "Sm : unexpected token");
2255 aPointA.X() =
2256 aPointA.Y() = nBorderwidth;
2257 aPointB.X() = aToSize.Width() - nBorderwidth;
2258 aPointB.Y() = aToSize.Height() - nBorderwidth;
2260 aPoly.SetPoint(aPointA, 0);
2261 aPoly.SetPoint(aPointB, 1);
2263 long nThick = GetFont().GetSize().Height()
2264 * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L;
2265 nWidth = nThick + 2 * nBorderwidth;
2267 SmRect::operator = (SmRect(aToSize.Width(), aToSize.Height()));
2271 /**************************************************************************/
2273 void SmRootSymbolNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
2275 nBodyWidth = nWidth;
2279 void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2281 // some additional length so that the horizontal
2282 // bar will be positioned above the argument
2283 SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / 10L);
2287 /**************************************************************************/
2290 void SmRectangleNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
2292 aToSize.Width() = nWidth;
2296 void SmRectangleNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nHeight)
2298 GetFont().FreezeBorderWidth();
2299 aToSize.Height() = nHeight;
2303 void SmRectangleNode::Arrange(const OutputDevice &rDev, const SmFormat &/*rFormat*/)
2305 long nFontHeight = GetFont().GetSize().Height();
2306 long nWidth = aToSize.Width(),
2307 nHeight = aToSize.Height();
2308 if (nHeight == 0)
2309 nHeight = nFontHeight / 30;
2310 if (nWidth == 0)
2311 nWidth = nFontHeight / 3;
2313 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2314 aTmpDev.SetFont(GetFont());
2316 // add some borderspace
2317 sal_uLong nTmpBorderWidth = GetFont().GetBorderWidth();
2318 nHeight += 2 * nTmpBorderWidth;
2320 //! use this method in order to have 'SmRect::HasAlignInfo() == true'
2321 //! and thus having the attribut-fences updated in 'SmRect::ExtendBy'
2322 SmRect::operator = (SmRect(nWidth, nHeight));
2326 /**************************************************************************/
2329 SmTextNode::SmTextNode( SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 nFontDescP ) :
2330 SmVisibleNode(eNodeType, rNodeToken)
2332 nFontDesc = nFontDescP;
2336 SmTextNode::SmTextNode( const SmToken &rNodeToken, sal_uInt16 nFontDescP ) :
2337 SmVisibleNode(NTEXT, rNodeToken)
2339 nFontDesc = nFontDescP;
2343 void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2345 SmNode::Prepare(rFormat, rDocShell);
2347 // default setting for horizontal alignment of nodes with TTEXT
2348 // content is as alignl (cannot be done in Arrange since it would
2349 // override the settings made by an SmAlignNode before)
2350 if (TTEXT == GetToken().eType)
2351 SetRectHorAlign( RHA_LEFT );
2353 aText = GetToken().aText;
2354 GetFont() = rFormat.GetFont(GetFontDesc());
2356 if (IsItalic( GetFont() ))
2357 Attributes() |= ATTR_ITALIC;
2358 if (IsBold( GetFont() ))
2359 Attributes() |= ATTR_BOLD;
2361 // special handling for ':' where it is a token on it's own and is likely
2362 // to be used for mathematical notations. (E.g. a:b = 2:3)
2363 // In that case it should not be displayed in italic.
2364 if (GetToken().aText.getLength() == 1 && GetToken().aText[0] == ':')
2365 Attributes() &= ~ATTR_ITALIC;
2369 void SmTextNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2371 PrepareAttributes();
2373 sal_uInt16 nSizeDesc = GetFontDesc() == FNT_FUNCTION ?
2374 SIZ_FUNCTION : SIZ_TEXT;
2375 GetFont() *= Fraction (rFormat.GetRelSize(nSizeDesc), 100);
2377 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2378 aTmpDev.SetFont(GetFont());
2380 SmRect::operator = (SmRect(aTmpDev, &rFormat, aText, GetFont().GetBorderWidth()));
2383 void SmTextNode::CreateTextFromNode(String &rText)
2385 bool bQuoted=false;
2386 if (GetToken().eType == TTEXT)
2388 rText.Append('\"');
2389 bQuoted=true;
2391 else
2393 SmParser aParseTest;
2394 SmNode *pTable = aParseTest.Parse(GetToken().aText);
2395 bQuoted=true;
2396 if ( (pTable->GetType() == NTABLE) && (pTable->GetNumSubNodes() == 1) )
2398 SmNode *pResult = pTable->GetSubNode(0);
2399 if ( (pResult->GetType() == NLINE) &&
2400 (pResult->GetNumSubNodes() == 1) )
2402 pResult = pResult->GetSubNode(0);
2403 if ( (pResult->GetType() == NEXPRESSION) &&
2404 (pResult->GetNumSubNodes() == 1) )
2406 pResult = pResult->GetSubNode(0);
2407 if (pResult->GetType() == NTEXT)
2408 bQuoted=false;
2412 delete pTable;
2414 if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
2416 //Search for existing functions and remove extraenous keyword
2417 rText += "func ";
2419 else if (bQuoted)
2420 rText += "italic ";
2422 if (bQuoted)
2423 rText.Append('\"');
2427 rText.Append(GetToken().aText);
2429 if (bQuoted)
2430 rText.Append('\"');
2431 rText.Append(' ');
2435 void SmTextNode::GetAccessibleText( OUStringBuffer &rText ) const
2437 rText.append(aText);
2440 void SmTextNode::AdjustFontDesc()
2442 if (GetToken().eType == TTEXT)
2443 nFontDesc = FNT_TEXT;
2444 else if(GetToken().eType == TFUNC)
2445 nFontDesc = FNT_FUNCTION;
2446 else {
2447 SmTokenType nTok;
2448 const SmTokenTableEntry *pEntry = SmParser::GetTokenTableEntry( aText );
2449 if (pEntry && pEntry->nGroup == TGFUNCTION) {
2450 nTok = pEntry->eType;
2451 nFontDesc = FNT_FUNCTION;
2452 } else {
2453 sal_Unicode firstChar = aText[0];
2454 if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',') {
2455 nFontDesc = FNT_NUMBER;
2456 nTok = TNUMBER;
2457 } else if (aText.getLength() > 1) {
2458 nFontDesc = FNT_VARIABLE;
2459 nTok = TIDENT;
2460 } else {
2461 nFontDesc = FNT_VARIABLE;
2462 nTok = TCHARACTER;
2465 SmToken tok = GetToken();
2466 tok.eType = nTok;
2467 SetToken(tok);
2471 sal_Unicode SmTextNode::ConvertSymbolToUnicode(sal_Unicode nIn)
2473 //Find the best match in accepted unicode for our private area symbols
2474 static const sal_Unicode aStarMathPrivateToUnicode[] =
2476 0x2030, 0xF613, 0xF612, 0x002B, 0x003C, 0x003E, 0xE425, 0xE421, 0xE088, 0x2208,
2477 0x0192, 0x2026, 0x2192, 0x221A, 0x221A, 0x221A, 0xE090, 0x005E, 0x02C7, 0x02D8,
2478 0x00B4, 0x0060, 0x02DC, 0x00AF, 0x0362, 0xE099, 0xE09A, 0x20DB, 0xE09C, 0xE09D,
2479 0x0028, 0x0029, 0x2220, 0x22AF, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7,
2480 0x002F, 0x005C, 0x274F, 0xE0AB, 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03A0,
2481 0x03a3, 0x03a5, 0x03a6, 0x03a8, 0x03A9, 0x03B1, 0x03B2, 0x03b3, 0x03b4, 0x03b5,
2482 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
2483 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03b5,
2484 0x03d1, 0x03d6, 0xE0D2, 0x03db, 0x2118, 0x2202, 0x2129, 0xE0D7, 0xE0D8, 0x22A4,
2485 0xE0DA, 0x2190, 0x2191, 0x2193
2487 if ((nIn >= 0xE080) && (nIn <= 0xE0DD))
2488 nIn = aStarMathPrivateToUnicode[nIn-0xE080];
2490 //For whatever unicode glyph that equation editor doesn't ship with that
2491 //we have a possible match we can munge it to.
2492 switch (nIn)
2494 case 0x2223:
2495 nIn = '|';
2496 break;
2497 default:
2498 break;
2501 return nIn;
2504 /**************************************************************************/
2506 void SmMatrixNode::CreateTextFromNode(String &rText)
2508 rText += "matrix {";
2509 for (sal_uInt16 i = 0; i < nNumRows; i++)
2511 for (sal_uInt16 j = 0; j < nNumCols; j++)
2513 SmNode *pNode = GetSubNode(i * nNumCols + j);
2514 if (pNode)
2515 pNode->CreateTextFromNode(rText);
2516 if (j != nNumCols-1)
2517 rText += "# ";
2519 if (i != nNumRows-1)
2520 rText += "## ";
2522 rText = comphelper::string::stripEnd(rText, ' ');
2523 rText += "} ";
2527 void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2529 SmNode *pNode;
2530 sal_uInt16 i, j;
2532 // initialize array that is to hold the maximum widhts of all
2533 // elements (subnodes) in that column.
2534 long *pColWidth = new long[nNumCols];
2535 for (j = 0; j < nNumCols; j++)
2536 pColWidth[j] = 0;
2538 // arrange subnodes and calculate the aboves arrays contents
2539 sal_uInt16 nNodes = GetNumSubNodes();
2540 for (i = 0; i < nNodes; i++)
2542 sal_uInt16 nIdx = nNodes - 1 - i;
2543 if (NULL != (pNode = GetSubNode(nIdx)))
2545 pNode->Arrange(rDev, rFormat);
2546 int nCol = nIdx % nNumCols;
2547 pColWidth[nCol] = std::max(pColWidth[nCol], pNode->GetItalicWidth());
2551 // norm distance from which the following two are calcutated
2552 const int nNormDist = 3 * GetFont().GetSize().Height();
2554 // define horizontal and vertical minimal distances that separate
2555 // the elements
2556 long nHorDist = nNormDist * rFormat.GetDistance(DIS_MATRIXCOL) / 100L,
2557 nVerDist = nNormDist * rFormat.GetDistance(DIS_MATRIXROW) / 100L;
2559 // build array that holds the leftmost position for each column
2560 long *pColLeft = new long[nNumCols];
2561 long nX = 0;
2562 for (j = 0; j < nNumCols; j++)
2563 { pColLeft[j] = nX;
2564 nX += pColWidth[j] + nHorDist;
2567 Point aPos, aDelta;
2568 SmRect aLineRect;
2569 SmRect::operator = (SmRect());
2570 for (i = 0; i < nNumRows; i++)
2571 { aLineRect = SmRect();
2572 for (j = 0; j < nNumCols; j++)
2573 { SmNode *pTmpNode = GetSubNode(i * nNumCols + j);
2574 OSL_ENSURE(pTmpNode, "Sm: NULL pointer");
2576 const SmRect &rNodeRect = pTmpNode->GetRect();
2578 // align all baselines in that row if possible
2579 aPos = rNodeRect.AlignTo(aLineRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
2580 aPos.X() += nHorDist;
2582 // get horizontal alignment
2583 const SmNode *pCoNode = pTmpNode->GetLeftMost();
2584 RectHorAlign eHorAlign = pCoNode->GetRectHorAlign();
2586 // caculate horizontal position of element depending on column
2587 // and horizontal alignment
2588 switch (eHorAlign)
2589 { case RHA_LEFT:
2590 aPos.X() = rNodeRect.GetLeft() + pColLeft[j];
2591 break;
2592 case RHA_CENTER:
2593 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2594 + pColWidth[j] / 2
2595 - rNodeRect.GetItalicCenterX();
2596 break;
2597 case RHA_RIGHT:
2598 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2599 + pColWidth[j] - rNodeRect.GetItalicWidth();
2600 break;
2603 pTmpNode->MoveTo(aPos);
2604 aLineRect.ExtendBy(rNodeRect, RCP_XOR);
2607 aPos = aLineRect.AlignTo(*this, RP_BOTTOM, RHA_CENTER, RVA_BASELINE);
2608 aPos.Y() += nVerDist;
2610 // move 'aLineRect' and rectangles in that line to final position
2611 aDelta.X() = 0; // since horizontal alignment is already done
2612 aDelta.Y() = aPos.Y() - aLineRect.GetTop();
2613 aLineRect.Move(aDelta);
2614 for (j = 0; j < nNumCols; j++)
2615 if (NULL != (pNode = GetSubNode(i * nNumCols + j)))
2616 pNode->Move(aDelta);
2618 ExtendBy(aLineRect, RCP_NONE);
2621 delete [] pColLeft;
2622 delete [] pColWidth;
2626 void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
2628 nNumRows = nMatrixRows;
2629 nNumCols = nMatrixCols;
2633 SmNode * SmMatrixNode::GetLeftMost()
2635 return this;
2639 /**************************************************************************/
2642 SmMathSymbolNode::SmMathSymbolNode(const SmToken &rNodeToken)
2643 : SmSpecialNode(NMATH, rNodeToken, FNT_MATH)
2645 sal_Unicode cChar = GetToken().cMathChar;
2646 if ((sal_Unicode) '\0' != cChar)
2647 SetText(OUString(cChar));
2650 void SmMathSymbolNode::AdaptToX(const OutputDevice &rDev, sal_uLong nWidth)
2652 // Since there is no function to do this, we try to approximate it:
2653 Size aFntSize (GetFont().GetSize());
2655 //! however the result is a bit better with 'nWidth' as initial font width
2656 aFntSize.Width() = nWidth;
2657 GetFont().SetSize(aFntSize);
2659 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2660 aTmpDev.SetFont(GetFont());
2662 // get denominator of error factor for width
2663 long nTmpBorderWidth = GetFont().GetBorderWidth();
2664 long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetItalicWidth();
2666 // scale fontwidth with this error factor
2667 aFntSize.Width() *= nWidth;
2668 aFntSize.Width() /= nDenom ? nDenom : 1;
2670 GetFont().SetSize(aFntSize);
2673 void SmMathSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2675 GetFont().FreezeBorderWidth();
2676 Size aFntSize (GetFont().GetSize());
2678 // Since we only want to scale the height, we might have
2679 // to determine the font width in order to keep it
2680 if (aFntSize.Width() == 0)
2682 OutputDevice &rDevNC = (OutputDevice &) rDev;
2683 rDevNC.Push(PUSH_FONT | PUSH_MAPMODE);
2684 rDevNC.SetFont(GetFont());
2685 aFntSize.Width() = rDev.GetFontMetric().GetSize().Width();
2686 rDevNC.Pop();
2688 OSL_ENSURE(aFntSize.Width() != 0, "Sm: ");
2690 //! however the result is a bit better with 'nHeight' as initial
2691 //! font height
2692 aFntSize.Height() = nHeight;
2693 GetFont().SetSize(aFntSize);
2695 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2696 aTmpDev.SetFont(GetFont());
2698 // get denominator of error factor for height
2699 long nTmpBorderWidth = GetFont().GetBorderWidth();
2700 long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetHeight();
2702 // scale fontwidth with this error factor
2703 aFntSize.Height() *= nHeight;
2704 aFntSize.Height() /= nDenom ? nDenom : 1;
2706 GetFont().SetSize(aFntSize);
2710 void SmMathSymbolNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2712 SmNode::Prepare(rFormat, rDocShell);
2714 GetFont() = rFormat.GetFont(GetFontDesc());
2715 // use same font size as is used for variables
2716 GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
2718 OSL_ENSURE(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL ||
2719 GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
2720 "wrong charset for character from StarMath/OpenSymbol font");
2722 Flags() |= FLG_FONT | FLG_ITALIC;
2726 void SmMathSymbolNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2728 const OUString &rText = GetText();
2730 if (rText.isEmpty() || rText[0] == '\0')
2731 { SmRect::operator = (SmRect());
2732 return;
2735 PrepareAttributes();
2737 GetFont() *= Fraction (rFormat.GetRelSize(SIZ_TEXT), 100);
2739 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2740 aTmpDev.SetFont(GetFont());
2742 SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
2745 void SmMathSymbolNode::CreateTextFromNode(String &rText)
2747 String sStr;
2748 MathType::LookupChar(GetToken().cMathChar, sStr);
2749 rText.Append(sStr);
2752 void SmRectangleNode::CreateTextFromNode(String &rText)
2754 switch (GetToken().eType)
2756 case TUNDERLINE:
2757 rText += "underline ";
2758 break;
2759 case TOVERLINE:
2760 rText += "overline ";
2761 break;
2762 case TOVERSTRIKE:
2763 rText += "overstrike ";
2764 break;
2765 default:
2766 break;
2770 void SmAttributNode::CreateTextFromNode(String &rText)
2772 SmNode *pNode;
2773 sal_uInt16 nSize = GetNumSubNodes();
2774 OSL_ENSURE(nSize == 2, "Node missing members");
2775 rText.Append('{');
2776 sal_Unicode nLast=0;
2777 if (NULL != (pNode = GetSubNode(0)))
2779 String aStr;
2780 pNode->CreateTextFromNode(aStr);
2781 if (aStr.Len() > 1)
2782 rText.Append(aStr);
2783 else
2785 nLast = aStr.GetChar(0);
2786 switch (nLast)
2788 case 0xAF: // MACRON
2789 rText += "overline ";
2790 break;
2791 case MS_DOT: // DOT ABOVE
2792 rText += "dot ";
2793 break;
2794 case 0x2dc: // SMALL TILDE
2795 rText += "widetilde ";
2796 break;
2797 case MS_DDOT: // DIAERESIS
2798 rText += "ddot ";
2799 break;
2800 case 0xE082:
2801 break;
2802 case 0xE09B:
2803 case MS_DDDOT: // COMBINING THREE DOTS ABOVE
2804 rText += "dddot ";
2805 break;
2806 case MS_ACUTE: // COMBINING ACUTE ACCENT
2807 rText += "acute ";
2808 break;
2809 case MS_GRAVE: // COMBINING GRAVE ACCENT
2810 rText += "grave ";
2811 break;
2812 case MS_CHECK: // COMBINING CARON
2813 rText += "check ";
2814 break;
2815 case MS_BREVE: // COMBINING BREVE
2816 rText += "breve ";
2817 break;
2818 case MS_CIRCLE: // COMBINING RING ABOVE
2819 rText += "circle ";
2820 break;
2821 case MS_VEC: // COMBINING RIGHT ARROW ABOVE
2822 rText += "vec ";
2823 break;
2824 case MS_TILDE: // COMBINING TILDE
2825 rText += "tilde ";
2826 break;
2827 case MS_HAT: // COMBINING CIRCUMFLEX ACCENT
2828 rText += "hat ";
2829 break;
2830 case MS_BAR: // COMBINING MACRON
2831 rText += "bar ";
2832 break;
2833 default:
2834 rText.Append(nLast);
2835 break;
2840 if (nSize == 2)
2841 if (NULL != (pNode = GetSubNode(1)))
2842 pNode->CreateTextFromNode(rText);
2844 rText = comphelper::string::stripEnd(rText, ' ');
2846 if (nLast == 0xE082)
2847 rText += " overbrace {}";
2849 rText += "} ";
2852 /**************************************************************************/
2854 static bool lcl_IsFromGreekSymbolSet( const String &rTokenText )
2856 bool bRes = false;
2858 // valid symbol name needs to have a '%' at pos 0 and at least an additonal char
2859 if (rTokenText.Len() > 2 && rTokenText.GetBuffer()[0] == (sal_Unicode)'%')
2861 String aName( rTokenText.Copy(1) );
2862 SmSym *pSymbol = SM_MOD()->GetSymbolManager().GetSymbolByName( aName );
2863 if (pSymbol && GetExportSymbolSetName(pSymbol->GetSymbolSetName()) == "Greek")
2864 bRes = true;
2867 return bRes;
2871 SmSpecialNode::SmSpecialNode(SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 _nFontDesc) :
2872 SmTextNode(eNodeType, rNodeToken, _nFontDesc)
2874 bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText );
2878 SmSpecialNode::SmSpecialNode(const SmToken &rNodeToken) :
2879 SmTextNode(NSPECIAL, rNodeToken, FNT_MATH) // default Font isn't always correct!
2881 bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText );
2885 void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2887 SmNode::Prepare(rFormat, rDocShell);
2889 const SmSym *pSym;
2890 SmModule *pp = SM_MOD();
2892 OUString aName(GetToken().aText.copy(1));
2893 if (NULL != (pSym = pp->GetSymbolManager().GetSymbolByName( aName )))
2895 sal_UCS4 cChar = pSym->GetCharacter();
2896 OUString aTmp( &cChar, 1 );
2897 SetText( aTmp );
2898 GetFont() = pSym->GetFace();
2900 else
2902 SetText( GetToken().aText );
2903 GetFont() = rFormat.GetFont(FNT_VARIABLE);
2905 // use same font size as is used for variables
2906 GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
2908 // Actually only WEIGHT_NORMAL and WEIGHT_BOLD should occur... However, the sms-file also
2909 // contains e.g. 'WEIGHT_ULTRALIGHT'. Consequently, compare here with '>' instead of '!='.
2910 // (In the long term the necessity for 'PrepareAttribut' and thus also for this here should be dropped)
2912 //! see also SmFontStyles::GetStyleName
2913 if (IsItalic( GetFont() ))
2914 SetAttribut(ATTR_ITALIC);
2915 if (IsBold( GetFont() ))
2916 SetAttribut(ATTR_BOLD);
2918 Flags() |= FLG_FONT;
2920 if (bIsFromGreekSymbolSet)
2922 OSL_ENSURE( GetText().getLength() == 1, "a symbol should only consist of 1 char!" );
2923 bool bItalic = false;
2924 sal_Int16 nStyle = rFormat.GetGreekCharStyle();
2925 OSL_ENSURE( nStyle >= 0 && nStyle <= 2, "unexpected value for GreekCharStyle" );
2926 if (nStyle == 1)
2927 bItalic = true;
2928 else if (nStyle == 2)
2930 const OUString& rTmp(GetText());
2931 if (rTmp.isEmpty())
2933 const sal_Unicode cUppercaseAlpha = 0x0391;
2934 const sal_Unicode cUppercaseOmega = 0x03A9;
2935 sal_Unicode cChar = rTmp[0];
2936 // uppercase letters should be straight and lowercase letters italic
2937 bItalic = !(cUppercaseAlpha <= cChar && cChar <= cUppercaseOmega);
2941 if (bItalic)
2942 Attributes() |= ATTR_ITALIC;
2943 else
2944 Attributes() &= ~ATTR_ITALIC;;
2949 void SmSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2951 PrepareAttributes();
2953 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2954 aTmpDev.SetFont(GetFont());
2956 SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
2959 /**************************************************************************/
2962 void SmGlyphSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2964 PrepareAttributes();
2966 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2967 aTmpDev.SetFont(GetFont());
2969 SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(),
2970 GetFont().GetBorderWidth()).AsGlyphRect());
2974 /**************************************************************************/
2977 void SmPlaceNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2979 SmNode::Prepare(rFormat, rDocShell);
2981 GetFont().SetColor(COL_GRAY);
2982 Flags() |= FLG_COLOR | FLG_FONT | FLG_ITALIC;
2986 void SmPlaceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2988 PrepareAttributes();
2990 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2991 aTmpDev.SetFont(GetFont());
2993 SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
2997 /**************************************************************************/
3000 void SmErrorNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3002 SmNode::Prepare(rFormat, rDocShell);
3004 GetFont().SetColor(COL_RED);
3005 Flags() |= FLG_VISIBLE | FLG_BOLD | FLG_ITALIC
3006 | FLG_COLOR | FLG_FONT | FLG_SIZE;
3010 void SmErrorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3012 PrepareAttributes();
3014 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3015 aTmpDev.SetFont(GetFont());
3017 const OUString &rText = GetText();
3018 SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
3022 /**************************************************************************/
3025 void SmBlankNode::IncreaseBy(const SmToken &rToken)
3027 switch(rToken.eType)
3029 case TBLANK: nNum += 4; break;
3030 case TSBLANK: nNum += 1; break;
3031 default:
3032 break;
3037 void SmBlankNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3039 SmNode::Prepare(rFormat, rDocShell);
3041 // Here it need/should not be the StarMath font, so that for the character
3042 // used in Arrange a normal (non-clipped) rectangle is generated
3043 GetFont() = rFormat.GetFont(FNT_VARIABLE);
3045 Flags() |= FLG_FONT | FLG_BOLD | FLG_ITALIC;
3049 void SmBlankNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3051 SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3052 aTmpDev.SetFont(GetFont());
3054 // make distance depend on the font height
3055 // (so that it increases when scaling (e.g. size *2 {a ~ b})
3056 long nDist = GetFont().GetSize().Height() / 10L,
3057 nSpace = nNum * nDist;
3059 // get a SmRect with Baseline and all the bells and whistles
3060 SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString(' '),
3061 GetFont().GetBorderWidth()));
3063 // and resize it to the requested size
3064 SetItalicSpaces(0, 0);
3065 SetWidth(nSpace);
3068 /**************************************************************************/
3069 //Implementation of all accept methods for SmVisitor
3071 void SmNode::Accept(SmVisitor*){
3072 //This method is only implemented to avoid making SmNode abstract because an
3073 //obscure copy constructor is used... I can't find it's implementation, and
3074 //don't want to figure out how to fix it... If you want to, just delete this
3075 //method, making SmNode abstract, and see where you can an problem with that.
3076 OSL_FAIL("SmNode should not be visitable!");
3079 void SmTableNode::Accept(SmVisitor* pVisitor) {
3080 pVisitor->Visit(this);
3083 void SmBraceNode::Accept(SmVisitor* pVisitor) {
3084 pVisitor->Visit(this);
3087 void SmBracebodyNode::Accept(SmVisitor* pVisitor) {
3088 pVisitor->Visit(this);
3091 void SmOperNode::Accept(SmVisitor* pVisitor) {
3092 pVisitor->Visit(this);
3095 void SmAlignNode::Accept(SmVisitor* pVisitor) {
3096 pVisitor->Visit(this);
3099 void SmAttributNode::Accept(SmVisitor* pVisitor) {
3100 pVisitor->Visit(this);
3103 void SmFontNode::Accept(SmVisitor* pVisitor) {
3104 pVisitor->Visit(this);
3107 void SmUnHorNode::Accept(SmVisitor* pVisitor) {
3108 pVisitor->Visit(this);
3111 void SmBinHorNode::Accept(SmVisitor* pVisitor) {
3112 pVisitor->Visit(this);
3115 void SmBinVerNode::Accept(SmVisitor* pVisitor) {
3116 pVisitor->Visit(this);
3119 void SmBinDiagonalNode::Accept(SmVisitor* pVisitor) {
3120 pVisitor->Visit(this);
3123 void SmSubSupNode::Accept(SmVisitor* pVisitor) {
3124 pVisitor->Visit(this);
3127 void SmMatrixNode::Accept(SmVisitor* pVisitor) {
3128 pVisitor->Visit(this);
3131 void SmPlaceNode::Accept(SmVisitor* pVisitor) {
3132 pVisitor->Visit(this);
3135 void SmTextNode::Accept(SmVisitor* pVisitor) {
3136 pVisitor->Visit(this);
3139 void SmSpecialNode::Accept(SmVisitor* pVisitor) {
3140 pVisitor->Visit(this);
3143 void SmGlyphSpecialNode::Accept(SmVisitor* pVisitor) {
3144 pVisitor->Visit(this);
3147 void SmMathSymbolNode::Accept(SmVisitor* pVisitor) {
3148 pVisitor->Visit(this);
3151 void SmBlankNode::Accept(SmVisitor* pVisitor) {
3152 pVisitor->Visit(this);
3155 void SmErrorNode::Accept(SmVisitor* pVisitor) {
3156 pVisitor->Visit(this);
3159 void SmLineNode::Accept(SmVisitor* pVisitor) {
3160 pVisitor->Visit(this);
3163 void SmExpressionNode::Accept(SmVisitor* pVisitor) {
3164 pVisitor->Visit(this);
3167 void SmPolyLineNode::Accept(SmVisitor* pVisitor) {
3168 pVisitor->Visit(this);
3171 void SmRootNode::Accept(SmVisitor* pVisitor) {
3172 pVisitor->Visit(this);
3175 void SmRootSymbolNode::Accept(SmVisitor* pVisitor) {
3176 pVisitor->Visit(this);
3179 void SmRectangleNode::Accept(SmVisitor* pVisitor) {
3180 pVisitor->Visit(this);
3183 void SmVerticalBraceNode::Accept(SmVisitor* pVisitor) {
3184 pVisitor->Visit(this);
3187 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */