1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_starmath.hxx"
35 #include "document.hxx"
37 #include "mathtype.hxx"
39 #include <tools/gen.hxx>
40 #include <tools/fract.hxx>
41 #include <rtl/math.hxx>
42 #include <tools/color.hxx>
43 #include <vcl/metric.hxx>
44 #include <vcl/lineinfo.hxx>
45 #include <vcl/outdev.hxx>
46 #include <sfx2/module.hxx>
52 #define APPEND(str,ascii) str.AppendAscii(RTL_CONSTASCII_STRINGPARAM(ascii))
54 // define this to draw rectangles for debugging
55 //#define SM_RECT_DEBUG
58 using ::rtl::OUString
;
61 ////////////////////////////////////////
63 // Allows for font and color changes. The original settings will be restored
65 // It's main purpose is to allow for the "const" in the 'OutputDevice'
66 // argument in the 'Arrange' functions and restore changes made in the 'Draw'
68 // Usually a MapMode of 1/100th mm will be used.
73 OutputDevice
&rOutDev
;
75 // disallow use of copy-constructor and assignment-operator
76 SmTmpDevice(const SmTmpDevice
&rTmpDev
);
77 SmTmpDevice
& operator = (const SmTmpDevice
&rTmpDev
);
79 Color
Impl_GetColor( const Color
& rColor
);
82 SmTmpDevice(OutputDevice
&rTheDev
, sal_Bool bUseMap100th_mm
);
83 ~SmTmpDevice() { rOutDev
.Pop(); }
85 void SetFont(const Font
&rNewFont
);
87 void SetLineColor( const Color
& rColor
) { rOutDev
.SetLineColor( Impl_GetColor(rColor
) ); }
88 void SetFillColor( const Color
& rColor
) { rOutDev
.SetFillColor( Impl_GetColor(rColor
) ); }
89 void SetTextColor( const Color
& rColor
) { rOutDev
.SetTextColor( Impl_GetColor(rColor
) ); }
91 operator OutputDevice
& () { return rOutDev
; }
95 SmTmpDevice::SmTmpDevice(OutputDevice
&rTheDev
, sal_Bool bUseMap100th_mm
) :
98 rOutDev
.Push( PUSH_FONT
| PUSH_MAPMODE
|
99 PUSH_LINECOLOR
| PUSH_FILLCOLOR
| PUSH_TEXTCOLOR
);
100 if (bUseMap100th_mm
&& MAP_100TH_MM
!= rOutDev
.GetMapMode().GetMapUnit())
102 DBG_ERROR( "incorrect MapMode?" );
103 rOutDev
.SetMapMode( MAP_100TH_MM
); //Immer fuer 100% fomatieren
108 Color
SmTmpDevice::Impl_GetColor( const Color
& rColor
)
110 ColorData nNewCol
= rColor
.GetColor();
111 if (COL_AUTO
== nNewCol
)
113 if (OUTDEV_PRINTER
== rOutDev
.GetOutDevType())
117 Color
aBgCol( rOutDev
.GetBackground().GetColor() );
118 if (OUTDEV_WINDOW
== rOutDev
.GetOutDevType())
119 aBgCol
= ((Window
&) rOutDev
).GetDisplayBackground().GetColor();
121 nNewCol
= SM_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR
).nColor
;
123 Color
aTmpColor( nNewCol
);
124 if (aBgCol
.IsDark() && aTmpColor
.IsDark())
126 else if (aBgCol
.IsBright() && aTmpColor
.IsBright())
130 return Color( nNewCol
);
134 void SmTmpDevice::SetFont(const Font
&rNewFont
)
136 rOutDev
.SetFont( rNewFont
);
137 rOutDev
.SetTextColor( Impl_GetColor( rNewFont
.GetColor() ) );
141 ///////////////////////////////////////////////////////////////////////////
144 SmNode::SmNode(SmNodeType eNodeType
, const SmToken
&rNodeToken
)
147 eScaleMode
= SCALE_NONE
;
148 aNodeToken
= rNodeToken
;
158 sal_Bool
SmNode::IsVisible() const
164 sal_uInt16
SmNode::GetNumSubNodes() const
170 SmNode
* SmNode::GetSubNode(sal_uInt16
/*nIndex*/)
176 SmNode
* SmNode::GetLeftMost()
177 // returns leftmost node of current subtree.
178 //! (this assumes the one with index 0 is always the leftmost subnode
179 //! for the current node).
181 SmNode
*pNode
= GetNumSubNodes() > 0 ?
182 GetSubNode(0) : NULL
;
184 return pNode
? pNode
->GetLeftMost() : this;
188 void SmNode::SetPhantom(sal_Bool bIsPhantomP
)
190 if (! (Flags() & FLG_VISIBLE
))
191 bIsPhantom
= bIsPhantomP
;
194 sal_uInt16 nSize
= GetNumSubNodes();
195 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
196 if (NULL
!= (pNode
= GetSubNode(i
)))
197 pNode
->SetPhantom(bIsPhantom
);
201 void SmNode::SetColor(const Color
& rColor
)
203 if (! (Flags() & FLG_COLOR
))
204 GetFont().SetColor(rColor
);
207 sal_uInt16 nSize
= GetNumSubNodes();
208 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
209 if (NULL
!= (pNode
= GetSubNode(i
)))
210 pNode
->SetColor(rColor
);
214 void SmNode::SetAttribut(sal_uInt16 nAttrib
)
217 (nAttrib
== ATTR_BOLD
&& !(Flags() & FLG_BOLD
)) ||
218 (nAttrib
== ATTR_ITALIC
&& !(Flags() & FLG_ITALIC
))
221 nAttributes
|= nAttrib
;
225 sal_uInt16 nSize
= GetNumSubNodes();
226 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
227 if (NULL
!= (pNode
= GetSubNode(i
)))
228 pNode
->SetAttribut(nAttrib
);
232 void SmNode::ClearAttribut(sal_uInt16 nAttrib
)
235 (nAttrib
== ATTR_BOLD
&& !(Flags() & FLG_BOLD
)) ||
236 (nAttrib
== ATTR_ITALIC
&& !(Flags() & FLG_ITALIC
))
239 nAttributes
&= ~nAttrib
;
243 sal_uInt16 nSize
= GetNumSubNodes();
244 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
245 if (NULL
!= (pNode
= GetSubNode(i
)))
246 pNode
->ClearAttribut(nAttrib
);
250 void SmNode::SetFont(const SmFace
&rFace
)
252 if (!(Flags() & FLG_FONT
))
256 sal_uInt16 nSize
= GetNumSubNodes();
257 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
258 if (NULL
!= (pNode
= GetSubNode(i
)))
259 pNode
->SetFont(rFace
);
263 void SmNode::SetFontSize(const Fraction
&rSize
, sal_uInt16 nType
)
264 //! 'rSize' is in units of pts
268 if (!(Flags() & FLG_SIZE
))
270 Fraction
aVal (SmPtsTo100th_mm(rSize
.GetNumerator()),
271 rSize
.GetDenominator());
272 //long nHeight = ::rtl::math::round(aVal);
273 long nHeight
= (long)aVal
;
275 aFntSize
= GetFont().GetSize();
276 aFntSize
.Width() = 0;
280 aFntSize
.Height() = nHeight
;
284 aFntSize
.Height() += nHeight
;
288 aFntSize
.Height() -= nHeight
;
291 case FNTSIZ_MULTIPLY
:
292 aFntSize
.Height() = (long) (Fraction(aFntSize
.Height()) * rSize
);
296 if (rSize
!= Fraction(0L))
297 aFntSize
.Height() = (long) (Fraction(aFntSize
.Height()) / rSize
);
303 // check the requested size against maximum value
304 static int __READONLY_DATA nMaxVal
= SmPtsTo100th_mm(128);
305 if (aFntSize
.Height() > nMaxVal
)
306 aFntSize
.Height() = nMaxVal
;
308 GetFont().SetSize(aFntSize
);
312 sal_uInt16 nSize
= GetNumSubNodes();
313 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
314 if (NULL
!= (pNode
= GetSubNode(i
)))
315 pNode
->SetFontSize(rSize
, nType
);
319 void SmNode::SetSize(const Fraction
&rSize
)
324 sal_uInt16 nSize
= GetNumSubNodes();
325 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
326 if (NULL
!= (pNode
= GetSubNode(i
)))
327 pNode
->SetSize(rSize
);
331 void SmNode::SetRectHorAlign(RectHorAlign eHorAlign
, sal_Bool bApplyToSubTree
)
333 if (!(Flags() & FLG_HORALIGN
))
334 eRectHorAlign
= eHorAlign
;
339 sal_uInt16 nSize
= GetNumSubNodes();
340 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
341 if (NULL
!= (pNode
= GetSubNode(i
)))
342 pNode
->SetRectHorAlign(eHorAlign
);
347 void SmNode::PrepareAttributes()
349 GetFont().SetWeight((Attributes() & ATTR_BOLD
) ? WEIGHT_BOLD
: WEIGHT_NORMAL
);
350 GetFont().SetItalic((Attributes() & ATTR_ITALIC
) ? ITALIC_NORMAL
: ITALIC_NONE
);
354 void SmNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
356 #if OSL_DEBUG_LEVEL > 1
359 bIsDebug
= sal_False
;
361 bIsPhantom
= sal_False
;
365 switch (rFormat
.GetHorAlign())
366 { case AlignLeft
: eRectHorAlign
= RHA_LEFT
; break;
367 case AlignCenter
: eRectHorAlign
= RHA_CENTER
; break;
368 case AlignRight
: eRectHorAlign
= RHA_RIGHT
; break;
371 GetFont() = rFormat
.GetFont(FNT_MATH
);
372 //GetFont().SetCharSet(RTL_TEXTENCODING_SYMBOL);
373 DBG_ASSERT( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE
,
374 "unexpected CharSet" );
375 GetFont().SetWeight(WEIGHT_NORMAL
);
376 GetFont().SetItalic(ITALIC_NONE
);
379 sal_uInt16 nSize
= GetNumSubNodes();
380 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
381 if (NULL
!= (pNode
= GetSubNode(i
)))
382 pNode
->Prepare(rFormat
, rDocShell
);
386 #if OSL_DEBUG_LEVEL > 1
387 void SmNode::ToggleDebug() const
388 // toggle 'bIsDebug' in current subtree
390 SmNode
*pThis
= (SmNode
*) this;
392 pThis
->bIsDebug
= bIsDebug
? sal_False
: sal_True
;
395 sal_uInt16 nSize
= GetNumSubNodes();
396 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
397 if (NULL
!= (pNode
= pThis
->GetSubNode(i
)))
398 pNode
->ToggleDebug();
403 void SmNode::Move(const Point
& rPosition
)
405 if (rPosition
.X() == 0 && rPosition
.Y() == 0)
408 SmRect::Move(rPosition
);
411 sal_uInt16 nSize
= GetNumSubNodes();
412 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
413 if (NULL
!= (pNode
= GetSubNode(i
)))
414 pNode
->Move(rPosition
);
418 void SmNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
421 sal_uInt16 nSize
= GetNumSubNodes();
422 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
423 if (NULL
!= (pNode
= GetSubNode(i
)))
424 pNode
->Arrange(rDev
, rFormat
);
427 void SmNode::CreateTextFromNode(String
&rText
)
430 sal_uInt16 nSize
= GetNumSubNodes();
433 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
434 if (NULL
!= (pNode
= GetSubNode(i
)))
435 pNode
->CreateTextFromNode(rText
);
438 rText
.EraseTrailingChars();
444 void SmNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong
/*nWidth*/)
449 void SmNode::AdaptToY(const OutputDevice
&/*rDev*/, sal_uLong
/*nHeight*/)
454 void SmNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
460 sal_uInt16 nSize
= GetNumSubNodes();
461 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
462 if (NULL
!= (pNode
= GetSubNode(i
)))
463 { Point
aOffset (pNode
->GetTopLeft() - GetTopLeft());
464 pNode
->Draw(rDev
, rPosition
+ aOffset
);
471 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
472 SmRect::Draw(rDev
, rPosition
, nRFlags
);
476 const SmNode
* SmNode::FindTokenAt(sal_uInt16 nRow
, sal_uInt16 nCol
) const
477 // returns (first) ** visible ** (sub)node with the tokens text at
478 // position 'nRow', 'nCol'.
479 //! (there should be exactly one such node if any)
482 && nRow
== GetToken().nRow
483 && nCol
>= GetToken().nCol
&& nCol
< GetToken().nCol
+ GetToken().aText
.Len())
487 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
488 for (sal_uInt16 i
= 0; i
< nNumSubNodes
; i
++)
489 { const SmNode
*pNode
= GetSubNode(i
);
494 const SmNode
*pResult
= pNode
->FindTokenAt(nRow
, nCol
);
504 const SmNode
* SmNode::FindRectClosestTo(const Point
&rPoint
) const
506 long nDist
= LONG_MAX
;
507 const SmNode
*pResult
= 0;
513 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
514 for (sal_uInt16 i
= 0; i
< nNumSubNodes
; i
++)
515 { const SmNode
*pNode
= GetSubNode(i
);
521 const SmNode
*pFound
= pNode
->FindRectClosestTo(rPoint
);
522 if (pFound
&& (nTmp
= pFound
->OrientedDist(rPoint
)) < nDist
)
526 // quit immediately if 'rPoint' is inside the *should not
527 // overlap with other rectangles* part.
528 // This (partly) serves for getting the attributes in eg
529 // "bar overstrike a".
530 // ('nDist < 0' is used as *quick shot* to avoid evaluation of
531 // the following expression, where the result is already determined)
532 if (nDist
< 0 && pFound
->IsInsideRect(rPoint
))
541 void SmNode::GetAccessibleText( String
&/*rText*/ ) const
543 DBG_ERROR( "SmNode: GetAccessibleText not overloaded" );
546 const SmNode
* SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx
) const
548 const SmNode
*pResult
= 0;
550 sal_Int32 nIdx
= GetAccessibleIndex();
553 GetAccessibleText( aTxt
); // get text if used in following 'if' statement
556 && nIdx
<= nAccIdx
&& nAccIdx
< nIdx
+ aTxt
.Len())
560 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
561 for (sal_uInt16 i
= 0; i
< nNumSubNodes
; i
++)
563 const SmNode
*pNode
= GetSubNode(i
);
567 pResult
= pNode
->FindNodeWithAccessibleIndex(nAccIdx
);
577 long SmNode::GetFormulaBaseline() const
579 DBG_ASSERT( 0, "This dummy implementation should not have been called." );
583 ///////////////////////////////////////////////////////////////////////////
585 SmStructureNode::SmStructureNode( const SmStructureNode
&rNode
) :
586 SmNode( rNode
.GetType(), rNode
.GetToken() )
589 for (i
= 0; i
< aSubNodes
.size(); i
++)
593 sal_uLong nSize
= rNode
.aSubNodes
.size();
594 aSubNodes
.resize( nSize
);
595 for (i
= 0; i
< nSize
; ++i
)
597 SmNode
*pNode
= rNode
.aSubNodes
[i
];
598 aSubNodes
[i
] = pNode
? new SmNode( *pNode
) : 0;
603 SmStructureNode::~SmStructureNode()
607 for (sal_uInt16 i
= 0; i
< GetNumSubNodes(); i
++)
608 if (NULL
!= (pNode
= GetSubNode(i
)))
613 SmStructureNode
& SmStructureNode::operator = ( const SmStructureNode
&rNode
)
615 SmNode::operator = ( rNode
);
618 for (i
= 0; i
< aSubNodes
.size(); i
++)
622 sal_uLong nSize
= rNode
.aSubNodes
.size();
623 aSubNodes
.resize( nSize
);
624 for (i
= 0; i
< nSize
; ++i
)
626 SmNode
*pNode
= rNode
.aSubNodes
[i
];
627 aSubNodes
[i
] = pNode
? new SmNode( *pNode
) : 0;
634 void SmStructureNode::SetSubNodes(SmNode
*pFirst
, SmNode
*pSecond
, SmNode
*pThird
)
636 size_t nSize
= pThird
? 3 : (pSecond
? 2 : (pFirst
? 1 : 0));
637 aSubNodes
.resize( nSize
);
639 aSubNodes
[0] = pFirst
;
641 aSubNodes
[1] = pSecond
;
643 aSubNodes
[2] = pThird
;
647 void SmStructureNode::SetSubNodes(const SmNodeArray
&rNodeArray
)
649 aSubNodes
= rNodeArray
;
653 sal_Bool
SmStructureNode::IsVisible() const
659 sal_uInt16
SmStructureNode::GetNumSubNodes() const
661 return (sal_uInt16
) aSubNodes
.size();
665 SmNode
* SmStructureNode::GetSubNode(sal_uInt16 nIndex
)
667 return aSubNodes
[nIndex
];
671 void SmStructureNode::GetAccessibleText( String
&rText
) const
673 sal_uInt16 nNodes
= GetNumSubNodes();
674 for (sal_uInt16 i
= 0; i
< nNodes
; ++i
)
676 const SmNode
*pNode
= ((SmStructureNode
*) this)->GetSubNode(i
);
679 if (pNode
->IsVisible())
680 ((SmStructureNode
*) pNode
)->nAccIndex
= rText
.Len();
681 pNode
->GetAccessibleText( rText
);
682 // if (rText.Len() && ' ' != rText.GetChar( rText.Len() - 1 ))
683 // rText += String::CreateFromAscii( " " );
688 ///////////////////////////////////////////////////////////////////////////
691 sal_Bool
SmVisibleNode::IsVisible() const
697 sal_uInt16
SmVisibleNode::GetNumSubNodes() const
703 SmNode
* SmVisibleNode::GetSubNode(sal_uInt16
/*nIndex*/)
709 ///////////////////////////////////////////////////////////////////////////
711 void SmGraphicNode::GetAccessibleText( String
&rText
) const
713 rText
+= GetToken().aText
;
716 ///////////////////////////////////////////////////////////////////////////
719 void SmExpressionNode::CreateTextFromNode(String
&rText
)
722 sal_uInt16 nSize
= GetNumSubNodes();
725 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
726 if (NULL
!= (pNode
= GetSubNode(i
)))
728 pNode
->CreateTextFromNode(rText
);
729 //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
730 if (pNode
->GetType() == NMATH
)
731 if ((nSize
!= 2) || ((rText
.GetChar(rText
.Len()-1) != '+') &&
732 (rText
.GetChar(rText
.Len()-1) != '-')))
738 rText
.EraseTrailingChars();
744 ///////////////////////////////////////////////////////////////////////////
746 void SmTableNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
747 // arranges all subnodes in one column
752 sal_uInt16 nSize
= GetNumSubNodes();
754 // make distance depend on font size
755 long nDist
= +(rFormat
.GetDistance(DIS_VERTICAL
)
756 * GetFont().GetSize().Height()) / 100L;
761 // arrange subnodes and get maximum width of them
765 for (i
= 0; i
< nSize
; i
++)
766 if (NULL
!= (pNode
= GetSubNode(i
)))
767 { pNode
->Arrange(rDev
, rFormat
);
768 if ((nTmp
= pNode
->GetItalicWidth()) > nMaxWidth
)
773 SmRect::operator = (SmRect(nMaxWidth
, 1));
774 for (i
= 0; i
< nSize
; i
++)
775 { if (NULL
!= (pNode
= GetSubNode(i
)))
776 { const SmRect
&rNodeRect
= pNode
->GetRect();
777 const SmNode
*pCoNode
= pNode
->GetLeftMost();
778 //SmTokenType eType = pCoNode->GetToken().eType;
779 RectHorAlign eHorAlign
= pCoNode
->GetRectHorAlign();
781 aPos
= rNodeRect
.AlignTo(*this, RP_BOTTOM
,
782 eHorAlign
, RVA_BASELINE
);
786 ExtendBy(rNodeRect
, nSize
> 1 ? RCP_NONE
: RCP_ARG
);
789 // --> 4.7.2010 #i972#
791 nFormulaBaseline
= GetBaseline();
794 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
795 aTmpDev
.SetFont(GetFont());
797 SmRect aRect
= (SmRect(aTmpDev
, &rFormat
, C2S("a"),
798 GetFont().GetBorderWidth()));
799 nFormulaBaseline
= GetAlignM();
800 // move from middle position by constant - distance
801 // between middle and baseline for single letter
802 nFormulaBaseline
+= aRect
.GetBaseline() - aRect
.GetAlignM();
808 SmNode
* SmTableNode::GetLeftMost()
814 long SmTableNode::GetFormulaBaseline() const
816 return nFormulaBaseline
;
820 /**************************************************************************/
823 void SmLineNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
825 SmNode::Prepare(rFormat
, rDocShell
);
827 //! wir verwenden hier den 'FNT_VARIABLE' Font, da er vom Ascent und Descent
828 //! ia besser zum Rest der Formel passt als der 'FNT_MATH' Font.
829 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
834 /**************************************************************************/
837 void SmLineNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
838 // arranges all subnodes in one row with some extra space between
841 sal_uInt16 nSize
= GetNumSubNodes();
843 for (i
= 0; i
< nSize
; i
++)
844 if (NULL
!= (pNode
= GetSubNode(i
)))
845 pNode
->Arrange(rDev
, rFormat
);
847 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
848 aTmpDev
.SetFont(GetFont());
852 // provide an empty rectangle with alignment parameters for the "current"
853 // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
854 // same sub-/supscript positions.)
855 //! be sure to use a character that has explicitly defined HiAttribut
856 //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
858 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, C2S("a"),
859 GetFont().GetBorderWidth()));
860 // make sure that the rectangle occupies (almost) no space
862 SetItalicSpaces(0, 0);
866 // make distance depend on font size
867 long nDist
= (rFormat
.GetDistance(DIS_HORIZONTAL
) * GetFont().GetSize().Height()) / 100L;
868 if (!IsUseExtraSpaces())
872 // copy the first node into LineNode and extend by the others
873 if (NULL
!= (pNode
= GetSubNode(0)))
874 SmRect::operator = (pNode
->GetRect());
876 for (i
= 1; i
< nSize
; i
++)
877 if (NULL
!= (pNode
= GetSubNode(i
)))
879 aPos
= pNode
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
881 // add horizontal space to the left for each but the first sub node
885 ExtendBy( *pNode
, RCP_XOR
);
890 /**************************************************************************/
893 void SmExpressionNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
894 // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
896 SmLineNode::Arrange(rDev
, rFormat
);
898 // copy alignment of leftmost subnode if any
899 SmNode
*pNode
= GetLeftMost();
901 SetRectHorAlign(pNode
->GetRectHorAlign(), sal_False
);
905 /**************************************************************************/
908 void SmUnHorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
910 sal_Bool bIsPostfix
= GetToken().eType
== TFACT
;
912 SmNode
*pOper
= GetSubNode(bIsPostfix
? 1 : 0),
913 *pBody
= GetSubNode(bIsPostfix
? 0 : 1);
914 DBG_ASSERT(pOper
, "Sm: NULL pointer");
915 DBG_ASSERT(pBody
, "Sm: NULL pointer");
917 pOper
->SetSize(Fraction (rFormat
.GetRelSize(SIZ_OPERATOR
), 100));
918 pOper
->Arrange(rDev
, rFormat
);
919 pBody
->Arrange(rDev
, rFormat
);
921 Point aPos
= pOper
->AlignTo(*pBody
, bIsPostfix
? RP_RIGHT
: RP_LEFT
,
922 RHA_CENTER
, RVA_BASELINE
);
923 // add a bit space between operator and argument
924 // (worst case -{1 over 2} where - and over have almost no space inbetween)
925 long nDelta
= pOper
->GetFont().GetSize().Height() / 20;
932 SmRect::operator = (*pBody
);
933 long nOldBot
= GetBottom();
935 ExtendBy(*pOper
, RCP_XOR
);
937 // workaround for Bug 50865: "a^2 a^+2" have different baselines
938 // for exponents (if size of exponent is large enough)
943 /**************************************************************************/
946 void SmRootNode::GetHeightVerOffset(const SmRect
&rRect
,
947 long &rHeight
, long &rVerOffset
) const
948 // calculate height and vertical offset of root sign suitable for 'rRect'
950 rVerOffset
= (rRect
.GetBottom() - rRect
.GetAlignB()) / 2;
951 rHeight
= rRect
.GetHeight() - rVerOffset
;
953 DBG_ASSERT(rHeight
>= 0, "Sm : Ooops...");
954 DBG_ASSERT(rVerOffset
>= 0, "Sm : Ooops...");
958 Point
SmRootNode::GetExtraPos(const SmRect
&rRootSymbol
,
959 const SmRect
&rExtra
) const
961 const Size
&rSymSize
= rRootSymbol
.GetSize();
963 Point aPos
= rRootSymbol
.GetTopLeft()
964 + Point((rSymSize
.Width() * 70) / 100,
965 (rSymSize
.Height() * 52) / 100);
967 // from this calculate topleft edge of 'rExtra'
968 aPos
.X() -= rExtra
.GetWidth() + rExtra
.GetItalicRightSpace();
969 aPos
.Y() -= rExtra
.GetHeight();
970 // if there's enough space move a bit less to the right
971 // examples: "nroot i a", "nroot j a"
972 // (it looks better if we don't use italic-spaces here)
973 long nX
= rRootSymbol
.GetLeft() + (rSymSize
.Width() * 30) / 100;
981 void SmRootNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
983 //! pExtra needs to have the smaller index than pRootSym in order to
984 //! not to get the root symbol but the pExtra when clicking on it in the
985 //! GraphicWindow. (That is because of the simplicity of the algorithm
986 //! that finds the node corresponding to a mouseclick in the window.)
987 SmNode
*pExtra
= GetSubNode(0),
988 *pRootSym
= GetSubNode(1),
989 *pBody
= GetSubNode(2);
990 DBG_ASSERT(pRootSym
, "Sm: NULL pointer");
991 DBG_ASSERT(pBody
, "Sm: NULL pointer");
993 pBody
->Arrange(rDev
, rFormat
);
997 GetHeightVerOffset(*pBody
, nHeight
, nVerOffset
);
998 nHeight
+= rFormat
.GetDistance(DIS_ROOT
)
999 * GetFont().GetSize().Height() / 100L;
1001 // font specialist advised to change the width first
1002 pRootSym
->AdaptToY(rDev
, nHeight
);
1003 pRootSym
->AdaptToX(rDev
, pBody
->GetItalicWidth());
1005 pRootSym
->Arrange(rDev
, rFormat
);
1007 Point aPos
= pRootSym
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, RVA_BASELINE
);
1008 //! overrride calulated vertical position
1009 aPos
.Y() = pRootSym
->GetTop() + pBody
->GetBottom() - pRootSym
->GetBottom();
1010 aPos
.Y() -= nVerOffset
;
1011 pRootSym
->MoveTo(aPos
);
1014 { pExtra
->SetSize(Fraction(rFormat
.GetRelSize(SIZ_INDEX
), 100));
1015 pExtra
->Arrange(rDev
, rFormat
);
1017 aPos
= GetExtraPos(*pRootSym
, *pExtra
);
1018 pExtra
->MoveTo(aPos
);
1021 SmRect::operator = (*pBody
);
1022 ExtendBy(*pRootSym
, RCP_THIS
);
1024 ExtendBy(*pExtra
, RCP_THIS
, (sal_Bool
) sal_True
);
1028 void SmRootNode::CreateTextFromNode(String
&rText
)
1030 SmNode
*pExtra
= GetSubNode(0);
1033 APPEND(rText
,"nroot ");
1034 pExtra
->CreateTextFromNode(rText
);
1037 APPEND(rText
,"sqrt ");
1038 GetSubNode(2)->CreateTextFromNode(rText
);
1042 /**************************************************************************/
1045 void SmBinHorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1047 SmNode
*pLeft
= GetSubNode(0),
1048 *pOper
= GetSubNode(1),
1049 *pRight
= GetSubNode(2);
1050 DBG_ASSERT(pLeft
!= NULL
, "Sm: NULL pointer");
1051 DBG_ASSERT(pOper
!= NULL
, "Sm: NULL pointer");
1052 DBG_ASSERT(pRight
!= NULL
, "Sm: NULL pointer");
1054 pOper
->SetSize(Fraction (rFormat
.GetRelSize(SIZ_OPERATOR
), 100));
1056 pLeft
->Arrange(rDev
, rFormat
);
1057 pOper
->Arrange(rDev
, rFormat
);
1058 pRight
->Arrange(rDev
, rFormat
);
1060 const SmRect
&rOpRect
= pOper
->GetRect();
1062 long nDist
= (rOpRect
.GetWidth() *
1063 rFormat
.GetDistance(DIS_HORIZONTAL
)) / 100L;
1065 SmRect::operator = (*pLeft
);
1068 aPos
= pOper
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1070 pOper
->MoveTo(aPos
);
1071 ExtendBy(*pOper
, RCP_XOR
);
1073 aPos
= pRight
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1076 pRight
->MoveTo(aPos
);
1077 ExtendBy(*pRight
, RCP_XOR
);
1081 /**************************************************************************/
1084 void SmBinVerNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1086 SmNode
*pNum
= GetSubNode(0),
1087 *pLine
= GetSubNode(1),
1088 *pDenom
= GetSubNode(2);
1089 DBG_ASSERT(pNum
, "Sm : NULL pointer");
1090 DBG_ASSERT(pLine
, "Sm : NULL pointer");
1091 DBG_ASSERT(pDenom
, "Sm : NULL pointer");
1093 sal_Bool bIsTextmode
= rFormat
.IsTextmode();
1096 Fraction
aFraction(rFormat
.GetRelSize(SIZ_INDEX
), 100);
1097 pNum
->SetSize(aFraction
);
1098 pLine
->SetSize(aFraction
);
1099 pDenom
->SetSize(aFraction
);
1102 pNum
->Arrange(rDev
, rFormat
);
1103 pDenom
->Arrange(rDev
, rFormat
);
1105 long nFontHeight
= GetFont().GetSize().Height(),
1106 nExtLen
= nFontHeight
* rFormat
.GetDistance(DIS_FRACTION
) / 100L,
1107 nThick
= nFontHeight
* rFormat
.GetDistance(DIS_STROKEWIDTH
) / 100L,
1108 nWidth
= Max(pNum
->GetItalicWidth(), pDenom
->GetItalicWidth()),
1109 nNumDist
= bIsTextmode
? 0 :
1110 nFontHeight
* rFormat
.GetDistance(DIS_NUMERATOR
) / 100L,
1111 nDenomDist
= bIsTextmode
? 0 :
1112 nFontHeight
* rFormat
.GetDistance(DIS_DENOMINATOR
) / 100L;
1114 // font specialist advised to change the width first
1115 pLine
->AdaptToY(rDev
, nThick
);
1116 pLine
->AdaptToX(rDev
, nWidth
+ 2 * nExtLen
);
1117 pLine
->Arrange(rDev
, rFormat
);
1119 // get horizontal alignment for numerator
1120 const SmNode
*pLM
= pNum
->GetLeftMost();
1121 RectHorAlign eHorAlign
= pLM
->GetRectHorAlign();
1123 // move numerator to its position
1124 Point aPos
= pNum
->AlignTo(*pLine
, RP_TOP
, eHorAlign
, RVA_BASELINE
);
1125 aPos
.Y() -= nNumDist
;
1128 // get horizontal alignment for denominator
1129 pLM
= pDenom
->GetLeftMost();
1130 eHorAlign
= pLM
->GetRectHorAlign();
1132 // move denominator to its position
1133 aPos
= pDenom
->AlignTo(*pLine
, RP_BOTTOM
, eHorAlign
, RVA_BASELINE
);
1134 aPos
.Y() += nDenomDist
;
1135 pDenom
->MoveTo(aPos
);
1137 SmRect::operator = (*pNum
);
1138 ExtendBy(*pDenom
, RCP_NONE
).ExtendBy(*pLine
, RCP_NONE
, pLine
->GetCenterY());
1141 void SmBinVerNode::CreateTextFromNode(String
&rText
)
1143 SmNode
*pNum
= GetSubNode(0),
1144 // *pLine = GetSubNode(1),
1145 *pDenom
= GetSubNode(2);
1146 pNum
->CreateTextFromNode(rText
);
1147 APPEND(rText
,"over ");
1148 pDenom
->CreateTextFromNode(rText
);
1152 SmNode
* SmBinVerNode::GetLeftMost()
1158 /**************************************************************************/
1161 double Det(const Point
&rHeading1
, const Point
&rHeading2
)
1162 // gibt den Wert der durch die beiden Punkte gebildeten Determinante
1165 return rHeading1
.X() * rHeading2
.Y() - rHeading1
.Y() * rHeading2
.X();
1169 sal_Bool
IsPointInLine(const Point
&rPoint1
,
1170 const Point
&rPoint2
, const Point
&rHeading2
)
1171 // ergibt sal_True genau dann, wenn der Punkt 'rPoint1' zu der Gerade gehoert die
1172 // durch den Punkt 'rPoint2' geht und den Richtungsvektor 'rHeading2' hat
1174 DBG_ASSERT(rHeading2
!= Point(), "Sm : 0 vector");
1176 sal_Bool bRes
= sal_False
;
1177 const double eps
= 5.0 * DBL_EPSILON
;
1180 if (labs(rHeading2
.X()) > labs(rHeading2
.Y()))
1182 fLambda
= (rPoint1
.X() - rPoint2
.X()) / (double) rHeading2
.X();
1183 bRes
= fabs(rPoint1
.Y() - (rPoint2
.Y() + fLambda
* rHeading2
.Y())) < eps
;
1187 fLambda
= (rPoint1
.Y() - rPoint2
.Y()) / (double) rHeading2
.Y();
1188 bRes
= fabs(rPoint1
.X() - (rPoint2
.X() + fLambda
* rHeading2
.X())) < eps
;
1195 sal_uInt16
GetLineIntersectionPoint(Point
&rResult
,
1196 const Point
& rPoint1
, const Point
&rHeading1
,
1197 const Point
& rPoint2
, const Point
&rHeading2
)
1199 DBG_ASSERT(rHeading1
!= Point(), "Sm : 0 vector");
1200 DBG_ASSERT(rHeading2
!= Point(), "Sm : 0 vector");
1202 sal_uInt16 nRes
= 1;
1203 const double eps
= 5.0 * DBL_EPSILON
;
1205 // sind die Richtumgsvektoren linear abhaengig ?
1206 double fDet
= Det(rHeading1
, rHeading2
);
1207 if (fabs(fDet
) < eps
)
1209 nRes
= IsPointInLine(rPoint1
, rPoint2
, rHeading2
) ? USHRT_MAX
: 0;
1210 rResult
= nRes
? rPoint1
: Point();
1214 // hier achten wir nicht auf Rechengenauigkeit
1215 // (das wuerde aufwendiger und lohnt sich hier kaum)
1216 double fLambda
= ( (rPoint1
.Y() - rPoint2
.Y()) * rHeading2
.X()
1217 - (rPoint1
.X() - rPoint2
.X()) * rHeading2
.Y())
1219 rResult
= Point(rPoint1
.X() + (long) (fLambda
* rHeading1
.X()),
1220 rPoint1
.Y() + (long) (fLambda
* rHeading1
.Y()));
1228 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken
&rNodeToken
)
1229 : SmStructureNode(NBINDIAGONAL
, rNodeToken
)
1231 bAscending
= sal_False
;
1236 void SmBinDiagonalNode::GetOperPosSize(Point
&rPos
, Size
&rSize
,
1237 const Point
&rDiagPoint
, double fAngleDeg
) const
1238 // gibt die Position und Groesse fuer den Diagonalstrich zurueck.
1239 // Vor.: das SmRect des Nodes gibt die Begrenzung vor(!), muss also selbst
1240 // bereits bekannt sein.
1243 const double fPi
= 3.1415926535897932384626433;
1244 double fAngleRad
= fAngleDeg
/ 180.0 * fPi
;
1245 long nRectLeft
= GetItalicLeft(),
1246 nRectRight
= GetItalicRight(),
1247 nRectTop
= GetTop(),
1248 nRectBottom
= GetBottom();
1249 Point
aRightHdg (100, 0),
1251 aDiagHdg ( (long)(100.0 * cos(fAngleRad
)),
1252 (long)(-100.0 * sin(fAngleRad
)) );
1254 long nLeft
, nRight
, nTop
, nBottom
; // Raender des Rechtecks fuer die
1260 // obere rechte Ecke bestimmen
1262 GetLineIntersectionPoint(aPoint
,
1263 Point(nRectLeft
, nRectTop
), aRightHdg
,
1264 rDiagPoint
, aDiagHdg
);
1266 // gibt es einen Schnittpunkt mit dem oberen Rand ?
1267 if (aPoint
.X() <= nRectRight
)
1269 nRight
= aPoint
.X();
1274 // es muss einen Schnittpunkt mit dem rechten Rand geben!
1275 GetLineIntersectionPoint(aPoint
,
1276 Point(nRectRight
, nRectTop
), aDownHdg
,
1277 rDiagPoint
, aDiagHdg
);
1279 nRight
= nRectRight
;
1284 // untere linke Ecke bestimmen
1286 GetLineIntersectionPoint(aPoint
,
1287 Point(nRectLeft
, nRectBottom
), aRightHdg
,
1288 rDiagPoint
, aDiagHdg
);
1290 // gibt es einen Schnittpunkt mit dem unteren Rand ?
1291 if (aPoint
.X() >= nRectLeft
)
1294 nBottom
= nRectBottom
;
1298 // es muss einen Schnittpunkt mit dem linken Rand geben!
1299 GetLineIntersectionPoint(aPoint
,
1300 Point(nRectLeft
, nRectTop
), aDownHdg
,
1301 rDiagPoint
, aDiagHdg
);
1304 nBottom
= aPoint
.Y();
1310 // obere linke Ecke bestimmen
1312 GetLineIntersectionPoint(aPoint
,
1313 Point(nRectLeft
, nRectTop
), aRightHdg
,
1314 rDiagPoint
, aDiagHdg
);
1316 // gibt es einen Schnittpunkt mit dem oberen Rand ?
1317 if (aPoint
.X() >= nRectLeft
)
1324 // es muss einen Schnittpunkt mit dem linken Rand geben!
1325 GetLineIntersectionPoint(aPoint
,
1326 Point(nRectLeft
, nRectTop
), aDownHdg
,
1327 rDiagPoint
, aDiagHdg
);
1334 // untere rechte Ecke bestimmen
1336 GetLineIntersectionPoint(aPoint
,
1337 Point(nRectLeft
, nRectBottom
), aRightHdg
,
1338 rDiagPoint
, aDiagHdg
);
1340 // gibt es einen Schnittpunkt mit dem unteren Rand ?
1341 if (aPoint
.X() <= nRectRight
)
1343 nRight
= aPoint
.X();
1344 nBottom
= nRectBottom
;
1348 // es muss einen Schnittpunkt mit dem rechten Rand geben!
1349 GetLineIntersectionPoint(aPoint
,
1350 Point(nRectRight
, nRectTop
), aDownHdg
,
1351 rDiagPoint
, aDiagHdg
);
1353 nRight
= nRectRight
;
1354 nBottom
= aPoint
.Y();
1358 rSize
= Size(nRight
- nLeft
+ 1, nBottom
- nTop
+ 1);
1364 void SmBinDiagonalNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1366 //! die beiden Argumente muessen in den Subnodes vor dem Operator kommen,
1367 //! damit das anklicken im GraphicWindow den FormulaCursor richtig setzt
1368 //! (vgl SmRootNode)
1369 SmNode
*pLeft
= GetSubNode(0),
1370 *pRight
= GetSubNode(1);
1371 DBG_ASSERT(pLeft
, "Sm : NULL pointer");
1372 DBG_ASSERT(pRight
, "Sm : NULL pointer");
1374 DBG_ASSERT(GetSubNode(2)->GetType() == NPOLYLINE
, "Sm : falscher Nodetyp");
1375 SmPolyLineNode
*pOper
= (SmPolyLineNode
*) GetSubNode(2);
1376 DBG_ASSERT(pOper
, "Sm : NULL pointer");
1378 //! some routines being called extract some info from the OutputDevice's
1379 //! font (eg the space to be used for borders OR the font name(!!)).
1380 //! Thus the font should reflect the needs and has to be set!
1381 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
1382 aTmpDev
.SetFont(GetFont());
1384 pLeft
->Arrange(aTmpDev
, rFormat
);
1385 pRight
->Arrange(aTmpDev
, rFormat
);
1387 // implizit die Weite (incl Rand) des Diagonalstrichs ermitteln
1388 pOper
->Arrange(aTmpDev
, rFormat
);
1390 long nDelta
= pOper
->GetWidth() * 8 / 10;
1392 // TopLeft Position vom rechten Argument ermitteln
1394 aPos
.X() = pLeft
->GetItalicRight() + nDelta
+ pRight
->GetItalicLeftSpace();
1396 aPos
.Y() = pLeft
->GetBottom() + nDelta
;
1398 aPos
.Y() = pLeft
->GetTop() - nDelta
- pRight
->GetHeight();
1400 pRight
->MoveTo(aPos
);
1402 // neue Baseline bestimmen
1403 long nTmpBaseline
= IsAscending() ? (pLeft
->GetBottom() + pRight
->GetTop()) / 2
1404 : (pLeft
->GetTop() + pRight
->GetBottom()) / 2;
1405 Point
aLogCenter ((pLeft
->GetItalicRight() + pRight
->GetItalicLeft()) / 2,
1408 SmRect::operator = (*pLeft
);
1409 ExtendBy(*pRight
, RCP_NONE
);
1412 // Position und Groesse des Diagonalstrich ermitteln
1414 GetOperPosSize(aPos
, aTmpSize
, aLogCenter
, IsAscending() ? 60.0 : -60.0);
1416 // font specialist advised to change the width first
1417 pOper
->AdaptToY(aTmpDev
, aTmpSize
.Height());
1418 pOper
->AdaptToX(aTmpDev
, aTmpSize
.Width());
1419 // und diese wirksam machen
1420 pOper
->Arrange(aTmpDev
, rFormat
);
1422 pOper
->MoveTo(aPos
);
1424 ExtendBy(*pOper
, RCP_NONE
, nTmpBaseline
);
1428 /**************************************************************************/
1431 void SmSubSupNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1433 DBG_ASSERT(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES
,
1434 "Sm: falsche Anzahl von subnodes");
1436 SmNode
*pBody
= GetBody();
1437 DBG_ASSERT(pBody
, "Sm: NULL pointer");
1439 long nOrigHeight
= pBody
->GetFont().GetSize().Height();
1441 pBody
->Arrange(rDev
, rFormat
);
1443 const SmRect
&rBodyRect
= pBody
->GetRect();
1444 SmRect::operator = (rBodyRect
);
1446 // line that separates sub- and supscript rectangles
1447 long nDelimLine
= SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1452 // iterate over all possible sub-/supscripts
1453 SmRect
aTmpRect (rBodyRect
);
1454 for (int i
= 0; i
< SUBSUP_NUM_ENTRIES
; i
++)
1455 { SmSubSup eSubSup
= (SmSubSup
) i
; // cast
1456 SmNode
*pSubSup
= GetSubSup(eSubSup
);
1461 // switch position of limits if we are in textmode
1462 if (rFormat
.IsTextmode() && (GetToken().nGroup
& TGLIMIT
))
1464 { case CSUB
: eSubSup
= RSUB
; break;
1465 case CSUP
: eSubSup
= RSUP
; break;
1470 // prevent sub-/supscripts from diminishing in size
1471 // (as would be in "a_{1_{2_{3_4}}}")
1472 if (GetFont().GetSize().Height() > rFormat
.GetBaseSize().Height() / 3)
1474 sal_uInt16 nIndex
= (eSubSup
== CSUB
|| eSubSup
== CSUP
) ?
1475 SIZ_LIMITS
: SIZ_INDEX
;
1476 Fraction
aFraction ( rFormat
.GetRelSize(nIndex
), 100 );
1477 pSubSup
->SetSize(aFraction
);
1480 pSubSup
->Arrange(rDev
, rFormat
);
1482 sal_Bool bIsTextmode
= rFormat
.IsTextmode();
1485 //! be sure that CSUB, CSUP are handled before the other cases!
1491 * rFormat
.GetDistance(DIS_SUBSCRIPT
) / 100L;
1492 aPos
= pSubSup
->GetRect().AlignTo(aTmpRect
,
1493 eSubSup
== LSUB
? RP_LEFT
: RP_RIGHT
,
1494 RHA_CENTER
, RVA_BOTTOM
);
1496 nDelta
= nDelimLine
- aPos
.Y();
1504 * rFormat
.GetDistance(DIS_SUPERSCRIPT
) / 100L;
1505 aPos
= pSubSup
->GetRect().AlignTo(aTmpRect
,
1506 eSubSup
== LSUP
? RP_LEFT
: RP_RIGHT
,
1507 RHA_CENTER
, RVA_TOP
);
1509 nDelta
= aPos
.Y() + pSubSup
->GetHeight() - nDelimLine
;
1516 * rFormat
.GetDistance(DIS_LOWERLIMIT
) / 100L;
1517 aPos
= pSubSup
->GetRect().AlignTo(rBodyRect
, RP_BOTTOM
,
1518 RHA_CENTER
, RVA_BASELINE
);
1524 * rFormat
.GetDistance(DIS_UPPERLIMIT
) / 100L;
1525 aPos
= pSubSup
->GetRect().AlignTo(rBodyRect
, RP_TOP
,
1526 RHA_CENTER
, RVA_BASELINE
);
1530 DBG_ASSERT(sal_False
, "Sm: unbekannter Fall");
1534 pSubSup
->MoveTo(aPos
);
1535 ExtendBy(*pSubSup
, RCP_THIS
, (sal_Bool
) sal_True
);
1537 // update rectangle to which RSUB, RSUP, LSUB, LSUP
1538 // will be aligned to
1539 if (eSubSup
== CSUB
|| eSubSup
== CSUP
)
1544 void SmSubSupNode::CreateTextFromNode(String
&rText
)
1547 GetSubNode(0)->CreateTextFromNode(rText
);
1549 if (NULL
!= (pNode
= GetSubNode(LSUB
+1)))
1551 APPEND(rText
,"lsub ");
1552 pNode
->CreateTextFromNode(rText
);
1554 if (NULL
!= (pNode
= GetSubNode(LSUP
+1)))
1556 APPEND(rText
,"lsup ");
1557 pNode
->CreateTextFromNode(rText
);
1559 if (NULL
!= (pNode
= GetSubNode(CSUB
+1)))
1561 APPEND(rText
,"csub ");
1562 pNode
->CreateTextFromNode(rText
);
1564 if (NULL
!= (pNode
= GetSubNode(CSUP
+1)))
1566 APPEND(rText
,"csup ");
1567 pNode
->CreateTextFromNode(rText
);
1569 if (NULL
!= (pNode
= GetSubNode(RSUB
+1)))
1571 rText
.EraseTrailingChars();
1573 pNode
->CreateTextFromNode(rText
);
1575 if (NULL
!= (pNode
= GetSubNode(RSUP
+1)))
1577 rText
.EraseTrailingChars();
1579 pNode
->CreateTextFromNode(rText
);
1584 /**************************************************************************/
1586 void SmBraceNode::CreateTextFromNode(String
&rText
)
1588 if (GetScaleMode() == SCALE_HEIGHT
)
1589 APPEND(rText
,"left ");
1592 GetSubNode(0)->CreateTextFromNode(aStr
);
1593 aStr
.EraseLeadingAndTrailingChars();
1594 aStr
.EraseLeadingChars('\\');
1597 if (aStr
.EqualsAscii("divides"))
1598 APPEND(rText
,"lline");
1599 else if (aStr
.EqualsAscii("parallel"))
1600 APPEND(rText
,"ldline");
1601 else if (aStr
.EqualsAscii("<"))
1602 APPEND(rText
,"langle");
1608 APPEND(rText
,"none ");
1610 GetSubNode(1)->CreateTextFromNode(rText
);
1611 if (GetScaleMode() == SCALE_HEIGHT
)
1612 APPEND(rText
,"right ");
1615 GetSubNode(2)->CreateTextFromNode(aStr
);
1616 aStr
.EraseLeadingAndTrailingChars();
1617 aStr
.EraseLeadingChars('\\');
1620 if (aStr
.EqualsAscii("divides"))
1621 APPEND(rText
,"rline");
1622 else if (aStr
.EqualsAscii("parallel"))
1623 APPEND(rText
,"rdline");
1624 else if (aStr
.EqualsAscii(">"))
1625 APPEND(rText
,"rangle");
1631 APPEND(rText
,"none ");
1637 void SmBraceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1639 SmNode
*pLeft
= GetSubNode(0),
1640 *pBody
= GetSubNode(1),
1641 *pRight
= GetSubNode(2);
1642 DBG_ASSERT(pLeft
, "Sm: NULL pointer");
1643 DBG_ASSERT(pBody
, "Sm: NULL pointer");
1644 DBG_ASSERT(pRight
, "Sm: NULL pointer");
1646 pBody
->Arrange(rDev
, rFormat
);
1648 sal_Bool bIsScaleNormal
= rFormat
.IsScaleNormalBrackets(),
1649 bScale
= pBody
->GetHeight() > 0 &&
1650 (GetScaleMode() == SCALE_HEIGHT
|| bIsScaleNormal
),
1651 bIsABS
= GetToken().eType
== TABS
;
1653 long nFaceHeight
= GetFont().GetSize().Height();
1655 // Uebergroesse in % ermitteln
1656 sal_uInt16 nPerc
= 0;
1657 if (!bIsABS
&& bScale
)
1658 { // im Fall von Klammern mit Uebergroesse...
1659 sal_uInt16 nIndex
= GetScaleMode() == SCALE_HEIGHT
?
1660 DIS_BRACKETSIZE
: DIS_NORMALBRACKETSIZE
;
1661 nPerc
= rFormat
.GetDistance(nIndex
);
1664 // ermitteln der Hoehe fuer die Klammern
1668 nBraceHeight
= pBody
->GetType() == NBRACEBODY
?
1669 ((SmBracebodyNode
*) pBody
)->GetBodyHeight()
1670 : pBody
->GetHeight();
1671 nBraceHeight
+= 2 * (nBraceHeight
* nPerc
/ 100L);
1674 nBraceHeight
= nFaceHeight
;
1676 // Abstand zum Argument
1677 nPerc
= bIsABS
? 0 : rFormat
.GetDistance(DIS_BRACKETSPACE
);
1678 long nDist
= nFaceHeight
* nPerc
/ 100L;
1680 // sofern erwuenscht skalieren der Klammern auf die gewuenschte Groesse
1683 Size
aTmpSize (pLeft
->GetFont().GetSize());
1684 DBG_ASSERT(pRight
->GetFont().GetSize() == aTmpSize
,
1685 "Sm : unterschiedliche Fontgroessen");
1686 aTmpSize
.Width() = Min((long) nBraceHeight
* 60L / 100L,
1687 rFormat
.GetBaseSize().Height() * 3L / 2L);
1688 // correction factor since change from StarMath to OpenSymbol font
1689 // because of the different font width in the FontMetric
1690 aTmpSize
.Width() *= 182;
1691 aTmpSize
.Width() /= 267;
1693 xub_Unicode cChar
= pLeft
->GetToken().cMathChar
;
1694 if (cChar
!= MS_LINE
&& cChar
!= MS_DLINE
)
1695 pLeft
->GetFont().SetSize(aTmpSize
);
1697 cChar
= pRight
->GetToken().cMathChar
;
1698 if (cChar
!= MS_LINE
&& cChar
!= MS_DLINE
)
1699 pRight
->GetFont().SetSize(aTmpSize
);
1701 pLeft
->AdaptToY(rDev
, nBraceHeight
);
1702 pRight
->AdaptToY(rDev
, nBraceHeight
);
1705 pLeft
->Arrange(rDev
, rFormat
);
1706 pRight
->Arrange(rDev
, rFormat
);
1708 // damit auch "\(a\) - (a) - left ( a right )" vernuenftig aussieht
1709 RectVerAlign eVerAlign
= bScale
? RVA_CENTERY
: RVA_BASELINE
;
1712 aPos
= pLeft
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, eVerAlign
);
1714 pLeft
->MoveTo(aPos
);
1716 aPos
= pRight
->AlignTo(*pBody
, RP_RIGHT
, RHA_CENTER
, eVerAlign
);
1718 pRight
->MoveTo(aPos
);
1720 SmRect::operator = (*pBody
);
1721 ExtendBy(*pLeft
, RCP_THIS
).ExtendBy(*pRight
, RCP_THIS
);
1725 /**************************************************************************/
1728 void SmBracebodyNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1730 sal_uInt16 nNumSubNodes
= GetNumSubNodes();
1731 if (nNumSubNodes
== 0)
1734 // arrange arguments
1736 for (i
= 0; i
< nNumSubNodes
; i
+= 2)
1737 GetSubNode(i
)->Arrange(rDev
, rFormat
);
1739 // build reference rectangle with necessary info for vertical alignment
1740 SmRect
aRefRect (*GetSubNode(0));
1741 for (i
= 0; i
< nNumSubNodes
; i
+= 2)
1743 SmRect
aTmpRect (*GetSubNode(i
));
1744 Point aPos
= aTmpRect
.AlignTo(aRefRect
, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1745 aTmpRect
.MoveTo(aPos
);
1746 aRefRect
.ExtendBy(aTmpRect
, RCP_XOR
);
1749 nBodyHeight
= aRefRect
.GetHeight();
1751 // scale separators to required height and arrange them
1752 sal_Bool bScale
= GetScaleMode() == SCALE_HEIGHT
|| rFormat
.IsScaleNormalBrackets();
1753 long nHeight
= bScale
? aRefRect
.GetHeight() : GetFont().GetSize().Height();
1754 sal_uInt16 nIndex
= GetScaleMode() == SCALE_HEIGHT
?
1755 DIS_BRACKETSIZE
: DIS_NORMALBRACKETSIZE
;
1756 sal_uInt16 nPerc
= rFormat
.GetDistance(nIndex
);
1758 nHeight
+= 2 * (nHeight
* nPerc
/ 100L);
1759 for (i
= 1; i
< nNumSubNodes
; i
+= 2)
1761 SmNode
*pNode
= GetSubNode(i
);
1762 pNode
->AdaptToY(rDev
, nHeight
);
1763 pNode
->Arrange(rDev
, rFormat
);
1766 // horizontal distance between argument and brackets or separators
1767 long nDist
= GetFont().GetSize().Height()
1768 * rFormat
.GetDistance(DIS_BRACKETSPACE
) / 100L;
1770 SmNode
*pLeft
= GetSubNode(0);
1771 SmRect::operator = (*pLeft
);
1772 for (i
= 1; i
< nNumSubNodes
; i
++)
1774 sal_Bool bIsSeparator
= i
% 2 != 0;
1775 RectVerAlign eVerAlign
= bIsSeparator
? RVA_CENTERY
: RVA_BASELINE
;
1777 SmNode
*pRight
= GetSubNode(i
);
1778 Point aPosX
= pRight
->AlignTo(*pLeft
, RP_RIGHT
, RHA_CENTER
, eVerAlign
),
1779 aPosY
= pRight
->AlignTo(aRefRect
, RP_RIGHT
, RHA_CENTER
, eVerAlign
);
1782 pRight
->MoveTo(Point(aPosX
.X(), aPosY
.Y()));
1783 ExtendBy(*pRight
, bIsSeparator
? RCP_THIS
: RCP_XOR
);
1790 /**************************************************************************/
1793 void SmVerticalBraceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1795 SmNode
*pBody
= GetSubNode(0),
1796 *pBrace
= GetSubNode(1),
1797 *pScript
= GetSubNode(2);
1798 DBG_ASSERT(pBody
, "Sm: NULL pointer!");
1799 DBG_ASSERT(pBrace
, "Sm: NULL pointer!");
1800 DBG_ASSERT(pScript
, "Sm: NULL pointer!");
1802 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
1803 aTmpDev
.SetFont(GetFont());
1805 pBody
->Arrange(aTmpDev
, rFormat
);
1807 // Groesse wie bei Grenzen fuer diesen Teil
1808 pScript
->SetSize( Fraction( rFormat
.GetRelSize(SIZ_LIMITS
), 100 ) );
1809 // etwas hoehere Klammern als normal
1810 pBrace
->SetSize( Fraction(3, 2) );
1812 long nItalicWidth
= pBody
->GetItalicWidth();
1813 if (nItalicWidth
> 0)
1814 pBrace
->AdaptToX(aTmpDev
, nItalicWidth
);
1816 pBrace
->Arrange(aTmpDev
, rFormat
);
1817 pScript
->Arrange(aTmpDev
, rFormat
);
1819 // die relativen Position und die Abstaende zueinander bestimmen
1821 long nFontHeight
= pBody
->GetFont().GetSize().Height();
1822 long nDistBody
= nFontHeight
* rFormat
.GetDistance(DIS_ORNAMENTSIZE
),
1823 nDistScript
= nFontHeight
;
1824 if (GetToken().eType
== TOVERBRACE
)
1827 nDistBody
= - nDistBody
;
1828 nDistScript
*= - rFormat
.GetDistance(DIS_UPPERLIMIT
);
1832 eRectPos
= RP_BOTTOM
;
1833 nDistScript
*= + rFormat
.GetDistance(DIS_LOWERLIMIT
);
1836 nDistScript
/= 100L;
1838 Point aPos
= pBrace
->AlignTo(*pBody
, eRectPos
, RHA_CENTER
, RVA_BASELINE
);
1839 aPos
.Y() += nDistBody
;
1840 pBrace
->MoveTo(aPos
);
1842 aPos
= pScript
->AlignTo(*pBrace
, eRectPos
, RHA_CENTER
, RVA_BASELINE
);
1843 aPos
.Y() += nDistScript
;
1844 pScript
->MoveTo(aPos
);
1846 SmRect::operator = (*pBody
);
1847 ExtendBy(*pBrace
, RCP_THIS
).ExtendBy(*pScript
, RCP_THIS
);
1851 /**************************************************************************/
1854 SmNode
* SmOperNode::GetSymbol()
1856 SmNode
*pNode
= GetSubNode(0);
1857 DBG_ASSERT(pNode
, "Sm: NULL pointer!");
1859 if (pNode
->GetType() == NSUBSUP
)
1860 pNode
= ((SmSubSupNode
*) pNode
)->GetBody();
1862 DBG_ASSERT(pNode
, "Sm: NULL pointer!");
1867 long SmOperNode::CalcSymbolHeight(const SmNode
&rSymbol
,
1868 const SmFormat
&rFormat
) const
1869 // returns the font height to be used for operator-symbol
1871 long nHeight
= GetFont().GetSize().Height();
1873 SmTokenType eTmpType
= GetToken().eType
;
1874 if (eTmpType
== TLIM
|| eTmpType
== TLIMINF
|| eTmpType
== TLIMSUP
)
1877 if (!rFormat
.IsTextmode())
1879 // set minimum size ()
1880 nHeight
+= (nHeight
* 20L) / 100L;
1883 * rFormat
.GetDistance(DIS_OPERATORSIZE
) / 100L;
1884 nHeight
= nHeight
* 686L / 845L;
1887 // correct user-defined symbols to match height of sum from used font
1888 if (rSymbol
.GetToken().eType
== TSPECIAL
)
1889 nHeight
= nHeight
* 845L / 686L;
1895 void SmOperNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1897 SmNode
*pOper
= GetSubNode(0);
1898 SmNode
*pBody
= GetSubNode(1);
1900 DBG_ASSERT(pOper
, "Sm: Subnode fehlt");
1901 DBG_ASSERT(pBody
, "Sm: Subnode fehlt");
1903 SmNode
*pSymbol
= GetSymbol();
1904 pSymbol
->SetSize(Fraction(CalcSymbolHeight(*pSymbol
, rFormat
),
1905 pSymbol
->GetFont().GetSize().Height()));
1907 pBody
->Arrange(rDev
, rFormat
);
1908 pOper
->Arrange(rDev
, rFormat
);
1910 long nOrigHeight
= GetFont().GetSize().Height(),
1912 * rFormat
.GetDistance(DIS_OPERATORSPACE
) / 100L;
1914 Point aPos
= pOper
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, /*RVA_CENTERY*/RVA_MID
);
1916 pOper
->MoveTo(aPos
);
1918 SmRect::operator = (*pBody
);
1919 ExtendBy(*pOper
, RCP_THIS
);
1923 /**************************************************************************/
1926 void SmAlignNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1927 // setzt im ganzen subtree (incl aktuellem node) das alignment
1929 DBG_ASSERT(GetNumSubNodes() > 0, "Sm: SubNode fehlt");
1931 SmNode
*pNode
= GetSubNode(0);
1933 RectHorAlign eHorAlign
= RHA_CENTER
;
1934 switch (GetToken().eType
)
1936 case TALIGNL
: eHorAlign
= RHA_LEFT
; break;
1937 case TALIGNC
: eHorAlign
= RHA_CENTER
; break;
1938 case TALIGNR
: eHorAlign
= RHA_RIGHT
; break;
1942 SetRectHorAlign(eHorAlign
);
1944 pNode
->Arrange(rDev
, rFormat
);
1946 SmRect::operator = (pNode
->GetRect());
1950 /**************************************************************************/
1953 void SmAttributNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1955 SmNode
*pAttr
= GetSubNode(0),
1956 *pBody
= GetSubNode(1);
1957 DBG_ASSERT(pBody
, "Sm: Body fehlt");
1958 DBG_ASSERT(pAttr
, "Sm: Attribut fehlt");
1960 pBody
->Arrange(rDev
, rFormat
);
1962 if (GetScaleMode() == SCALE_WIDTH
)
1963 pAttr
->AdaptToX(rDev
, pBody
->GetItalicWidth());
1964 pAttr
->Arrange(rDev
, rFormat
);
1966 // get relative position of attribut
1967 RectVerAlign eVerAlign
;
1969 switch (GetToken().eType
)
1971 eVerAlign
= RVA_ATTRIBUT_LO
;
1974 eVerAlign
= RVA_ATTRIBUT_MID
;
1977 eVerAlign
= RVA_ATTRIBUT_HI
;
1978 if (pBody
->GetType() == NATTRIBUT
)
1979 nDist
= GetFont().GetSize().Height()
1980 * rFormat
.GetDistance(DIS_ORNAMENTSPACE
) / 100L;
1982 Point aPos
= pAttr
->AlignTo(*pBody
, RP_ATTRIBUT
, RHA_CENTER
, eVerAlign
);
1984 pAttr
->MoveTo(aPos
);
1986 SmRect::operator = (*pBody
);
1987 ExtendBy(*pAttr
, RCP_THIS
, (sal_Bool
) sal_True
);
1991 /**************************************************************************/
1996 void SmFontNode::CreateTextFromNode(String
&rText
)
1998 switch (GetToken().eType
)
2001 APPEND(rText
,"bold ");
2004 APPEND(rText
,"nbold ");
2007 APPEND(rText
,"italic ");
2010 APPEND(rText
,"nitalic ");
2013 APPEND(rText
,"phantom ");
2017 APPEND(rText
,"size ");
2026 case FNTSIZ_MULTIPLY
:
2032 case FNTSIZ_ABSOLUT
:
2036 rText
+= String( ::rtl::math::doubleToUString(
2037 static_cast<double>(aFontSize
),
2038 rtl_math_StringFormat_Automatic
,
2039 rtl_math_DecimalPlaces_Max
, '.', sal_True
));
2044 APPEND(rText
,"color black ");
2047 APPEND(rText
,"color white ");
2050 APPEND(rText
,"color red ");
2053 APPEND(rText
,"color green ");
2056 APPEND(rText
,"color blue ");
2059 APPEND(rText
,"color cyan ");
2062 APPEND(rText
,"color magenta ");
2065 APPEND(rText
,"color yellow ");
2068 APPEND(rText
,"font sans ");
2071 APPEND(rText
,"font serif ");
2074 APPEND(rText
,"font fixed ");
2079 GetSubNode(1)->CreateTextFromNode(rText
);
2083 void SmFontNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2085 //! prepare subnodes first
2086 SmNode::Prepare(rFormat
, rDocShell
);
2089 switch (GetToken().eType
)
2091 case TFIXED
: nFnt
= FNT_FIXED
; break;
2092 case TSANS
: nFnt
= FNT_SANS
; break;
2093 case TSERIF
: nFnt
= FNT_SERIF
; break;
2098 { GetFont() = rFormat
.GetFont( sal::static_int_cast
< sal_uInt16
>(nFnt
) );
2102 //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
2103 //! other font nodes (those with lower depth in the tree)
2104 Flags() |= FLG_FONT
;
2108 void SmFontNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2110 SmNode
*pNode
= GetSubNode(1);
2111 DBG_ASSERT(pNode
, "Sm: SubNode fehlt");
2113 switch (GetToken().eType
)
2115 pNode
->SetFontSize(aFontSize
, nSizeType
);
2120 pNode
->SetFont(GetFont());
2122 case TUNKNOWN
: break; // no assertion on "font <?> <?>"
2124 case TPHANTOM
: SetPhantom(sal_True
); break;
2125 case TBOLD
: SetAttribut(ATTR_BOLD
); break;
2126 case TITALIC
: SetAttribut(ATTR_ITALIC
); break;
2127 case TNBOLD
: ClearAttribut(ATTR_BOLD
); break;
2128 case TNITALIC
: ClearAttribut(ATTR_ITALIC
); break;
2130 case TBLACK
: SetColor(Color(COL_BLACK
)); break;
2131 case TWHITE
: SetColor(Color(COL_WHITE
)); break;
2132 case TRED
: SetColor(Color(COL_RED
)); break;
2133 case TGREEN
: SetColor(Color(COL_GREEN
)); break;
2134 case TBLUE
: SetColor(Color(COL_BLUE
)); break;
2135 case TCYAN
: SetColor(Color(COL_CYAN
)); break;
2136 case TMAGENTA
: SetColor(Color(COL_MAGENTA
)); break;
2137 case TYELLOW
: SetColor(Color(COL_YELLOW
)); break;
2140 DBG_ASSERT(sal_False
, "Sm: unbekannter Fall");
2143 pNode
->Arrange(rDev
, rFormat
);
2145 SmRect::operator = (pNode
->GetRect());
2149 void SmFontNode::SetSizeParameter(const Fraction
& rValue
, sal_uInt16 Type
)
2156 /**************************************************************************/
2159 SmPolyLineNode::SmPolyLineNode(const SmToken
&rNodeToken
)
2160 : SmGraphicNode(NPOLYLINE
, rNodeToken
)
2167 void SmPolyLineNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong nNewWidth
)
2169 aToSize
.Width() = nNewWidth
;
2173 void SmPolyLineNode::AdaptToY(const OutputDevice
&/*rDev*/, sal_uLong nNewHeight
)
2175 GetFont().FreezeBorderWidth();
2176 aToSize
.Height() = nNewHeight
;
2180 void SmPolyLineNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2182 //! some routines being called extract some info from the OutputDevice's
2183 //! font (eg the space to be used for borders OR the font name(!!)).
2184 //! Thus the font should reflect the needs and has to be set!
2185 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2186 aTmpDev
.SetFont(GetFont());
2188 long nBorderwidth
= GetFont().GetBorderWidth();
2191 // Das Polygon mit den beiden Endpunkten bilden
2193 DBG_ASSERT(aPoly
.GetSize() == 2, "Sm : falsche Anzahl von Punkten");
2194 Point aPointA
, aPointB
;
2195 if (GetToken().eType
== TWIDESLASH
)
2197 aPointA
.X() = nBorderwidth
;
2198 aPointA
.Y() = aToSize
.Height() - nBorderwidth
;
2199 aPointB
.X() = aToSize
.Width() - nBorderwidth
;
2200 aPointB
.Y() = nBorderwidth
;
2204 DBG_ASSERT(GetToken().eType
== TWIDEBACKSLASH
, "Sm : unerwartetes Token");
2206 aPointA
.Y() = nBorderwidth
;
2207 aPointB
.X() = aToSize
.Width() - nBorderwidth
;
2208 aPointB
.Y() = aToSize
.Height() - nBorderwidth
;
2210 aPoly
.SetPoint(aPointA
, 0);
2211 aPoly
.SetPoint(aPointB
, 1);
2213 long nThick
= GetFont().GetSize().Height()
2214 * rFormat
.GetDistance(DIS_STROKEWIDTH
) / 100L;
2215 nWidth
= nThick
+ 2 * nBorderwidth
;
2217 SmRect::operator = (SmRect(aToSize
.Width(), aToSize
.Height()));
2221 void SmPolyLineNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
2226 long nBorderwidth
= GetFont().GetBorderWidth();
2229 aInfo
.SetWidth(nWidth
- 2 * nBorderwidth
);
2231 Point
aOffset (Point() - aPoly
.GetBoundRect().TopLeft()
2232 + Point(nBorderwidth
, nBorderwidth
)),
2233 aPos (rPosition
+ aOffset
);
2234 ((Polygon
&) aPoly
).Move(aPos
.X(), aPos
.Y());
2236 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_False
);
2237 aTmpDev
.SetLineColor( GetFont().GetColor() );
2239 rDev
.DrawPolyLine(aPoly
, aInfo
);
2241 #ifdef SM_RECT_DEBUG
2245 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2246 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2251 /**************************************************************************/
2253 void SmRootSymbolNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong nWidth
)
2255 nBodyWidth
= nWidth
;
2259 void SmRootSymbolNode::AdaptToY(const OutputDevice
&rDev
, sal_uLong nHeight
)
2261 // etwas extra Laenge damit der horizontale Balken spaeter ueber dem
2262 // Argument positioniert ist
2263 SmMathSymbolNode::AdaptToY(rDev
, nHeight
+ nHeight
/ 10L);
2267 void SmRootSymbolNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
2272 // draw root-sign itself
2273 SmMathSymbolNode::Draw(rDev
, rPosition
);
2275 SmTmpDevice
aTmpDev( (OutputDevice
&) rDev
, sal_True
);
2276 aTmpDev
.SetFillColor(GetFont().GetColor());
2277 rDev
.SetLineColor();
2278 aTmpDev
.SetFont( GetFont() );
2280 // since the width is always unscaled it corresponds ot the _original_
2281 // _unscaled_ font height to be used, we use that to calculate the
2282 // bar height. Thus it is independent of the arguments height.
2283 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
2284 long nBarHeight
= GetWidth() * 7L / 100L;
2285 long nBarWidth
= nBodyWidth
+ GetBorderWidth();
2286 Point
aBarOffset( GetWidth(), +GetBorderWidth() );
2287 Point
aBarPos( rPosition
+ aBarOffset
);
2289 Rectangle
aBar(aBarPos
, Size( nBarWidth
, nBarHeight
) );
2290 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
2291 //! increasing zoomfactor.
2292 // This is done by shifting it's output-position to a point that
2293 // corresponds exactly to a pixel on the output device.
2294 Point
aDrawPos( rDev
.PixelToLogic(rDev
.LogicToPixel(aBar
.TopLeft())) );
2295 //aDrawPos.X() = aBar.Left(); //! don't change X position
2296 aBar
.SetPos( aDrawPos
);
2298 rDev
.DrawRect( aBar
);
2300 #ifdef SM_RECT_DEBUG
2304 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2305 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2310 /**************************************************************************/
2313 void SmRectangleNode::AdaptToX(const OutputDevice
&/*rDev*/, sal_uLong nWidth
)
2315 aToSize
.Width() = nWidth
;
2319 void SmRectangleNode::AdaptToY(const OutputDevice
&/*rDev*/, sal_uLong nHeight
)
2321 GetFont().FreezeBorderWidth();
2322 aToSize
.Height() = nHeight
;
2326 void SmRectangleNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&/*rFormat*/)
2328 long nFontHeight
= GetFont().GetSize().Height();
2329 long nWidth
= aToSize
.Width(),
2330 nHeight
= aToSize
.Height();
2332 nHeight
= nFontHeight
/ 30;
2334 nWidth
= nFontHeight
/ 3;
2336 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2337 aTmpDev
.SetFont(GetFont());
2339 // add some borderspace
2340 sal_uLong nTmpBorderWidth
= GetFont().GetBorderWidth();
2341 //nWidth += nTmpBorderWidth;
2342 nHeight
+= 2 * nTmpBorderWidth
;
2344 //! use this method in order to have 'SmRect::HasAlignInfo() == sal_True'
2345 //! and thus having the attribut-fences updated in 'SmRect::ExtendBy'
2346 SmRect::operator = (SmRect(nWidth
, nHeight
));
2350 void SmRectangleNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
2355 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_False
);
2356 aTmpDev
.SetFillColor(GetFont().GetColor());
2357 rDev
.SetLineColor();
2358 aTmpDev
.SetFont(GetFont());
2360 sal_uLong nTmpBorderWidth
= GetFont().GetBorderWidth();
2362 // get rectangle and remove borderspace
2363 Rectangle
aTmp (AsRectangle() + rPosition
- GetTopLeft());
2364 aTmp
.Left() += nTmpBorderWidth
;
2365 aTmp
.Right() -= nTmpBorderWidth
;
2366 aTmp
.Top() += nTmpBorderWidth
;
2367 aTmp
.Bottom() -= nTmpBorderWidth
;
2369 DBG_ASSERT(aTmp
.GetHeight() > 0 && aTmp
.GetWidth() > 0,
2370 "Sm: leeres Rechteck");
2372 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
2373 //! increasing zoomfactor.
2374 // This is done by shifting it's output-position to a point that
2375 // corresponds exactly to a pixel on the output device.
2376 Point
aPos (rDev
.PixelToLogic(rDev
.LogicToPixel(aTmp
.TopLeft())));
2379 rDev
.DrawRect(aTmp
);
2381 #ifdef SM_RECT_DEBUG
2385 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2386 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2391 /**************************************************************************/
2394 SmTextNode::SmTextNode( SmNodeType eNodeType
, const SmToken
&rNodeToken
, sal_uInt16 nFontDescP
) :
2395 SmVisibleNode(eNodeType
, rNodeToken
)
2397 nFontDesc
= nFontDescP
;
2401 SmTextNode::SmTextNode( const SmToken
&rNodeToken
, sal_uInt16 nFontDescP
) :
2402 SmVisibleNode(NTEXT
, rNodeToken
)
2404 nFontDesc
= nFontDescP
;
2408 void SmTextNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2410 SmNode::Prepare(rFormat
, rDocShell
);
2412 // default setting for horizontal alignment of nodes with TTEXT
2413 // content is as alignl (cannot be done in Arrange since it would
2414 // override the settings made by an SmAlignNode before)
2415 if (TTEXT
== GetToken().eType
)
2416 SetRectHorAlign( RHA_LEFT
);
2418 aText
= GetToken().aText
;
2419 GetFont() = rFormat
.GetFont(GetFontDesc());
2421 if (IsItalic( GetFont() ))
2422 Attributes() |= ATTR_ITALIC
;
2423 if (IsBold( GetFont() ))
2424 Attributes() |= ATTR_BOLD
;
2426 // special handling for ':' where it is a token on it's own and is likely
2427 // to be used for mathematical notations. (E.g. a:b = 2:3)
2428 // In that case it should not be displayed in italic.
2429 if (GetToken().aText
.Len() == 1 && GetToken().aText
.GetChar(0) == ':')
2430 Attributes() &= ~ATTR_ITALIC
;
2434 void SmTextNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2436 PrepareAttributes();
2438 sal_uInt16 nSizeDesc
= GetFontDesc() == FNT_FUNCTION
?
2439 SIZ_FUNCTION
: SIZ_TEXT
;
2440 GetFont() *= Fraction (rFormat
.GetRelSize(nSizeDesc
), 100);
2442 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2443 aTmpDev
.SetFont(GetFont());
2445 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, aText
, GetFont().GetBorderWidth()));
2448 void SmTextNode::CreateTextFromNode(String
&rText
)
2450 sal_Bool bQuoted
=sal_False
;
2451 if (GetToken().eType
== TTEXT
)
2458 SmParser aParseTest
;
2459 SmNode
*pTable
= aParseTest
.Parse(GetToken().aText
);
2461 if ( (pTable
->GetType() == NTABLE
) && (pTable
->GetNumSubNodes() == 1) )
2463 SmNode
*pResult
= pTable
->GetSubNode(0);
2464 if ( (pResult
->GetType() == NLINE
) &&
2465 (pResult
->GetNumSubNodes() == 1) )
2467 pResult
= pResult
->GetSubNode(0);
2468 if ( (pResult
->GetType() == NEXPRESSION
) &&
2469 (pResult
->GetNumSubNodes() == 1) )
2471 pResult
= pResult
->GetSubNode(0);
2472 if (pResult
->GetType() == NTEXT
)
2479 if ((GetToken().eType
== TIDENT
) && (GetFontDesc() == FNT_FUNCTION
))
2481 //Search for existing functions and remove extraenous keyword
2482 APPEND(rText
,"func ");
2485 APPEND(rText
,"italic ");
2492 rText
.Append(GetToken().aText
);
2499 void SmTextNode::Draw(OutputDevice
&rDev
, const Point
& rPosition
) const
2501 if (IsPhantom() || aText
.Len() == 0 || aText
.GetChar(0) == xub_Unicode('\0'))
2504 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_False
);
2505 aTmpDev
.SetFont(GetFont());
2507 Point
aPos (rPosition
);
2508 aPos
.Y() += GetBaselineOffset();
2509 // auf Pixelkoordinaten runden
2510 aPos
= rDev
.PixelToLogic( rDev
.LogicToPixel(aPos
) );
2512 #if OSL_DEBUG_LEVEL > 1
2514 sal_UCS4 cChar
= OUString( aText
).iterateCodePoints( &nPos
);
2518 rDev
.DrawStretchText(aPos
, GetWidth(), aText
);
2520 #ifdef SM_RECT_DEBUG
2524 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2525 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2529 void SmTextNode::GetAccessibleText( String
&rText
) const
2534 /**************************************************************************/
2536 void SmMatrixNode::CreateTextFromNode(String
&rText
)
2538 APPEND(rText
,"matrix {");
2539 for (sal_uInt16 i
= 0; i
< nNumRows
; i
++)
2541 for (sal_uInt16 j
= 0; j
< nNumCols
; j
++)
2543 SmNode
*pNode
= GetSubNode(i
* nNumCols
+ j
);
2544 pNode
->CreateTextFromNode(rText
);
2545 if (j
!= nNumCols
-1)
2548 if (i
!= nNumRows
-1)
2549 APPEND(rText
,"## ");
2551 rText
.EraseTrailingChars();
2556 void SmMatrixNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2563 // initialize array that is to hold the maximum widhts of all
2564 // elements (subnodes) in that column.
2565 long *pColWidth
= new long[nNumCols
];
2566 for (j
= 0; j
< nNumCols
; j
++)
2569 // arrange subnodes and calculate the aboves arrays contents
2570 sal_uInt16 nNodes
= GetNumSubNodes();
2571 for (i
= 0; i
< nNodes
; i
++)
2573 sal_uInt16 nIdx
= nNodes
- 1 - i
;
2574 if (NULL
!= (pNode
= GetSubNode(nIdx
)))
2576 pNode
->Arrange(rDev
, rFormat
);
2577 int nCol
= nIdx
% nNumCols
;
2578 pColWidth
[nCol
] = Max(pColWidth
[nCol
], pNode
->GetItalicWidth());
2582 // norm distance from which the following two are calcutated
2583 const int nNormDist
= 3 * GetFont().GetSize().Height();
2585 // define horizontal and vertical minimal distances that seperate
2587 long nHorDist
= nNormDist
* rFormat
.GetDistance(DIS_MATRIXCOL
) / 100L,
2588 nVerDist
= nNormDist
* rFormat
.GetDistance(DIS_MATRIXROW
) / 100L;
2590 // build array that holds the leftmost position for each column
2591 long *pColLeft
= new long[nNumCols
];
2593 for (j
= 0; j
< nNumCols
; j
++)
2595 nX
+= pColWidth
[j
] + nHorDist
;
2600 SmRect::operator = (SmRect());
2601 for (i
= 0; i
< nNumRows
; i
++)
2602 { aLineRect
= SmRect();
2603 for (j
= 0; j
< nNumCols
; j
++)
2604 { SmNode
*pTmpNode
= GetSubNode(i
* nNumCols
+ j
);
2605 DBG_ASSERT(pTmpNode
, "Sm: NULL pointer");
2607 const SmRect
&rNodeRect
= pTmpNode
->GetRect();
2609 // align all baselines in that row if possible
2610 aPos
= rNodeRect
.AlignTo(aLineRect
, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
2611 aPos
.X() += nHorDist
;
2613 // get horizontal alignment
2614 const SmNode
*pCoNode
= pTmpNode
->GetLeftMost();
2615 RectHorAlign eHorAlign
= pCoNode
->GetRectHorAlign();
2617 // caculate horizontal position of element depending on column
2618 // and horizontal alignment
2621 aPos
.X() = rNodeRect
.GetLeft() + pColLeft
[j
];
2624 aPos
.X() = rNodeRect
.GetLeft() + pColLeft
[j
]
2626 - rNodeRect
.GetItalicCenterX();
2629 aPos
.X() = rNodeRect
.GetLeft() + pColLeft
[j
]
2630 + pColWidth
[j
] - rNodeRect
.GetItalicWidth();
2634 pTmpNode
->MoveTo(aPos
);
2635 aLineRect
.ExtendBy(rNodeRect
, RCP_XOR
);
2638 aPos
= aLineRect
.AlignTo(*this, RP_BOTTOM
, RHA_CENTER
, RVA_BASELINE
);
2639 aPos
.Y() += nVerDist
;
2641 // move 'aLineRect' and rectangles in that line to final position
2642 aDelta
.X() = 0; // since horizontal alignment is already done
2643 aDelta
.Y() = aPos
.Y() - aLineRect
.GetTop();
2644 aLineRect
.Move(aDelta
);
2645 for (j
= 0; j
< nNumCols
; j
++)
2646 if (NULL
!= (pNode
= GetSubNode(i
* nNumCols
+ j
)))
2647 pNode
->Move(aDelta
);
2649 ExtendBy(aLineRect
, RCP_NONE
);
2653 delete [] pColWidth
;
2657 void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows
, sal_uInt16 nMatrixCols
)
2659 nNumRows
= nMatrixRows
;
2660 nNumCols
= nMatrixCols
;
2664 SmNode
* SmMatrixNode::GetLeftMost()
2670 /**************************************************************************/
2673 SmMathSymbolNode::SmMathSymbolNode(const SmToken
&rNodeToken
)
2674 : SmSpecialNode(NMATH
, rNodeToken
, FNT_MATH
)
2676 xub_Unicode cChar
= GetToken().cMathChar
;
2677 if ((xub_Unicode
) '\0' != cChar
)
2681 void SmMathSymbolNode::AdaptToX(const OutputDevice
&rDev
, sal_uLong nWidth
)
2683 // Since there is no function to do this, we try to approximate it:
2684 Size
aFntSize (GetFont().GetSize());
2686 //! however the result is a bit better with 'nWidth' as initial font width
2687 aFntSize
.Width() = nWidth
;
2688 GetFont().SetSize(aFntSize
);
2690 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2691 aTmpDev
.SetFont(GetFont());
2693 // get denominator of error factor for width
2694 long nTmpBorderWidth
= GetFont().GetBorderWidth();
2695 long nDenom
= SmRect(aTmpDev
, NULL
, GetText(), nTmpBorderWidth
).GetItalicWidth();
2697 // scale fontwidth with this error factor
2698 aFntSize
.Width() *= nWidth
;
2699 aFntSize
.Width() /= nDenom
? nDenom
: 1;
2701 GetFont().SetSize(aFntSize
);
2704 void SmMathSymbolNode::AdaptToY(const OutputDevice
&rDev
, sal_uLong nHeight
)
2706 GetFont().FreezeBorderWidth();
2707 Size
aFntSize (GetFont().GetSize());
2709 // da wir nur die Hoehe skalieren wollen muesen wir hier ggf die Fontweite
2710 // ermitteln um diese beizubehalten.
2711 if (aFntSize
.Width() == 0)
2713 OutputDevice
&rDevNC
= (OutputDevice
&) rDev
;
2714 rDevNC
.Push(PUSH_FONT
| PUSH_MAPMODE
);
2715 rDevNC
.SetFont(GetFont());
2716 aFntSize
.Width() = rDev
.GetFontMetric().GetSize().Width();
2719 DBG_ASSERT(aFntSize
.Width() != 0, "Sm: ");
2721 //! however the result is a bit better with 'nHeight' as initial
2723 aFntSize
.Height() = nHeight
;
2724 GetFont().SetSize(aFntSize
);
2726 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2727 aTmpDev
.SetFont(GetFont());
2729 // get denominator of error factor for height
2730 long nTmpBorderWidth
= GetFont().GetBorderWidth();
2731 long nDenom
= SmRect(aTmpDev
, NULL
, GetText(), nTmpBorderWidth
).GetHeight();
2733 // scale fontwidth with this error factor
2734 aFntSize
.Height() *= nHeight
;
2735 aFntSize
.Height() /= nDenom
? nDenom
: 1;
2737 GetFont().SetSize(aFntSize
);
2741 void SmMathSymbolNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2743 SmNode::Prepare(rFormat
, rDocShell
);
2745 GetFont() = rFormat
.GetFont(GetFontDesc());
2746 // use same font size as is used for variables
2747 GetFont().SetSize( rFormat
.GetFont( FNT_VARIABLE
).GetSize() );
2749 DBG_ASSERT(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL
||
2750 GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE
,
2751 "incorrect charset for character from StarMath/OpenSymbol font");
2753 Flags() |= FLG_FONT
| FLG_ITALIC
;
2757 void SmMathSymbolNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2759 const XubString
&rText
= GetText();
2761 if (rText
.Len() == 0 || rText
.GetChar(0) == xub_Unicode('\0'))
2762 { SmRect::operator = (SmRect());
2766 PrepareAttributes();
2768 GetFont() *= Fraction (rFormat
.GetRelSize(SIZ_TEXT
), 100);
2770 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2771 aTmpDev
.SetFont(GetFont());
2773 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, rText
, GetFont().GetBorderWidth()));
2776 void SmMathSymbolNode::CreateTextFromNode(String
&rText
)
2779 MathType::LookupChar(GetToken().cMathChar
, sStr
);
2783 void SmRectangleNode::CreateTextFromNode(String
&rText
)
2785 switch (GetToken().eType
)
2788 APPEND(rText
,"underline ");
2791 APPEND(rText
,"overline ");
2794 APPEND(rText
,"overstrike ");
2801 void SmAttributNode::CreateTextFromNode(String
&rText
)
2804 sal_uInt16 nSize
= GetNumSubNodes();
2805 DBG_ASSERT(nSize
== 2, "Node missing members");
2807 sal_Unicode nLast
=0;
2808 if (NULL
!= (pNode
= GetSubNode(0)))
2811 pNode
->CreateTextFromNode(aStr
);
2816 nLast
= aStr
.GetChar(0);
2820 APPEND(rText
,"overline ");
2823 APPEND(rText
,"dot ");
2826 APPEND(rText
,"widetilde ");
2829 APPEND(rText
,"ddot ");
2834 APPEND(rText
,"dddot ");
2837 rText
.Append(nLast
);
2844 if (NULL
!= (pNode
= GetSubNode(1)))
2845 pNode
->CreateTextFromNode(rText
);
2847 rText
.EraseTrailingChars();
2849 if (nLast
== 0xE082)
2850 APPEND(rText
," overbrace {}");
2855 /**************************************************************************/
2857 bool lcl_IsFromGreekSymbolSet( const String
&rTokenText
)
2861 // valid symbol name needs to have a '%' at pos 0 and at least an additonal char
2862 if (rTokenText
.Len() > 2 && rTokenText
.GetBuffer()[0] == (sal_Unicode
)'%')
2864 String
aName( rTokenText
.Copy(1) );
2865 SmSym
*pSymbol
= SM_MOD()->GetSymbolManager().GetSymbolByName( aName
);
2866 if (pSymbol
&& GetExportSymbolSetName( pSymbol
->GetSymbolSetName() ).EqualsAscii( "Greek" ) )
2874 SmSpecialNode::SmSpecialNode(SmNodeType eNodeType
, const SmToken
&rNodeToken
, sal_uInt16 _nFontDesc
) :
2875 SmTextNode(eNodeType
, rNodeToken
, _nFontDesc
)
2877 bIsFromGreekSymbolSet
= lcl_IsFromGreekSymbolSet( rNodeToken
.aText
);
2881 SmSpecialNode::SmSpecialNode(const SmToken
&rNodeToken
) :
2882 SmTextNode(NSPECIAL
, rNodeToken
, FNT_MATH
) //! default Font nicht immer richtig
2884 bIsFromGreekSymbolSet
= lcl_IsFromGreekSymbolSet( rNodeToken
.aText
);
2888 void SmSpecialNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2890 SmNode::Prepare(rFormat
, rDocShell
);
2893 SmModule
*pp
= SM_MOD();
2895 String
aName( GetToken().aText
.Copy(1) );
2896 if (NULL
!= (pSym
= pp
->GetSymbolManager().GetSymbolByName( aName
)))
2898 sal_UCS4 cChar
= pSym
->GetCharacter();
2899 String
aTmp( OUString( &cChar
, 1 ) );
2901 GetFont() = pSym
->GetFace();
2905 SetText( GetToken().aText
);
2906 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
2908 // use same font size as is used for variables
2909 GetFont().SetSize( rFormat
.GetFont( FNT_VARIABLE
).GetSize() );
2911 //! eigentlich sollten nur WEIGHT_NORMAL und WEIGHT_BOLD vorkommen...
2912 //! In der sms-Datei gibt es jedoch zB auch 'WEIGHT_ULTRALIGHT'
2913 //! daher vergleichen wir hier mit > statt mit != .
2914 //! (Langfristig sollte die Notwendigkeit fuer 'PrepareAttribut', und damit
2915 //! fuer dieses hier, mal entfallen.)
2917 //! see also SmFontStyles::GetStyleName
2918 if (IsItalic( GetFont() ))
2919 SetAttribut(ATTR_ITALIC
);
2920 if (IsBold( GetFont() ))
2921 SetAttribut(ATTR_BOLD
);
2923 Flags() |= FLG_FONT
;
2925 if (bIsFromGreekSymbolSet
)
2927 DBG_ASSERT( GetText().Len() == 1, "a symbol should only consist of 1 char!" );
2928 bool bItalic
= false;
2929 sal_Int16 nStyle
= rFormat
.GetGreekCharStyle();
2930 DBG_ASSERT( nStyle
>= 0 && nStyle
<= 2, "unexpected value for GreekCharStyle" );
2933 else if (nStyle
== 2)
2935 String
aTmp( GetText() );
2938 const sal_Unicode cUppercaseAlpha
= 0x0391;
2939 const sal_Unicode cUppercaseOmega
= 0x03A9;
2940 sal_Unicode cChar
= aTmp
.GetBuffer()[0];
2941 // uppercase letters should be straight and lowercase letters italic
2942 bItalic
= !(cUppercaseAlpha
<= cChar
&& cChar
<= cUppercaseOmega
);
2947 Attributes() |= ATTR_ITALIC
;
2949 Attributes() &= ~ATTR_ITALIC
;;
2954 void SmSpecialNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2956 PrepareAttributes();
2958 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2959 aTmpDev
.SetFont(GetFont());
2961 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(), GetFont().GetBorderWidth()));
2965 void SmSpecialNode::Draw(OutputDevice
&rDev
, const Point
& rPosition
) const
2967 //! since this chars might come from any font, that we may not have
2968 //! set to ALIGN_BASELINE yet, we do it now.
2969 ((SmSpecialNode
*)this)->GetFont().SetAlign(ALIGN_BASELINE
);
2971 SmTextNode::Draw(rDev
, rPosition
);
2975 /**************************************************************************/
2978 void SmGlyphSpecialNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2980 PrepareAttributes();
2982 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
2983 aTmpDev
.SetFont(GetFont());
2985 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(),
2986 GetFont().GetBorderWidth()).AsGlyphRect());
2990 /**************************************************************************/
2993 void SmPlaceNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2995 SmNode::Prepare(rFormat
, rDocShell
);
2997 GetFont().SetColor(COL_GRAY
);
2998 Flags() |= FLG_COLOR
| FLG_FONT
| FLG_ITALIC
;
3002 void SmPlaceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
3004 PrepareAttributes();
3006 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
3007 aTmpDev
.SetFont(GetFont());
3009 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(), GetFont().GetBorderWidth()));
3013 /**************************************************************************/
3016 void SmErrorNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
3018 SmNode::Prepare(rFormat
, rDocShell
);
3020 GetFont().SetColor(COL_RED
);
3021 Flags() |= FLG_VISIBLE
| FLG_BOLD
| FLG_ITALIC
3022 | FLG_COLOR
| FLG_FONT
| FLG_SIZE
;
3026 void SmErrorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
3028 PrepareAttributes();
3030 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
3031 aTmpDev
.SetFont(GetFont());
3033 const XubString
&rText
= GetText();
3034 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, rText
, GetFont().GetBorderWidth()));
3038 /**************************************************************************/
3041 void SmBlankNode::IncreaseBy(const SmToken
&rToken
)
3043 switch(rToken
.eType
)
3045 case TBLANK
: nNum
+= 4; break;
3046 case TSBLANK
: nNum
+= 1; break;
3053 void SmBlankNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
3055 SmNode::Prepare(rFormat
, rDocShell
);
3057 //! hier muss/sollte es lediglich nicht der StarMath Font sein,
3058 //! damit fuer das in Arrange verwendete Zeichen ein "normales"
3059 //! (ungecliptes) Rechteck erzeugt wird.
3060 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
3062 Flags() |= FLG_FONT
| FLG_BOLD
| FLG_ITALIC
;
3066 void SmBlankNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
3068 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, sal_True
);
3069 aTmpDev
.SetFont(GetFont());
3071 // Abstand von der Fonthoehe abhaengig machen
3072 // (damit er beim skalieren (zB size *2 {a ~ b}) mitwaechst)
3073 long nDist
= GetFont().GetSize().Height() / 10L,
3074 nSpace
= nNum
* nDist
;
3076 // ein SmRect mit Baseline und allem drum und dran besorgen
3077 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, XubString(xub_Unicode(' ')),
3078 GetFont().GetBorderWidth()));
3080 // und dieses auf die gewuenschte Breite bringen
3081 SetItalicSpaces(0, 0);