merged tag ooo/DEV300_m102
[LibreOffice.git] / starmath / source / node.cxx
blobc4e731de932cd5c245a4f085fbbcd835733e46fc
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"
31 #include "node.hxx"
32 #include "rect.hxx"
33 #include "symbol.hxx"
34 #include "smmod.hxx"
35 #include "document.hxx"
36 #include "view.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>
48 #include <math.h>
49 #include <float.h>
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 ////////////////////////////////////////
62 // SmTmpDevice
63 // Allows for font and color changes. The original settings will be restored
64 // in the destructor.
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'
67 // functions.
68 // Usually a MapMode of 1/100th mm will be used.
71 class SmTmpDevice
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 );
81 public:
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) :
96 rOutDev(rTheDev)
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())
114 nNewCol = COL_BLACK;
115 else
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())
125 nNewCol = COL_WHITE;
126 else if (aBgCol.IsBright() && aTmpColor.IsBright())
127 nNewCol = COL_BLACK;
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)
146 eType = eNodeType;
147 eScaleMode = SCALE_NONE;
148 aNodeToken = rNodeToken;
149 nAccIndex = -1;
153 SmNode::~SmNode()
158 sal_Bool SmNode::IsVisible() const
160 return sal_False;
164 sal_uInt16 SmNode::GetNumSubNodes() const
166 return 0;
170 SmNode * SmNode::GetSubNode(sal_uInt16 /*nIndex*/)
172 return NULL;
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;
193 SmNode *pNode;
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);
206 SmNode *pNode;
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)
216 if (
217 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
218 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
221 nAttributes |= nAttrib;
224 SmNode *pNode;
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)
234 if (
235 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
236 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
239 nAttributes &= ~nAttrib;
242 SmNode *pNode;
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))
253 GetFont() = rFace;
255 SmNode *pNode;
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
266 Size aFntSize;
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;
277 switch(nType)
279 case FNTSIZ_ABSOLUT:
280 aFntSize.Height() = nHeight;
281 break;
283 case FNTSIZ_PLUS:
284 aFntSize.Height() += nHeight;
285 break;
287 case FNTSIZ_MINUS:
288 aFntSize.Height() -= nHeight;
289 break;
291 case FNTSIZ_MULTIPLY:
292 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) * rSize);
293 break;
295 case FNTSIZ_DIVIDE:
296 if (rSize != Fraction(0L))
297 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) / rSize);
298 break;
299 default:
300 break;
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);
311 SmNode *pNode;
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)
321 GetFont() *= rSize;
323 SmNode *pNode;
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;
336 if (bApplyToSubTree)
338 SmNode *pNode;
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
357 bIsDebug = sal_True;
358 #else
359 bIsDebug = sal_False;
360 #endif
361 bIsPhantom = sal_False;
362 nFlags = 0;
363 nAttributes = 0;
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);
378 SmNode *pNode;
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;
394 SmNode *pNode;
395 sal_uInt16 nSize = GetNumSubNodes();
396 for (sal_uInt16 i = 0; i < nSize; i++)
397 if (NULL != (pNode = pThis->GetSubNode(i)))
398 pNode->ToggleDebug();
400 #endif
403 void SmNode::Move(const Point& rPosition)
405 if (rPosition.X() == 0 && rPosition.Y() == 0)
406 return;
408 SmRect::Move(rPosition);
410 SmNode *pNode;
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)
420 SmNode *pNode;
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)
429 SmNode *pNode;
430 sal_uInt16 nSize = GetNumSubNodes();
431 if (nSize > 1)
432 rText.Append('{');
433 for (sal_uInt16 i = 0; i < nSize; i++)
434 if (NULL != (pNode = GetSubNode(i)))
435 pNode->CreateTextFromNode(rText);
436 if (nSize > 1)
438 rText.EraseTrailingChars();
439 APPEND(rText,"} ");
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
456 if (IsPhantom())
457 return;
459 const SmNode *pNode;
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);
467 #ifdef SM_RECT_DEBUG
468 if (!IsDebug())
469 return;
471 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
472 SmRect::Draw(rDev, rPosition, nRFlags);
473 #endif
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)
481 if ( IsVisible()
482 && nRow == GetToken().nRow
483 && nCol >= GetToken().nCol && nCol < GetToken().nCol + GetToken().aText.Len())
484 return this;
485 else
487 sal_uInt16 nNumSubNodes = GetNumSubNodes();
488 for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
489 { const SmNode *pNode = GetSubNode(i);
491 if (!pNode)
492 continue;
494 const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
495 if (pResult)
496 return pResult;
500 return 0;
504 const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
506 long nDist = LONG_MAX;
507 const SmNode *pResult = 0;
509 if (IsVisible())
510 pResult = this;
511 else
513 sal_uInt16 nNumSubNodes = GetNumSubNodes();
514 for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
515 { const SmNode *pNode = GetSubNode(i);
517 if (!pNode)
518 continue;
520 long nTmp;
521 const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
522 if (pFound && (nTmp = pFound->OrientedDist(rPoint)) < nDist)
523 { nDist = nTmp;
524 pResult = pFound;
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))
533 break;
538 return pResult;
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();
551 String aTxt;
552 if (nIdx >= 0)
553 GetAccessibleText( aTxt ); // get text if used in following 'if' statement
555 if (nIdx >= 0
556 && nIdx <= nAccIdx && nAccIdx < nIdx + aTxt.Len())
557 pResult = this;
558 else
560 sal_uInt16 nNumSubNodes = GetNumSubNodes();
561 for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
563 const SmNode *pNode = GetSubNode(i);
564 if (!pNode)
565 continue;
567 pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
568 if (pResult)
569 return pResult;
573 return pResult;
577 long SmNode::GetFormulaBaseline() const
579 DBG_ASSERT( 0, "This dummy implementation should not have been called." );
580 return 0;
583 ///////////////////////////////////////////////////////////////////////////
585 SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
586 SmNode( rNode.GetType(), rNode.GetToken() )
588 sal_uLong i;
589 for (i = 0; i < aSubNodes.size(); i++)
590 delete aSubNodes[i];
591 aSubNodes.resize(0);
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()
605 SmNode *pNode;
607 for (sal_uInt16 i = 0; i < GetNumSubNodes(); i++)
608 if (NULL != (pNode = GetSubNode(i)))
609 delete pNode;
613 SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
615 SmNode::operator = ( rNode );
617 sal_uLong i;
618 for (i = 0; i < aSubNodes.size(); i++)
619 delete aSubNodes[i];
620 aSubNodes.resize(0);
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;
630 return *this;
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 );
638 if (pFirst)
639 aSubNodes[0] = pFirst;
640 if (pSecond)
641 aSubNodes[1] = pSecond;
642 if (pThird)
643 aSubNodes[2] = pThird;
647 void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
649 aSubNodes = rNodeArray;
653 sal_Bool SmStructureNode::IsVisible() const
655 return sal_False;
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);
677 if (pNode)
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
693 return sal_True;
697 sal_uInt16 SmVisibleNode::GetNumSubNodes() const
699 return 0;
703 SmNode * SmVisibleNode::GetSubNode(sal_uInt16 /*nIndex*/)
705 return NULL;
709 ///////////////////////////////////////////////////////////////////////////
711 void SmGraphicNode::GetAccessibleText( String &rText ) const
713 rText += GetToken().aText;
716 ///////////////////////////////////////////////////////////////////////////
719 void SmExpressionNode::CreateTextFromNode(String &rText)
721 SmNode *pNode;
722 sal_uInt16 nSize = GetNumSubNodes();
723 if (nSize > 1)
724 rText.Append('{');
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) != '-')))
733 rText.Append(' ');
736 if (nSize > 1)
738 rText.EraseTrailingChars();
739 APPEND(rText,"} ");
744 ///////////////////////////////////////////////////////////////////////////
746 void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
747 // arranges all subnodes in one column
749 Point rPosition;
751 SmNode *pNode;
752 sal_uInt16 nSize = GetNumSubNodes();
754 // make distance depend on font size
755 long nDist = +(rFormat.GetDistance(DIS_VERTICAL)
756 * GetFont().GetSize().Height()) / 100L;
758 if (nSize < 1)
759 return;
761 // arrange subnodes and get maximum width of them
762 long nMaxWidth = 0,
763 nTmp;
764 sal_uInt16 i;
765 for (i = 0; i < nSize; i++)
766 if (NULL != (pNode = GetSubNode(i)))
767 { pNode->Arrange(rDev, rFormat);
768 if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
769 nMaxWidth = nTmp;
772 Point aPos;
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);
783 if (i)
784 aPos.Y() += nDist;
785 pNode->MoveTo(aPos);
786 ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG);
789 // --> 4.7.2010 #i972#
790 if (HasBaseline())
791 nFormulaBaseline = GetBaseline();
792 else
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();
804 // <--
808 SmNode * SmTableNode::GetLeftMost()
810 return this;
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);
830 Flags() |= FLG_FONT;
834 /**************************************************************************/
837 void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
838 // arranges all subnodes in one row with some extra space between
840 SmNode *pNode;
841 sal_uInt16 nSize = GetNumSubNodes();
842 sal_uInt16 i;
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());
850 if (nSize < 1)
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
857 //! 'vec {a}'.
858 SmRect::operator = (SmRect(aTmpDev, &rFormat, C2S("a"),
859 GetFont().GetBorderWidth()));
860 // make sure that the rectangle occupies (almost) no space
861 SetWidth(1);
862 SetItalicSpaces(0, 0);
863 return;
866 // make distance depend on font size
867 long nDist = (rFormat.GetDistance(DIS_HORIZONTAL) * GetFont().GetSize().Height()) / 100L;
868 if (!IsUseExtraSpaces())
869 nDist = 0;
871 Point aPos;
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
882 aPos.X() += nDist;
884 pNode->MoveTo(aPos);
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();
900 if (pNode)
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;
926 if (bIsPostfix)
927 aPos.X() += nDelta;
928 else
929 aPos.X() -= nDelta;
930 pOper->MoveTo(aPos);
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)
939 SetBottom(nOldBot);
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;
974 if (aPos.X() > nX)
975 aPos.X() = nX;
977 return aPos;
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);
995 long nHeight,
996 nVerOffset;
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);
1013 if (pExtra)
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);
1023 if (pExtra)
1024 ExtendBy(*pExtra, RCP_THIS, (sal_Bool) sal_True);
1028 void SmRootNode::CreateTextFromNode(String &rText)
1030 SmNode *pExtra = GetSubNode(0);
1031 if (pExtra)
1033 APPEND(rText,"nroot ");
1034 pExtra->CreateTextFromNode(rText);
1036 else
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);
1067 Point aPos;
1068 aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1069 aPos.X() += nDist;
1070 pOper->MoveTo(aPos);
1071 ExtendBy(*pOper, RCP_XOR);
1073 aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1074 aPos.X() += nDist;
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();
1094 if (bIsTextmode)
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;
1126 pNum->MoveTo(aPos);
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()
1154 return this;
1158 /**************************************************************************/
1161 double Det(const Point &rHeading1, const Point &rHeading2)
1162 // gibt den Wert der durch die beiden Punkte gebildeten Determinante
1163 // zurueck
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;
1179 double fLambda;
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;
1185 else
1187 fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y();
1188 bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
1191 return bRes;
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();
1212 else
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())
1218 / fDet;
1219 rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()),
1220 rPoint1.Y() + (long) (fLambda * rHeading1.Y()));
1223 return nRes;
1228 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken)
1229 : SmStructureNode(NBINDIAGONAL, rNodeToken)
1231 bAscending = sal_False;
1232 SetNumSubNodes(3);
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),
1250 aDownHdg (0, 100),
1251 aDiagHdg ( (long)(100.0 * cos(fAngleRad)),
1252 (long)(-100.0 * sin(fAngleRad)) );
1254 long nLeft, nRight, nTop, nBottom; // Raender des Rechtecks fuer die
1255 // Diagonale
1256 Point aPoint;
1257 if (IsAscending())
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();
1270 nTop = nRectTop;
1272 else
1274 // es muss einen Schnittpunkt mit dem rechten Rand geben!
1275 GetLineIntersectionPoint(aPoint,
1276 Point(nRectRight, nRectTop), aDownHdg,
1277 rDiagPoint, aDiagHdg);
1279 nRight = nRectRight;
1280 nTop = aPoint.Y();
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)
1293 nLeft = aPoint.X();
1294 nBottom = nRectBottom;
1296 else
1298 // es muss einen Schnittpunkt mit dem linken Rand geben!
1299 GetLineIntersectionPoint(aPoint,
1300 Point(nRectLeft, nRectTop), aDownHdg,
1301 rDiagPoint, aDiagHdg);
1303 nLeft = nRectLeft;
1304 nBottom = aPoint.Y();
1307 else
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)
1319 nLeft = aPoint.X();
1320 nTop = nRectTop;
1322 else
1324 // es muss einen Schnittpunkt mit dem linken Rand geben!
1325 GetLineIntersectionPoint(aPoint,
1326 Point(nRectLeft, nRectTop), aDownHdg,
1327 rDiagPoint, aDiagHdg);
1329 nLeft = nRectLeft;
1330 nTop = aPoint.Y();
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;
1346 else
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);
1359 rPos.X() = nLeft;
1360 rPos.Y() = nTop;
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
1393 Point aPos;
1394 aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace();
1395 if (IsAscending())
1396 aPos.Y() = pLeft->GetBottom() + nDelta;
1397 else
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,
1406 nTmpBaseline);
1408 SmRect::operator = (*pLeft);
1409 ExtendBy(*pRight, RCP_NONE);
1412 // Position und Groesse des Diagonalstrich ermitteln
1413 Size aTmpSize;
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);
1449 Point aPos;
1450 long nDelta, nDist;
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);
1458 if (!pSubSup)
1459 continue;
1461 // switch position of limits if we are in textmode
1462 if (rFormat.IsTextmode() && (GetToken().nGroup & TGLIMIT))
1463 switch (eSubSup)
1464 { case CSUB: eSubSup = RSUB; break;
1465 case CSUP: eSubSup = RSUP; break;
1466 default:
1467 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();
1483 nDist = 0;
1485 //! be sure that CSUB, CSUP are handled before the other cases!
1486 switch (eSubSup)
1487 { case RSUB :
1488 case LSUB :
1489 if (!bIsTextmode)
1490 nDist = nOrigHeight
1491 * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L;
1492 aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1493 eSubSup == LSUB ? RP_LEFT : RP_RIGHT,
1494 RHA_CENTER, RVA_BOTTOM);
1495 aPos.Y() += nDist;
1496 nDelta = nDelimLine - aPos.Y();
1497 if (nDelta > 0)
1498 aPos.Y() += nDelta;
1499 break;
1500 case RSUP :
1501 case LSUP :
1502 if (!bIsTextmode)
1503 nDist = nOrigHeight
1504 * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L;
1505 aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1506 eSubSup == LSUP ? RP_LEFT : RP_RIGHT,
1507 RHA_CENTER, RVA_TOP);
1508 aPos.Y() -= nDist;
1509 nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
1510 if (nDelta > 0)
1511 aPos.Y() -= nDelta;
1512 break;
1513 case CSUB :
1514 if (!bIsTextmode)
1515 nDist = nOrigHeight
1516 * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L;
1517 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM,
1518 RHA_CENTER, RVA_BASELINE);
1519 aPos.Y() += nDist;
1520 break;
1521 case CSUP :
1522 if (!bIsTextmode)
1523 nDist = nOrigHeight
1524 * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L;
1525 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP,
1526 RHA_CENTER, RVA_BASELINE);
1527 aPos.Y() -= nDist;
1528 break;
1529 default :
1530 DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
1531 break;
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)
1540 aTmpRect = *this;
1544 void SmSubSupNode::CreateTextFromNode(String &rText)
1546 SmNode *pNode;
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();
1572 rText.Append('_');
1573 pNode->CreateTextFromNode(rText);
1575 if (NULL != (pNode = GetSubNode(RSUP+1)))
1577 rText.EraseTrailingChars();
1578 rText.Append('^');
1579 pNode->CreateTextFromNode(rText);
1584 /**************************************************************************/
1586 void SmBraceNode::CreateTextFromNode(String &rText)
1588 if (GetScaleMode() == SCALE_HEIGHT)
1589 APPEND(rText,"left ");
1591 String aStr;
1592 GetSubNode(0)->CreateTextFromNode(aStr);
1593 aStr.EraseLeadingAndTrailingChars();
1594 aStr.EraseLeadingChars('\\');
1595 if (aStr.Len())
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");
1603 else
1604 rText.Append(aStr);
1605 rText.Append(' ');
1607 else
1608 APPEND(rText,"none ");
1610 GetSubNode(1)->CreateTextFromNode(rText);
1611 if (GetScaleMode() == SCALE_HEIGHT)
1612 APPEND(rText,"right ");
1614 String aStr;
1615 GetSubNode(2)->CreateTextFromNode(aStr);
1616 aStr.EraseLeadingAndTrailingChars();
1617 aStr.EraseLeadingChars('\\');
1618 if (aStr.Len())
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");
1626 else
1627 rText.Append(aStr);
1628 rText.Append(' ');
1630 else
1631 APPEND(rText,"none ");
1633 rText.Append(' ');
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
1665 long nBraceHeight;
1666 if (bScale)
1668 nBraceHeight = pBody->GetType() == NBRACEBODY ?
1669 ((SmBracebodyNode *) pBody)->GetBodyHeight()
1670 : pBody->GetHeight();
1671 nBraceHeight += 2 * (nBraceHeight * nPerc / 100L);
1673 else
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
1681 if (bScale)
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;
1711 Point aPos;
1712 aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign);
1713 aPos.X() -= nDist;
1714 pLeft->MoveTo(aPos);
1716 aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign);
1717 aPos.X() += nDist;
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)
1732 return;
1734 // arrange arguments
1735 sal_uInt16 i;
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);
1757 if (bScale)
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);
1780 aPosX.X() += nDist;
1782 pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
1783 ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR);
1785 pLeft = pRight;
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
1820 RectPos eRectPos;
1821 long nFontHeight = pBody->GetFont().GetSize().Height();
1822 long nDistBody = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
1823 nDistScript = nFontHeight;
1824 if (GetToken().eType == TOVERBRACE)
1826 eRectPos = RP_TOP;
1827 nDistBody = - nDistBody;
1828 nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
1830 else // TUNDERBRACE
1832 eRectPos = RP_BOTTOM;
1833 nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
1835 nDistBody /= 100L;
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!");
1863 return pNode;
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)
1875 return nHeight;
1877 if (!rFormat.IsTextmode())
1879 // set minimum size ()
1880 nHeight += (nHeight * 20L) / 100L;
1882 nHeight += nHeight
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;
1891 return nHeight;
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(),
1911 nDist = nOrigHeight
1912 * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L;
1914 Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID);
1915 aPos.X() -= nDist;
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;
1939 default:
1940 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;
1968 long nDist = 0;
1969 switch (GetToken().eType)
1970 { case TUNDERLINE :
1971 eVerAlign = RVA_ATTRIBUT_LO;
1972 break;
1973 case TOVERSTRIKE :
1974 eVerAlign = RVA_ATTRIBUT_MID;
1975 break;
1976 default :
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);
1983 aPos.Y() -= nDist;
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)
2000 case TBOLD:
2001 APPEND(rText,"bold ");
2002 break;
2003 case TNBOLD:
2004 APPEND(rText,"nbold ");
2005 break;
2006 case TITALIC:
2007 APPEND(rText,"italic ");
2008 break;
2009 case TNITALIC:
2010 APPEND(rText,"nitalic ");
2011 break;
2012 case TPHANTOM:
2013 APPEND(rText,"phantom ");
2014 break;
2015 case TSIZE:
2017 APPEND(rText,"size ");
2018 switch (nSizeType)
2020 case FNTSIZ_PLUS:
2021 rText.Append('+');
2022 break;
2023 case FNTSIZ_MINUS:
2024 rText.Append('-');
2025 break;
2026 case FNTSIZ_MULTIPLY:
2027 rText.Append('*');
2028 break;
2029 case FNTSIZ_DIVIDE:
2030 rText.Append('/');
2031 break;
2032 case FNTSIZ_ABSOLUT:
2033 default:
2034 break;
2036 rText += String( ::rtl::math::doubleToUString(
2037 static_cast<double>(aFontSize),
2038 rtl_math_StringFormat_Automatic,
2039 rtl_math_DecimalPlaces_Max, '.', sal_True));
2040 rText.Append(' ');
2042 break;
2043 case TBLACK:
2044 APPEND(rText,"color black ");
2045 break;
2046 case TWHITE:
2047 APPEND(rText,"color white ");
2048 break;
2049 case TRED:
2050 APPEND(rText,"color red ");
2051 break;
2052 case TGREEN:
2053 APPEND(rText,"color green ");
2054 break;
2055 case TBLUE:
2056 APPEND(rText,"color blue ");
2057 break;
2058 case TCYAN:
2059 APPEND(rText,"color cyan ");
2060 break;
2061 case TMAGENTA:
2062 APPEND(rText,"color magenta ");
2063 break;
2064 case TYELLOW:
2065 APPEND(rText,"color yellow ");
2066 break;
2067 case TSANS:
2068 APPEND(rText,"font sans ");
2069 break;
2070 case TSERIF:
2071 APPEND(rText,"font serif ");
2072 break;
2073 case TFIXED:
2074 APPEND(rText,"font fixed ");
2075 break;
2076 default:
2077 break;
2079 GetSubNode(1)->CreateTextFromNode(rText);
2083 void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2085 //! prepare subnodes first
2086 SmNode::Prepare(rFormat, rDocShell);
2088 int nFnt = -1;
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;
2094 default:
2095 break;
2097 if (nFnt != -1)
2098 { GetFont() = rFormat.GetFont( sal::static_int_cast< sal_uInt16 >(nFnt) );
2099 SetFont(GetFont());
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)
2114 { case TSIZE :
2115 pNode->SetFontSize(aFontSize, nSizeType);
2116 break;
2117 case TSANS :
2118 case TSERIF :
2119 case TFIXED :
2120 pNode->SetFont(GetFont());
2121 break;
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;
2139 default:
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)
2151 nSizeType = Type;
2152 aFontSize = rValue;
2156 /**************************************************************************/
2159 SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
2160 : SmGraphicNode(NPOLYLINE, rNodeToken)
2162 aPoly.SetSize(2);
2163 nWidth = 0;
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;
2202 else
2204 DBG_ASSERT(GetToken().eType == TWIDEBACKSLASH, "Sm : unerwartetes Token");
2205 aPointA.X() =
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
2223 if (IsPhantom())
2224 return;
2226 long nBorderwidth = GetFont().GetBorderWidth();
2228 LineInfo aInfo;
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
2242 if (!IsDebug())
2243 return;
2245 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2246 SmRect::Draw(rDev, rPosition, nRFlags);
2247 #endif
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
2269 if (IsPhantom())
2270 return;
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
2301 if (!IsDebug())
2302 return;
2304 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2305 SmRect::Draw(rDev, rPosition, nRFlags);
2306 #endif
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();
2331 if (nHeight == 0)
2332 nHeight = nFontHeight / 30;
2333 if (nWidth == 0)
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
2352 if (IsPhantom())
2353 return;
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())));
2377 aTmp.SetPos(aPos);
2379 rDev.DrawRect(aTmp);
2381 #ifdef SM_RECT_DEBUG
2382 if (!IsDebug())
2383 return;
2385 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2386 SmRect::Draw(rDev, rPosition, nRFlags);
2387 #endif
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)
2453 rText.Append('\"');
2454 bQuoted=sal_True;
2456 else
2458 SmParser aParseTest;
2459 SmNode *pTable = aParseTest.Parse(GetToken().aText);
2460 bQuoted=sal_True;
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)
2473 bQuoted=sal_False;
2477 delete pTable;
2479 if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
2481 //Search for existing functions and remove extraenous keyword
2482 APPEND(rText,"func ");
2484 else if (bQuoted)
2485 APPEND(rText,"italic ");
2487 if (bQuoted)
2488 rText.Append('\"');
2492 rText.Append(GetToken().aText);
2494 if (bQuoted)
2495 rText.Append('\"');
2496 rText.Append(' ');
2499 void SmTextNode::Draw(OutputDevice &rDev, const Point& rPosition) const
2501 if (IsPhantom() || aText.Len() == 0 || aText.GetChar(0) == xub_Unicode('\0'))
2502 return;
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
2513 sal_Int32 nPos = 0;
2514 sal_UCS4 cChar = OUString( aText ).iterateCodePoints( &nPos );
2515 (void) cChar;
2516 #endif
2518 rDev.DrawStretchText(aPos, GetWidth(), aText);
2520 #ifdef SM_RECT_DEBUG
2521 if (!IsDebug())
2522 return;
2524 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2525 SmRect::Draw(rDev, rPosition, nRFlags);
2526 #endif
2529 void SmTextNode::GetAccessibleText( String &rText ) const
2531 rText += aText;
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)
2546 APPEND(rText,"# ");
2548 if (i != nNumRows-1)
2549 APPEND(rText,"## ");
2551 rText.EraseTrailingChars();
2552 APPEND(rText,"} ");
2556 void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2558 Point aPosition,
2559 aOffset;
2560 SmNode *pNode;
2561 sal_uInt16 i, j;
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++)
2567 pColWidth[j] = 0;
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
2586 // the elements
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];
2592 long nX = 0;
2593 for (j = 0; j < nNumCols; j++)
2594 { pColLeft[j] = nX;
2595 nX += pColWidth[j] + nHorDist;
2598 Point aPos, aDelta;
2599 SmRect aLineRect;
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
2619 switch (eHorAlign)
2620 { case RHA_LEFT:
2621 aPos.X() = rNodeRect.GetLeft() + pColLeft[j];
2622 break;
2623 case RHA_CENTER:
2624 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2625 + pColWidth[j] / 2
2626 - rNodeRect.GetItalicCenterX();
2627 break;
2628 case RHA_RIGHT:
2629 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2630 + pColWidth[j] - rNodeRect.GetItalicWidth();
2631 break;
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);
2652 delete [] pColLeft;
2653 delete [] pColWidth;
2657 void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
2659 nNumRows = nMatrixRows;
2660 nNumCols = nMatrixCols;
2664 SmNode * SmMatrixNode::GetLeftMost()
2666 return this;
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)
2678 SetText( 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();
2717 rDevNC.Pop();
2719 DBG_ASSERT(aFntSize.Width() != 0, "Sm: ");
2721 //! however the result is a bit better with 'nHeight' as initial
2722 //! font height
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());
2763 return;
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)
2778 String sStr;
2779 MathType::LookupChar(GetToken().cMathChar, sStr);
2780 rText.Append(sStr);
2783 void SmRectangleNode::CreateTextFromNode(String &rText)
2785 switch (GetToken().eType)
2787 case TUNDERLINE:
2788 APPEND(rText,"underline ");
2789 break;
2790 case TOVERLINE:
2791 APPEND(rText,"overline ");
2792 break;
2793 case TOVERSTRIKE:
2794 APPEND(rText,"overstrike ");
2795 break;
2796 default:
2797 break;
2801 void SmAttributNode::CreateTextFromNode(String &rText)
2803 SmNode *pNode;
2804 sal_uInt16 nSize = GetNumSubNodes();
2805 DBG_ASSERT(nSize == 2, "Node missing members");
2806 rText.Append('{');
2807 sal_Unicode nLast=0;
2808 if (NULL != (pNode = GetSubNode(0)))
2810 String aStr;
2811 pNode->CreateTextFromNode(aStr);
2812 if (aStr.Len() > 1)
2813 rText.Append(aStr);
2814 else
2816 nLast = aStr.GetChar(0);
2817 switch (nLast)
2819 case 0xAF:
2820 APPEND(rText,"overline ");
2821 break;
2822 case 0x2d9:
2823 APPEND(rText,"dot ");
2824 break;
2825 case 0x2dc:
2826 APPEND(rText,"widetilde ");
2827 break;
2828 case 0xA8:
2829 APPEND(rText,"ddot ");
2830 break;
2831 case 0xE082:
2832 break;
2833 case 0xE09B:
2834 APPEND(rText,"dddot ");
2835 break;
2836 default:
2837 rText.Append(nLast);
2838 break;
2843 if (nSize == 2)
2844 if (NULL != (pNode = GetSubNode(1)))
2845 pNode->CreateTextFromNode(rText);
2847 rText.EraseTrailingChars();
2849 if (nLast == 0xE082)
2850 APPEND(rText," overbrace {}");
2852 APPEND(rText,"} ");
2855 /**************************************************************************/
2857 bool lcl_IsFromGreekSymbolSet( const String &rTokenText )
2859 bool bRes = false;
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" ) )
2867 bRes = true;
2870 return bRes;
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);
2892 const SmSym *pSym;
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 ) );
2900 SetText( aTmp );
2901 GetFont() = pSym->GetFace();
2903 else
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" );
2931 if (nStyle == 1)
2932 bItalic = true;
2933 else if (nStyle == 2)
2935 String aTmp( GetText() );
2936 if (aTmp.Len() > 0)
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);
2946 if (bItalic)
2947 Attributes() |= ATTR_ITALIC;
2948 else
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;
3047 default:
3048 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);
3082 SetWidth(nSpace);