1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
25 #include "document.hxx"
27 #include "mathtype.hxx"
28 #include "tmpdevice.hxx"
29 #include "visitors.hxx"
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>
41 SmNode::SmNode(SmNodeType eNodeType
, const SmToken
&rNodeToken
)
42 : aNodeToken( rNodeToken
)
44 , eScaleMode( SCALE_NONE
)
45 , eRectHorAlign( RHA_LEFT
)
50 , bIsSelected( false )
62 bool SmNode::IsVisible() const
68 sal_uInt16
SmNode::GetNumSubNodes() const
74 SmNode
* SmNode::GetSubNode(sal_uInt16
/*nIndex*/)
80 SmNode
* SmNode::GetLeftMost()
81 // returns leftmost node of current subtree.
82 //! (this assumes the one with index 0 is always the leftmost subnode
83 //! for the current node).
85 SmNode
*pNode
= GetNumSubNodes() > 0 ?
88 return pNode
? pNode
->GetLeftMost() : this;
92 void SmNode::SetPhantom(bool bIsPhantomP
)
94 if (! (Flags() & FLG_VISIBLE
))
95 bIsPhantom
= bIsPhantomP
;
98 sal_uInt16 nSize
= GetNumSubNodes();
99 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
100 if (NULL
!= (pNode
= GetSubNode(i
)))
101 pNode
->SetPhantom(bIsPhantom
);
105 void SmNode::SetColor(const Color
& rColor
)
107 if (! (Flags() & FLG_COLOR
))
108 GetFont().SetColor(rColor
);
111 sal_uInt16 nSize
= GetNumSubNodes();
112 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
113 if (NULL
!= (pNode
= GetSubNode(i
)))
114 pNode
->SetColor(rColor
);
118 void SmNode::SetAttribut(sal_uInt16 nAttrib
)
121 (nAttrib
== ATTR_BOLD
&& !(Flags() & FLG_BOLD
)) ||
122 (nAttrib
== ATTR_ITALIC
&& !(Flags() & FLG_ITALIC
))
125 nAttributes
|= nAttrib
;
129 sal_uInt16 nSize
= GetNumSubNodes();
130 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
131 if (NULL
!= (pNode
= GetSubNode(i
)))
132 pNode
->SetAttribut(nAttrib
);
136 void SmNode::ClearAttribut(sal_uInt16 nAttrib
)
139 (nAttrib
== ATTR_BOLD
&& !(Flags() & FLG_BOLD
)) ||
140 (nAttrib
== ATTR_ITALIC
&& !(Flags() & FLG_ITALIC
))
143 nAttributes
&= ~nAttrib
;
147 sal_uInt16 nSize
= GetNumSubNodes();
148 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
149 if (NULL
!= (pNode
= GetSubNode(i
)))
150 pNode
->ClearAttribut(nAttrib
);
154 void SmNode::SetFont(const SmFace
&rFace
)
156 if (!(Flags() & FLG_FONT
))
160 sal_uInt16 nSize
= GetNumSubNodes();
161 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
162 if (NULL
!= (pNode
= GetSubNode(i
)))
163 pNode
->SetFont(rFace
);
167 void SmNode::SetFontSize(const Fraction
&rSize
, FontSizeType nType
)
168 //! 'rSize' is in units of pts
172 if (!(Flags() & FLG_SIZE
))
174 Fraction
aVal (SmPtsTo100th_mm(rSize
.GetNumerator()),
175 rSize
.GetDenominator());
176 long nHeight
= (long)aVal
;
178 aFntSize
= GetFont().GetSize();
179 aFntSize
.Width() = 0;
182 case FontSizeType::ABSOLUT
:
183 aFntSize
.Height() = nHeight
;
186 case FontSizeType::PLUS
:
187 aFntSize
.Height() += nHeight
;
190 case FontSizeType::MINUS
:
191 aFntSize
.Height() -= nHeight
;
194 case FontSizeType::MULTIPLY
:
195 aFntSize
.Height() = (long) (Fraction(aFntSize
.Height()) * rSize
);
198 case FontSizeType::DIVIDE
:
199 if (rSize
!= Fraction(0L))
200 aFntSize
.Height() = (long) (Fraction(aFntSize
.Height()) / rSize
);
206 // check the requested size against maximum value
207 static int const nMaxVal
= SmPtsTo100th_mm(128);
208 if (aFntSize
.Height() > nMaxVal
)
209 aFntSize
.Height() = nMaxVal
;
211 GetFont().SetSize(aFntSize
);
215 sal_uInt16 nSize
= GetNumSubNodes();
216 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
217 if (NULL
!= (pNode
= GetSubNode(i
)))
218 pNode
->SetFontSize(rSize
, nType
);
222 void SmNode::SetSize(const Fraction
&rSize
)
227 sal_uInt16 nSize
= GetNumSubNodes();
228 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
229 if (NULL
!= (pNode
= GetSubNode(i
)))
230 pNode
->SetSize(rSize
);
234 void SmNode::SetRectHorAlign(RectHorAlign eHorAlign
, bool bApplyToSubTree
)
236 if (!(Flags() & FLG_HORALIGN
))
237 eRectHorAlign
= eHorAlign
;
242 sal_uInt16 nSize
= GetNumSubNodes();
243 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
244 if (NULL
!= (pNode
= GetSubNode(i
)))
245 pNode
->SetRectHorAlign(eHorAlign
);
250 void SmNode::PrepareAttributes()
252 GetFont().SetWeight((Attributes() & ATTR_BOLD
) ? WEIGHT_BOLD
: WEIGHT_NORMAL
);
253 GetFont().SetItalic((Attributes() & ATTR_ITALIC
) ? ITALIC_NORMAL
: ITALIC_NONE
);
257 void SmNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
259 #if OSL_DEBUG_LEVEL > 1
268 switch (rFormat
.GetHorAlign())
269 { case AlignLeft
: eRectHorAlign
= RHA_LEFT
; break;
270 case AlignCenter
: eRectHorAlign
= RHA_CENTER
; break;
271 case AlignRight
: eRectHorAlign
= RHA_RIGHT
; break;
274 GetFont() = rFormat
.GetFont(FNT_MATH
);
275 OSL_ENSURE( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE
,
276 "unexpected CharSet" );
277 GetFont().SetWeight(WEIGHT_NORMAL
);
278 GetFont().SetItalic(ITALIC_NONE
);
281 sal_uInt16 nSize
= GetNumSubNodes();
282 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
283 if (NULL
!= (pNode
= GetSubNode(i
)))
284 pNode
->Prepare(rFormat
, rDocShell
);
287 sal_uInt16
SmNode::FindIndex() const
289 const SmStructureNode
* pParent
= GetParent();
290 if (!pParent
) { return 0; }
292 for (sal_uInt16 i
= 0; i
< pParent
->GetNumSubNodes(); ++i
) {
293 if (pParent
->GetSubNode(i
) == this) {
298 DBG_ASSERT(false, "Connection between parent and child is inconsistent.");
303 #if OSL_DEBUG_LEVEL > 1
304 void SmNode::ToggleDebug() const
305 // toggle 'bIsDebug' in current subtree
307 SmNode
*pThis
= (SmNode
*) this;
309 pThis
->bIsDebug
= bIsDebug
? false : true;
312 sal_uInt16 nSize
= GetNumSubNodes();
313 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
314 if (NULL
!= (pNode
= pThis
->GetSubNode(i
)))
315 pNode
->ToggleDebug();
320 void SmNode::Move(const Point
& rPosition
)
322 if (rPosition
.X() == 0 && rPosition
.Y() == 0)
325 SmRect::Move(rPosition
);
328 sal_uInt16 nSize
= GetNumSubNodes();
329 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
330 if (NULL
!= (pNode
= GetSubNode(i
)))
331 pNode
->Move(rPosition
);
335 void SmNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
338 sal_uInt16 nSize
= GetNumSubNodes();
339 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
340 if (NULL
!= (pNode
= GetSubNode(i
)))
341 pNode
->Arrange(rDev
, rFormat
);
344 void SmNode::CreateTextFromNode(OUString
&rText
)
347 sal_uInt16 nSize
= GetNumSubNodes();
350 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
351 if (NULL
!= (pNode
= GetSubNode(i
)))
352 pNode
->CreateTextFromNode(rText
);
355 rText
= comphelper::string::stripEnd(rText
, ' ');
361 void SmNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong
/*nWidth*/)
366 void SmNode::AdaptToY(const OutputDevice
&/*rDev*/, sal_uLong
/*nHeight*/)
371 const SmNode
* SmNode::FindTokenAt(sal_uInt16 nRow
, sal_uInt16 nCol
) const
372 // returns (first) ** visible ** (sub)node with the tokens text at
373 // position 'nRow', 'nCol'.
374 //! (there should be exactly one such node if any)
377 && nRow
== GetToken().nRow
378 && nCol
>= GetToken().nCol
&& nCol
< GetToken().nCol
+ GetToken().aText
.getLength())
382 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
383 for (sal_uInt16 i
= 0; i
< nNumSubNodes
; i
++)
384 { const SmNode
*pNode
= GetSubNode(i
);
389 const SmNode
*pResult
= pNode
->FindTokenAt(nRow
, nCol
);
399 const SmNode
* SmNode::FindRectClosestTo(const Point
&rPoint
) const
401 long nDist
= LONG_MAX
;
402 const SmNode
*pResult
= 0;
408 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
409 for (sal_uInt16 i
= 0; i
< nNumSubNodes
; i
++)
410 { const SmNode
*pNode
= GetSubNode(i
);
416 const SmNode
*pFound
= pNode
->FindRectClosestTo(rPoint
);
417 if (pFound
&& (nTmp
= pFound
->OrientedDist(rPoint
)) < nDist
)
421 // quit immediately if 'rPoint' is inside the *should not
422 // overlap with other rectangles* part.
423 // This (partly) serves for getting the attributes in eg
424 // "bar overstrike a".
425 // ('nDist < 0' is used as *quick shot* to avoid evaluation of
426 // the following expression, where the result is already determined)
427 if (nDist
< 0 && pFound
->IsInsideRect(rPoint
))
436 void SmNode::GetAccessibleText( OUStringBuffer
&/*rText*/ ) const
438 SAL_WARN("starmath", "SmNode: GetAccessibleText not overridden");
441 const SmNode
* SmNode::FindNodeWithAccessibleIndex(sal_Int32 nAccIdx
) const
443 const SmNode
*pResult
= 0;
445 sal_Int32 nIdx
= GetAccessibleIndex();
448 GetAccessibleText( aTxt
); // get text if used in following 'if' statement
451 && nIdx
<= nAccIdx
&& nAccIdx
< nIdx
+ aTxt
.getLength())
455 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
456 for (sal_uInt16 i
= 0; i
< nNumSubNodes
; i
++)
458 const SmNode
*pNode
= GetSubNode(i
);
462 pResult
= pNode
->FindNodeWithAccessibleIndex(nAccIdx
);
471 #ifdef DEBUG_ENABLE_DUMPASDOT
472 void SmNode::DumpAsDot(std::ostream
&out
, OUString
* label
, int number
, int& id
, int parent
) const
474 //If this is the root start the file
476 out
<<"digraph {"<<std::endl
;
478 out
<<"labelloc = \"t\";"<<std::endl
;
480 //CreateTextFromNode(eq);
481 eq
= eq
.replaceAll("\n", " ");
482 eq
= eq
.replaceAll("\\", "\\\\");
483 eq
= eq
.replaceAll("\"", "\\\"");
484 out
<<"label= \"Equation: \\\"";
485 out
<< OUStringToOString(eq
, RTL_TEXTENCODING_UTF8
).getStr();
486 out
<<"\\\"\";"<<std::endl
;
490 //Some how out<<(int)this; doesn't work... So we do this nasty workaround...
492 sprintf(strid
, "%i", id
);
495 sprintf(strnr
, "%i", number
);
497 //Dump connection to this node
500 sprintf(pid
, "%i", parent
);
501 out
<<"n"<<pid
<<" -> n"<<strid
<<" [label=\""<<strnr
<<"\"];"<<std::endl
;
502 //If doesn't have parent and isn't a rootnode:
503 } else if(number
!= -1) {
504 out
<<"orphaned -> n"<<strid
<<" [label=\""<<strnr
<<"\"];"<<std::endl
;
508 out
<<"n"<< strid
<<" [label=\"";
509 switch( GetType() ) {
510 case NTABLE
: out
<<"SmTableNode"; break;
511 case NBRACE
: out
<<"SmBraceNode"; break;
512 case NBRACEBODY
: out
<<"SmBracebodyNode"; break;
513 case NOPER
: out
<<"SmOperNode"; break;
514 case NALIGN
: out
<<"SmAlignNode"; break;
515 case NATTRIBUT
: out
<<"SmAttributNode"; break;
516 case NFONT
: out
<<"SmFontNode"; break;
517 case NUNHOR
: out
<<"SmUnHorNode"; break;
518 case NBINHOR
: out
<<"SmBinHorNode"; break;
519 case NBINVER
: out
<<"SmBinVerNode"; break;
520 case NBINDIAGONAL
: out
<<"SmBinDiagonalNode"; break;
521 case NSUBSUP
: out
<<"SmSubSupNode"; break;
522 case NMATRIX
: out
<<"SmMatrixNode"; break;
523 case NPLACE
: out
<<"SmPlaceNode"; break;
526 out
<< OUStringToOString(((SmTextNode
*)this)->GetText(), RTL_TEXTENCODING_UTF8
).getStr();
528 case NSPECIAL
: out
<<"SmSpecialNode"; break;
529 case NGLYPH_SPECIAL
: out
<<"SmGlyphSpecialNode"; break;
531 out
<<"SmMathSymbolNode: ";
532 out
<< OUStringToOString(((SmMathSymbolNode
*)this)->GetText(), RTL_TEXTENCODING_UTF8
).getStr();
534 case NBLANK
: out
<<"SmBlankNode"; break;
535 case NERROR
: out
<<"SmErrorNode"; break;
536 case NLINE
: out
<<"SmLineNode"; break;
537 case NEXPRESSION
: out
<<"SmExpressionNode"; break;
538 case NPOLYLINE
: out
<<"SmPolyLineNode"; break;
539 case NROOT
: out
<<"SmRootNode"; break;
540 case NROOTSYMBOL
: out
<<"SmRootSymbolNode"; break;
541 case NRECTANGLE
: out
<<"SmRectangleNode"; break;
542 case NVERTICAL_BRACE
: out
<<"SmVerticalBraceNode"; break;
543 case NMATHIDENT
: out
<<"SmMathIdentifierNode"; break;
544 case NINTDYNSYMBOL
: out
<<"SmDynIntegralSymbolNode"; break;
545 case NINTDYN
: out
<<"SmDynIntegralNode"; break;
551 out
<<", style=dashed";
552 out
<<"];"<<std::endl
;
557 sal_uInt16 nSize
= GetNumSubNodes();
558 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
559 if (NULL
!= (pNode
= GetSubNode(i
)))
560 pNode
->DumpAsDot(out
, NULL
, i
, ++id
, myid
);
562 //If this is the root end the file
566 #endif /* DEBUG_ENABLE_DUMPASDOT */
568 long SmNode::GetFormulaBaseline() const
570 SAL_WARN("starmath", "This dummy implementation should not have been called.");
576 SmStructureNode::SmStructureNode( const SmStructureNode
&rNode
) :
577 SmNode( rNode
.GetType(), rNode
.GetToken() )
580 for (i
= 0; i
< aSubNodes
.size(); i
++)
584 auto nSize
= rNode
.aSubNodes
.size();
585 aSubNodes
.resize( nSize
);
586 for (i
= 0; i
< nSize
; ++i
)
588 SmNode
*pNode
= rNode
.aSubNodes
[i
];
589 aSubNodes
[i
] = pNode
? new SmNode( *pNode
) : 0;
595 SmStructureNode::~SmStructureNode()
599 for (sal_uInt16 i
= 0; i
< GetNumSubNodes(); i
++)
600 if (NULL
!= (pNode
= GetSubNode(i
)))
605 SmStructureNode
& SmStructureNode::operator = ( const SmStructureNode
&rNode
)
607 SmNode::operator = ( rNode
);
610 for (i
= 0; i
< aSubNodes
.size(); i
++)
614 auto nSize
= rNode
.aSubNodes
.size();
615 aSubNodes
.resize( nSize
);
616 for (i
= 0; i
< nSize
; ++i
)
618 SmNode
*pNode
= rNode
.aSubNodes
[i
];
619 aSubNodes
[i
] = pNode
? new SmNode( *pNode
) : 0;
628 void SmStructureNode::SetSubNodes(SmNode
*pFirst
, SmNode
*pSecond
, SmNode
*pThird
)
630 size_t nSize
= pThird
? 3 : (pSecond
? 2 : (pFirst
? 1 : 0));
631 aSubNodes
.resize( nSize
);
633 aSubNodes
[0] = pFirst
;
635 aSubNodes
[1] = pSecond
;
637 aSubNodes
[2] = pThird
;
643 void SmStructureNode::SetSubNodes(const SmNodeArray
&rNodeArray
)
645 aSubNodes
= rNodeArray
;
650 bool SmStructureNode::IsVisible() const
656 sal_uInt16
SmStructureNode::GetNumSubNodes() const
658 return (sal_uInt16
) aSubNodes
.size();
662 SmNode
* SmStructureNode::GetSubNode(sal_uInt16 nIndex
)
664 return aSubNodes
[nIndex
];
668 void SmStructureNode::GetAccessibleText( OUStringBuffer
&rText
) const
670 sal_uInt16 nNodes
= GetNumSubNodes();
671 for (sal_uInt16 i
= 0; i
< nNodes
; ++i
)
673 SmNode
*pNode
= const_cast<SmStructureNode
*>(this)->GetSubNode(i
);
676 if (pNode
->IsVisible())
677 static_cast<SmStructureNode
*>(pNode
)->nAccIndex
= rText
.getLength();
678 pNode
->GetAccessibleText( rText
);
686 bool SmVisibleNode::IsVisible() const
692 sal_uInt16
SmVisibleNode::GetNumSubNodes() const
698 SmNode
* SmVisibleNode::GetSubNode(sal_uInt16
/*nIndex*/)
706 void SmGraphicNode::GetAccessibleText( OUStringBuffer
&rText
) const
708 rText
.append(GetToken().aText
);
714 void SmExpressionNode::CreateTextFromNode(OUString
&rText
)
717 sal_uInt16 nSize
= GetNumSubNodes();
720 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
721 if (NULL
!= (pNode
= GetSubNode(i
)))
723 pNode
->CreateTextFromNode(rText
);
724 //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
725 if (pNode
->GetType() == NMATH
)
727 ( !rText
.endsWith("+") && !rText
.endsWith("-") ))
733 rText
= comphelper::string::stripEnd(rText
, ' ');
741 void SmTableNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
742 // arranges all subnodes in one column
745 sal_uInt16 nSize
= GetNumSubNodes();
747 // make distance depend on font size
748 long nDist
= +(rFormat
.GetDistance(DIS_VERTICAL
)
749 * GetFont().GetSize().Height()) / 100L;
754 // arrange subnodes and get maximum width of them
758 for (i
= 0; i
< nSize
; i
++)
759 if (NULL
!= (pNode
= GetSubNode(i
)))
760 { pNode
->Arrange(rDev
, rFormat
);
761 if ((nTmp
= pNode
->GetItalicWidth()) > nMaxWidth
)
766 SmRect::operator = (SmRect(nMaxWidth
, 1));
767 for (i
= 0; i
< nSize
; i
++)
768 { if (NULL
!= (pNode
= GetSubNode(i
)))
769 { const SmRect
&rNodeRect
= pNode
->GetRect();
770 const SmNode
*pCoNode
= pNode
->GetLeftMost();
771 RectHorAlign eHorAlign
= pCoNode
->GetRectHorAlign();
773 aPos
= rNodeRect
.AlignTo(*this, RP_BOTTOM
,
774 eHorAlign
, RVA_BASELINE
);
778 ExtendBy(rNodeRect
, nSize
> 1 ? RCP_NONE
: RCP_ARG
);
783 nFormulaBaseline
= GetBaseline();
786 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
787 aTmpDev
.SetFont(GetFont());
789 SmRect aRect
= (SmRect(aTmpDev
, &rFormat
, OUString("a"),
790 GetFont().GetBorderWidth()));
791 nFormulaBaseline
= GetAlignM();
792 // move from middle position by constant - distance
793 // between middle and baseline for single letter
794 nFormulaBaseline
+= aRect
.GetBaseline() - aRect
.GetAlignM();
799 SmNode
* SmTableNode::GetLeftMost()
805 long SmTableNode::GetFormulaBaseline() const
807 return nFormulaBaseline
;
811 /**************************************************************************/
814 void SmLineNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
816 SmNode::Prepare(rFormat
, rDocShell
);
818 // Here we use the 'FNT_VARIABLE' font since it's ascent and descent in general fit better
819 // to the rest of the formula compared to the 'FNT_MATH' font.
820 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
825 /**************************************************************************/
828 void SmLineNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
829 // arranges all subnodes in one row with some extra space between
832 sal_uInt16 nSize
= GetNumSubNodes();
834 for (i
= 0; i
< nSize
; i
++)
835 if (NULL
!= (pNode
= GetSubNode(i
)))
836 pNode
->Arrange(rDev
, rFormat
);
838 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
839 aTmpDev
.SetFont(GetFont());
843 // provide an empty rectangle with alignment parameters for the "current"
844 // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
845 // same sub-/supscript positions.)
846 //! be sure to use a character that has explicitly defined HiAttribut
847 //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
849 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, OUString("a"),
850 GetFont().GetBorderWidth()));
851 // make sure that the rectangle occupies (almost) no space
853 SetItalicSpaces(0, 0);
857 // make distance depend on font size
858 long nDist
= (rFormat
.GetDistance(DIS_HORIZONTAL
) * GetFont().GetSize().Height()) / 100L;
859 if (!IsUseExtraSpaces())
863 // copy the first node into LineNode and extend by the others
864 if (NULL
!= (pNode
= GetSubNode(0)))
865 SmRect::operator = (pNode
->GetRect());
867 for (i
= 1; i
< nSize
; i
++)
868 if (NULL
!= (pNode
= GetSubNode(i
)))
870 aPos
= pNode
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
872 // add horizontal space to the left for each but the first sub node
876 ExtendBy( *pNode
, RCP_XOR
);
881 /**************************************************************************/
884 void SmExpressionNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
885 // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
887 SmLineNode::Arrange(rDev
, rFormat
);
889 // copy alignment of leftmost subnode if any
890 SmNode
*pNode
= GetLeftMost();
892 SetRectHorAlign(pNode
->GetRectHorAlign(), false);
896 /**************************************************************************/
899 void SmUnHorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
901 bool bIsPostfix
= GetToken().eType
== TFACT
;
903 SmNode
*pOper
= GetSubNode(bIsPostfix
? 1 : 0),
904 *pBody
= GetSubNode(bIsPostfix
? 0 : 1);
905 OSL_ENSURE(pOper
, "Sm: NULL pointer");
906 OSL_ENSURE(pBody
, "Sm: NULL pointer");
908 pOper
->SetSize(Fraction (rFormat
.GetRelSize(SIZ_OPERATOR
), 100));
909 pOper
->Arrange(rDev
, rFormat
);
910 pBody
->Arrange(rDev
, rFormat
);
912 Point aPos
= pOper
->AlignTo(*pBody
, bIsPostfix
? RP_RIGHT
: RP_LEFT
,
913 RHA_CENTER
, RVA_BASELINE
);
914 // add a bit space between operator and argument
915 // (worst case -{1 over 2} where - and over have almost no space inbetween)
916 long nDelta
= pOper
->GetFont().GetSize().Height() / 20;
923 SmRect::operator = (*pBody
);
924 long nOldBot
= GetBottom();
926 ExtendBy(*pOper
, RCP_XOR
);
928 // workaround for Bug 50865: "a^2 a^+2" have different baselines
929 // for exponents (if size of exponent is large enough)
934 /**************************************************************************/
937 void SmRootNode::GetHeightVerOffset(const SmRect
&rRect
,
938 long &rHeight
, long &rVerOffset
)
939 // calculate height and vertical offset of root sign suitable for 'rRect'
941 rVerOffset
= (rRect
.GetBottom() - rRect
.GetAlignB()) / 2;
942 rHeight
= rRect
.GetHeight() - rVerOffset
;
944 OSL_ENSURE(rHeight
>= 0, "Sm : Ooops...");
945 OSL_ENSURE(rVerOffset
>= 0, "Sm : Ooops...");
949 Point
SmRootNode::GetExtraPos(const SmRect
&rRootSymbol
,
950 const SmRect
&rExtra
)
952 const Size
&rSymSize
= rRootSymbol
.GetSize();
954 Point aPos
= rRootSymbol
.GetTopLeft()
955 + Point((rSymSize
.Width() * 70) / 100,
956 (rSymSize
.Height() * 52) / 100);
958 // from this calculate topleft edge of 'rExtra'
959 aPos
.X() -= rExtra
.GetWidth() + rExtra
.GetItalicRightSpace();
960 aPos
.Y() -= rExtra
.GetHeight();
961 // if there's enough space move a bit less to the right
962 // examples: "nroot i a", "nroot j a"
963 // (it looks better if we don't use italic-spaces here)
964 long nX
= rRootSymbol
.GetLeft() + (rSymSize
.Width() * 30) / 100;
972 void SmRootNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
974 //! pExtra needs to have the smaller index than pRootSym in order to
975 //! not to get the root symbol but the pExtra when clicking on it in the
976 //! GraphicWindow. (That is because of the simplicity of the algorithm
977 //! that finds the node corresponding to a mouseclick in the window.)
978 SmNode
*pExtra
= GetSubNode(0),
979 *pRootSym
= GetSubNode(1),
980 *pBody
= GetSubNode(2);
981 OSL_ENSURE(pRootSym
, "Sm: NULL pointer");
982 OSL_ENSURE(pBody
, "Sm: NULL pointer");
984 pBody
->Arrange(rDev
, rFormat
);
988 GetHeightVerOffset(*pBody
, nHeight
, nVerOffset
);
989 nHeight
+= rFormat
.GetDistance(DIS_ROOT
)
990 * GetFont().GetSize().Height() / 100L;
992 // font specialist advised to change the width first
993 pRootSym
->AdaptToY(rDev
, nHeight
);
994 pRootSym
->AdaptToX(rDev
, pBody
->GetItalicWidth());
996 pRootSym
->Arrange(rDev
, rFormat
);
998 Point aPos
= pRootSym
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, RVA_BASELINE
);
999 //! override calculated vertical position
1000 aPos
.Y() = pRootSym
->GetTop() + pBody
->GetBottom() - pRootSym
->GetBottom();
1001 aPos
.Y() -= nVerOffset
;
1002 pRootSym
->MoveTo(aPos
);
1005 { pExtra
->SetSize(Fraction(rFormat
.GetRelSize(SIZ_INDEX
), 100));
1006 pExtra
->Arrange(rDev
, rFormat
);
1008 aPos
= GetExtraPos(*pRootSym
, *pExtra
);
1009 pExtra
->MoveTo(aPos
);
1012 SmRect::operator = (*pBody
);
1013 ExtendBy(*pRootSym
, RCP_THIS
);
1015 ExtendBy(*pExtra
, RCP_THIS
, true);
1019 void SmRootNode::CreateTextFromNode(OUString
&rText
)
1021 SmNode
*pExtra
= GetSubNode(0);
1025 pExtra
->CreateTextFromNode(rText
);
1030 if (!pExtra
&& GetSubNode(2)->GetNumSubNodes() > 1)
1033 GetSubNode(2)->CreateTextFromNode(rText
);
1035 if (!pExtra
&& GetSubNode(2)->GetNumSubNodes() > 1)
1039 /**************************************************************************/
1042 void SmDynIntegralNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1044 SmNode
*pDynIntegralSym
= Symbol(),
1046 OSL_ENSURE(pDynIntegralSym
, "Sm: NULL pointer");
1047 OSL_ENSURE(pBody
, "Sm: NULL pointer");
1049 pBody
->Arrange(rDev
, rFormat
);
1051 long nHeight
= pBody
->GetHeight();
1052 pDynIntegralSym
->AdaptToY(rDev
, nHeight
);
1054 pDynIntegralSym
->Arrange(rDev
, rFormat
);
1056 Point aPos
= pDynIntegralSym
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, RVA_BASELINE
);
1057 //! override calculated vertical position
1058 aPos
.Y() = pDynIntegralSym
->GetTop() + pBody
->GetBottom() - pDynIntegralSym
->GetBottom();
1059 pDynIntegralSym
->MoveTo(aPos
);
1062 // override its own rectangle with pBody's
1063 SmRect::operator = (*pBody
);
1064 // extends this rectangle with the symbol's one
1065 ExtendBy(*pDynIntegralSym
, RCP_THIS
);
1070 void SmDynIntegralNode::CreateTextFromNode(OUString
&rText
)
1074 SmNode
*pBody
= GetSubNode(1);
1076 if (pBody
->GetNumSubNodes() > 1)
1079 pBody
->CreateTextFromNode(rText
);
1081 if (pBody
->GetNumSubNodes() > 1)
1087 /**************************************************************************/
1090 void SmBinHorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1092 SmNode
*pLeft
= GetSubNode(0),
1093 *pOper
= GetSubNode(1),
1094 *pRight
= GetSubNode(2);
1095 OSL_ENSURE(pLeft
!= NULL
, "Sm: NULL pointer");
1096 OSL_ENSURE(pOper
!= NULL
, "Sm: NULL pointer");
1097 OSL_ENSURE(pRight
!= NULL
, "Sm: NULL pointer");
1099 pOper
->SetSize(Fraction (rFormat
.GetRelSize(SIZ_OPERATOR
), 100));
1101 pLeft
->Arrange(rDev
, rFormat
);
1102 pOper
->Arrange(rDev
, rFormat
);
1103 pRight
->Arrange(rDev
, rFormat
);
1105 const SmRect
&rOpRect
= pOper
->GetRect();
1107 long nDist
= (rOpRect
.GetWidth() *
1108 rFormat
.GetDistance(DIS_HORIZONTAL
)) / 100L;
1110 SmRect::operator = (*pLeft
);
1113 aPos
= pOper
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1115 pOper
->MoveTo(aPos
);
1116 ExtendBy(*pOper
, RCP_XOR
);
1118 aPos
= pRight
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1121 pRight
->MoveTo(aPos
);
1122 ExtendBy(*pRight
, RCP_XOR
);
1126 /**************************************************************************/
1129 void SmBinVerNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1131 SmNode
*pNum
= GetSubNode(0),
1132 *pLine
= GetSubNode(1),
1133 *pDenom
= GetSubNode(2);
1134 OSL_ENSURE(pNum
, "Sm : NULL pointer");
1135 OSL_ENSURE(pLine
, "Sm : NULL pointer");
1136 OSL_ENSURE(pDenom
, "Sm : NULL pointer");
1138 bool bIsTextmode
= rFormat
.IsTextmode();
1141 Fraction
aFraction(rFormat
.GetRelSize(SIZ_INDEX
), 100);
1142 pNum
->SetSize(aFraction
);
1143 pLine
->SetSize(aFraction
);
1144 pDenom
->SetSize(aFraction
);
1147 pNum
->Arrange(rDev
, rFormat
);
1148 pDenom
->Arrange(rDev
, rFormat
);
1150 long nFontHeight
= GetFont().GetSize().Height(),
1151 nExtLen
= nFontHeight
* rFormat
.GetDistance(DIS_FRACTION
) / 100L,
1152 nThick
= nFontHeight
* rFormat
.GetDistance(DIS_STROKEWIDTH
) / 100L,
1153 nWidth
= std::max(pNum
->GetItalicWidth(), pDenom
->GetItalicWidth()),
1154 nNumDist
= bIsTextmode
? 0 :
1155 nFontHeight
* rFormat
.GetDistance(DIS_NUMERATOR
) / 100L,
1156 nDenomDist
= bIsTextmode
? 0 :
1157 nFontHeight
* rFormat
.GetDistance(DIS_DENOMINATOR
) / 100L;
1159 // font specialist advised to change the width first
1160 pLine
->AdaptToY(rDev
, nThick
);
1161 pLine
->AdaptToX(rDev
, nWidth
+ 2 * nExtLen
);
1162 pLine
->Arrange(rDev
, rFormat
);
1164 // get horizontal alignment for numerator
1165 const SmNode
*pLM
= pNum
->GetLeftMost();
1166 RectHorAlign eHorAlign
= pLM
->GetRectHorAlign();
1168 // move numerator to its position
1169 Point aPos
= pNum
->AlignTo(*pLine
, RP_TOP
, eHorAlign
, RVA_BASELINE
);
1170 aPos
.Y() -= nNumDist
;
1173 // get horizontal alignment for denominator
1174 pLM
= pDenom
->GetLeftMost();
1175 eHorAlign
= pLM
->GetRectHorAlign();
1177 // move denominator to its position
1178 aPos
= pDenom
->AlignTo(*pLine
, RP_BOTTOM
, eHorAlign
, RVA_BASELINE
);
1179 aPos
.Y() += nDenomDist
;
1180 pDenom
->MoveTo(aPos
);
1182 SmRect::operator = (*pNum
);
1183 ExtendBy(*pDenom
, RCP_NONE
).ExtendBy(*pLine
, RCP_NONE
, pLine
->GetCenterY());
1186 void SmBinVerNode::CreateTextFromNode(OUString
&rText
)
1188 SmNode
*pNum
= GetSubNode(0),
1189 *pDenom
= GetSubNode(2);
1190 pNum
->CreateTextFromNode(rText
);
1192 pDenom
->CreateTextFromNode(rText
);
1196 SmNode
* SmBinVerNode::GetLeftMost()
1204 /// @return value of the determinant formed by the two points
1205 double Det(const Point
&rHeading1
, const Point
&rHeading2
)
1207 return rHeading1
.X() * rHeading2
.Y() - rHeading1
.Y() * rHeading2
.X();
1211 /// Is true iff the point 'rPoint1' belongs to the straight line through 'rPoint2'
1212 /// and has the direction vector 'rHeading2'
1213 bool IsPointInLine(const Point
&rPoint1
,
1214 const Point
&rPoint2
, const Point
&rHeading2
)
1216 OSL_ENSURE(rHeading2
!= Point(), "Sm : 0 vector");
1219 static const double eps
= 5.0 * DBL_EPSILON
;
1222 if (labs(rHeading2
.X()) > labs(rHeading2
.Y()))
1224 fLambda
= (rPoint1
.X() - rPoint2
.X()) / (double) rHeading2
.X();
1225 bRes
= fabs(rPoint1
.Y() - (rPoint2
.Y() + fLambda
* rHeading2
.Y())) < eps
;
1229 fLambda
= (rPoint1
.Y() - rPoint2
.Y()) / (double) rHeading2
.Y();
1230 bRes
= fabs(rPoint1
.X() - (rPoint2
.X() + fLambda
* rHeading2
.X())) < eps
;
1237 sal_uInt16
GetLineIntersectionPoint(Point
&rResult
,
1238 const Point
& rPoint1
, const Point
&rHeading1
,
1239 const Point
& rPoint2
, const Point
&rHeading2
)
1241 OSL_ENSURE(rHeading1
!= Point(), "Sm : 0 vector");
1242 OSL_ENSURE(rHeading2
!= Point(), "Sm : 0 vector");
1244 sal_uInt16 nRes
= 1;
1245 static const double eps
= 5.0 * DBL_EPSILON
;
1247 // are the direction vectors linearly dependent?
1248 double fDet
= Det(rHeading1
, rHeading2
);
1249 if (fabs(fDet
) < eps
)
1251 nRes
= IsPointInLine(rPoint1
, rPoint2
, rHeading2
) ? USHRT_MAX
: 0;
1252 rResult
= nRes
? rPoint1
: Point();
1256 // here we do not pay attention to the computational accurancy
1257 // (that would be more complicated and is not really worth it in this case)
1258 double fLambda
= ( (rPoint1
.Y() - rPoint2
.Y()) * rHeading2
.X()
1259 - (rPoint1
.X() - rPoint2
.X()) * rHeading2
.Y())
1261 rResult
= Point(rPoint1
.X() + (long) (fLambda
* rHeading1
.X()),
1262 rPoint1
.Y() + (long) (fLambda
* rHeading1
.Y()));
1271 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken
&rNodeToken
)
1272 : SmStructureNode(NBINDIAGONAL
, rNodeToken
)
1279 /// @return position and size of the diagonal line
1280 /// premise: SmRect of the node defines the limitation(!) consequently it has to be known upfront
1281 void SmBinDiagonalNode::GetOperPosSize(Point
&rPos
, Size
&rSize
,
1282 const Point
&rDiagPoint
, double fAngleDeg
) const
1285 static const double fPi
= 3.1415926535897932384626433;
1286 double fAngleRad
= fAngleDeg
/ 180.0 * fPi
;
1287 long nRectLeft
= GetItalicLeft(),
1288 nRectRight
= GetItalicRight(),
1289 nRectTop
= GetTop(),
1290 nRectBottom
= GetBottom();
1291 Point
aRightHdg (100, 0),
1293 aDiagHdg ( (long)(100.0 * cos(fAngleRad
)),
1294 (long)(-100.0 * sin(fAngleRad
)) );
1296 long nLeft
, nRight
, nTop
, nBottom
; // margins of the rectangle for the diagonal
1300 // determine top right corner
1301 GetLineIntersectionPoint(aPoint
,
1302 Point(nRectLeft
, nRectTop
), aRightHdg
,
1303 rDiagPoint
, aDiagHdg
);
1304 // is there a point of intersection with the top border?
1305 if (aPoint
.X() <= nRectRight
)
1307 nRight
= aPoint
.X();
1312 // there has to be a point of intersection with the right border!
1313 GetLineIntersectionPoint(aPoint
,
1314 Point(nRectRight
, nRectTop
), aDownHdg
,
1315 rDiagPoint
, aDiagHdg
);
1317 nRight
= nRectRight
;
1321 // determine bottom left corner
1322 GetLineIntersectionPoint(aPoint
,
1323 Point(nRectLeft
, nRectBottom
), aRightHdg
,
1324 rDiagPoint
, aDiagHdg
);
1325 // is there a point of intersection with the bottom border?
1326 if (aPoint
.X() >= nRectLeft
)
1329 nBottom
= nRectBottom
;
1333 // there has to be a point of intersection with the left border!
1334 GetLineIntersectionPoint(aPoint
,
1335 Point(nRectLeft
, nRectTop
), aDownHdg
,
1336 rDiagPoint
, aDiagHdg
);
1339 nBottom
= aPoint
.Y();
1344 // determine top left corner
1345 GetLineIntersectionPoint(aPoint
,
1346 Point(nRectLeft
, nRectTop
), aRightHdg
,
1347 rDiagPoint
, aDiagHdg
);
1348 // is there a point of intersection with the top border?
1349 if (aPoint
.X() >= nRectLeft
)
1356 // there has to be a point of intersection with the left border!
1357 GetLineIntersectionPoint(aPoint
,
1358 Point(nRectLeft
, nRectTop
), aDownHdg
,
1359 rDiagPoint
, aDiagHdg
);
1365 // determine bottom right corner
1366 GetLineIntersectionPoint(aPoint
,
1367 Point(nRectLeft
, nRectBottom
), aRightHdg
,
1368 rDiagPoint
, aDiagHdg
);
1369 // is there a point of intersection with the bottom border?
1370 if (aPoint
.X() <= nRectRight
)
1372 nRight
= aPoint
.X();
1373 nBottom
= nRectBottom
;
1377 // there has to be a point of intersection with the right border!
1378 GetLineIntersectionPoint(aPoint
,
1379 Point(nRectRight
, nRectTop
), aDownHdg
,
1380 rDiagPoint
, aDiagHdg
);
1382 nRight
= nRectRight
;
1383 nBottom
= aPoint
.Y();
1387 rSize
= Size(nRight
- nLeft
+ 1, nBottom
- nTop
+ 1);
1393 void SmBinDiagonalNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1395 // Both arguments have to get into the SubNodes before the Operator so that clicking
1396 // within the GraphicWindow sets the FormulaCursor correctly (cf. SmRootNode)
1397 SmNode
*pLeft
= GetSubNode(0),
1398 *pRight
= GetSubNode(1);
1399 OSL_ENSURE(pLeft
, "Sm : NULL pointer");
1400 OSL_ENSURE(pRight
, "Sm : NULL pointer");
1402 OSL_ENSURE(GetSubNode(2)->GetType() == NPOLYLINE
, "Sm : wrong node type");
1403 SmPolyLineNode
*pOper
= static_cast<SmPolyLineNode
*>(GetSubNode(2));
1404 OSL_ENSURE(pOper
, "Sm : NULL pointer");
1406 //! some routines being called extract some info from the OutputDevice's
1407 //! font (eg the space to be used for borders OR the font name(!!)).
1408 //! Thus the font should reflect the needs and has to be set!
1409 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
1410 aTmpDev
.SetFont(GetFont());
1412 pLeft
->Arrange(aTmpDev
, rFormat
);
1413 pRight
->Arrange(aTmpDev
, rFormat
);
1415 // determine implicitly the values (incl. the margin) of the diagonal line
1416 pOper
->Arrange(aTmpDev
, rFormat
);
1418 long nDelta
= pOper
->GetWidth() * 8 / 10;
1420 // determine TopLeft position from the right argument
1422 aPos
.X() = pLeft
->GetItalicRight() + nDelta
+ pRight
->GetItalicLeftSpace();
1424 aPos
.Y() = pLeft
->GetBottom() + nDelta
;
1426 aPos
.Y() = pLeft
->GetTop() - nDelta
- pRight
->GetHeight();
1428 pRight
->MoveTo(aPos
);
1430 // determine new baseline
1431 long nTmpBaseline
= IsAscending() ? (pLeft
->GetBottom() + pRight
->GetTop()) / 2
1432 : (pLeft
->GetTop() + pRight
->GetBottom()) / 2;
1433 Point
aLogCenter ((pLeft
->GetItalicRight() + pRight
->GetItalicLeft()) / 2,
1436 SmRect::operator = (*pLeft
);
1437 ExtendBy(*pRight
, RCP_NONE
);
1440 // determine position and size of diagonal line
1442 GetOperPosSize(aPos
, aTmpSize
, aLogCenter
, IsAscending() ? 60.0 : -60.0);
1444 // font specialist advised to change the width first
1445 pOper
->AdaptToY(aTmpDev
, aTmpSize
.Height());
1446 pOper
->AdaptToX(aTmpDev
, aTmpSize
.Width());
1447 // and make it active
1448 pOper
->Arrange(aTmpDev
, rFormat
);
1450 pOper
->MoveTo(aPos
);
1452 ExtendBy(*pOper
, RCP_NONE
, nTmpBaseline
);
1456 /**************************************************************************/
1459 void SmSubSupNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1461 OSL_ENSURE(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES
,
1462 "Sm: wrong number of subnodes");
1464 SmNode
*pBody
= GetBody();
1465 OSL_ENSURE(pBody
, "Sm: NULL pointer");
1467 long nOrigHeight
= pBody
->GetFont().GetSize().Height();
1469 pBody
->Arrange(rDev
, rFormat
);
1471 const SmRect
&rBodyRect
= pBody
->GetRect();
1472 SmRect::operator = (rBodyRect
);
1474 // line that separates sub- and supscript rectangles
1475 long nDelimLine
= SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1480 // iterate over all possible sub-/supscripts
1481 SmRect
aTmpRect (rBodyRect
);
1482 for (int i
= 0; i
< SUBSUP_NUM_ENTRIES
; i
++)
1483 { SmSubSup eSubSup
= (SmSubSup
) i
; // cast
1484 SmNode
*pSubSup
= GetSubSup(eSubSup
);
1489 // switch position of limits if we are in textmode
1490 if (rFormat
.IsTextmode() && (GetToken().nGroup
& TGLIMIT
))
1492 { case CSUB
: eSubSup
= RSUB
; break;
1493 case CSUP
: eSubSup
= RSUP
; break;
1498 // prevent sub-/supscripts from diminishing in size
1499 // (as would be in "a_{1_{2_{3_4}}}")
1500 if (GetFont().GetSize().Height() > rFormat
.GetBaseSize().Height() / 3)
1502 sal_uInt16 nIndex
= (eSubSup
== CSUB
|| eSubSup
== CSUP
) ?
1503 SIZ_LIMITS
: SIZ_INDEX
;
1504 Fraction
aFraction ( rFormat
.GetRelSize(nIndex
), 100 );
1505 pSubSup
->SetSize(aFraction
);
1508 pSubSup
->Arrange(rDev
, rFormat
);
1510 bool bIsTextmode
= rFormat
.IsTextmode();
1513 //! be sure that CSUB, CSUP are handled before the other cases!
1519 * rFormat
.GetDistance(DIS_SUBSCRIPT
) / 100L;
1520 aPos
= pSubSup
->GetRect().AlignTo(aTmpRect
,
1521 eSubSup
== LSUB
? RP_LEFT
: RP_RIGHT
,
1522 RHA_CENTER
, RVA_BOTTOM
);
1524 nDelta
= nDelimLine
- aPos
.Y();
1532 * rFormat
.GetDistance(DIS_SUPERSCRIPT
) / 100L;
1533 aPos
= pSubSup
->GetRect().AlignTo(aTmpRect
,
1534 eSubSup
== LSUP
? RP_LEFT
: RP_RIGHT
,
1535 RHA_CENTER
, RVA_TOP
);
1537 nDelta
= aPos
.Y() + pSubSup
->GetHeight() - nDelimLine
;
1544 * rFormat
.GetDistance(DIS_LOWERLIMIT
) / 100L;
1545 aPos
= pSubSup
->GetRect().AlignTo(rBodyRect
, RP_BOTTOM
,
1546 RHA_CENTER
, RVA_BASELINE
);
1552 * rFormat
.GetDistance(DIS_UPPERLIMIT
) / 100L;
1553 aPos
= pSubSup
->GetRect().AlignTo(rBodyRect
, RP_TOP
,
1554 RHA_CENTER
, RVA_BASELINE
);
1559 pSubSup
->MoveTo(aPos
);
1560 ExtendBy(*pSubSup
, RCP_THIS
, true);
1562 // update rectangle to which RSUB, RSUP, LSUB, LSUP
1563 // will be aligned to
1564 if (eSubSup
== CSUB
|| eSubSup
== CSUP
)
1569 void SmSubSupNode::CreateTextFromNode(OUString
&rText
)
1572 GetSubNode(0)->CreateTextFromNode(rText
);
1574 if (NULL
!= (pNode
= GetSubNode(LSUB
+1)))
1577 pNode
->CreateTextFromNode(rText
);
1579 if (NULL
!= (pNode
= GetSubNode(LSUP
+1)))
1582 pNode
->CreateTextFromNode(rText
);
1584 if (NULL
!= (pNode
= GetSubNode(CSUB
+1)))
1587 pNode
->CreateTextFromNode(rText
);
1589 if (NULL
!= (pNode
= GetSubNode(CSUP
+1)))
1592 pNode
->CreateTextFromNode(rText
);
1594 if (NULL
!= (pNode
= GetSubNode(RSUB
+1)))
1596 rText
= comphelper::string::stripEnd(rText
, ' ');
1598 pNode
->CreateTextFromNode(rText
);
1600 if (NULL
!= (pNode
= GetSubNode(RSUP
+1)))
1602 rText
= comphelper::string::stripEnd(rText
, ' ');
1604 pNode
->CreateTextFromNode(rText
);
1609 /**************************************************************************/
1611 void SmBraceNode::CreateTextFromNode(OUString
&rText
)
1613 if (GetScaleMode() == SCALE_HEIGHT
)
1617 GetSubNode(0)->CreateTextFromNode(aStr
);
1618 aStr
= comphelper::string::strip(aStr
, ' ');
1619 aStr
= comphelper::string::stripStart(aStr
, '\\');
1620 if (!aStr
.isEmpty())
1622 if (aStr
== "divides")
1624 else if (aStr
== "parallel")
1626 else if (aStr
== "<")
1635 GetSubNode(1)->CreateTextFromNode(rText
);
1636 if (GetScaleMode() == SCALE_HEIGHT
)
1640 GetSubNode(2)->CreateTextFromNode(aStr
);
1641 aStr
= comphelper::string::strip(aStr
, ' ');
1642 aStr
= comphelper::string::stripStart(aStr
, '\\');
1643 if (!aStr
.isEmpty())
1645 if (aStr
== "divides")
1647 else if (aStr
== "parallel")
1649 else if (aStr
== ">")
1662 void SmBraceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1664 SmNode
*pLeft
= GetSubNode(0),
1665 *pBody
= GetSubNode(1),
1666 *pRight
= GetSubNode(2);
1667 OSL_ENSURE(pLeft
, "Sm: NULL pointer");
1668 OSL_ENSURE(pBody
, "Sm: NULL pointer");
1669 OSL_ENSURE(pRight
, "Sm: NULL pointer");
1671 pBody
->Arrange(rDev
, rFormat
);
1673 bool bIsScaleNormal
= rFormat
.IsScaleNormalBrackets(),
1674 bScale
= pBody
->GetHeight() > 0 &&
1675 (GetScaleMode() == SCALE_HEIGHT
|| bIsScaleNormal
),
1676 bIsABS
= GetToken().eType
== TABS
;
1678 long nFaceHeight
= GetFont().GetSize().Height();
1680 // determine oversize in %
1681 sal_uInt16 nPerc
= 0;
1682 if (!bIsABS
&& bScale
)
1683 { // in case of oversize braces...
1684 sal_uInt16 nIndex
= GetScaleMode() == SCALE_HEIGHT
?
1685 DIS_BRACKETSIZE
: DIS_NORMALBRACKETSIZE
;
1686 nPerc
= rFormat
.GetDistance(nIndex
);
1689 // determine the height for the braces
1693 nBraceHeight
= pBody
->GetType() == NBRACEBODY
?
1694 static_cast<SmBracebodyNode
*>(pBody
)->GetBodyHeight()
1695 : pBody
->GetHeight();
1696 nBraceHeight
+= 2 * (nBraceHeight
* nPerc
/ 100L);
1699 nBraceHeight
= nFaceHeight
;
1701 // distance to the argument
1702 nPerc
= bIsABS
? 0 : rFormat
.GetDistance(DIS_BRACKETSPACE
);
1703 long nDist
= nFaceHeight
* nPerc
/ 100L;
1705 // if wanted, scale the braces to the wanted size
1708 Size
aTmpSize (pLeft
->GetFont().GetSize());
1709 OSL_ENSURE(pRight
->GetFont().GetSize() == aTmpSize
,
1710 "Sm : different font sizes");
1711 aTmpSize
.Width() = std::min((long) nBraceHeight
* 60L / 100L,
1712 rFormat
.GetBaseSize().Height() * 3L / 2L);
1713 // correction factor since change from StarMath to OpenSymbol font
1714 // because of the different font width in the FontMetric
1715 aTmpSize
.Width() *= 182;
1716 aTmpSize
.Width() /= 267;
1718 sal_Unicode cChar
= pLeft
->GetToken().cMathChar
;
1719 if (cChar
!= MS_LINE
&& cChar
!= MS_DLINE
&&
1720 cChar
!= MS_VERTLINE
&& cChar
!= MS_DVERTLINE
)
1721 pLeft
->GetFont().SetSize(aTmpSize
);
1723 cChar
= pRight
->GetToken().cMathChar
;
1724 if (cChar
!= MS_LINE
&& cChar
!= MS_DLINE
&&
1725 cChar
!= MS_VERTLINE
&& cChar
!= MS_DVERTLINE
)
1726 pRight
->GetFont().SetSize(aTmpSize
);
1728 pLeft
->AdaptToY(rDev
, nBraceHeight
);
1729 pRight
->AdaptToY(rDev
, nBraceHeight
);
1732 pLeft
->Arrange(rDev
, rFormat
);
1733 pRight
->Arrange(rDev
, rFormat
);
1735 // required in order to make "\(a\) - (a) - left ( a right )" look alright
1736 RectVerAlign eVerAlign
= bScale
? RVA_CENTERY
: RVA_BASELINE
;
1739 aPos
= pLeft
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, eVerAlign
);
1741 pLeft
->MoveTo(aPos
);
1743 aPos
= pRight
->AlignTo(*pBody
, RP_RIGHT
, RHA_CENTER
, eVerAlign
);
1745 pRight
->MoveTo(aPos
);
1747 SmRect::operator = (*pBody
);
1748 ExtendBy(*pLeft
, RCP_THIS
).ExtendBy(*pRight
, RCP_THIS
);
1752 /**************************************************************************/
1755 void SmBracebodyNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1757 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
1758 if (nNumSubNodes
== 0)
1761 // arrange arguments
1763 for (i
= 0; i
< nNumSubNodes
; i
+= 2)
1764 GetSubNode(i
)->Arrange(rDev
, rFormat
);
1766 // build reference rectangle with necessary info for vertical alignment
1767 SmRect
aRefRect (*GetSubNode(0));
1768 for (i
= 0; i
< nNumSubNodes
; i
+= 2)
1770 SmRect
aTmpRect (*GetSubNode(i
));
1771 Point aPos
= aTmpRect
.AlignTo(aRefRect
, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1772 aTmpRect
.MoveTo(aPos
);
1773 aRefRect
.ExtendBy(aTmpRect
, RCP_XOR
);
1776 nBodyHeight
= aRefRect
.GetHeight();
1778 // scale separators to required height and arrange them
1779 bool bScale
= GetScaleMode() == SCALE_HEIGHT
|| rFormat
.IsScaleNormalBrackets();
1780 long nHeight
= bScale
? aRefRect
.GetHeight() : GetFont().GetSize().Height();
1781 sal_uInt16 nIndex
= GetScaleMode() == SCALE_HEIGHT
?
1782 DIS_BRACKETSIZE
: DIS_NORMALBRACKETSIZE
;
1783 sal_uInt16 nPerc
= rFormat
.GetDistance(nIndex
);
1785 nHeight
+= 2 * (nHeight
* nPerc
/ 100L);
1786 for (i
= 1; i
< nNumSubNodes
; i
+= 2)
1788 SmNode
*pNode
= GetSubNode(i
);
1789 pNode
->AdaptToY(rDev
, nHeight
);
1790 pNode
->Arrange(rDev
, rFormat
);
1793 // horizontal distance between argument and brackets or separators
1794 long nDist
= GetFont().GetSize().Height()
1795 * rFormat
.GetDistance(DIS_BRACKETSPACE
) / 100L;
1797 SmNode
*pLeft
= GetSubNode(0);
1798 SmRect::operator = (*pLeft
);
1799 for (i
= 1; i
< nNumSubNodes
; i
++)
1801 bool bIsSeparator
= i
% 2 != 0;
1802 RectVerAlign eVerAlign
= bIsSeparator
? RVA_CENTERY
: RVA_BASELINE
;
1804 SmNode
*pRight
= GetSubNode(i
);
1805 Point aPosX
= pRight
->AlignTo(*pLeft
, RP_RIGHT
, RHA_CENTER
, eVerAlign
),
1806 aPosY
= pRight
->AlignTo(aRefRect
, RP_RIGHT
, RHA_CENTER
, eVerAlign
);
1809 pRight
->MoveTo(Point(aPosX
.X(), aPosY
.Y()));
1810 ExtendBy(*pRight
, bIsSeparator
? RCP_THIS
: RCP_XOR
);
1817 /**************************************************************************/
1820 void SmVerticalBraceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1822 SmNode
*pBody
= GetSubNode(0),
1823 *pBrace
= GetSubNode(1),
1824 *pScript
= GetSubNode(2);
1825 OSL_ENSURE(pBody
, "Sm: NULL pointer!");
1826 OSL_ENSURE(pBrace
, "Sm: NULL pointer!");
1827 OSL_ENSURE(pScript
, "Sm: NULL pointer!");
1829 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
1830 aTmpDev
.SetFont(GetFont());
1832 pBody
->Arrange(aTmpDev
, rFormat
);
1834 // size is the same as for limits for this part
1835 pScript
->SetSize( Fraction( rFormat
.GetRelSize(SIZ_LIMITS
), 100 ) );
1836 // braces are a bit taller than usually
1837 pBrace
->SetSize( Fraction(3, 2) );
1839 long nItalicWidth
= pBody
->GetItalicWidth();
1840 if (nItalicWidth
> 0)
1841 pBrace
->AdaptToX(aTmpDev
, nItalicWidth
);
1843 pBrace
->Arrange(aTmpDev
, rFormat
);
1844 pScript
->Arrange(aTmpDev
, rFormat
);
1846 // determine the relative position and the distances between each other
1848 long nFontHeight
= pBody
->GetFont().GetSize().Height();
1849 long nDistBody
= nFontHeight
* rFormat
.GetDistance(DIS_ORNAMENTSIZE
),
1850 nDistScript
= nFontHeight
;
1851 if (GetToken().eType
== TOVERBRACE
)
1854 nDistBody
= - nDistBody
;
1855 nDistScript
*= - rFormat
.GetDistance(DIS_UPPERLIMIT
);
1859 eRectPos
= RP_BOTTOM
;
1860 nDistScript
*= + rFormat
.GetDistance(DIS_LOWERLIMIT
);
1863 nDistScript
/= 100L;
1865 Point aPos
= pBrace
->AlignTo(*pBody
, eRectPos
, RHA_CENTER
, RVA_BASELINE
);
1866 aPos
.Y() += nDistBody
;
1867 pBrace
->MoveTo(aPos
);
1869 aPos
= pScript
->AlignTo(*pBrace
, eRectPos
, RHA_CENTER
, RVA_BASELINE
);
1870 aPos
.Y() += nDistScript
;
1871 pScript
->MoveTo(aPos
);
1873 SmRect::operator = (*pBody
);
1874 ExtendBy(*pBrace
, RCP_THIS
).ExtendBy(*pScript
, RCP_THIS
);
1878 /**************************************************************************/
1881 SmNode
* SmOperNode::GetSymbol()
1883 SmNode
*pNode
= GetSubNode(0);
1884 OSL_ENSURE(pNode
, "Sm: NULL pointer!");
1886 if (pNode
->GetType() == NSUBSUP
)
1887 pNode
= static_cast<SmSubSupNode
*>(pNode
)->GetBody();
1889 OSL_ENSURE(pNode
, "Sm: NULL pointer!");
1894 long SmOperNode::CalcSymbolHeight(const SmNode
&rSymbol
,
1895 const SmFormat
&rFormat
) const
1896 // returns the font height to be used for operator-symbol
1898 long nHeight
= GetFont().GetSize().Height();
1900 SmTokenType eTmpType
= GetToken().eType
;
1901 if (eTmpType
== TLIM
|| eTmpType
== TLIMINF
|| eTmpType
== TLIMSUP
)
1904 if (!rFormat
.IsTextmode())
1906 // set minimum size ()
1907 nHeight
+= (nHeight
* 20L) / 100L;
1910 * rFormat
.GetDistance(DIS_OPERATORSIZE
) / 100L;
1911 nHeight
= nHeight
* 686L / 845L;
1914 // correct user-defined symbols to match height of sum from used font
1915 if (rSymbol
.GetToken().eType
== TSPECIAL
)
1916 nHeight
= nHeight
* 845L / 686L;
1922 void SmOperNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1924 SmNode
*pOper
= GetSubNode(0);
1925 SmNode
*pBody
= GetSubNode(1);
1927 OSL_ENSURE(pOper
, "Sm: missing subnode");
1928 OSL_ENSURE(pBody
, "Sm: missing subnode");
1930 SmNode
*pSymbol
= GetSymbol();
1931 pSymbol
->SetSize(Fraction(CalcSymbolHeight(*pSymbol
, rFormat
),
1932 pSymbol
->GetFont().GetSize().Height()));
1934 pBody
->Arrange(rDev
, rFormat
);
1935 pOper
->Arrange(rDev
, rFormat
);
1937 long nOrigHeight
= GetFont().GetSize().Height(),
1939 * rFormat
.GetDistance(DIS_OPERATORSPACE
) / 100L;
1941 Point aPos
= pOper
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, /*RVA_CENTERY*/RVA_MID
);
1943 pOper
->MoveTo(aPos
);
1945 SmRect::operator = (*pBody
);
1946 ExtendBy(*pOper
, RCP_THIS
);
1950 /**************************************************************************/
1953 void SmAlignNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1954 // set alignment within the entire subtree (including current node)
1956 OSL_ENSURE(GetNumSubNodes() > 0, "Sm: missing subnode");
1958 SmNode
*pNode
= GetSubNode(0);
1960 RectHorAlign eHorAlign
= RHA_CENTER
;
1961 switch (GetToken().eType
)
1963 case TALIGNL
: eHorAlign
= RHA_LEFT
; break;
1964 case TALIGNC
: eHorAlign
= RHA_CENTER
; break;
1965 case TALIGNR
: eHorAlign
= RHA_RIGHT
; break;
1969 SetRectHorAlign(eHorAlign
);
1971 pNode
->Arrange(rDev
, rFormat
);
1973 SmRect::operator = (pNode
->GetRect());
1977 /**************************************************************************/
1980 void SmAttributNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1982 SmNode
*pAttr
= GetSubNode(0),
1983 *pBody
= GetSubNode(1);
1984 OSL_ENSURE(pBody
, "Sm: body missing");
1985 OSL_ENSURE(pAttr
, "Sm: attribute missing");
1987 pBody
->Arrange(rDev
, rFormat
);
1989 if (GetScaleMode() == SCALE_WIDTH
)
1990 pAttr
->AdaptToX(rDev
, pBody
->GetItalicWidth());
1991 pAttr
->Arrange(rDev
, rFormat
);
1993 // get relative position of attribute
1994 RectVerAlign eVerAlign
;
1996 switch (GetToken().eType
)
1998 eVerAlign
= RVA_ATTRIBUT_LO
;
2001 eVerAlign
= RVA_ATTRIBUT_MID
;
2004 eVerAlign
= RVA_ATTRIBUT_HI
;
2005 if (pBody
->GetType() == NATTRIBUT
)
2006 nDist
= GetFont().GetSize().Height()
2007 * rFormat
.GetDistance(DIS_ORNAMENTSPACE
) / 100L;
2009 Point aPos
= pAttr
->AlignTo(*pBody
, RP_ATTRIBUT
, RHA_CENTER
, eVerAlign
);
2011 pAttr
->MoveTo(aPos
);
2013 SmRect::operator = (*pBody
);
2014 ExtendBy(*pAttr
, RCP_THIS
, true);
2017 void SmFontNode::CreateTextFromNode(OUString
&rText
)
2019 switch (GetToken().eType
)
2031 rText
+= "nitalic ";
2034 rText
+= "phantom ";
2041 case FontSizeType::PLUS
:
2044 case FontSizeType::MINUS
:
2047 case FontSizeType::MULTIPLY
:
2050 case FontSizeType::DIVIDE
:
2053 case FontSizeType::ABSOLUT
:
2057 rText
+= ::rtl::math::doubleToUString(
2058 static_cast<double>(aFontSize
),
2059 rtl_math_StringFormat_Automatic
,
2060 rtl_math_DecimalPlaces_Max
, '.', true);
2065 rText
+= "color black ";
2068 rText
+= "color white ";
2071 rText
+= "color red ";
2074 rText
+= "color green ";
2077 rText
+= "color blue ";
2080 rText
+= "color cyan ";
2083 rText
+= "color magenta ";
2086 rText
+= "color yellow ";
2089 rText
+= "color teal";
2092 rText
+= "color silver";
2095 rText
+= "color gray";
2098 rText
+= "color maroon";
2101 rText
+= "color purple";
2104 rText
+= "color lime";
2107 rText
+= "color olive";
2110 rText
+= "color navy";
2113 rText
+= "color aqua";
2116 rText
+= "color fuchsia";
2119 rText
+= "font sans ";
2122 rText
+= "font serif ";
2125 rText
+= "font fixed ";
2130 GetSubNode(1)->CreateTextFromNode(rText
);
2133 void SmFontNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2135 //! prepare subnodes first
2136 SmNode::Prepare(rFormat
, rDocShell
);
2139 switch (GetToken().eType
)
2141 case TFIXED
: nFnt
= FNT_FIXED
; break;
2142 case TSANS
: nFnt
= FNT_SANS
; break;
2143 case TSERIF
: nFnt
= FNT_SERIF
; break;
2148 { GetFont() = rFormat
.GetFont( sal::static_int_cast
< sal_uInt16
>(nFnt
) );
2152 //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
2153 //! other font nodes (those with lower depth in the tree)
2154 Flags() |= FLG_FONT
;
2157 void SmFontNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2159 SmNode
*pNode
= GetSubNode(1);
2160 OSL_ENSURE(pNode
, "Sm: missing subnode");
2162 switch (GetToken().eType
)
2164 pNode
->SetFontSize(aFontSize
, nSizeType
);
2169 pNode
->SetFont(GetFont());
2171 case TUNKNOWN
: break; // no assertion on "font <?> <?>"
2173 case TPHANTOM
: SetPhantom(true); break;
2174 case TBOLD
: SetAttribut(ATTR_BOLD
); break;
2175 case TITALIC
: SetAttribut(ATTR_ITALIC
); break;
2176 case TNBOLD
: ClearAttribut(ATTR_BOLD
); break;
2177 case TNITALIC
: ClearAttribut(ATTR_ITALIC
); break;
2179 case TBLACK
: SetColor(Color(COL_BLACK
)); break;
2180 case TWHITE
: SetColor(Color(COL_WHITE
)); break;
2181 case TRED
: SetColor(Color(COL_LIGHTRED
)); break;
2182 case TGREEN
: SetColor(Color(COL_GREEN
)); break;
2183 case TBLUE
: SetColor(Color(COL_LIGHTBLUE
)); break;
2184 case TCYAN
: SetColor(Color(COL_LIGHTCYAN
)); break; // as in Calc
2185 case TMAGENTA
: SetColor(Color(COL_LIGHTMAGENTA
)); break; // as in Calc
2186 case TYELLOW
: SetColor(Color(COL_YELLOW
)); break;
2187 case TTEAL
: SetColor(Color(COL_CYAN
)); break;
2188 case TSILVER
: SetColor(Color(COL_LIGHTGRAY
)); break;
2189 case TGRAY
: SetColor(Color(COL_GRAY
)); break;
2190 case TMAROON
: SetColor(Color(COL_RED
)); break;
2191 case TPURPLE
: SetColor(Color(COL_MAGENTA
)); break;
2192 case TLIME
: SetColor(Color(COL_LIGHTGREEN
)); break;
2193 case TOLIVE
: SetColor(Color(COL_BROWN
)); break;
2194 case TNAVY
: SetColor(Color(COL_BLUE
)); break;
2195 case TAQUA
: SetColor(Color(COL_LIGHTCYAN
)); break;
2196 case TFUCHSIA
: SetColor(Color(COL_LIGHTMAGENTA
)); break;
2199 SAL_WARN("starmath", "unknown case");
2202 pNode
->Arrange(rDev
, rFormat
);
2204 SmRect::operator = (pNode
->GetRect());
2208 void SmFontNode::SetSizeParameter(const Fraction
& rValue
, FontSizeType Type
)
2215 /**************************************************************************/
2218 SmPolyLineNode::SmPolyLineNode(const SmToken
&rNodeToken
)
2219 : SmGraphicNode(NPOLYLINE
, rNodeToken
)
2226 void SmPolyLineNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong nNewWidth
)
2228 aToSize
.Width() = nNewWidth
;
2232 void SmPolyLineNode::AdaptToY(const OutputDevice
&/*rDev*/, sal_uLong nNewHeight
)
2234 GetFont().FreezeBorderWidth();
2235 aToSize
.Height() = nNewHeight
;
2239 void SmPolyLineNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2241 //! some routines being called extract some info from the OutputDevice's
2242 //! font (eg the space to be used for borders OR the font name(!!)).
2243 //! Thus the font should reflect the needs and has to be set!
2244 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2245 aTmpDev
.SetFont(GetFont());
2247 long nBorderwidth
= GetFont().GetBorderWidth();
2249 // create polygon using both endpoints
2250 OSL_ENSURE(aPoly
.GetSize() == 2, "Sm : wrong number of points");
2251 Point aPointA
, aPointB
;
2252 if (GetToken().eType
== TWIDESLASH
)
2254 aPointA
.X() = nBorderwidth
;
2255 aPointA
.Y() = aToSize
.Height() - nBorderwidth
;
2256 aPointB
.X() = aToSize
.Width() - nBorderwidth
;
2257 aPointB
.Y() = nBorderwidth
;
2261 OSL_ENSURE(GetToken().eType
== TWIDEBACKSLASH
, "Sm : unexpected token");
2263 aPointA
.Y() = nBorderwidth
;
2264 aPointB
.X() = aToSize
.Width() - nBorderwidth
;
2265 aPointB
.Y() = aToSize
.Height() - nBorderwidth
;
2267 aPoly
.SetPoint(aPointA
, 0);
2268 aPoly
.SetPoint(aPointB
, 1);
2270 long nThick
= GetFont().GetSize().Height()
2271 * rFormat
.GetDistance(DIS_STROKEWIDTH
) / 100L;
2272 nWidth
= nThick
+ 2 * nBorderwidth
;
2274 SmRect::operator = (SmRect(aToSize
.Width(), aToSize
.Height()));
2278 /**************************************************************************/
2280 void SmRootSymbolNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong nWidth
)
2282 nBodyWidth
= nWidth
;
2286 void SmRootSymbolNode::AdaptToY(const OutputDevice
&rDev
, sal_uLong nHeight
)
2288 // some additional length so that the horizontal
2289 // bar will be positioned above the argument
2290 SmMathSymbolNode::AdaptToY(rDev
, nHeight
+ nHeight
/ 10L);
2294 /**************************************************************************/
2297 void SmDynIntegralSymbolNode::AdaptToY(const OutputDevice
&rDev
, sal_uLong nHeight
)
2299 static const long nFactor
= 12L;
2301 // The new height equals (1 + nFactor) * oldHeight
2302 // nFactor was chosen for keeping the integral sign from becoming too "fat".
2303 SmMathSymbolNode::AdaptToY(rDev
, nHeight
+ nHeight
/ nFactor
);
2306 long nCurWidth
= GetSize().Width();
2307 SmMathSymbolNode::AdaptToX(rDev
, nCurWidth
+ nCurWidth
/ nFactor
);
2311 /**************************************************************************/
2314 void SmRectangleNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong nWidth
)
2316 aToSize
.Width() = nWidth
;
2320 void SmRectangleNode::AdaptToY(const OutputDevice
&/*rDev*/, sal_uLong nHeight
)
2322 GetFont().FreezeBorderWidth();
2323 aToSize
.Height() = nHeight
;
2327 void SmRectangleNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&/*rFormat*/)
2329 long nFontHeight
= GetFont().GetSize().Height();
2330 long nWidth
= aToSize
.Width(),
2331 nHeight
= aToSize
.Height();
2333 nHeight
= nFontHeight
/ 30;
2335 nWidth
= nFontHeight
/ 3;
2337 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2338 aTmpDev
.SetFont(GetFont());
2340 // add some borderspace
2341 sal_uLong nTmpBorderWidth
= GetFont().GetBorderWidth();
2342 nHeight
+= 2 * nTmpBorderWidth
;
2344 //! use this method in order to have 'SmRect::HasAlignInfo() == true'
2345 //! and thus having the attribute-fences updated in 'SmRect::ExtendBy'
2346 SmRect::operator = (SmRect(nWidth
, nHeight
));
2350 /**************************************************************************/
2353 SmTextNode::SmTextNode( SmNodeType eNodeType
, const SmToken
&rNodeToken
, sal_uInt16 nFontDescP
)
2354 : SmVisibleNode(eNodeType
, rNodeToken
)
2355 , nFontDesc(nFontDescP
)
2356 , nSelectionStart(0)
2361 SmTextNode::SmTextNode( const SmToken
&rNodeToken
, sal_uInt16 nFontDescP
)
2362 : SmVisibleNode(NTEXT
, rNodeToken
)
2363 , nFontDesc(nFontDescP
)
2364 , nSelectionStart(0)
2369 void SmTextNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2371 SmNode::Prepare(rFormat
, rDocShell
);
2373 // default setting for horizontal alignment of nodes with TTEXT
2374 // content is as alignl (cannot be done in Arrange since it would
2375 // override the settings made by an SmAlignNode before)
2376 if (TTEXT
== GetToken().eType
)
2377 SetRectHorAlign( RHA_LEFT
);
2379 aText
= GetToken().aText
;
2380 GetFont() = rFormat
.GetFont(GetFontDesc());
2382 if (IsItalic( GetFont() ))
2383 Attributes() |= ATTR_ITALIC
;
2384 if (IsBold( GetFont() ))
2385 Attributes() |= ATTR_BOLD
;
2387 // special handling for ':' where it is a token on it's own and is likely
2388 // to be used for mathematical notations. (E.g. a:b = 2:3)
2389 // In that case it should not be displayed in italic.
2390 if (GetToken().aText
.getLength() == 1 && GetToken().aText
[0] == ':')
2391 Attributes() &= ~ATTR_ITALIC
;
2395 void SmTextNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2397 PrepareAttributes();
2399 sal_uInt16 nSizeDesc
= GetFontDesc() == FNT_FUNCTION
?
2400 SIZ_FUNCTION
: SIZ_TEXT
;
2401 GetFont() *= Fraction (rFormat
.GetRelSize(nSizeDesc
), 100);
2403 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2404 aTmpDev
.SetFont(GetFont());
2406 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, aText
, GetFont().GetBorderWidth()));
2409 void SmTextNode::CreateTextFromNode(OUString
&rText
)
2412 if (GetToken().eType
== TTEXT
)
2419 SmParser aParseTest
;
2420 SmNode
*pTable
= aParseTest
.Parse(GetToken().aText
);
2422 if ( (pTable
->GetType() == NTABLE
) && (pTable
->GetNumSubNodes() == 1) )
2424 SmNode
*pResult
= pTable
->GetSubNode(0);
2425 if ( (pResult
->GetType() == NLINE
) &&
2426 (pResult
->GetNumSubNodes() == 1) )
2428 pResult
= pResult
->GetSubNode(0);
2429 if ( (pResult
->GetType() == NEXPRESSION
) &&
2430 (pResult
->GetNumSubNodes() == 1) )
2432 pResult
= pResult
->GetSubNode(0);
2433 if (pResult
->GetType() == NTEXT
)
2440 if ((GetToken().eType
== TIDENT
) && (GetFontDesc() == FNT_FUNCTION
))
2442 //Search for existing functions and remove extraenous keyword
2453 rText
+= GetToken().aText
;
2461 void SmTextNode::GetAccessibleText( OUStringBuffer
&rText
) const
2463 rText
.append(aText
);
2466 void SmTextNode::AdjustFontDesc()
2468 if (GetToken().eType
== TTEXT
)
2469 nFontDesc
= FNT_TEXT
;
2470 else if(GetToken().eType
== TFUNC
)
2471 nFontDesc
= FNT_FUNCTION
;
2474 const SmTokenTableEntry
*pEntry
= SmParser::GetTokenTableEntry( aText
);
2475 if (pEntry
&& pEntry
->nGroup
== TGFUNCTION
) {
2476 nTok
= pEntry
->eType
;
2477 nFontDesc
= FNT_FUNCTION
;
2479 sal_Unicode firstChar
= aText
[0];
2480 if( ('0' <= firstChar
&& firstChar
<= '9') || firstChar
== '.' || firstChar
== ',') {
2481 nFontDesc
= FNT_NUMBER
;
2483 } else if (aText
.getLength() > 1) {
2484 nFontDesc
= FNT_VARIABLE
;
2487 nFontDesc
= FNT_VARIABLE
;
2491 SmToken tok
= GetToken();
2497 sal_Unicode
SmTextNode::ConvertSymbolToUnicode(sal_Unicode nIn
)
2499 //Find the best match in accepted unicode for our private area symbols
2500 static const sal_Unicode aStarMathPrivateToUnicode
[] =
2502 0x2030, 0xF613, 0xF612, 0x002B, 0x003C, 0x003E, 0xE425, 0xE421, 0xE088, 0x2208,
2503 0x0192, 0x2026, 0x2192, 0x221A, 0x221A, 0x221A, 0xE090, 0x005E, 0x02C7, 0x02D8,
2504 0x00B4, 0x0060, 0x02DC, 0x00AF, 0x0362, 0xE099, 0xE09A, 0x20DB, 0xE09C, 0xE09D,
2505 0x0028, 0x0029, 0x2220, 0x22AF, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7,
2506 0x002F, 0x005C, 0x274F, 0xE0AB, 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03A0,
2507 0x03a3, 0x03a5, 0x03a6, 0x03a8, 0x03A9, 0x03B1, 0x03B2, 0x03b3, 0x03b4, 0x03b5,
2508 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
2509 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03b5,
2510 0x03d1, 0x03d6, 0xE0D2, 0x03db, 0x2118, 0x2202, 0x2129, 0xE0D7, 0xE0D8, 0x22A4,
2511 0xE0DA, 0x2190, 0x2191, 0x2193
2513 if ((nIn
>= 0xE080) && (nIn
<= 0xE0DD))
2514 nIn
= aStarMathPrivateToUnicode
[nIn
-0xE080];
2516 //For whatever unicode glyph that equation editor doesn't ship with that
2517 //we have a possible match we can munge it to.
2530 /**************************************************************************/
2532 void SmMatrixNode::CreateTextFromNode(OUString
&rText
)
2534 rText
+= "matrix {";
2535 for (sal_uInt16 i
= 0; i
< nNumRows
; i
++)
2537 for (sal_uInt16 j
= 0; j
< nNumCols
; j
++)
2539 SmNode
*pNode
= GetSubNode(i
* nNumCols
+ j
);
2541 pNode
->CreateTextFromNode(rText
);
2542 if (j
!= nNumCols
-1)
2545 if (i
!= nNumRows
-1)
2548 rText
= comphelper::string::stripEnd(rText
, ' ');
2553 void SmMatrixNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2558 // initialize array that is to hold the maximum widths of all
2559 // elements (subnodes) in that column.
2560 std::vector
<long> aColWidth(nNumCols
);
2562 // arrange subnodes and calculate the aboves arrays contents
2563 sal_uInt16 nNodes
= GetNumSubNodes();
2564 for (i
= 0; i
< nNodes
; i
++)
2566 sal_uInt16 nIdx
= nNodes
- 1 - i
;
2567 if (NULL
!= (pNode
= GetSubNode(nIdx
)))
2569 pNode
->Arrange(rDev
, rFormat
);
2570 int nCol
= nIdx
% nNumCols
;
2571 aColWidth
[nCol
] = std::max(aColWidth
[nCol
], pNode
->GetItalicWidth());
2575 // norm distance from which the following two are calcutated
2576 const long nNormDist
= 3 * GetFont().GetSize().Height();
2578 // define horizontal and vertical minimal distances that separate
2580 long nHorDist
= nNormDist
* rFormat
.GetDistance(DIS_MATRIXCOL
) / 100L,
2581 nVerDist
= nNormDist
* rFormat
.GetDistance(DIS_MATRIXROW
) / 100L;
2583 // build array that holds the leftmost position for each column
2584 std::vector
<long> aColLeft(nNumCols
);
2586 for (j
= 0; j
< nNumCols
; j
++)
2589 nX
+= aColWidth
[j
] + nHorDist
;
2594 SmRect::operator = (SmRect());
2595 for (i
= 0; i
< nNumRows
; i
++)
2596 { aLineRect
= SmRect();
2597 for (j
= 0; j
< nNumCols
; j
++)
2598 { SmNode
*pTmpNode
= GetSubNode(i
* nNumCols
+ j
);
2599 OSL_ENSURE(pTmpNode
, "Sm: NULL pointer");
2601 const SmRect
&rNodeRect
= pTmpNode
->GetRect();
2603 // align all baselines in that row if possible
2604 aPos
= rNodeRect
.AlignTo(aLineRect
, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
2605 aPos
.X() += nHorDist
;
2607 // get horizontal alignment
2608 const SmNode
*pCoNode
= pTmpNode
->GetLeftMost();
2609 RectHorAlign eHorAlign
= pCoNode
->GetRectHorAlign();
2611 // calculate horizontal position of element depending on column
2612 // and horizontal alignment
2615 aPos
.X() = rNodeRect
.GetLeft() + aColLeft
[j
];
2618 aPos
.X() = rNodeRect
.GetLeft() + aColLeft
[j
]
2620 - rNodeRect
.GetItalicCenterX();
2623 aPos
.X() = rNodeRect
.GetLeft() + aColLeft
[j
]
2624 + aColWidth
[j
] - rNodeRect
.GetItalicWidth();
2628 pTmpNode
->MoveTo(aPos
);
2629 aLineRect
.ExtendBy(rNodeRect
, RCP_XOR
);
2632 aPos
= aLineRect
.AlignTo(*this, RP_BOTTOM
, RHA_CENTER
, RVA_BASELINE
);
2633 aPos
.Y() += nVerDist
;
2635 // move 'aLineRect' and rectangles in that line to final position
2636 aDelta
.X() = 0; // since horizontal alignment is already done
2637 aDelta
.Y() = aPos
.Y() - aLineRect
.GetTop();
2638 aLineRect
.Move(aDelta
);
2639 for (j
= 0; j
< nNumCols
; j
++)
2640 if (NULL
!= (pNode
= GetSubNode(i
* nNumCols
+ j
)))
2641 pNode
->Move(aDelta
);
2643 ExtendBy(aLineRect
, RCP_NONE
);
2648 void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows
, sal_uInt16 nMatrixCols
)
2650 nNumRows
= nMatrixRows
;
2651 nNumCols
= nMatrixCols
;
2655 SmNode
* SmMatrixNode::GetLeftMost()
2661 /**************************************************************************/
2664 SmMathSymbolNode::SmMathSymbolNode(const SmToken
&rNodeToken
)
2665 : SmSpecialNode(NMATH
, rNodeToken
, FNT_MATH
)
2667 sal_Unicode cChar
= GetToken().cMathChar
;
2668 if ((sal_Unicode
) '\0' != cChar
)
2669 SetText(OUString(cChar
));
2672 void SmMathSymbolNode::AdaptToX(const OutputDevice
&rDev
, sal_uLong nWidth
)
2674 // Since there is no function to do this, we try to approximate it:
2675 Size
aFntSize (GetFont().GetSize());
2677 //! however the result is a bit better with 'nWidth' as initial font width
2678 aFntSize
.Width() = nWidth
;
2679 GetFont().SetSize(aFntSize
);
2681 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2682 aTmpDev
.SetFont(GetFont());
2684 // get denominator of error factor for width
2685 long nTmpBorderWidth
= GetFont().GetBorderWidth();
2686 long nDenom
= SmRect(aTmpDev
, NULL
, GetText(), nTmpBorderWidth
).GetItalicWidth();
2688 // scale fontwidth with this error factor
2689 aFntSize
.Width() *= nWidth
;
2690 aFntSize
.Width() /= nDenom
? nDenom
: 1;
2692 GetFont().SetSize(aFntSize
);
2695 void SmMathSymbolNode::AdaptToY(const OutputDevice
&rDev
, sal_uLong nHeight
)
2697 GetFont().FreezeBorderWidth();
2698 Size
aFntSize (GetFont().GetSize());
2700 // Since we only want to scale the height, we might have
2701 // to determine the font width in order to keep it
2702 if (aFntSize
.Width() == 0)
2704 OutputDevice
&rDevNC
= (OutputDevice
&) rDev
;
2705 rDevNC
.Push(PushFlags::FONT
| PushFlags::MAPMODE
);
2706 rDevNC
.SetFont(GetFont());
2707 aFntSize
.Width() = rDev
.GetFontMetric().GetSize().Width();
2710 OSL_ENSURE(aFntSize
.Width() != 0, "Sm: ");
2712 //! however the result is a bit better with 'nHeight' as initial
2714 aFntSize
.Height() = nHeight
;
2715 GetFont().SetSize(aFntSize
);
2717 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2718 aTmpDev
.SetFont(GetFont());
2720 // get denominator of error factor for height
2721 long nTmpBorderWidth
= GetFont().GetBorderWidth();
2722 long nDenom
= SmRect(aTmpDev
, NULL
, GetText(), nTmpBorderWidth
).GetHeight();
2724 // scale fontwidth with this error factor
2725 aFntSize
.Height() *= nHeight
;
2726 aFntSize
.Height() /= nDenom
? nDenom
: 1;
2728 GetFont().SetSize(aFntSize
);
2732 void SmMathSymbolNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2734 SmNode::Prepare(rFormat
, rDocShell
);
2736 GetFont() = rFormat
.GetFont(GetFontDesc());
2737 // use same font size as is used for variables
2738 GetFont().SetSize( rFormat
.GetFont( FNT_VARIABLE
).GetSize() );
2740 OSL_ENSURE(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL
||
2741 GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE
,
2742 "wrong charset for character from StarMath/OpenSymbol font");
2744 Flags() |= FLG_FONT
| FLG_ITALIC
;
2748 void SmMathSymbolNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2750 const OUString
&rText
= GetText();
2752 if (rText
.isEmpty() || rText
[0] == '\0')
2753 { SmRect::operator = (SmRect());
2757 PrepareAttributes();
2759 GetFont() *= Fraction (rFormat
.GetRelSize(SIZ_TEXT
), 100);
2761 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2762 aTmpDev
.SetFont(GetFont());
2764 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, rText
, GetFont().GetBorderWidth()));
2767 void SmMathSymbolNode::CreateTextFromNode(OUString
&rText
)
2770 MathType::LookupChar(GetToken().cMathChar
, sStr
);
2774 void SmRectangleNode::CreateTextFromNode(OUString
&rText
)
2776 switch (GetToken().eType
)
2779 rText
+= "underline ";
2782 rText
+= "overline ";
2785 rText
+= "overstrike ";
2792 void SmAttributNode::CreateTextFromNode(OUString
&rText
)
2795 sal_uInt16 nSize
= GetNumSubNodes();
2796 OSL_ENSURE(nSize
== 2, "Node missing members");
2798 sal_Unicode nLast
=0;
2799 if (NULL
!= (pNode
= GetSubNode(0)))
2802 pNode
->CreateTextFromNode(aStr
);
2803 if (aStr
.getLength() > 1)
2810 case MS_BAR
: // MACRON
2811 rText
+= "overline ";
2813 case MS_DOT
: // DOT ABOVE
2816 case 0x2dc: // SMALL TILDE
2817 rText
+= "widetilde ";
2819 case MS_DDOT
: // DIAERESIS
2825 case MS_DDDOT
: // COMBINING THREE DOTS ABOVE
2828 case MS_ACUTE
: // ACUTE ACCENT
2829 case MS_COMBACUTE
: // COMBINING ACUTE ACCENT
2832 case MS_GRAVE
: // GRAVE ACCENT
2833 case MS_COMBGRAVE
: // COMBINING GRAVE ACCENT
2836 case MS_CHECK
: // CARON
2837 case MS_COMBCHECK
: // COMBINING CARON
2840 case MS_BREVE
: // BREVE
2841 case MS_COMBBREVE
: // COMBINING BREVE
2844 case MS_CIRCLE
: // RING ABOVE
2845 case MS_COMBCIRCLE
: // COMBINING RING ABOVE
2848 case MS_RIGHTARROW
: // RIGHTWARDS ARROW
2849 case MS_VEC
: // COMBINING RIGHT ARROW ABOVE
2852 case MS_TILDE
: // TILDE
2853 case MS_COMBTILDE
: // COMBINING TILDE
2856 case MS_HAT
: // CIRCUMFLEX ACCENT
2857 case MS_COMBHAT
: // COMBINING CIRCUMFLEX ACCENT
2860 case MS_COMBBAR
: // COMBINING MACRON
2864 rText
+= OUString( nLast
);
2871 if (NULL
!= (pNode
= GetSubNode(1)))
2872 pNode
->CreateTextFromNode(rText
);
2874 rText
= comphelper::string::stripEnd(rText
, ' ');
2876 if (nLast
== 0xE082)
2877 rText
+= " overbrace {}";
2882 /**************************************************************************/
2884 static bool lcl_IsFromGreekSymbolSet( const OUString
&rTokenText
)
2888 // valid symbol name needs to have a '%' at pos 0 and at least an additional char
2889 if (rTokenText
.getLength() > 2 && rTokenText
[0] == (sal_Unicode
)'%')
2891 OUString
aName( rTokenText
.copy(1) );
2892 SmSym
*pSymbol
= SM_MOD()->GetSymbolManager().GetSymbolByName( aName
);
2893 if (pSymbol
&& GetExportSymbolSetName(pSymbol
->GetSymbolSetName()) == "Greek")
2901 SmSpecialNode::SmSpecialNode(SmNodeType eNodeType
, const SmToken
&rNodeToken
, sal_uInt16 _nFontDesc
) :
2902 SmTextNode(eNodeType
, rNodeToken
, _nFontDesc
)
2904 bIsFromGreekSymbolSet
= lcl_IsFromGreekSymbolSet( rNodeToken
.aText
);
2908 SmSpecialNode::SmSpecialNode(const SmToken
&rNodeToken
) :
2909 SmTextNode(NSPECIAL
, rNodeToken
, FNT_MATH
) // default Font isn't always correct!
2911 bIsFromGreekSymbolSet
= lcl_IsFromGreekSymbolSet( rNodeToken
.aText
);
2915 void SmSpecialNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2917 SmNode::Prepare(rFormat
, rDocShell
);
2920 SmModule
*pp
= SM_MOD();
2922 OUString
aName(GetToken().aText
.copy(1));
2923 if (NULL
!= (pSym
= pp
->GetSymbolManager().GetSymbolByName( aName
)))
2925 sal_UCS4 cChar
= pSym
->GetCharacter();
2926 OUString
aTmp( &cChar
, 1 );
2928 GetFont() = pSym
->GetFace();
2932 SetText( GetToken().aText
);
2933 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
2935 // use same font size as is used for variables
2936 GetFont().SetSize( rFormat
.GetFont( FNT_VARIABLE
).GetSize() );
2938 // Actually only WEIGHT_NORMAL and WEIGHT_BOLD should occur... However, the sms-file also
2939 // contains e.g. 'WEIGHT_ULTRALIGHT'. Consequently, compare here with '>' instead of '!='.
2940 // (In the long term the necessity for 'PrepareAttribut' and thus also for this here should be dropped)
2942 //! see also SmFontStyles::GetStyleName
2943 if (IsItalic( GetFont() ))
2944 SetAttribut(ATTR_ITALIC
);
2945 if (IsBold( GetFont() ))
2946 SetAttribut(ATTR_BOLD
);
2948 Flags() |= FLG_FONT
;
2950 if (bIsFromGreekSymbolSet
)
2952 OSL_ENSURE( GetText().getLength() == 1, "a symbol should only consist of 1 char!" );
2953 bool bItalic
= false;
2954 sal_Int16 nStyle
= rFormat
.GetGreekCharStyle();
2955 OSL_ENSURE( nStyle
>= 0 && nStyle
<= 2, "unexpected value for GreekCharStyle" );
2958 else if (nStyle
== 2)
2960 const OUString
& rTmp(GetText());
2963 static const sal_Unicode cUppercaseAlpha
= 0x0391;
2964 static const sal_Unicode cUppercaseOmega
= 0x03A9;
2965 sal_Unicode cChar
= rTmp
[0];
2966 // uppercase letters should be straight and lowercase letters italic
2967 bItalic
= !(cUppercaseAlpha
<= cChar
&& cChar
<= cUppercaseOmega
);
2972 Attributes() |= ATTR_ITALIC
;
2974 Attributes() &= ~ATTR_ITALIC
;
2979 void SmSpecialNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2981 PrepareAttributes();
2983 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2984 aTmpDev
.SetFont(GetFont());
2986 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(), GetFont().GetBorderWidth()));
2989 /**************************************************************************/
2992 void SmGlyphSpecialNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2994 PrepareAttributes();
2996 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
2997 aTmpDev
.SetFont(GetFont());
2999 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(),
3000 GetFont().GetBorderWidth()).AsGlyphRect());
3004 /**************************************************************************/
3007 void SmPlaceNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
3009 SmNode::Prepare(rFormat
, rDocShell
);
3011 GetFont().SetColor(COL_GRAY
);
3012 Flags() |= FLG_COLOR
| FLG_FONT
| FLG_ITALIC
;
3016 void SmPlaceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
3018 PrepareAttributes();
3020 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
3021 aTmpDev
.SetFont(GetFont());
3023 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(), GetFont().GetBorderWidth()));
3027 /**************************************************************************/
3030 void SmErrorNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
3032 SmNode::Prepare(rFormat
, rDocShell
);
3034 GetFont().SetColor(COL_RED
);
3035 Flags() |= FLG_VISIBLE
| FLG_BOLD
| FLG_ITALIC
3036 | FLG_COLOR
| FLG_FONT
| FLG_SIZE
;
3040 void SmErrorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
3042 PrepareAttributes();
3044 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
3045 aTmpDev
.SetFont(GetFont());
3047 const OUString
&rText
= GetText();
3048 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, rText
, GetFont().GetBorderWidth()));
3052 /**************************************************************************/
3055 void SmBlankNode::IncreaseBy(const SmToken
&rToken
)
3057 switch(rToken
.eType
)
3059 case TBLANK
: nNum
+= 4; break;
3060 case TSBLANK
: nNum
+= 1; break;
3067 void SmBlankNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
3069 SmNode::Prepare(rFormat
, rDocShell
);
3071 // Here it need/should not be the StarMath font, so that for the character
3072 // used in Arrange a normal (non-clipped) rectangle is generated
3073 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
3075 Flags() |= FLG_FONT
| FLG_BOLD
| FLG_ITALIC
;
3079 void SmBlankNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
3081 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, true);
3082 aTmpDev
.SetFont(GetFont());
3084 // make distance depend on the font height
3085 // (so that it increases when scaling (e.g. size *2 {a ~ b})
3086 long nDist
= GetFont().GetSize().Height() / 10L,
3087 nSpace
= nNum
* nDist
;
3089 // get a SmRect with Baseline and all the bells and whistles
3090 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, OUString(' '),
3091 GetFont().GetBorderWidth()));
3093 // and resize it to the requested size
3094 SetItalicSpaces(0, 0);
3098 /**************************************************************************/
3099 //Implementation of all accept methods for SmVisitor
3101 void SmNode::Accept(SmVisitor
*){
3102 //This method is only implemented to avoid making SmNode abstract because an
3103 //obscure copy constructor is used... I can't find it's implementation, and
3104 //don't want to figure out how to fix it... If you want to, just delete this
3105 //method, making SmNode abstract, and see where you can an problem with that.
3106 SAL_WARN("starmath", "SmNode should not be visitable!");
3109 void SmTableNode::Accept(SmVisitor
* pVisitor
) {
3110 pVisitor
->Visit(this);
3113 void SmBraceNode::Accept(SmVisitor
* pVisitor
) {
3114 pVisitor
->Visit(this);
3117 void SmBracebodyNode::Accept(SmVisitor
* pVisitor
) {
3118 pVisitor
->Visit(this);
3121 void SmOperNode::Accept(SmVisitor
* pVisitor
) {
3122 pVisitor
->Visit(this);
3125 void SmAlignNode::Accept(SmVisitor
* pVisitor
) {
3126 pVisitor
->Visit(this);
3129 void SmAttributNode::Accept(SmVisitor
* pVisitor
) {
3130 pVisitor
->Visit(this);
3133 void SmFontNode::Accept(SmVisitor
* pVisitor
) {
3134 pVisitor
->Visit(this);
3137 void SmUnHorNode::Accept(SmVisitor
* pVisitor
) {
3138 pVisitor
->Visit(this);
3141 void SmBinHorNode::Accept(SmVisitor
* pVisitor
) {
3142 pVisitor
->Visit(this);
3145 void SmBinVerNode::Accept(SmVisitor
* pVisitor
) {
3146 pVisitor
->Visit(this);
3149 void SmBinDiagonalNode::Accept(SmVisitor
* pVisitor
) {
3150 pVisitor
->Visit(this);
3153 void SmSubSupNode::Accept(SmVisitor
* pVisitor
) {
3154 pVisitor
->Visit(this);
3157 void SmMatrixNode::Accept(SmVisitor
* pVisitor
) {
3158 pVisitor
->Visit(this);
3161 void SmPlaceNode::Accept(SmVisitor
* pVisitor
) {
3162 pVisitor
->Visit(this);
3165 void SmTextNode::Accept(SmVisitor
* pVisitor
) {
3166 pVisitor
->Visit(this);
3169 void SmSpecialNode::Accept(SmVisitor
* pVisitor
) {
3170 pVisitor
->Visit(this);
3173 void SmGlyphSpecialNode::Accept(SmVisitor
* pVisitor
) {
3174 pVisitor
->Visit(this);
3177 void SmMathSymbolNode::Accept(SmVisitor
* pVisitor
) {
3178 pVisitor
->Visit(this);
3181 void SmBlankNode::Accept(SmVisitor
* pVisitor
) {
3182 pVisitor
->Visit(this);
3185 void SmErrorNode::Accept(SmVisitor
* pVisitor
) {
3186 pVisitor
->Visit(this);
3189 void SmLineNode::Accept(SmVisitor
* pVisitor
) {
3190 pVisitor
->Visit(this);
3193 void SmExpressionNode::Accept(SmVisitor
* pVisitor
) {
3194 pVisitor
->Visit(this);
3197 void SmPolyLineNode::Accept(SmVisitor
* pVisitor
) {
3198 pVisitor
->Visit(this);
3201 void SmRootNode::Accept(SmVisitor
* pVisitor
) {
3202 pVisitor
->Visit(this);
3205 void SmRootSymbolNode::Accept(SmVisitor
* pVisitor
) {
3206 pVisitor
->Visit(this);
3209 void SmDynIntegralNode::Accept(SmVisitor
* pVisitor
) {
3210 pVisitor
->Visit(this);
3214 void SmDynIntegralSymbolNode::Accept(SmVisitor
* pVisitor
) {
3215 pVisitor
->Visit(this);
3218 void SmRectangleNode::Accept(SmVisitor
* pVisitor
) {
3219 pVisitor
->Visit(this);
3222 void SmVerticalBraceNode::Accept(SmVisitor
* pVisitor
) {
3223 pVisitor
->Visit(this);
3226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */