/Users/ericb/Desktop/SRC680_m247/starmath/source/node.cxx

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  OpenOffice.org - a multi-platform office productivity suite
00004  *
00005  *  $RCSfile: node.cxx,v $
00006  *
00007  *  $Revision: 1.40 $
00008  *
00009  *  last change: $Author: vg $ $Date: 2007/05/25 12:14:09 $
00010  *
00011  *  The Contents of this file are made available subject to
00012  *  the terms of GNU Lesser General Public License Version 2.1.
00013  *
00014  *
00015  *    GNU Lesser General Public License Version 2.1
00016  *    =============================================
00017  *    Copyright 2005 by Sun Microsystems, Inc.
00018  *    901 San Antonio Road, Palo Alto, CA 94303, USA
00019  *
00020  *    This library is free software; you can redistribute it and/or
00021  *    modify it under the terms of the GNU Lesser General Public
00022  *    License version 2.1, as published by the Free Software Foundation.
00023  *
00024  *    This library is distributed in the hope that it will be useful,
00025  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00026  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027  *    Lesser General Public License for more details.
00028  *
00029  *    You should have received a copy of the GNU Lesser General Public
00030  *    License along with this library; if not, write to the Free Software
00031  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00032  *    MA  02111-1307  USA
00033  *
00034  ************************************************************************/
00035 
00036 // MARKER(update_precomp.py): autogen include statement, do not remove
00037 #include "precompiled_starmath.hxx"
00038 
00039 #define APPEND(str,ascii) str.AppendAscii(RTL_CONSTASCII_STRINGPARAM(ascii))
00040 
00041 #ifndef _SV_GEN_HXX //autogen
00042 #include <tools/gen.hxx>
00043 #endif
00044 #ifndef _FRACT_HXX //autogen
00045 #include <tools/fract.hxx>
00046 #endif
00047 #ifndef INCLUDED_RTL_MATH_HXX
00048 #include <rtl/math.hxx>
00049 #endif
00050 #ifndef _TOOLS_COLOR_HXX
00051 #include <tools/color.hxx>
00052 #endif
00053 #ifndef _SV_METRIC_HXX //autogen
00054 #include <vcl/metric.hxx>
00055 #endif
00056 #ifndef _SV_LINEINFO_HXX
00057 #include <vcl/lineinfo.hxx>
00058 #endif
00059 #ifndef _SV_OUTDEV_HXX //autogen
00060 #include <vcl/outdev.hxx>
00061 #endif
00062 #ifndef _SFXMODULE_HXX //autogen
00063 #include <sfx2/module.hxx>
00064 #endif
00065 
00066 
00067 #ifndef NODE_HXX
00068 #include "node.hxx"
00069 #endif
00070 #ifndef RECT_HXX
00071 #include <rect.hxx>
00072 #endif
00073 #ifndef SYMBOL_HXX
00074 #include "symbol.hxx"
00075 #endif
00076 #ifndef _SMMOD_HXX
00077 #include "smmod.hxx"
00078 #endif
00079 #ifndef DOCUMENT_HXX
00080 #include <document.hxx>
00081 #endif
00082 #ifndef VIEW_HXX
00083 #include <view.hxx>
00084 #endif
00085 #ifndef _MATHTYPE_HXX
00086 #include "mathtype.hxx"
00087 #endif
00088 
00089 #include <math.h>
00090 #include <float.h>
00091 
00092 // define this to draw rectangles for debugging
00093 //#define SM_RECT_DEBUG
00094 
00096 // SmTmpDevice
00097 // Allows for font and color changes. The original settings will be restored
00098 // in the destructor.
00099 // It's main purpose is to allow for the "const" in the 'OutputDevice'
00100 // argument in the 'Arrange' functions and restore changes made in the 'Draw'
00101 // functions.
00102 // Usually a MapMode of 1/100th mm will be used.
00103 //
00104 
00105 class SmTmpDevice
00106 {
00107         OutputDevice  &rOutDev;
00108 
00109         // disallow use of copy-constructor and assignment-operator
00110         SmTmpDevice(const SmTmpDevice &rTmpDev);
00111         SmTmpDevice & operator = (const SmTmpDevice &rTmpDev);
00112 
00113     Color   Impl_GetColor( const Color& rColor );
00114 
00115 public:
00116     SmTmpDevice(OutputDevice &rTheDev, BOOL bUseMap100th_mm);
00117     ~SmTmpDevice()  { rOutDev.Pop(); }
00118 
00119     void SetFont(const Font &rNewFont);
00120 
00121     void SetLineColor( const Color& rColor )    { rOutDev.SetLineColor( Impl_GetColor(rColor) ); }
00122     void SetFillColor( const Color& rColor )    { rOutDev.SetFillColor( Impl_GetColor(rColor) ); }
00123     void SetTextColor( const Color& rColor )    { rOutDev.SetTextColor( Impl_GetColor(rColor) ); }
00124 
00125     operator OutputDevice & () { return rOutDev; }
00126 };
00127 
00128 
00129 SmTmpDevice::SmTmpDevice(OutputDevice &rTheDev, BOOL bUseMap100th_mm) :
00130         rOutDev(rTheDev)
00131 {
00132     rOutDev.Push( PUSH_FONT | PUSH_MAPMODE |
00133                   PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
00134     if (bUseMap100th_mm  &&  MAP_100TH_MM != rOutDev.GetMapMode().GetMapUnit())
00135     {
00136         DBG_ERROR( "incorrect MapMode?" );
00137         rOutDev.SetMapMode( MAP_100TH_MM );     //Immer fuer 100% fomatieren
00138     }
00139 }
00140 
00141 
00142 Color SmTmpDevice::Impl_GetColor( const Color& rColor )
00143 {
00144     ColorData nNewCol = rColor.GetColor();
00145     if (COL_AUTO == nNewCol)
00146     {
00147         if (OUTDEV_PRINTER == rOutDev.GetOutDevType())
00148             nNewCol = COL_BLACK;
00149         else
00150         {
00151             Color aBgCol( rOutDev.GetBackground().GetColor() );
00152             if (OUTDEV_WINDOW == rOutDev.GetOutDevType())
00153                 aBgCol = ((Window &) rOutDev).GetDisplayBackground().GetColor();
00154 
00155             nNewCol = SM_MOD1()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
00156 
00157             Color aTmpColor( nNewCol );
00158             if (aBgCol.IsDark() && aTmpColor.IsDark())
00159                 nNewCol = COL_WHITE;
00160             else if (aBgCol.IsBright() && aTmpColor.IsBright())
00161                 nNewCol = COL_BLACK;
00162         }
00163     }
00164     return Color( nNewCol );
00165 }
00166 
00167 
00168 void SmTmpDevice::SetFont(const Font &rNewFont)
00169 {
00170     rOutDev.SetFont( rNewFont );
00171     rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor() ) );
00172 }
00173 
00174 
00176 
00177 
00178 SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken)
00179 {
00180         eType      = eNodeType;
00181         eScaleMode = SCALE_NONE;
00182         aNodeToken = rNodeToken;
00183     nAccIndex  = -1;
00184 }
00185 
00186 
00187 SmNode::~SmNode()
00188 {
00189 }
00190 
00191 
00192 BOOL SmNode::IsVisible() const
00193 {
00194     return FALSE;
00195 }
00196 
00197 
00198 USHORT SmNode::GetNumSubNodes() const
00199 {
00200         return 0;
00201 }
00202 
00203 
00204 SmNode * SmNode::GetSubNode(USHORT /*nIndex*/)
00205 {
00206         return NULL;
00207 }
00208 
00209 
00210 SmNode * SmNode::GetLeftMost()
00211         //      returns leftmost node of current subtree.
00214 {
00215         SmNode *pNode = GetNumSubNodes() > 0 ?
00216                                                 GetSubNode(0) : NULL;
00217 
00218         return pNode ? pNode->GetLeftMost() : this;
00219 }
00220 
00221 
00222 void SmNode::SetPhantom(BOOL bIsPhantomP)
00223 {
00224         if (! (Flags() & FLG_VISIBLE))
00225                 bIsPhantom = bIsPhantomP;
00226 
00227         SmNode *pNode;
00228         USHORT  nSize = GetNumSubNodes();
00229         for (USHORT i = 0; i < nSize; i++)
00230         if (NULL != (pNode = GetSubNode(i)))
00231                         pNode->SetPhantom(bIsPhantom);
00232 }
00233 
00234 
00235 void SmNode::SetColor(const Color& rColor)
00236 {
00237         if (! (Flags() & FLG_COLOR))
00238                 GetFont().SetColor(rColor);
00239 
00240         SmNode *pNode;
00241         USHORT  nSize = GetNumSubNodes();
00242         for (USHORT i = 0; i < nSize; i++)
00243         if (NULL != (pNode = GetSubNode(i)))
00244                         pNode->SetColor(rColor);
00245 }
00246 
00247 
00248 void SmNode::SetAttribut(USHORT nAttrib)
00249 {
00250         if (   nAttrib == ATTR_BOLD      &&  !(Flags() & FLG_BOLD)
00251                 || nAttrib == ATTR_ITALIC  &&  !(Flags() & FLG_ITALIC))
00252                 nAttributes |= nAttrib;
00253 
00254         SmNode *pNode;
00255         USHORT nSize = GetNumSubNodes();
00256         for (USHORT i = 0; i < nSize; i++)
00257         if (NULL != (pNode = GetSubNode(i)))
00258                         pNode->SetAttribut(nAttrib);
00259 }
00260 
00261 
00262 void SmNode::ClearAttribut(USHORT nAttrib)
00263 {
00264         if (   nAttrib == ATTR_BOLD      &&  !(Flags() & FLG_BOLD)
00265                 || nAttrib == ATTR_ITALIC  &&  !(Flags() & FLG_ITALIC))
00266                 nAttributes &= ~nAttrib;
00267 
00268         SmNode *pNode;
00269         USHORT nSize = GetNumSubNodes();
00270         for (USHORT i = 0; i < nSize; i++)
00271         if (NULL != (pNode = GetSubNode(i)))
00272                         pNode->ClearAttribut(nAttrib);
00273 }
00274 
00275 
00276 void SmNode::SetFont(const SmFace &rFace)
00277 {
00278         if (!(Flags() & FLG_FONT))
00279                 GetFont() = rFace;
00280 
00281         SmNode *pNode;
00282         USHORT  nSize = GetNumSubNodes();
00283         for (USHORT i = 0; i < nSize; i++)
00284         if (NULL != (pNode = GetSubNode(i)))
00285                         pNode->SetFont(rFace);
00286 }
00287 
00288 
00289 void SmNode::SetFontSize(const Fraction &rSize, USHORT nType)
00291 {
00292     Size  aFntSize;
00293 
00294         if (!(Flags() & FLG_SIZE))
00295         {
00296                 Fraction  aVal (SmPtsTo100th_mm(rSize.GetNumerator()),
00297                                                 rSize.GetDenominator());
00298                 //long    nHeight = ::rtl::math::round(aVal);
00299                 long      nHeight = (long)aVal;
00300 
00301         aFntSize = GetFont().GetSize();
00302         aFntSize.Width() = 0;
00303                 switch(nType)
00304                 {
00305                         case FNTSIZ_ABSOLUT:
00306                 aFntSize.Height() = nHeight;
00307                                 break;
00308 
00309                         case FNTSIZ_PLUS:
00310                 aFntSize.Height() += nHeight;
00311                                 break;
00312 
00313                         case FNTSIZ_MINUS:
00314                 aFntSize.Height() -= nHeight;
00315                                 break;
00316 
00317                         case FNTSIZ_MULTIPLY:
00318                 aFntSize.Height()   = (long) (Fraction(aFntSize.Height()) * rSize);
00319                                 break;
00320 
00321                         case FNTSIZ_DIVIDE:
00322                                 if (rSize != Fraction(0L))
00323                     aFntSize.Height()   = (long) (Fraction(aFntSize.Height()) / rSize);
00324                                 break;
00325             default:
00326                 break;
00327                 }
00328 
00329                 // check the requested size against maximum value
00330                 static int __READONLY_DATA      nMaxVal = SmPtsTo100th_mm(128);
00331         if (aFntSize.Height() > nMaxVal)
00332             aFntSize.Height() = nMaxVal;
00333 
00334         GetFont().SetSize(aFntSize);
00335         }
00336 
00337         SmNode *pNode;
00338         USHORT  nSize = GetNumSubNodes();
00339         for (USHORT i = 0;      i < nSize;      i++)
00340         if (NULL != (pNode = GetSubNode(i)))
00341                         pNode->SetFontSize(rSize, nType);
00342 }
00343 
00344 
00345 void SmNode::SetSize(const Fraction &rSize)
00346 {
00347         GetFont() *= rSize;
00348 
00349         SmNode *pNode;
00350         USHORT  nSize = GetNumSubNodes();
00351         for (USHORT i = 0;      i < nSize;      i++)
00352         if (NULL != (pNode = GetSubNode(i)))
00353                         pNode->SetSize(rSize);
00354 }
00355 
00356 
00357 void SmNode::SetRectHorAlign(RectHorAlign eHorAlign, BOOL bApplyToSubTree )
00358 {
00359         if (!(Flags() & FLG_HORALIGN))
00360                 eRectHorAlign = eHorAlign;
00361 
00362     if (bApplyToSubTree)
00363     {
00364         SmNode *pNode;
00365         USHORT  nSize = GetNumSubNodes();
00366         for (USHORT i = 0; i < nSize; i++)
00367             if (NULL != (pNode = GetSubNode(i)))
00368                 pNode->SetRectHorAlign(eHorAlign);
00369     }
00370 }
00371 
00372 
00373 void SmNode::PrepareAttributes()
00374 {
00375         GetFont().SetWeight((Attributes() & ATTR_BOLD)   ? WEIGHT_BOLD   : WEIGHT_NORMAL);
00376         GetFont().SetItalic((Attributes() & ATTR_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE);
00377 }
00378 
00379 
00380 void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
00381 {
00382 #if OSL_DEBUG_LEVEL > 1
00383         bIsDebug        = TRUE;
00384 #else
00385         bIsDebug        = FALSE;
00386 #endif
00387         bIsPhantom      = FALSE;
00388         nFlags          = 0;
00389         nAttributes = 0;
00390 
00391         switch (rFormat.GetHorAlign())
00392         {       case AlignLeft:         eRectHorAlign = RHA_LEFT;       break;
00393                 case AlignCenter:       eRectHorAlign = RHA_CENTER;     break;
00394                 case AlignRight:        eRectHorAlign = RHA_RIGHT;      break;
00395         }
00396 
00397         GetFont() = rFormat.GetFont(FNT_MATH);
00398     //GetFont().SetCharSet(RTL_TEXTENCODING_SYMBOL);
00399     DBG_ASSERT( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
00400             "unexpected CharSet" );
00401         GetFont().SetWeight(WEIGHT_NORMAL);
00402         GetFont().SetItalic(ITALIC_NONE);
00403 
00404         SmNode *pNode;
00405         USHORT          nSize = GetNumSubNodes();
00406         for (USHORT i = 0; i < nSize; i++)
00407         if (NULL != (pNode = GetSubNode(i)))
00408                         pNode->Prepare(rFormat, rDocShell);
00409 }
00410 
00411 
00412 #if OSL_DEBUG_LEVEL > 1
00413 void  SmNode::ToggleDebug() const
00414         // toggle 'bIsDebug' in current subtree
00415 {
00416         SmNode *pThis = (SmNode *) this;
00417 
00418         pThis->bIsDebug = bIsDebug ? FALSE : TRUE;
00419 
00420         SmNode *pNode;
00421         USHORT          nSize = GetNumSubNodes();
00422         for (USHORT i = 0; i < nSize; i++)
00423         if (NULL != (pNode = pThis->GetSubNode(i)))
00424                         pNode->ToggleDebug();
00425 }
00426 #endif
00427 
00428 
00429 void SmNode::Move(const Point& rPosition)
00430 {
00431         if (rPosition.X() == 0  &&      rPosition.Y() == 0)
00432                 return;
00433 
00434         SmRect::Move(rPosition);
00435 
00436         SmNode *pNode;
00437         USHORT  nSize = GetNumSubNodes();
00438         for (USHORT i = 0;      i < nSize;      i++)
00439         if (NULL != (pNode = GetSubNode(i)))
00440                         pNode->Move(rPosition);
00441 }
00442 
00443 
00444 void SmNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
00445 {
00446         SmNode *pNode;
00447         USHORT  nSize = GetNumSubNodes();
00448         for (USHORT i = 0;      i < nSize;      i++)
00449         if (NULL != (pNode = GetSubNode(i)))
00450                         pNode->Arrange(rDev, rFormat);
00451 }
00452 
00453 void SmNode::CreateTextFromNode(String &rText)
00454 {
00455         SmNode *pNode;
00456         USHORT  nSize = GetNumSubNodes();
00457         if (nSize > 1)
00458                 rText.Append('{');
00459         for (USHORT i = 0;      i < nSize;      i++)
00460         if (NULL != (pNode = GetSubNode(i)))
00461                         pNode->CreateTextFromNode(rText);
00462         if (nSize > 1)
00463         {
00464                 rText.EraseTrailingChars();
00465                 APPEND(rText,"} ");
00466         }
00467 }
00468 
00469 
00470 void SmNode::AdaptToX(const OutputDevice &/*rDev*/, ULONG /*nWidth*/)
00471 {
00472 }
00473 
00474 
00475 void SmNode::AdaptToY(const OutputDevice &/*rDev*/, ULONG /*nHeight*/)
00476 {
00477 }
00478 
00479 
00480 void SmNode::Draw(OutputDevice &rDev, const Point &rPosition) const
00481 {
00482         if (IsPhantom())
00483                 return;
00484 
00485         const SmNode *pNode;
00486         USHORT  nSize = GetNumSubNodes();
00487         for (USHORT i = 0; i < nSize; i++)
00488         if (NULL != (pNode = GetSubNode(i)))
00489                 {       Point  aOffset (pNode->GetTopLeft() - GetTopLeft());
00490                         pNode->Draw(rDev, rPosition + aOffset);
00491                 }
00492 
00493 #ifdef SM_RECT_DEBUG
00494         if (!IsDebug())
00495                 return;
00496 
00497         int  nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
00498         SmRect::Draw(rDev, rPosition, nRFlags);
00499 #endif
00500 }
00501 
00502 const SmNode * SmNode::FindTokenAt(USHORT nRow, USHORT nCol) const
00503         // returns (first) ** visible ** (sub)node with the tokens text at
00504         // position 'nRow', 'nCol'.
00506 {
00507         if (    IsVisible()
00508                 &&      nRow == GetToken().nRow
00509                 &&      nCol >= GetToken().nCol  &&  nCol < GetToken().nCol + GetToken().aText.Len())
00510                 return this;
00511         else
00512         {
00513                 USHORT  nNumSubNodes = GetNumSubNodes();
00514                 for (USHORT  i = 0;  i < nNumSubNodes;  i++)
00515                 {       const SmNode *pNode = GetSubNode(i);
00516 
00517                         if (!pNode)
00518                                 continue;
00519 
00520                         const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
00521                         if (pResult)
00522                                 return pResult;
00523                 }
00524         }
00525 
00526         return 0;
00527 }
00528 
00529 
00530 const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
00531 {
00532         long              nDist   = LONG_MAX;
00533         const SmNode *pResult = 0;
00534 
00535         if (IsVisible())
00536                 pResult = this;
00537         else
00538         {
00539                 USHORT  nNumSubNodes = GetNumSubNodes();
00540                 for (USHORT  i = 0;  i < nNumSubNodes;  i++)
00541                 {       const SmNode *pNode = GetSubNode(i);
00542 
00543                         if (!pNode)
00544                                 continue;
00545 
00546                         long  nTmp;
00547                         const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
00548                         if (pFound  &&  (nTmp = pFound->OrientedDist(rPoint)) < nDist)
00549                         {       nDist   = nTmp;
00550                                 pResult = pFound;
00551 
00552                                 // quit immediately if 'rPoint' is inside the *should not
00553                                 // overlap with other rectangles* part.
00554                                 // This (partly) serves for getting the attributes in eg
00555                                 // "bar overstrike a".
00556                                 // ('nDist < 0' is used as *quick shot* to avoid evaluation of
00557                                 // the following expression, where the result is already determined)
00558                                 if (nDist < 0  &&  pFound->IsInsideRect(rPoint))
00559                                         break;
00560                         }
00561                 }
00562         }
00563 
00564         return pResult;
00565 }
00566 
00567 void SmNode::GetAccessibleText( String &/*rText*/ ) const
00568 {
00569     DBG_ERROR( "SmNode: GetAccessibleText not overloaded" );
00570 }
00571 
00572 const SmNode * SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx) const
00573 {
00574         const SmNode *pResult = 0;
00575 
00576     sal_Int32 nIdx = GetAccessibleIndex();
00577     String aTxt;
00578     if (nIdx >= 0)
00579         GetAccessibleText( aTxt );  // get text if used in following 'if' statement
00580 
00581     if (nIdx >= 0
00582         &&  nIdx <= nAccIdx  &&  nAccIdx < nIdx + aTxt.Len())
00583                 pResult = this;
00584         else
00585         {
00586                 USHORT  nNumSubNodes = GetNumSubNodes();
00587                 for (USHORT  i = 0;  i < nNumSubNodes;  i++)
00588         {
00589             const SmNode *pNode = GetSubNode(i);
00590                         if (!pNode)
00591                                 continue;
00592 
00593             pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
00594             if (pResult)
00595                 return pResult;
00596                 }
00597         }
00598 
00599         return pResult;
00600 }
00601 
00603 
00604 SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
00605     SmNode( rNode.GetType(), rNode.GetToken() )
00606 {
00607     ULONG i;
00608     for (i = 0;  i < aSubNodes.GetSize();  i++)
00609         delete aSubNodes.Get(i);
00610     aSubNodes.Clear();
00611 
00612     ULONG nSize = rNode.aSubNodes.GetSize();
00613     aSubNodes.SetSize( nSize );
00614     for (i = 0;  i < nSize;  ++i)
00615     {
00616         SmNode *pNode = rNode.aSubNodes.Get(i);
00617         aSubNodes.Put( i, pNode ? new SmNode( *pNode ) : 0 );
00618     }
00619 }
00620 
00621 
00622 SmStructureNode::~SmStructureNode()
00623 {
00624         SmNode *pNode;
00625 
00626         for (USHORT i = 0;      i < GetNumSubNodes();  i++)
00627         if (NULL != (pNode = GetSubNode(i)))
00628                         delete pNode;
00629 }
00630 
00631 
00632 SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
00633 {
00634     SmNode::operator = ( rNode );
00635 
00636     ULONG i;
00637     for (i = 0;  i < aSubNodes.GetSize();  i++)
00638         delete aSubNodes.Get(i);
00639     aSubNodes.Clear();
00640 
00641     ULONG nSize = rNode.aSubNodes.GetSize();
00642     aSubNodes.SetSize( nSize );
00643     for (i = 0;  i < nSize;  ++i)
00644     {
00645         SmNode *pNode = rNode.aSubNodes.Get(i);
00646         aSubNodes.Put( i, pNode ? new SmNode( *pNode ) : 0 );
00647     }
00648 
00649     return *this;
00650 }
00651 
00652 
00653 void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThird)
00654 {
00655         if (pFirst)
00656                 aSubNodes.Put(0, pFirst);
00657         if (pSecond)
00658                 aSubNodes.Put(1, pSecond);
00659         if (pThird)
00660                 aSubNodes.Put(2, pThird);
00661 }
00662 
00663 
00664 void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
00665 {
00666         aSubNodes = rNodeArray;
00667 }
00668 
00669 
00670 BOOL SmStructureNode::IsVisible() const
00671 {
00672         return FALSE;
00673 }
00674 
00675 
00676 USHORT SmStructureNode::GetNumSubNodes() const
00677 {
00678         return (USHORT) aSubNodes.GetSize();
00679 }
00680 
00681 
00682 SmNode * SmStructureNode::GetSubNode(USHORT nIndex)
00683 {
00684         return aSubNodes.Get(nIndex);
00685 }
00686 
00687 
00688 void SmStructureNode::GetAccessibleText( String &rText ) const
00689 {
00690     USHORT nNodes = GetNumSubNodes();
00691     for (USHORT i = 0;  i < nNodes;  ++i)
00692     {
00693         const SmNode *pNode = ((SmStructureNode *) this)->GetSubNode(i);
00694         if (pNode)
00695         {
00696             if (pNode->IsVisible())
00697                 ((SmStructureNode *) pNode)->nAccIndex = rText.Len();
00698             pNode->GetAccessibleText( rText );
00699 //            if (rText.Len()  &&  ' ' != rText.GetChar( rText.Len() - 1 ))
00700 //                rText += String::CreateFromAscii( " " );
00701         }
00702     }
00703 }
00704 
00706 
00707 
00708 BOOL SmVisibleNode::IsVisible() const
00709 {
00710         return TRUE;
00711 }
00712 
00713 
00714 USHORT SmVisibleNode::GetNumSubNodes() const
00715 {
00716         return 0;
00717 }
00718 
00719 
00720 SmNode * SmVisibleNode::GetSubNode(USHORT /*nIndex*/)
00721 {
00722         return NULL;
00723 }
00724 
00725 
00727 
00728 void SmGraphicNode::GetAccessibleText( String &rText ) const
00729 {
00730     rText += GetToken().aText;
00731 }
00732 
00734 
00735 
00736 void SmExpressionNode::CreateTextFromNode(String &rText)
00737 {
00738         SmNode *pNode;
00739         USHORT  nSize = GetNumSubNodes();
00740         if (nSize > 1)
00741                 rText.Append('{');
00742         for (USHORT i = 0;      i < nSize;      i++)
00743         if (NULL != (pNode = GetSubNode(i)))
00744                 {
00745                         pNode->CreateTextFromNode(rText);
00746                         //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
00747                         if (pNode->GetType() == NMATH)
00748                                 if ((nSize != 2) || ((rText.GetChar(rText.Len()-1) != '+') &&
00749                                         (rText.GetChar(rText.Len()-1) != '-')))
00750                                         rText.Append(' ');
00751                 }
00752 
00753         if (nSize > 1)
00754         {
00755                 rText.EraseTrailingChars();
00756                 APPEND(rText,"} ");
00757         }
00758 }
00759 
00760 
00762 
00763 void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
00764         // arranges all subnodes in one column
00765 {
00766         Point rPosition;
00767 
00768         SmNode *pNode;
00769         USHORT  nSize   = GetNumSubNodes();
00770 
00771         // make distance depend on font size
00772         long  nDist = +(rFormat.GetDistance(DIS_VERTICAL)
00773                                         * GetFont().GetSize().Height()) / 100L;
00774 
00775         if (nSize < 1)
00776                 return;
00777 
00778         // arrange subnodes and get maximum width of them
00779         long  nMaxWidth = 0,
00780                   nTmp;
00781     USHORT i;
00782         for (i = 0;     i < nSize;      i++)
00783         if (NULL != (pNode = GetSubNode(i)))
00784                 {       pNode->Arrange(rDev, rFormat);
00785                         if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
00786                                 nMaxWidth = nTmp;
00787                 }
00788 
00789         Point  aPos;
00790         SmRect::operator = (SmRect(nMaxWidth, 0));
00791         for (i = 0;  i < nSize;  i++)
00792     {   if (NULL != (pNode = GetSubNode(i)))
00793                 {       const SmRect &rNodeRect = pNode->GetRect();
00794                         const SmNode *pCoNode   = pNode->GetLeftMost();
00795             //SmTokenType   eType    = pCoNode->GetToken().eType;
00796             RectHorAlign  eHorAlign = pCoNode->GetRectHorAlign();
00797 
00798                         aPos = rNodeRect.AlignTo(*this, RP_BOTTOM,
00799                                                 eHorAlign, RVA_BASELINE);
00800                         if (i)
00801                                 aPos.Y() += nDist;
00802                         pNode->MoveTo(aPos);
00803                         ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG);
00804                 }
00805         }
00806 }
00807 
00808 
00809 SmNode * SmTableNode::GetLeftMost()
00810 {
00811         return this;
00812 }
00813 
00814 
00815 /**************************************************************************/
00816 
00817 
00818 void SmLineNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
00819 {
00820         SmNode::Prepare(rFormat, rDocShell);
00821 
00824         GetFont() = rFormat.GetFont(FNT_VARIABLE);
00825         Flags() |= FLG_FONT;
00826 }
00827 
00828 
00829 /**************************************************************************/
00830 
00831 
00832 void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
00833         // arranges all subnodes in one row with some extra space between
00834 {
00835         SmNode *pNode;
00836         USHORT  nSize = GetNumSubNodes();
00837         USHORT i;
00838         for (i = 0;     i < nSize;      i++)
00839         if (NULL != (pNode = GetSubNode(i)))
00840                         pNode->Arrange(rDev, rFormat);
00841 
00842     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
00843         aTmpDev.SetFont(GetFont());
00844 
00845         // provide an empty rectangle with alignment parameters for the "current"
00846         // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
00847         // same sub-/supscript positions.)
00851         SmRect::operator = (SmRect(aTmpDev, &rFormat, C2S("a"),
00852                                                            GetFont().GetBorderWidth()));
00853         // make sure that the rectangle occupies (almost) no space
00854         SetWidth(1);
00855         SetItalicSpaces(0, 0);
00856 
00857         if (nSize < 1)
00858                 return;
00859 
00860         // make distance depend on font size
00861         long  nDist = +(rFormat.GetDistance(DIS_HORIZONTAL)
00862                                         * GetFont().GetSize().Height()) / 100L;
00863 
00864         Point   aPos;
00865         for (i = 0;  i < nSize;  i++)
00866         if (NULL != (pNode = GetSubNode(i)))
00867                 {
00868                         aPos = pNode->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
00869 
00870                         // no horizontal space before first node
00871                         if (i)
00872                                 aPos.X() += nDist;
00873 
00874                         pNode->MoveTo(aPos);
00875             ExtendBy( *pNode, RCP_XOR );
00876                 }
00877 }
00878 
00879 
00880 /**************************************************************************/
00881 
00882 
00883 void SmExpressionNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
00884         // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
00885 {
00886         DBG_ASSERT(GetNumSubNodes() > 0, "Sm: keine subnodes");
00887 
00888         SmLineNode::Arrange(rDev, rFormat);
00889 
00890         //      copy alignment of leftmost subnode if any
00891     SmNode *pNode = GetLeftMost();
00892         if (pNode)
00893         SetRectHorAlign(pNode->GetRectHorAlign(), FALSE);
00894 }
00895 
00896 
00897 /**************************************************************************/
00898 
00899 
00900 void SmUnHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
00901 {
00902         BOOL  bIsPostfix = GetToken().eType == TFACT;
00903 
00904         SmNode *pOper = GetSubNode(bIsPostfix ? 1 : 0),
00905                    *pBody = GetSubNode(bIsPostfix ? 0 : 1);
00906         DBG_ASSERT(pOper, "Sm: NULL pointer");
00907         DBG_ASSERT(pBody, "Sm: NULL pointer");
00908 
00909         pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
00910         pOper->Arrange(rDev, rFormat);
00911         pBody->Arrange(rDev, rFormat);
00912 
00913         Point  aPos = pOper->AlignTo(*pBody, bIsPostfix ? RP_RIGHT : RP_LEFT,
00914                                                 RHA_CENTER, RVA_BASELINE);
00915         // add a bit space between operator and argument
00916         // (worst case -{1 over 2} where - and over have almost no space inbetween)
00917         long  nDelta = pOper->GetFont().GetSize().Height() / 20;
00918         if (bIsPostfix)
00919                 aPos.X() += nDelta;
00920         else
00921                 aPos.X() -= nDelta;
00922         pOper->MoveTo(aPos);
00923 
00924         SmRect::operator = (*pBody);
00925         long  nOldBot = GetBottom();
00926 
00927         ExtendBy(*pOper, RCP_XOR);
00928 
00929         // workaround for Bug 50865: "a^2 a^+2" have different baselines
00930         // for exponents (if size of exponent is large enough)
00931         SetBottom(nOldBot);
00932 }
00933 
00934 
00935 /**************************************************************************/
00936 
00937 
00938 void SmRootNode::GetHeightVerOffset(const SmRect &rRect,
00939                                                                         long &rHeight, long &rVerOffset) const
00940         // calculate height and vertical offset of root sign suitable for 'rRect'
00941 {
00942         rVerOffset = (rRect.GetBottom() - rRect.GetAlignB()) / 2;
00943         rHeight    = rRect.GetHeight() - rVerOffset;
00944 
00945         DBG_ASSERT(rHeight        >= 0, "Sm : Ooops...");
00946         DBG_ASSERT(rVerOffset >= 0, "Sm : Ooops...");
00947 }
00948 
00949 
00950 Point SmRootNode::GetExtraPos(const SmRect &rRootSymbol,
00951                                                           const SmRect &rExtra) const
00952 {
00953         const Size &rSymSize = rRootSymbol.GetSize();
00954 
00955         Point  aPos = rRootSymbol.GetTopLeft()
00956                         + Point((rSymSize.Width()  * 70) / 100,
00957                                         (rSymSize.Height() * 52) / 100);
00958 
00959         // from this calculate topleft edge of 'rExtra'
00960         aPos.X() -= rExtra.GetWidth() + rExtra.GetItalicRightSpace();
00961         aPos.Y() -= rExtra.GetHeight();
00962         // if there's enough space move a bit less to the right
00963         // examples: "nroot i a", "nroot j a"
00964         // (it looks better if we don't use italic-spaces here)
00965         long  nX = rRootSymbol.GetLeft() + (rSymSize.Width() * 30) / 100;
00966         if (aPos.X() > nX)
00967                 aPos.X() = nX;
00968 
00969         return aPos;
00970 }
00971 
00972 
00973 void SmRootNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
00974 {
00979         SmNode *pExtra   = GetSubNode(0),
00980                    *pRootSym = GetSubNode(1),
00981                    *pBody        = GetSubNode(2);
00982         DBG_ASSERT(pRootSym, "Sm: NULL pointer");
00983         DBG_ASSERT(pBody,        "Sm: NULL pointer");
00984 
00985         pBody->Arrange(rDev, rFormat);
00986 
00987         long  nHeight,
00988                   nVerOffset;
00989         GetHeightVerOffset(*pBody, nHeight, nVerOffset);
00990         nHeight += rFormat.GetDistance(DIS_ROOT)
00991                            * GetFont().GetSize().Height() / 100L;
00992 
00993     // font specialist advised to change the width first
00994     pRootSym->AdaptToY(rDev, nHeight);
00995         pRootSym->AdaptToX(rDev, pBody->GetItalicWidth());
00996 
00997         pRootSym->Arrange(rDev, rFormat);
00998 
00999         Point  aPos = pRootSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
01001         aPos.Y()  = pRootSym->GetTop() + pBody->GetBottom() - pRootSym->GetBottom();
01002         aPos.Y() -= nVerOffset;
01003         pRootSym->MoveTo(aPos);
01004 
01005         if (pExtra)
01006         {       pExtra->SetSize(Fraction(rFormat.GetRelSize(SIZ_INDEX), 100));
01007                 pExtra->Arrange(rDev, rFormat);
01008 
01009                 aPos = GetExtraPos(*pRootSym, *pExtra);
01010                 pExtra->MoveTo(aPos);
01011         }
01012 
01013         SmRect::operator = (*pBody);
01014         ExtendBy(*pRootSym, RCP_THIS);
01015         if (pExtra)
01016                 ExtendBy(*pExtra, RCP_THIS, (BOOL) TRUE);
01017 }
01018 
01019 
01020 void SmRootNode::CreateTextFromNode(String &rText)
01021 {
01022         SmNode *pExtra = GetSubNode(0);
01023         if (pExtra)
01024         {
01025                 APPEND(rText,"nroot ");
01026                 pExtra->CreateTextFromNode(rText);
01027         }
01028         else
01029                 APPEND(rText,"sqrt ");
01030         GetSubNode(2)->CreateTextFromNode(rText);
01031 }
01032 
01033 
01034 /**************************************************************************/
01035 
01036 
01037 void SmBinHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01038 {
01039         SmNode *pLeft  = GetSubNode(0),
01040                    *pOper  = GetSubNode(1),
01041                    *pRight = GetSubNode(2);
01042         DBG_ASSERT(pLeft  != NULL, "Sm: NULL pointer");
01043         DBG_ASSERT(pOper  != NULL, "Sm: NULL pointer");
01044         DBG_ASSERT(pRight != NULL, "Sm: NULL pointer");
01045 
01046         pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
01047 
01048         pLeft ->Arrange(rDev, rFormat);
01049         pOper ->Arrange(rDev, rFormat);
01050     pRight->Arrange(rDev, rFormat);
01051 
01052         const SmRect &rOpRect = pOper->GetRect();
01053 
01054         long nDist = (rOpRect.GetWidth() *
01055                                  rFormat.GetDistance(DIS_HORIZONTAL)) / 100L;
01056 
01057         SmRect::operator = (*pLeft);
01058 
01059         Point aPos;
01060         aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
01061         aPos.X() += nDist;
01062         pOper->MoveTo(aPos);
01063         ExtendBy(*pOper, RCP_XOR);
01064 
01065         aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
01066         aPos.X() += nDist;
01067 
01068         pRight->MoveTo(aPos);
01069         ExtendBy(*pRight, RCP_XOR);
01070 }
01071 
01072 
01073 /**************************************************************************/
01074 
01075 
01076 void SmBinVerNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01077 {
01078         SmNode *pNum   = GetSubNode(0),
01079                    *pLine  = GetSubNode(1),
01080                    *pDenom = GetSubNode(2);
01081         DBG_ASSERT(pNum,   "Sm : NULL pointer");
01082         DBG_ASSERT(pLine,  "Sm : NULL pointer");
01083         DBG_ASSERT(pDenom, "Sm : NULL pointer");
01084 
01085         BOOL  bIsTextmode = rFormat.IsTextmode();
01086         if (bIsTextmode)
01087         {
01088                 Fraction  aFraction(rFormat.GetRelSize(SIZ_INDEX), 100);
01089                 pNum  ->SetSize(aFraction);
01090                 pLine ->SetSize(aFraction);
01091                 pDenom->SetSize(aFraction);
01092         }
01093 
01094         pNum  ->Arrange(rDev, rFormat);
01095         pDenom->Arrange(rDev, rFormat);
01096 
01097         long  nFontHeight = GetFont().GetSize().Height(),
01098                   nExtLen         = nFontHeight * rFormat.GetDistance(DIS_FRACTION)     / 100L,
01099                   nThick          = nFontHeight * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L,
01100                   nWidth          = Max(pNum->GetItalicWidth(), pDenom->GetItalicWidth()),
01101                   nNumDist    = bIsTextmode ? 0 :
01102                                                         nFontHeight * rFormat.GetDistance(DIS_NUMERATOR)   / 100L,
01103                   nDenomDist  = bIsTextmode ? 0 :
01104                                                         nFontHeight * rFormat.GetDistance(DIS_DENOMINATOR) / 100L;
01105 
01106     // font specialist advised to change the width first
01107     pLine->AdaptToY(rDev, nThick);
01108         pLine->AdaptToX(rDev, nWidth + 2 * nExtLen);
01109         pLine->Arrange(rDev, rFormat);
01110 
01111         // get horizontal alignment for numerator
01112         const SmNode *pLM               = pNum->GetLeftMost();
01113     RectHorAlign  eHorAlign = pLM->GetRectHorAlign();
01114 
01115         // move numerator to its position
01116         Point  aPos = pNum->AlignTo(*pLine, RP_TOP, eHorAlign, RVA_BASELINE);
01117         aPos.Y() -= nNumDist;
01118         pNum->MoveTo(aPos);
01119 
01120         // get horizontal alignment for denominator
01121         pLM               = pDenom->GetLeftMost();
01122     eHorAlign = pLM->GetRectHorAlign();
01123 
01124         // move denominator to its position
01125         aPos = pDenom->AlignTo(*pLine, RP_BOTTOM, eHorAlign, RVA_BASELINE);
01126         aPos.Y() += nDenomDist;
01127         pDenom->MoveTo(aPos);
01128 
01129         SmRect::operator = (*pNum);
01130         ExtendBy(*pDenom, RCP_NONE).ExtendBy(*pLine, RCP_NONE, pLine->GetCenterY());
01131 }
01132 
01133 void SmBinVerNode::CreateTextFromNode(String &rText)
01134 {
01135         SmNode *pNum   = GetSubNode(0),
01136     //      *pLine  = GetSubNode(1),
01137                    *pDenom = GetSubNode(2);
01138         pNum->CreateTextFromNode(rText);
01139         APPEND(rText,"over ");
01140         pDenom->CreateTextFromNode(rText);
01141 }
01142 
01143 
01144 SmNode * SmBinVerNode::GetLeftMost()
01145 {
01146         return this;
01147 }
01148 
01149 
01150 /**************************************************************************/
01151 
01152 
01153 double Det(const Point &rHeading1, const Point &rHeading2)
01154         // gibt den Wert der durch die beiden Punkte gebildeten Determinante
01155     // zurueck
01156 {
01157         return rHeading1.X() * rHeading2.Y() - rHeading1.Y() * rHeading2.X();
01158 }
01159 
01160 
01161 BOOL IsPointInLine(const Point &rPoint1,
01162                                    const Point &rPoint2, const Point &rHeading2)
01163     // ergibt TRUE genau dann, wenn der Punkt 'rPoint1' zu der Gerade gehoert die
01164         // durch den Punkt 'rPoint2' geht und den Richtungsvektor 'rHeading2' hat
01165 {
01166         DBG_ASSERT(rHeading2 != Point(), "Sm : 0 vector");
01167 
01168         BOOL bRes = FALSE;
01169         const double eps = 5.0 * DBL_EPSILON;
01170 
01171         double fLambda;
01172         if (labs(rHeading2.X()) > labs(rHeading2.Y()))
01173         {
01174                 fLambda = (rPoint1.X() - rPoint2.X()) / (double) rHeading2.X();
01175                 bRes = fabs(rPoint1.Y() - (rPoint2.Y() + fLambda * rHeading2.Y())) < eps;
01176         }
01177         else
01178         {
01179                 fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y();
01180                 bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
01181         }
01182 
01183         return bRes;
01184 }
01185 
01186 
01187 USHORT GetLineIntersectionPoint(Point &rResult,
01188                                                                 const Point& rPoint1, const Point &rHeading1,
01189                                                                 const Point& rPoint2, const Point &rHeading2)
01190 {
01191         DBG_ASSERT(rHeading1 != Point(), "Sm : 0 vector");
01192         DBG_ASSERT(rHeading2 != Point(), "Sm : 0 vector");
01193 
01194         USHORT nRes = 1;
01195         const double eps = 5.0 * DBL_EPSILON;
01196 
01197     // sind die Richtumgsvektoren linear abhaengig ?
01198         double  fDet = Det(rHeading1, rHeading2);
01199         if (fabs(fDet) < eps)
01200         {
01201                 nRes    = IsPointInLine(rPoint1, rPoint2, rHeading2) ? USHRT_MAX : 0;
01202                 rResult = nRes ? rPoint1 : Point();
01203         }
01204         else
01205         {
01206                 // hier achten wir nicht auf Rechengenauigkeit
01207         // (das wuerde aufwendiger und lohnt sich hier kaum)
01208                 double fLambda = (        (rPoint1.Y() - rPoint2.Y()) * rHeading2.X()
01209                                                         - (rPoint1.X() - rPoint2.X()) * rHeading2.Y())
01210                                                  / fDet;
01211                 rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()),
01212                                                 rPoint1.Y() + (long) (fLambda * rHeading1.Y()));
01213         }
01214 
01215         return nRes;
01216 }
01217 
01218 
01219 
01220 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken)
01221 :       SmStructureNode(NBINDIAGONAL, rNodeToken)
01222 {
01223         bAscending = FALSE;
01224         SetNumSubNodes(3);
01225 }
01226 
01227 
01228 void SmBinDiagonalNode::GetOperPosSize(Point &rPos, Size &rSize,
01229                                                 const Point &rDiagPoint, double fAngleDeg) const
01230     // gibt die Position und Groesse fuer den Diagonalstrich zurueck.
01231     // Vor.: das SmRect des Nodes gibt die Begrenzung vor(!), muss also selbst
01232         //              bereits bekannt sein.
01233 
01234 {
01235         const double  fPi   = 3.1415926535897932384626433;
01236         double  fAngleRad   = fAngleDeg / 180.0 * fPi;
01237         long    nRectLeft   = GetItalicLeft(),
01238                         nRectRight  = GetItalicRight(),
01239                         nRectTop    = GetTop(),
01240                         nRectBottom = GetBottom();
01241         Point   aRightHdg         (100, 0),
01242                         aDownHdg          (0, 100),
01243                         aDiagHdg          ( (long)(100.0 * cos(fAngleRad)),
01244                                                         (long)(-100.0 * sin(fAngleRad)) );
01245 
01246     long  nLeft, nRight, nTop, nBottom;     // Raender des Rechtecks fuer die
01247                                                                                         // Diagonale
01248         Point aPoint;
01249         if (IsAscending())
01250         {
01251                 //
01252                 // obere rechte Ecke bestimmen
01253                 //
01254                 GetLineIntersectionPoint(aPoint,
01255                         Point(nRectLeft, nRectTop), aRightHdg,
01256                         rDiagPoint, aDiagHdg);
01257                 //
01258                 // gibt es einen Schnittpunkt mit dem oberen Rand ?
01259                 if (aPoint.X() <= nRectRight)
01260                 {
01261                         nRight = aPoint.X();
01262                         nTop   = nRectTop;
01263                 }
01264                 else
01265                 {
01266             // es muss einen Schnittpunkt mit dem rechten Rand geben!
01267                         GetLineIntersectionPoint(aPoint,
01268                                 Point(nRectRight, nRectTop), aDownHdg,
01269                                 rDiagPoint, aDiagHdg);
01270 
01271                         nRight = nRectRight;
01272                         nTop   = aPoint.Y();
01273                 }
01274 
01275                 //
01276                 // untere linke Ecke bestimmen
01277                 //
01278                 GetLineIntersectionPoint(aPoint,
01279                         Point(nRectLeft, nRectBottom), aRightHdg,
01280                         rDiagPoint, aDiagHdg);
01281                 //
01282                 // gibt es einen Schnittpunkt mit dem unteren Rand ?
01283                 if (aPoint.X() >= nRectLeft)
01284                 {
01285                         nLeft   = aPoint.X();
01286                         nBottom = nRectBottom;
01287                 }
01288                 else
01289                 {
01290             // es muss einen Schnittpunkt mit dem linken Rand geben!
01291                         GetLineIntersectionPoint(aPoint,
01292                                 Point(nRectLeft, nRectTop), aDownHdg,
01293                                 rDiagPoint, aDiagHdg);
01294 
01295                         nLeft   = nRectLeft;
01296                         nBottom = aPoint.Y();
01297                 }
01298         }
01299         else
01300         {
01301                 //
01302                 // obere linke Ecke bestimmen
01303                 //
01304                 GetLineIntersectionPoint(aPoint,
01305                         Point(nRectLeft, nRectTop), aRightHdg,
01306                         rDiagPoint, aDiagHdg);
01307                 //
01308                 // gibt es einen Schnittpunkt mit dem oberen Rand ?
01309                 if (aPoint.X() >= nRectLeft)
01310                 {
01311                         nLeft = aPoint.X();
01312                         nTop  = nRectTop;
01313                 }
01314                 else
01315                 {
01316             // es muss einen Schnittpunkt mit dem linken Rand geben!
01317                         GetLineIntersectionPoint(aPoint,
01318                                 Point(nRectLeft, nRectTop), aDownHdg,
01319                                 rDiagPoint, aDiagHdg);
01320 
01321                         nLeft = nRectLeft;
01322                         nTop  = aPoint.Y();
01323                 }
01324 
01325                 //
01326                 // untere rechte Ecke bestimmen
01327                 //
01328                 GetLineIntersectionPoint(aPoint,
01329                         Point(nRectLeft, nRectBottom), aRightHdg,
01330                         rDiagPoint, aDiagHdg);
01331                 //
01332                 // gibt es einen Schnittpunkt mit dem unteren Rand ?
01333                 if (aPoint.X() <= nRectRight)
01334                 {
01335                         nRight  = aPoint.X();
01336                         nBottom = nRectBottom;
01337                 }
01338                 else
01339                 {
01340             // es muss einen Schnittpunkt mit dem rechten Rand geben!
01341                         GetLineIntersectionPoint(aPoint,
01342                                 Point(nRectRight, nRectTop), aDownHdg,
01343                                 rDiagPoint, aDiagHdg);
01344 
01345                         nRight  = nRectRight;
01346                         nBottom = aPoint.Y();
01347                 }
01348         }
01349 
01350         rSize = Size(nRight - nLeft + 1, nBottom - nTop + 1);
01351         rPos.X() = nLeft;
01352         rPos.Y() = nTop;
01353 }
01354 
01355 
01356 void SmBinDiagonalNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01357 {
01361         SmNode *pLeft  = GetSubNode(0),
01362                    *pRight = GetSubNode(1);
01363         DBG_ASSERT(pLeft, "Sm : NULL pointer");
01364         DBG_ASSERT(pRight, "Sm : NULL pointer");
01365 
01366         DBG_ASSERT(GetSubNode(2)->GetType() == NPOLYLINE, "Sm : falscher Nodetyp");
01367         SmPolyLineNode *pOper = (SmPolyLineNode *) GetSubNode(2);
01368         DBG_ASSERT(pOper, "Sm : NULL pointer");
01369 
01373     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
01374         aTmpDev.SetFont(GetFont());
01375 
01376         pLeft->Arrange(aTmpDev, rFormat);
01377         pRight->Arrange(aTmpDev, rFormat);
01378 
01379         // implizit die Weite (incl Rand) des Diagonalstrichs ermitteln
01380         pOper->Arrange(aTmpDev, rFormat);
01381 
01382         long nDelta = pOper->GetWidth() * 8 / 10;
01383 
01384         // TopLeft Position vom rechten Argument ermitteln
01385         Point aPos;
01386         aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace();
01387         if (IsAscending())
01388                 aPos.Y() = pLeft->GetBottom() + nDelta;
01389         else
01390                 aPos.Y() = pLeft->GetTop() - nDelta - pRight->GetHeight();
01391 
01392         pRight->MoveTo(aPos);
01393 
01394         // neue Baseline bestimmen
01395     long nTmpBaseline = IsAscending() ? (pLeft->GetBottom() + pRight->GetTop()) / 2
01396                                                 : (pLeft->GetTop() + pRight->GetBottom()) / 2;
01397         Point  aLogCenter ((pLeft->GetItalicRight() + pRight->GetItalicLeft()) / 2,
01398                        nTmpBaseline);
01399 
01400         SmRect::operator = (*pLeft);
01401         ExtendBy(*pRight, RCP_NONE);
01402 
01403 
01404     // Position und Groesse des Diagonalstrich ermitteln
01405     Size  aTmpSize;
01406     GetOperPosSize(aPos, aTmpSize, aLogCenter, IsAscending() ? 60.0 : -60.0);
01407 
01408     // font specialist advised to change the width first
01409     pOper->AdaptToY(aTmpDev, aTmpSize.Height());
01410     pOper->AdaptToX(aTmpDev, aTmpSize.Width());
01411         // und diese wirksam machen
01412         pOper->Arrange(aTmpDev, rFormat);
01413 
01414         pOper->MoveTo(aPos);
01415 
01416     ExtendBy(*pOper, RCP_NONE, nTmpBaseline);
01417 }
01418 
01419 
01420 /**************************************************************************/
01421 
01422 
01423 void SmSubSupNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01424 {
01425         DBG_ASSERT(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES,
01426                            "Sm: falsche Anzahl von subnodes");
01427 
01428         SmNode *pBody = GetBody();
01429         DBG_ASSERT(pBody, "Sm: NULL pointer");
01430 
01431         long  nOrigHeight = pBody->GetFont().GetSize().Height();
01432 
01433         pBody->Arrange(rDev, rFormat);
01434 
01435         const SmRect &rBodyRect = pBody->GetRect();
01436         SmRect::operator = (rBodyRect);
01437 
01438         // line that separates sub- and supscript rectangles
01439         long  nDelimLine = SmFromTo(GetAlignB(), GetAlignT(), 0.4);
01440 
01441         Point  aPos;
01442         long   nDelta, nDist;
01443 
01444         // iterate over all possible sub-/supscripts
01445         SmRect  aTmpRect (rBodyRect);
01446         for (int i = 0;  i < SUBSUP_NUM_ENTRIES;  i++)
01447         {       SmSubSup  eSubSup = (SmSubSup) i;       // cast
01448                 SmNode *pSubSup = GetSubSup(eSubSup);
01449 
01450                 if (!pSubSup)
01451                         continue;
01452 
01453                 // switch position of limits if we are in textmode
01454                 if (rFormat.IsTextmode()  &&  (GetToken().nGroup & TGLIMIT))
01455                         switch (eSubSup)
01456                         {       case CSUB:      eSubSup = RSUB;         break;
01457                                 case CSUP:      eSubSup = RSUP;         break;
01458                 default:
01459                     break;
01460                         }
01461 
01462                 // prevent sub-/supscripts from diminishing in size
01463                 // (as would be in "a_{1_{2_{3_4}}}")
01464                 if (GetFont().GetSize().Height() > rFormat.GetBaseSize().Height() / 3)
01465                 {
01466                         USHORT nIndex = (eSubSup == CSUB  ||  eSubSup == CSUP) ?
01467                                                                         SIZ_LIMITS : SIZ_INDEX;
01468                         Fraction  aFraction ( rFormat.GetRelSize(nIndex), 100 );
01469                         pSubSup->SetSize(aFraction);
01470                 }
01471 
01472                 pSubSup->Arrange(rDev, rFormat);
01473 
01474                 BOOL  bIsTextmode = rFormat.IsTextmode();
01475                 nDist = 0;
01476 
01478                 switch (eSubSup)
01479                 {       case RSUB :
01480                         case LSUB :
01481                                 if (!bIsTextmode)
01482                                         nDist = nOrigHeight
01483                                                         * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L;
01484                                 aPos  = pSubSup->GetRect().AlignTo(aTmpRect,
01485                                                                 eSubSup == LSUB ? RP_LEFT : RP_RIGHT,
01486                                                                 RHA_CENTER, RVA_BOTTOM);
01487                                 aPos.Y() += nDist;
01488                                 nDelta = nDelimLine - aPos.Y();
01489                                 if (nDelta > 0)
01490                                         aPos.Y() += nDelta;
01491                                 break;
01492                         case RSUP :
01493                         case LSUP :
01494                                 if (!bIsTextmode)
01495                                         nDist = nOrigHeight
01496                                                         * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L;
01497                                 aPos  = pSubSup->GetRect().AlignTo(aTmpRect,
01498                                                                 eSubSup == LSUP ? RP_LEFT : RP_RIGHT,
01499                                                                 RHA_CENTER, RVA_TOP);
01500                                 aPos.Y() -= nDist;
01501                                 nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
01502                                 if (nDelta > 0)
01503                                         aPos.Y() -= nDelta;
01504                                 break;
01505                         case CSUB :
01506                                 if (!bIsTextmode)
01507                                         nDist = nOrigHeight
01508                                                         * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L;
01509                                 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM,
01510                                                                 RHA_CENTER, RVA_BASELINE);
01511                                 aPos.Y() += nDist;
01512                                 break;
01513                         case CSUP :
01514                                 if (!bIsTextmode)
01515                                         nDist = nOrigHeight
01516                                                         * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L;
01517                                 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP,
01518                                                                 RHA_CENTER, RVA_BASELINE);
01519                                 aPos.Y() -= nDist;
01520                                 break;
01521                         default :
01522                                 DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
01523                 break;
01524                 }
01525 
01526                 pSubSup->MoveTo(aPos);
01527                 ExtendBy(*pSubSup, RCP_THIS, (BOOL) TRUE);
01528 
01529                 // update rectangle to which  RSUB, RSUP, LSUB, LSUP
01530                 // will be aligned to
01531                 if (eSubSup == CSUB  ||  eSubSup == CSUP)
01532                         aTmpRect = *this;
01533         }
01534 }
01535 
01536 void SmSubSupNode::CreateTextFromNode(String &rText)
01537 {
01538         SmNode *pNode;
01539         GetSubNode(0)->CreateTextFromNode(rText);
01540 
01541     if (NULL != (pNode = GetSubNode(LSUB+1)))
01542         {
01543                 APPEND(rText,"lsub ");
01544                 pNode->CreateTextFromNode(rText);
01545         }
01546     if (NULL != (pNode = GetSubNode(LSUP+1)))
01547         {
01548                 APPEND(rText,"lsup ");
01549                 pNode->CreateTextFromNode(rText);
01550         }
01551     if (NULL != (pNode = GetSubNode(CSUB+1)))
01552         {
01553                 APPEND(rText,"csub ");
01554                 pNode->CreateTextFromNode(rText);
01555         }
01556     if (NULL != (pNode = GetSubNode(CSUP+1)))
01557         {
01558                 APPEND(rText,"csup ");
01559                 pNode->CreateTextFromNode(rText);
01560         }
01561     if (NULL != (pNode = GetSubNode(RSUB+1)))
01562         {
01563                 rText.EraseTrailingChars();
01564                 rText.Append('_');
01565                 pNode->CreateTextFromNode(rText);
01566         }
01567     if (NULL != (pNode = GetSubNode(RSUP+1)))
01568         {
01569                 rText.EraseTrailingChars();
01570                 rText.Append('^');
01571                 pNode->CreateTextFromNode(rText);
01572         }
01573 }
01574 
01575 
01576 /**************************************************************************/
01577 
01578 void SmBraceNode::CreateTextFromNode(String &rText)
01579 {
01580         if (GetScaleMode() == SCALE_HEIGHT)
01581                 APPEND(rText,"left ");
01582     {
01583         String aStr;
01584             GetSubNode(0)->CreateTextFromNode(aStr);
01585         aStr.EraseLeadingAndTrailingChars();
01586         aStr.EraseLeadingChars('\\');
01587         if (aStr.Len())
01588         {
01589             if (aStr.EqualsAscii("divides"))
01590                 APPEND(rText,"lline");
01591             else if (aStr.EqualsAscii("parallel"))
01592                 APPEND(rText,"ldline");
01593             else if (aStr.EqualsAscii("<"))
01594                 APPEND(rText,"langle");
01595             else
01596                 rText.Append(aStr);
01597                 rText.Append(' ');
01598         }
01599         else
01600             APPEND(rText,"none ");
01601     }
01602         GetSubNode(1)->CreateTextFromNode(rText);
01603         if (GetScaleMode() == SCALE_HEIGHT)
01604                 APPEND(rText,"right ");
01605     {
01606         String aStr;
01607             GetSubNode(2)->CreateTextFromNode(aStr);
01608         aStr.EraseLeadingAndTrailingChars();
01609         aStr.EraseLeadingChars('\\');
01610         if (aStr.Len())
01611         {
01612             if (aStr.EqualsAscii("divides"))
01613                 APPEND(rText,"rline");
01614             else if (aStr.EqualsAscii("parallel"))
01615                 APPEND(rText,"rdline");
01616             else if (aStr.EqualsAscii(">"))
01617                 APPEND(rText,"rangle");
01618             else
01619                 rText.Append(aStr);
01620                 rText.Append(' ');
01621         }
01622         else
01623             APPEND(rText,"none ");
01624     }
01625         rText.Append(' ');
01626 
01627 }
01628 
01629 void SmBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01630 {
01631         SmNode *pLeft  = GetSubNode(0),
01632                    *pBody  = GetSubNode(1),
01633                    *pRight = GetSubNode(2);
01634         DBG_ASSERT(pLeft,  "Sm: NULL pointer");
01635         DBG_ASSERT(pBody,  "Sm: NULL pointer");
01636         DBG_ASSERT(pRight, "Sm: NULL pointer");
01637 
01638         pBody->Arrange(rDev, rFormat);
01639 
01640         BOOL  bIsScaleNormal = rFormat.IsScaleNormalBrackets(),
01641                   bScale             = pBody->GetHeight() > 0  &&
01642                                                    (GetScaleMode() == SCALE_HEIGHT  ||  bIsScaleNormal),
01643                   bIsABS             = GetToken().eType == TABS;
01644 
01645         long  nFaceHeight = GetFont().GetSize().Height();
01646 
01647     // Uebergroesse in % ermitteln
01648         USHORT  nPerc = 0;
01649         if (!bIsABS && bScale)
01650     {   // im Fall von Klammern mit Uebergroesse...
01651         USHORT nIndex = GetScaleMode() == SCALE_HEIGHT ?
01652                                                         DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
01653                 nPerc = rFormat.GetDistance(nIndex);
01654         }
01655 
01656     // ermitteln der Hoehe fuer die Klammern
01657         long  nBraceHeight;
01658         if (bScale)
01659         {
01660                 nBraceHeight = pBody->GetType() == NBRACEBODY ?
01661                                                           ((SmBracebodyNode *) pBody)->GetBodyHeight()
01662                                                         : pBody->GetHeight();
01663                 nBraceHeight += 2 * (nBraceHeight * nPerc / 100L);
01664         }
01665         else
01666                 nBraceHeight = nFaceHeight;
01667 
01668         // Abstand zum Argument
01669         nPerc = bIsABS ? 0 : rFormat.GetDistance(DIS_BRACKETSPACE);
01670         long  nDist = nFaceHeight * nPerc / 100L;
01671 
01672     // sofern erwuenscht skalieren der Klammern auf die gewuenschte Groesse
01673         if (bScale)
01674         {
01675         Size  aTmpSize (pLeft->GetFont().GetSize());
01676         DBG_ASSERT(pRight->GetFont().GetSize() == aTmpSize,
01677                     "Sm : unterschiedliche Fontgroessen");
01678         aTmpSize.Width() = Min((long) nBraceHeight * 60L / 100L,
01679                                                         rFormat.GetBaseSize().Height() * 3L / 2L);
01680         // correction factor since change from StarMath to StarSymbol font
01681         // because of the different font width in the FontMetric
01682         aTmpSize.Width() *= 182;
01683         aTmpSize.Width() /= 267;
01684 
01685                 xub_Unicode cChar = pLeft->GetToken().cMathChar;
01686                 if (cChar != MS_LINE  &&  cChar != MS_DLINE)
01687             pLeft ->GetFont().SetSize(aTmpSize);
01688 
01689                 cChar = pRight->GetToken().cMathChar;
01690                 if (cChar != MS_LINE  &&  cChar != MS_DLINE)
01691             pRight->GetFont().SetSize(aTmpSize);
01692 
01693                 pLeft ->AdaptToY(rDev, nBraceHeight);
01694                 pRight->AdaptToY(rDev, nBraceHeight);
01695         }
01696 
01697         pLeft ->Arrange(rDev, rFormat);
01698         pRight->Arrange(rDev, rFormat);
01699 
01700     // damit auch "\(a\) - (a) - left ( a right )" vernuenftig aussieht
01701         RectVerAlign  eVerAlign = bScale ? RVA_CENTERY : RVA_BASELINE;
01702 
01703         Point             aPos;
01704         aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign);
01705         aPos.X() -= nDist;
01706         pLeft->MoveTo(aPos);
01707 
01708         aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign);
01709         aPos.X() += nDist;
01710         pRight->MoveTo(aPos);
01711 
01712         SmRect::operator = (*pBody);
01713         ExtendBy(*pLeft, RCP_THIS).ExtendBy(*pRight, RCP_THIS);
01714 }
01715 
01716 
01717 /**************************************************************************/
01718 
01719 
01720 void SmBracebodyNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01721 {
01722         USHORT  nNumSubNodes = GetNumSubNodes();
01723         if (nNumSubNodes == 0)
01724                 return;
01725 
01726         // arrange arguments
01727         USHORT i;
01728         for (i = 0;  i < nNumSubNodes;  i += 2)
01729                 GetSubNode(i)->Arrange(rDev, rFormat);
01730 
01731         // build reference rectangle with necessary info for vertical alignment
01732         SmRect  aRefRect (*GetSubNode(0));
01733         for (i = 0;  i < nNumSubNodes;  i += 2)
01734         {
01735                 SmRect aTmpRect (*GetSubNode(i));
01736                 Point  aPos = aTmpRect.AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
01737                 aTmpRect.MoveTo(aPos);
01738                 aRefRect.ExtendBy(aTmpRect, RCP_XOR);
01739         }
01740 
01741         nBodyHeight = aRefRect.GetHeight();
01742 
01743         // scale separators to required height and arrange them
01744         BOOL bScale  = GetScaleMode() == SCALE_HEIGHT  ||  rFormat.IsScaleNormalBrackets();
01745         long nHeight = bScale ? aRefRect.GetHeight() : GetFont().GetSize().Height();
01746     USHORT nIndex  = GetScaleMode() == SCALE_HEIGHT ?
01747                                                 DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
01748         USHORT nPerc   = rFormat.GetDistance(nIndex);
01749         if (bScale)
01750                 nHeight += 2 * (nHeight * nPerc / 100L);
01751         for (i = 1;  i < nNumSubNodes;  i += 2)
01752         {
01753                 SmNode *pNode = GetSubNode(i);
01754                 pNode->AdaptToY(rDev, nHeight);
01755                 pNode->Arrange(rDev, rFormat);
01756         }
01757 
01758         // horizontal distance between argument and brackets or separators
01759         long  nDist = GetFont().GetSize().Height()
01760                                   * rFormat.GetDistance(DIS_BRACKETSPACE) / 100L;
01761 
01762         SmNode *pLeft = GetSubNode(0);
01763         SmRect::operator = (*pLeft);
01764         for (i = 1;  i < nNumSubNodes;  i++)
01765         {
01766                 BOOL          bIsSeparator = i % 2 != 0;
01767                 RectVerAlign  eVerAlign    = bIsSeparator ? RVA_CENTERY : RVA_BASELINE;
01768 
01769                 SmNode *pRight = GetSubNode(i);
01770                 Point  aPosX = pRight->AlignTo(*pLeft,   RP_RIGHT, RHA_CENTER, eVerAlign),
01771                            aPosY = pRight->AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, eVerAlign);
01772                 aPosX.X() += nDist;
01773 
01774                 pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
01775                 ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR);
01776 
01777                 pLeft = pRight;
01778         }
01779 }
01780 
01781 
01782 /**************************************************************************/
01783 
01784 
01785 void SmVerticalBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01786 {
01787         SmNode *pBody   = GetSubNode(0),
01788                    *pBrace  = GetSubNode(1),
01789                    *pScript = GetSubNode(2);
01790         DBG_ASSERT(pBody,   "Sm: NULL pointer!");
01791         DBG_ASSERT(pBrace,  "Sm: NULL pointer!");
01792         DBG_ASSERT(pScript, "Sm: NULL pointer!");
01793 
01794     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
01795         aTmpDev.SetFont(GetFont());
01796 
01797         pBody->Arrange(aTmpDev, rFormat);
01798 
01799         // Groesse wie bei Grenzen fuer diesen Teil
01800         pScript->SetSize( Fraction( rFormat.GetRelSize(SIZ_LIMITS), 100 ) );
01801         // etwas hoehere Klammern als normal
01802         pBrace ->SetSize( Fraction(3, 2) );
01803 
01804         long  nItalicWidth = pBody->GetItalicWidth();
01805         if (nItalicWidth > 0)
01806                 pBrace->AdaptToX(aTmpDev, nItalicWidth);
01807 
01808         pBrace ->Arrange(aTmpDev, rFormat);
01809         pScript->Arrange(aTmpDev, rFormat);
01810 
01811         // die relativen Position und die Abstaende zueinander bestimmen
01812         RectPos  eRectPos;
01813         long nFontHeight = pBody->GetFont().GetSize().Height();
01814         long nDistBody   = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
01815                  nDistScript = nFontHeight;
01816         if (GetToken().eType == TOVERBRACE)
01817         {
01818                 eRectPos = RP_TOP;
01819                 nDistBody    = - nDistBody;
01820                 nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
01821         }
01822         else // TUNDERBRACE
01823         {
01824                 eRectPos = RP_BOTTOM;
01825                 nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
01826         }
01827         nDistBody   /= 100L;
01828         nDistScript /= 100L;
01829 
01830         Point  aPos = pBrace->AlignTo(*pBody, eRectPos, RHA_CENTER, RVA_BASELINE);
01831         aPos.Y() += nDistBody;
01832         pBrace->MoveTo(aPos);
01833 
01834         aPos = pScript->AlignTo(*pBrace, eRectPos, RHA_CENTER, RVA_BASELINE);
01835         aPos.Y() += nDistScript;
01836         pScript->MoveTo(aPos);
01837 
01838         SmRect::operator = (*pBody);
01839         ExtendBy(*pBrace, RCP_THIS).ExtendBy(*pScript, RCP_THIS);
01840 }
01841 
01842 
01843 /**************************************************************************/
01844 
01845 
01846 SmNode * SmOperNode::GetSymbol()
01847 {
01848         SmNode *pNode = GetSubNode(0);
01849         DBG_ASSERT(pNode, "Sm: NULL pointer!");
01850 
01851         if (pNode->GetType() == NSUBSUP)
01852                 pNode = ((SmSubSupNode *) pNode)->GetBody();
01853 
01854         DBG_ASSERT(pNode, "Sm: NULL pointer!");
01855         return pNode;
01856 }
01857 
01858 
01859 long SmOperNode::CalcSymbolHeight(const SmNode &rSymbol,
01860                                                                   const SmFormat &rFormat) const
01861         // returns the font height to be used for operator-symbol
01862 {
01863         long  nHeight = GetFont().GetSize().Height();
01864 
01865     SmTokenType  eTmpType = GetToken().eType;
01866     if (eTmpType == TLIM  ||  eTmpType == TLIMINF  ||  eTmpType == TLIMSUP)
01867                 return nHeight;
01868 
01869         if (!rFormat.IsTextmode())
01870         {
01871                 // set minimum size ()
01872                 nHeight += (nHeight * 20L) / 100L;
01873 
01874                 nHeight += nHeight
01875                                    * rFormat.GetDistance(DIS_OPERATORSIZE) / 100L;
01876                 nHeight = nHeight * 686L / 845L;
01877         }
01878 
01879     // correct user-defined symbols to match height of sum from used font
01880     if (rSymbol.GetToken().eType == TSPECIAL)
01881                 nHeight = nHeight * 845L / 686L;
01882 
01883         return nHeight;
01884 }
01885 
01886 
01887 void SmOperNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01888 {
01889         SmNode *pOper = GetSubNode(0);
01890         SmNode *pBody = GetSubNode(1);
01891 
01892         DBG_ASSERT(pOper, "Sm: Subnode fehlt");
01893         DBG_ASSERT(pBody, "Sm: Subnode fehlt");
01894 
01895         SmNode *pSymbol = GetSymbol();
01896         pSymbol->SetSize(Fraction(CalcSymbolHeight(*pSymbol, rFormat),
01897                                                           pSymbol->GetFont().GetSize().Height()));
01898 
01899         pBody->Arrange(rDev, rFormat);
01900         pOper->Arrange(rDev, rFormat);
01901 
01902         long  nOrigHeight = GetFont().GetSize().Height(),
01903                   nDist = nOrigHeight
01904                                   * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L;
01905 
01906         Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID);
01907         aPos.X() -= nDist;
01908         pOper->MoveTo(aPos);
01909 
01910         SmRect::operator = (*pBody);
01911         ExtendBy(*pOper, RCP_THIS);
01912 }
01913 
01914 
01915 /**************************************************************************/
01916 
01917 
01918 void SmAlignNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01919         // setzt im ganzen subtree (incl aktuellem node) das alignment
01920 {
01921         DBG_ASSERT(GetNumSubNodes() > 0, "Sm: SubNode fehlt");
01922 
01923         SmNode  *pNode = GetSubNode(0);
01924 
01925     RectHorAlign  eHorAlign = RHA_CENTER;
01926         switch (GetToken().eType)
01927         {
01928                 case TALIGNL:   eHorAlign = RHA_LEFT;   break;
01929                 case TALIGNC:   eHorAlign = RHA_CENTER; break;
01930                 case TALIGNR:   eHorAlign = RHA_RIGHT;  break;
01931         default:
01932             break;
01933         }
01934         SetRectHorAlign(eHorAlign);
01935 
01936         pNode->Arrange(rDev, rFormat);
01937 
01938         SmRect::operator = (pNode->GetRect());
01939 }
01940 
01941 
01942 /**************************************************************************/
01943 
01944 
01945 void SmAttributNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
01946 {
01947         SmNode *pAttr = GetSubNode(0),
01948                    *pBody = GetSubNode(1);
01949         DBG_ASSERT(pBody, "Sm: Body fehlt");
01950         DBG_ASSERT(pAttr, "Sm: Attribut fehlt");
01951 
01952         pBody->Arrange(rDev, rFormat);
01953 
01954         if (GetScaleMode() == SCALE_WIDTH)
01955                 pAttr->AdaptToX(rDev, pBody->GetItalicWidth());
01956         pAttr->Arrange(rDev, rFormat);
01957 
01958         // get relative position of attribut
01959         RectVerAlign  eVerAlign;
01960         long              nDist = 0;
01961         switch (GetToken().eType)
01962         {       case TUNDERLINE :
01963                         eVerAlign = RVA_ATTRIBUT_LO;
01964                         break;
01965                 case TOVERSTRIKE :
01966                         eVerAlign = RVA_ATTRIBUT_MID;
01967                         break;
01968                 default :
01969                         eVerAlign = RVA_ATTRIBUT_HI;
01970                         if (pBody->GetType() == NATTRIBUT)
01971                                 nDist = GetFont().GetSize().Height()
01972                                                 * rFormat.GetDistance(DIS_ORNAMENTSPACE) / 100L;
01973         }
01974         Point  aPos = pAttr->AlignTo(*pBody, RP_ATTRIBUT, RHA_CENTER, eVerAlign);
01975         aPos.Y() -= nDist;
01976         pAttr->MoveTo(aPos);
01977 
01978         SmRect::operator = (*pBody);
01979         ExtendBy(*pAttr, RCP_THIS, (BOOL) TRUE);
01980 }
01981 
01982 
01983 /**************************************************************************/
01984 
01985 
01986 
01987 
01988 void SmFontNode::CreateTextFromNode(String &rText)
01989 {
01990         switch (GetToken().eType)
01991         {
01992                 case TBOLD:
01993                         APPEND(rText,"bold ");
01994                         break;
01995                 case TNBOLD:
01996                         APPEND(rText,"nbold ");
01997                         break;
01998                 case TITALIC:
01999                         APPEND(rText,"italic ");
02000                         break;
02001                 case TNITALIC:
02002                         APPEND(rText,"nitalic ");
02003                         break;
02004                 case TPHANTOM:
02005                         APPEND(rText,"phantom ");
02006                         break;
02007                 case TSIZE:
02008                         {
02009                                 APPEND(rText,"size ");
02010                                 switch (nSizeType)
02011                                 {
02012                                         case FNTSIZ_PLUS:
02013                                                 rText.Append('+');
02014                                                 break;
02015                                         case FNTSIZ_MINUS:
02016                                                 rText.Append('-');
02017                                                 break;
02018                                         case FNTSIZ_MULTIPLY:
02019                                                 rText.Append('*');
02020                                                 break;
02021                                         case FNTSIZ_DIVIDE:
02022                                                 rText.Append('/');
02023                                                 break;
02024                                         case FNTSIZ_ABSOLUT:
02025                                         default:
02026                                                 break;
02027                                 }
02028                 rText += String( ::rtl::math::doubleToUString(
02029                             static_cast<double>(aFontSize),
02030                             rtl_math_StringFormat_Automatic,
02031                             rtl_math_DecimalPlaces_Max, '.', sal_True));
02032                                 rText.Append(' ');
02033                         }
02034                         break;
02035                 case TBLACK:
02036                         APPEND(rText,"color black ");
02037                         break;
02038                 case TWHITE:
02039                         APPEND(rText,"color white ");
02040                         break;
02041                 case TRED:
02042                         APPEND(rText,"color red ");
02043                         break;
02044                 case TGREEN:
02045                         APPEND(rText,"color green ");
02046                         break;
02047                 case TBLUE:
02048                         APPEND(rText,"color blue ");
02049                         break;
02050                 case TCYAN:
02051                         APPEND(rText,"color cyan ");
02052                         break;
02053                 case TMAGENTA:
02054                         APPEND(rText,"color magenta ");
02055                         break;
02056                 case TYELLOW:
02057                         APPEND(rText,"color yellow ");
02058                         break;
02059                 case TSANS:
02060                         APPEND(rText,"font sans ");
02061                         break;
02062                 case TSERIF:
02063                         APPEND(rText,"font serif ");
02064                         break;
02065                 case TFIXED:
02066                         APPEND(rText,"font fixed ");
02067                         break;
02068                 default:
02069                         break;
02070         }
02071         GetSubNode(1)->CreateTextFromNode(rText);
02072 }
02073 
02074 
02075 void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02076 {
02078         SmNode::Prepare(rFormat, rDocShell);
02079 
02080         int  nFnt = -1;
02081         switch (GetToken().eType)
02082         {
02083                 case TFIXED:    nFnt = FNT_FIXED;       break;
02084                 case TSANS:             nFnt = FNT_SANS;        break;
02085                 case TSERIF:    nFnt = FNT_SERIF;       break;
02086         default:
02087             break;
02088         }
02089         if (nFnt != -1)
02090     {   GetFont() = rFormat.GetFont( sal::static_int_cast< USHORT >(nFnt) );
02091                 SetFont(GetFont());
02092         }
02093 
02096         Flags() |= FLG_FONT;
02097 }
02098 
02099 
02100 void SmFontNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02101 {
02102         SmNode *pNode = GetSubNode(1);
02103         DBG_ASSERT(pNode, "Sm: SubNode fehlt");
02104 
02105         switch (GetToken().eType)
02106         {       case TSIZE :
02107                         pNode->SetFontSize(aFontSize, nSizeType);
02108                         break;
02109                 case TSANS :
02110                 case TSERIF :
02111                 case TFIXED :
02112                         pNode->SetFont(GetFont());
02113                         break;
02114                 case TUNKNOWN : break;  // no assertion on "font <?> <?>"
02115 
02116                 case TPHANTOM : SetPhantom(TRUE);                               break;
02117                 case TBOLD :    SetAttribut(ATTR_BOLD);                 break;
02118                 case TITALIC :  SetAttribut(ATTR_ITALIC);               break;
02119                 case TNBOLD :   ClearAttribut(ATTR_BOLD);               break;
02120                 case TNITALIC : ClearAttribut(ATTR_ITALIC);             break;
02121 
02122                 case TBLACK :   SetColor(Color(COL_BLACK));             break;
02123                 case TWHITE :   SetColor(Color(COL_WHITE));             break;
02124                 case TRED :             SetColor(Color(COL_RED));               break;
02125                 case TGREEN :   SetColor(Color(COL_GREEN));             break;
02126                 case TBLUE :    SetColor(Color(COL_BLUE));              break;
02127                 case TCYAN :    SetColor(Color(COL_CYAN));              break;
02128                 case TMAGENTA : SetColor(Color(COL_MAGENTA));   break;
02129                 case TYELLOW :  SetColor(Color(COL_YELLOW));    break;
02130 
02131                 default:
02132                         DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
02133         }
02134 
02135         pNode->Arrange(rDev, rFormat);
02136 
02137         SmRect::operator = (pNode->GetRect());
02138 }
02139 
02140 
02141 void SmFontNode::SetSizeParameter(const Fraction& rValue, USHORT Type)
02142 {
02143         nSizeType = Type;
02144         aFontSize = rValue;
02145 }
02146 
02147 
02148 /**************************************************************************/
02149 
02150 
02151 SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
02152 :       SmGraphicNode(NPOLYLINE, rNodeToken)
02153 {
02154         aPoly.SetSize(2);
02155         nWidth = 0;
02156 }
02157 
02158 
02159 void SmPolyLineNode::AdaptToX(const OutputDevice &/*rDev*/, ULONG nNewWidth)
02160 {
02161     aToSize.Width() = nNewWidth;
02162 }
02163 
02164 
02165 void SmPolyLineNode::AdaptToY(const OutputDevice &/*rDev*/, ULONG nNewHeight)
02166 {
02167         GetFont().FreezeBorderWidth();
02168     aToSize.Height() = nNewHeight;
02169 }
02170 
02171 
02172 void SmPolyLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02173 {
02177     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02178         aTmpDev.SetFont(GetFont());
02179 
02180         long  nBorderwidth = GetFont().GetBorderWidth();
02181 
02182         //
02183         // Das Polygon mit den beiden Endpunkten bilden
02184         //
02185         DBG_ASSERT(aPoly.GetSize() == 2, "Sm : falsche Anzahl von Punkten");
02186         Point  aPointA, aPointB;
02187         if (GetToken().eType == TWIDESLASH)
02188         {
02189                 aPointA.X() = nBorderwidth;
02190                 aPointA.Y() = aToSize.Height() - nBorderwidth;
02191                 aPointB.X() = aToSize.Width() - nBorderwidth;
02192                 aPointB.Y() = nBorderwidth;
02193         }
02194         else
02195         {
02196                 DBG_ASSERT(GetToken().eType == TWIDEBACKSLASH, "Sm : unerwartetes Token");
02197                 aPointA.X() =
02198                 aPointA.Y() = nBorderwidth;
02199                 aPointB.X() = aToSize.Width() - nBorderwidth;
02200                 aPointB.Y() = aToSize.Height() - nBorderwidth;
02201         }
02202         aPoly.SetPoint(aPointA, 0);
02203         aPoly.SetPoint(aPointB, 1);
02204 
02205         long  nThick       = GetFont().GetSize().Height()
02206                                                         * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L;
02207         nWidth = nThick + 2 * nBorderwidth;
02208 
02209         SmRect::operator = (SmRect(aToSize.Width(), aToSize.Height()));
02210 }
02211 
02212 
02213 void SmPolyLineNode::Draw(OutputDevice &rDev, const Point &rPosition) const
02214 {
02215         if (IsPhantom())
02216                 return;
02217 
02218         long nBorderwidth = GetFont().GetBorderWidth();
02219 
02220         LineInfo  aInfo;
02221         aInfo.SetWidth(nWidth - 2 * nBorderwidth);
02222 
02223         Point aOffset (Point() - aPoly.GetBoundRect().TopLeft()
02224                                    + Point(nBorderwidth, nBorderwidth)),
02225                   aPos (rPosition + aOffset);
02226         ((Polygon &) aPoly).Move(aPos.X(), aPos.Y());
02227 
02228     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, FALSE);
02229     aTmpDev.SetLineColor( GetFont().GetColor() );
02230 
02231     rDev.DrawPolyLine(aPoly, aInfo);
02232 
02233 #ifdef SM_RECT_DEBUG
02234         if (!IsDebug())
02235                 return;
02236 
02237         int  nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
02238         SmRect::Draw(rDev, rPosition, nRFlags);
02239 #endif
02240 }
02241 
02242 
02243 /**************************************************************************/
02244 
02245 void SmRootSymbolNode::AdaptToX(const OutputDevice &/*rDev*/, ULONG nWidth)
02246 {
02247     nBodyWidth = nWidth;
02248 }
02249 
02250 
02251 void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, ULONG nHeight)
02252 {
02253     // etwas extra Laenge damit der horizontale Balken spaeter ueber dem
02254     // Argument positioniert ist
02255     SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / 10L);
02256 }
02257 
02258 
02259 void SmRootSymbolNode::Draw(OutputDevice &rDev, const Point &rPosition) const
02260 {
02261         if (IsPhantom())
02262                 return;
02263 
02264         // draw root-sign itself
02265     SmMathSymbolNode::Draw(rDev, rPosition);
02266 
02267     SmTmpDevice  aTmpDev( (OutputDevice &) rDev, TRUE );
02268     aTmpDev.SetFillColor(GetFont().GetColor());
02269     rDev.SetLineColor();
02270     aTmpDev.SetFont( GetFont() );
02271 
02272     // since the width is always unscaled it corresponds ot the _original_
02273     // _unscaled_ font height to be used, we use that to calculate the
02274     // bar height. Thus it is independent of the arguments height.
02275     // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
02276     long nBarHeight = GetWidth() * 7L / 100L;
02277     long nBarWidth = nBodyWidth + GetBorderWidth();
02278     Point aBarOffset( GetWidth(), +GetBorderWidth() );
02279     Point aBarPos( rPosition + aBarOffset );
02280 
02281     Rectangle  aBar(aBarPos, Size( nBarWidth, nBarHeight) );
02284     //  This is done by shifting it's output-position to a point that
02285     //  corresponds exactly to a pixel on the output device.
02286     Point  aDrawPos( rDev.PixelToLogic(rDev.LogicToPixel(aBar.TopLeft())) );
02287     //aDrawPos.X() = aBar.Left();     //! don't change X position
02288     aBar.SetPos( aDrawPos );
02289 
02290     rDev.DrawRect( aBar );
02291 
02292 #ifdef SM_RECT_DEBUG
02293         if (!IsDebug())
02294                 return;
02295 
02296         int  nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
02297         SmRect::Draw(rDev, rPosition, nRFlags);
02298 #endif
02299 }
02300 
02301 
02302 /**************************************************************************/
02303 
02304 
02305 void SmRectangleNode::AdaptToX(const OutputDevice &/*rDev*/, ULONG nWidth)
02306 {
02307         aToSize.Width() = nWidth;
02308 }
02309 
02310 
02311 void SmRectangleNode::AdaptToY(const OutputDevice &/*rDev*/, ULONG nHeight)
02312 {
02313         GetFont().FreezeBorderWidth();
02314         aToSize.Height() = nHeight;
02315 }
02316 
02317 
02318 void SmRectangleNode::Arrange(const OutputDevice &rDev, const SmFormat &/*rFormat*/)
02319 {
02320         long  nFontHeight = GetFont().GetSize().Height();
02321         long  nWidth  = aToSize.Width(),
02322                   nHeight = aToSize.Height();
02323         if (nHeight == 0)
02324                 nHeight = nFontHeight / 30;
02325         if (nWidth == 0)
02326                 nWidth  = nFontHeight / 3;
02327 
02328     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02329         aTmpDev.SetFont(GetFont());
02330 
02331         // add some borderspace
02332     ULONG  nTmpBorderWidth = GetFont().GetBorderWidth();
02333     //nWidth  += nTmpBorderWidth;
02334     nHeight += 2 * nTmpBorderWidth;
02335 
02338         SmRect::operator = (SmRect(nWidth, nHeight));
02339 }
02340 
02341 
02342 void SmRectangleNode::Draw(OutputDevice &rDev, const Point &rPosition) const
02343 {
02344         if (IsPhantom())
02345                 return;
02346 
02347     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, FALSE);
02348     aTmpDev.SetFillColor(GetFont().GetColor());
02349     rDev.SetLineColor();
02350     aTmpDev.SetFont(GetFont());
02351 
02352     ULONG  nTmpBorderWidth = GetFont().GetBorderWidth();
02353 
02354         // get rectangle and remove borderspace
02355         Rectangle  aTmp (AsRectangle() + rPosition - GetTopLeft());
02356     aTmp.Left()   += nTmpBorderWidth;
02357     aTmp.Right()  -= nTmpBorderWidth;
02358     aTmp.Top()    += nTmpBorderWidth;
02359     aTmp.Bottom() -= nTmpBorderWidth;
02360 
02361         DBG_ASSERT(aTmp.GetHeight() > 0  &&  aTmp.GetWidth() > 0,
02362                            "Sm: leeres Rechteck");
02363 
02366         //      This is done by shifting it's output-position to a point that
02367         //      corresponds exactly to a pixel on the output device.
02368     Point  aPos (rDev.PixelToLogic(rDev.LogicToPixel(aTmp.TopLeft())));
02369         aTmp.SetPos(aPos);
02370 
02371     rDev.DrawRect(aTmp);
02372 
02373 #ifdef SM_RECT_DEBUG
02374         if (!IsDebug())
02375                 return;
02376 
02377         int  nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
02378         SmRect::Draw(rDev, rPosition, nRFlags);
02379 #endif
02380 }
02381 
02382 
02383 /**************************************************************************/
02384 
02385 
02386 void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02387 {
02388         SmNode::Prepare(rFormat, rDocShell);
02389 
02390     // default setting for horizontal alignment of nodes with TTEXT
02391     // content is as alignl (cannot be done in Arrange since it would
02392     // override the settings made by an SmAlignNode before)
02393     if (TTEXT == GetToken().eType)
02394         SetRectHorAlign( RHA_LEFT );
02395 
02396     aText = GetToken().aText;
02397         GetFont() = rFormat.GetFont(GetFontDesc());
02398 
02399     if (IsItalic( GetFont() ))
02400                 Attributes() |= ATTR_ITALIC;
02401     if (IsBold( GetFont() ))
02402                 Attributes() |= ATTR_BOLD;
02403 
02404 };
02405 
02406 
02407 void SmTextNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02408 {
02409         PrepareAttributes();
02410 
02411         USHORT  nSizeDesc = GetFontDesc() == FNT_FUNCTION ?
02412                                                         SIZ_FUNCTION : SIZ_TEXT;
02413         GetFont() *= Fraction (rFormat.GetRelSize(nSizeDesc), 100);
02414 
02415     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02416         aTmpDev.SetFont(GetFont());
02417 
02418         SmRect::operator = (SmRect(aTmpDev, &rFormat, aText, GetFont().GetBorderWidth()));
02419 }
02420 
02421 void SmTextNode::CreateTextFromNode(String &rText)
02422 {
02423     BOOL bQuoted=FALSE;
02424         if (GetToken().eType == TTEXT)
02425     {
02426                 rText.Append('\"');
02427         bQuoted=TRUE;
02428     }
02429     else
02430     {
02431         SmParser aParseTest;
02432         SmNode *pTable = aParseTest.Parse(GetToken().aText);
02433         bQuoted=TRUE;
02434         if ( (pTable->GetType() == NTABLE) && (pTable->GetNumSubNodes() == 1) )
02435         {
02436             SmNode *pResult = pTable->GetSubNode(0);
02437             if ( (pResult->GetType() == NLINE) &&
02438                 (pResult->GetNumSubNodes() == 1) )
02439             {
02440                 pResult = pResult->GetSubNode(0);
02441                 if ( (pResult->GetType() == NEXPRESSION) &&
02442                     (pResult->GetNumSubNodes() == 1) )
02443                 {
02444                     pResult = pResult->GetSubNode(0);
02445                     if (pResult->GetType() == NTEXT)
02446                         bQuoted=FALSE;
02447                 }
02448             }
02449         }
02450         delete pTable;
02451 
02452         if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
02453         {
02454             //Search for existing functions and remove extraenous keyword
02455             APPEND(rText,"func ");
02456         }
02457         else if (bQuoted)
02458             APPEND(rText,"italic ");
02459 
02460         if (bQuoted)
02461             rText.Append('\"');
02462 
02463     }
02464 
02465         rText.Append(GetToken().aText);
02466 
02467         if (bQuoted)
02468                 rText.Append('\"');
02469         rText.Append(' ');
02470 }
02471 
02472 void SmTextNode::Draw(OutputDevice &rDev, const Point& rPosition) const
02473 {
02474         if (IsPhantom()  ||  aText.Len() == 0  ||  aText.GetChar(0) == xub_Unicode('\0'))
02475                 return;
02476 
02477     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, FALSE);
02478     aTmpDev.SetFont(GetFont());
02479 
02480     Point  aPos (rPosition);
02481         aPos.Y() += GetBaselineOffset();
02482         // auf Pixelkoordinaten runden
02483     aPos = rDev.PixelToLogic( rDev.LogicToPixel(aPos) );
02484 
02485     rDev.DrawStretchText(aPos, GetWidth(), aText);
02486 
02487 #ifdef SM_RECT_DEBUG
02488         if (!IsDebug())
02489                 return;
02490 
02491         int  nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
02492         SmRect::Draw(rDev, rPosition, nRFlags);
02493 #endif
02494 }
02495 
02496 void SmTextNode::GetAccessibleText( String &rText ) const
02497 {
02498     rText += aText;
02499 }
02500 
02501 /**************************************************************************/
02502 
02503 void SmMatrixNode::CreateTextFromNode(String &rText)
02504 {
02505         APPEND(rText,"matrix {");
02506     for (USHORT i = 0;  i < nNumRows; i++)
02507         {
02508         for (USHORT j = 0;  j < nNumCols; j++)
02509                 {
02510                         SmNode *pNode = GetSubNode(i * nNumCols + j);
02511                         pNode->CreateTextFromNode(rText);
02512                         if (j != nNumCols-1)
02513                                 APPEND(rText,"# ");
02514                 }
02515                 if (i != nNumRows-1)
02516                         APPEND(rText,"## ");
02517         }
02518         rText.EraseTrailingChars();
02519         APPEND(rText,"} ");
02520 }
02521 
02522 
02523 void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02524 {
02525         Point   aPosition,
02526                         aOffset;
02527         SmNode *pNode;
02528     USHORT  i, j;
02529 
02530         // initialize array that is to hold the maximum widhts of all
02531         // elements (subnodes) in that column.
02532         long *pColWidth = new long[nNumCols];
02533         for (j = 0;  j  < nNumCols;  j++)
02534                 pColWidth[j] = 0;
02535 
02536         // arrange subnodes and calculate the aboves arrays contents
02537     USHORT nNodes = GetNumSubNodes();
02538     for (i = 0;  i < nNodes;  i++)
02539     {
02540         USHORT nIdx = nNodes - 1 - i;
02541         if (NULL != (pNode = GetSubNode(nIdx)))
02542         {   
02543             pNode->Arrange(rDev, rFormat);
02544             int  nCol = nIdx % nNumCols;
02545             pColWidth[nCol] = Max(pColWidth[nCol], pNode->GetItalicWidth());
02546         }
02547     }
02548 
02549         // norm distance from which the following two are calcutated
02550         const int  nNormDist = 3 * GetFont().GetSize().Height();
02551 
02552         // define horizontal and vertical minimal distances that seperate
02553         // the elements
02554         long  nHorDist = nNormDist * rFormat.GetDistance(DIS_MATRIXCOL) / 100L,
02555                   nVerDist = nNormDist * rFormat.GetDistance(DIS_MATRIXROW) / 100L;
02556 
02557         // build array that holds the leftmost position for each column
02558         long *pColLeft = new long[nNumCols];
02559         long  nX = 0;
02560         for (j = 0;  j < nNumCols;      j++)
02561         {       pColLeft[j] = nX;
02562                 nX += pColWidth[j] + nHorDist;
02563         }
02564 
02565         Point   aPos, aDelta;
02566         SmRect  aLineRect;
02567         SmRect::operator = (SmRect());
02568         for (i = 0;  i < nNumRows;      i++)
02569         {       aLineRect = SmRect();
02570                 for (j = 0;  j < nNumCols;      j++)
02571         {   SmNode *pTmpNode = GetSubNode(i * nNumCols + j);
02572             DBG_ASSERT(pTmpNode, "Sm: NULL pointer");
02573 
02574             const SmRect &rNodeRect = pTmpNode->GetRect();
02575 
02576                         // align all baselines in that row if possible
02577                         aPos = rNodeRect.AlignTo(aLineRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
02578                         aPos.X() += nHorDist;
02579 
02580                         // get horizontal alignment
02581             const SmNode *pCoNode   = pTmpNode->GetLeftMost();
02582             RectHorAlign  eHorAlign = pCoNode->GetRectHorAlign();
02583 
02584                         // caculate horizontal position of element depending on column
02585                         // and horizontal alignment
02586                         switch (eHorAlign)
02587                         {       case RHA_LEFT:
02588                                         aPos.X() = rNodeRect.GetLeft() + pColLeft[j];
02589                                         break;
02590                                 case RHA_CENTER:
02591                                         aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
02592                                                            + pColWidth[j] / 2
02593                                                            - rNodeRect.GetItalicCenterX();
02594                                         break;
02595                                 case RHA_RIGHT:
02596                                         aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
02597                                                            + pColWidth[j] - rNodeRect.GetItalicWidth();
02598                                         break;
02599                         }
02600 
02601             pTmpNode->MoveTo(aPos);
02602                         aLineRect.ExtendBy(rNodeRect, RCP_XOR);
02603                 }
02604 
02605                 aPos = aLineRect.AlignTo(*this, RP_BOTTOM, RHA_CENTER, RVA_BASELINE);
02606                 aPos.Y() += nVerDist;
02607 
02608                 // move 'aLineRect' and rectangles in that line to final position
02609                 aDelta.X() = 0;         // since horizontal alignment is already done
02610                 aDelta.Y() = aPos.Y() - aLineRect.GetTop();
02611                 aLineRect.Move(aDelta);
02612                 for (j = 0;  j < nNumCols;      j++)
02613             if (NULL != (pNode = GetSubNode(i * nNumCols + j)))
02614                                 pNode->Move(aDelta);
02615 
02616                 ExtendBy(aLineRect, RCP_NONE);
02617         }
02618 
02619         delete [] pColLeft;
02620         delete [] pColWidth;
02621 }
02622 
02623 
02624 void SmMatrixNode::SetRowCol(USHORT nMatrixRows, USHORT nMatrixCols)
02625 {
02626         nNumRows = nMatrixRows;
02627         nNumCols = nMatrixCols;
02628 }
02629 
02630 
02631 SmNode * SmMatrixNode::GetLeftMost()
02632 {
02633         return this;
02634 }
02635 
02636 
02637 /**************************************************************************/
02638 
02639 
02640 SmMathSymbolNode::SmMathSymbolNode(const SmToken &rNodeToken)
02641 :       SmSpecialNode(NMATH, rNodeToken, FNT_MATH)
02642 {
02643         xub_Unicode cChar = GetToken().cMathChar;
02644         if ((xub_Unicode) '\0' != cChar)
02645                 SetText( cChar );
02646 }
02647 
02648 void SmMathSymbolNode::AdaptToX(const OutputDevice &rDev, ULONG nWidth)
02649 {
02650     // Since there is no function to do this, we try to approximate it:
02651     Size  aFntSize (GetFont().GetSize());
02652 
02654     aFntSize.Width() = nWidth;
02655     GetFont().SetSize(aFntSize);
02656 
02657     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02658     aTmpDev.SetFont(GetFont());
02659 
02660     // get denominator of error factor for width
02661     long nTmpBorderWidth = GetFont().GetBorderWidth();
02662     long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetItalicWidth();
02663 
02664     // scale fontwidth with this error factor
02665     aFntSize.Width() *= nWidth;
02666     aFntSize.Width() /= nDenom ? nDenom : 1;
02667 
02668     GetFont().SetSize(aFntSize);
02669 }
02670 
02671 void SmMathSymbolNode::AdaptToY(const OutputDevice &rDev, ULONG nHeight)
02672 {
02673     GetFont().FreezeBorderWidth();
02674     Size  aFntSize (GetFont().GetSize());
02675 
02676     // da wir nur die Hoehe skalieren wollen muesen wir hier ggf die Fontweite
02677     // ermitteln um diese beizubehalten.
02678     if (aFntSize.Width() == 0)
02679     {
02680         OutputDevice &rDevNC = (OutputDevice &) rDev;
02681         rDevNC.Push(PUSH_FONT | PUSH_MAPMODE);
02682         rDevNC.SetFont(GetFont());
02683         aFntSize.Width() = rDev.GetFontMetric().GetSize().Width();
02684         rDevNC.Pop();
02685     }
02686     DBG_ASSERT(aFntSize.Width() != 0, "Sm: ");
02687 
02690     aFntSize.Height() = nHeight;
02691     GetFont().SetSize(aFntSize);
02692 
02693     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02694     aTmpDev.SetFont(GetFont());
02695 
02696     // get denominator of error factor for height
02697     long nTmpBorderWidth = GetFont().GetBorderWidth();
02698     long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetHeight();
02699 
02700     // scale fontwidth with this error factor
02701     aFntSize.Height() *= nHeight;
02702     aFntSize.Height() /= nDenom ? nDenom : 1;
02703 
02704     GetFont().SetSize(aFntSize);
02705 }
02706 
02707 
02708 void SmMathSymbolNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02709 {
02710         SmNode::Prepare(rFormat, rDocShell);
02711 
02712     DBG_ASSERT(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL  ||
02713                GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
02714         "incorrect charset for character from StarMath/StarSymbol font");
02715 
02716         Flags() |= FLG_FONT | FLG_ITALIC;
02717 };
02718 
02719 
02720 void SmMathSymbolNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02721 {
02722         const XubString &rText = GetText();
02723 
02724         if (rText.Len() == 0  ||  rText.GetChar(0) == xub_Unicode('\0'))
02725         {       SmRect::operator = (SmRect());
02726                 return;
02727         }
02728 
02729         PrepareAttributes();
02730 
02731         GetFont() *= Fraction (rFormat.GetRelSize(SIZ_TEXT), 100);
02732 
02733     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02734         aTmpDev.SetFont(GetFont());
02735 
02736         SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
02737 }
02738 
02739 void SmMathSymbolNode::CreateTextFromNode(String &rText)
02740 {
02741         String sStr;
02742         MathType::LookupChar(GetToken().cMathChar, sStr);
02743         rText.Append(sStr);
02744 }
02745 
02746 void SmRectangleNode::CreateTextFromNode(String &rText)
02747 {
02748     switch (GetToken().eType)
02749     {
02750     case TUNDERLINE:
02751         APPEND(rText,"underline ");
02752         break;
02753     case TOVERLINE:
02754         APPEND(rText,"overline ");
02755         break;
02756     case TOVERSTRIKE:
02757         APPEND(rText,"overstrike ");
02758         break;
02759     default:
02760         break;
02761     }
02762 }
02763 
02764 void SmAttributNode::CreateTextFromNode(String &rText)
02765 {
02766         SmNode *pNode;
02767         USHORT  nSize = GetNumSubNodes();
02768     DBG_ASSERT(nSize == 2, "Node missing members");
02769     rText.Append('{');
02770     sal_Unicode nLast=0;
02771     if (NULL != (pNode = GetSubNode(0)))
02772     {
02773         String aStr;
02774         pNode->CreateTextFromNode(aStr);
02775         if (aStr.Len() > 1)
02776             rText.Append(aStr);
02777         else
02778         {
02779             nLast = aStr.GetChar(0);
02780             switch (nLast)
02781             {
02782             case 0xAF:
02783                 APPEND(rText,"overline ");
02784                 break;
02785             case 0x2d9:
02786                 APPEND(rText,"dot ");
02787                 break;
02788             case 0x2dc:
02789                 APPEND(rText,"widetilde ");
02790                 break;
02791             case 0xA8:
02792                 APPEND(rText,"ddot ");
02793                 break;
02794             case 0xE082:
02795                 break;
02796             case 0xE09B:
02797                 APPEND(rText,"dddot ");
02798                 break;
02799             default:
02800                 rText.Append(nLast);
02801                 break;
02802             }
02803         }
02804     }
02805 
02806         if (nSize == 2)
02807         if (NULL != (pNode = GetSubNode(1)))
02808                         pNode->CreateTextFromNode(rText);
02809 
02810         rText.EraseTrailingChars();
02811 
02812     if (nLast == 0xE082)
02813         APPEND(rText," overbrace {}");
02814 
02815         APPEND(rText,"} ");
02816 }
02817 
02818 /**************************************************************************/
02819 
02820 
02821 void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02822 {
02823         SmNode::Prepare(rFormat, rDocShell);
02824 
02825         const SmSym       *pSym;
02826         SmModule  *pp = SM_MOD1();
02827 
02828     if (NULL != (pSym = pp->GetSymSetManager().GetSymbolByName(GetToken().aText)))
02829     {
02830         SetText( pSym->GetCharacter() );
02831                 GetFont() = pSym->GetFace();
02832         }
02833         else
02834     {
02835         SetText( GetToken().aText );
02836                 GetFont() = rFormat.GetFont(FNT_VARIABLE);
02837         }
02838         // use same font size as is used for variables
02839         GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
02840 
02846     //
02848     if (IsItalic( GetFont() ))
02849         SetAttribut(ATTR_ITALIC);
02850     if (IsBold( GetFont() ))
02851                 SetAttribut(ATTR_BOLD);
02852 
02853         Flags() |= FLG_FONT;
02854 };
02855 
02856 
02857 void SmSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02858 {
02859         PrepareAttributes();
02860 
02861     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02862         aTmpDev.SetFont(GetFont());
02863 
02864         SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
02865 }
02866 
02867 
02868 void SmSpecialNode::Draw(OutputDevice &rDev, const Point& rPosition) const
02869 {
02872         ((SmSpecialNode *)this)->GetFont().SetAlign(ALIGN_BASELINE);
02873 
02874         SmTextNode::Draw(rDev, rPosition);
02875 }
02876 
02877 
02878 /**************************************************************************/
02879 
02880 
02881 void SmGlyphSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02882 {
02883         PrepareAttributes();
02884 
02885     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02886         aTmpDev.SetFont(GetFont());
02887 
02888         SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(),
02889                                                            GetFont().GetBorderWidth()).AsGlyphRect());
02890 }
02891 
02892 
02893 /**************************************************************************/
02894 
02895 
02896 void SmPlaceNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02897 {
02898         SmNode::Prepare(rFormat, rDocShell);
02899 
02900         GetFont().SetColor(COL_GRAY);
02901         Flags() |= FLG_COLOR | FLG_FONT | FLG_ITALIC;
02902 };
02903 
02904 
02905 void SmPlaceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02906 {
02907         PrepareAttributes();
02908 
02909     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02910         aTmpDev.SetFont(GetFont());
02911 
02912         SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
02913 }
02914 
02915 
02916 /**************************************************************************/
02917 
02918 
02919 void SmErrorNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02920 {
02921         SmNode::Prepare(rFormat, rDocShell);
02922 
02923         GetFont().SetColor(COL_RED);
02924         Flags() |= FLG_VISIBLE | FLG_BOLD | FLG_ITALIC
02925                            | FLG_COLOR | FLG_FONT | FLG_SIZE;
02926 }
02927 
02928 
02929 void SmErrorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02930 {
02931         PrepareAttributes();
02932 
02933     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02934         aTmpDev.SetFont(GetFont());
02935 
02936         const XubString &rText = GetText();
02937         SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
02938 }
02939 
02940 
02941 /**************************************************************************/
02942 
02943 
02944 void SmBlankNode::IncreaseBy(const SmToken &rToken)
02945 {
02946         switch(rToken.eType)
02947         {
02948                 case TBLANK:    nNum += 4;      break;
02949                 case TSBLANK:   nNum += 1;      break;
02950         default:
02951             break;
02952         }
02953 }
02954 
02955 
02956 void SmBlankNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
02957 {
02958         SmNode::Prepare(rFormat, rDocShell);
02959 
02963         GetFont() = rFormat.GetFont(FNT_VARIABLE);
02964 
02965         Flags() |= FLG_FONT | FLG_BOLD | FLG_ITALIC;
02966 }
02967 
02968 
02969 void SmBlankNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
02970 {
02971     SmTmpDevice  aTmpDev ((OutputDevice &) rDev, TRUE);
02972         aTmpDev.SetFont(GetFont());
02973 
02974     // Abstand von der Fonthoehe abhaengig machen
02975     // (damit er beim skalieren (zB size *2 {a ~ b}) mitwaechst)
02976         long  nDist  = GetFont().GetSize().Height() / 10L,
02977                   nSpace = nNum * nDist;
02978 
02979         // ein SmRect mit Baseline und allem drum und dran besorgen
02980         SmRect::operator = (SmRect(aTmpDev, &rFormat, XubString(xub_Unicode(' ')),
02981                                                            GetFont().GetBorderWidth()));
02982 
02983     // und dieses auf die gewuenschte Breite bringen
02984         SetItalicSpaces(0, 0);
02985         SetWidth(nSpace);
02986 }
02987 
02988 
02989 

Generated on Wed Feb 20 17:21:57 2008 for maths by  doxygen 1.5.1