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

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  OpenOffice.org - a multi-platform office productivity suite
00004  *
00005  *  $RCSfile: rect.cxx,v $
00006  *
00007  *  $Revision: 1.19 $
00008  *
00009  *  last change: $Author: vg $ $Date: 2007/05/25 12:14:35 $
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 
00040 #ifndef _STRING_HXX //autogen
00041 #include <tools/string.hxx>
00042 #endif
00043 #ifndef _TOOLS_DEBUG_HXX //autogen
00044 #include <tools/debug.hxx>
00045 #endif
00046 #ifndef _SV_SVAPP_HXX //autogen
00047 #include <vcl/svapp.hxx>
00048 #endif
00049 #ifndef _SV_WRKWIN_HXX //autogen
00050 #include <vcl/wrkwin.hxx>
00051 #endif
00052 #ifndef _SV_VIRDEV_HXX //autogen
00053 #include <vcl/virdev.hxx>
00054 #endif
00055 
00056 
00057 #include "rect.hxx"
00058 #include "types.hxx"
00059 #include "utility.hxx"
00060 #include "smmod.hxx"
00061 
00062 
00064 
00065 
00066 // '\0' terminiertes Array mit Zeichen, die im StarMath Font als Buchstaben
00067 // betrachtet werden sollen, (um im Gegensatz zu den anderen Operatoren
00068 // und Symbolen ein "normales"(ungecliptes) SmRect zu erhalten).
00069 static xub_Unicode __READONLY_DATA aMathAlpha[] =
00070 {
00071     MS_ALEPH,               MS_IM,                  MS_RE,
00072     MS_WP,                  xub_Unicode(0xE070),    MS_EMPTYSET,
00073     xub_Unicode(0x2113),    xub_Unicode(0xE0D6),    xub_Unicode(0x2107),
00074     xub_Unicode(0x2127),    xub_Unicode(0x210A),    MS_HBAR,
00075     MS_LAMBDABAR,           MS_SETN,                MS_SETZ,
00076     MS_SETQ,                MS_SETR,                MS_SETC,
00077     xub_Unicode(0x2373),    xub_Unicode(0xE0A5),    xub_Unicode(0x2112),
00078     xub_Unicode(0x2130),    xub_Unicode(0x2131),
00079         xub_Unicode('\0')
00080 };
00081 
00082 BOOL SmIsMathAlpha(const XubString &rText)
00083         // ergibt genau dann TRUE, wenn das Zeichen (aus dem StarMath Font) wie ein
00084         // Buchstabe behandelt werden soll.
00085 {
00086         if (rText.Len() == 0)
00087                 return FALSE;
00088 
00089     DBG_ASSERT(rText.Len() == 1, "Sm : String enthaelt nicht genau ein Zeichen");
00090         xub_Unicode cChar = rText.GetChar(0);
00091 
00092         // ist es ein griechisches Zeichen ?
00093     if (xub_Unicode(0xE0AC) <= cChar  &&  cChar <= xub_Unicode(0xE0D4))
00094                 return TRUE;
00095         else
00096         {
00097                 // kommt es in 'aMathAlpha' vor ?
00098                 const xub_Unicode *pChar = aMathAlpha;
00099                 while (*pChar  &&  *pChar != cChar)
00100                         pChar++;
00101                 return *pChar != xub_Unicode('\0');
00102         }
00103 }
00104 
00105 
00107 //
00108 // SmRect members
00109 //
00110 
00111 
00112 SmRect::SmRect()
00113         // constructs empty rectangle at (0, 0) with width and height 0.
00114 {
00115         DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: ooops...");
00116         DBG_ASSERT(aSize == Size(0, 0), "Sm: ooops...");
00117 
00118         bHasBaseline = bHasAlignInfo = FALSE;
00119         nBaseline = nAlignT = nAlignM = nAlignB =
00120         nGlyphTop = nGlyphBottom =
00121         nItalicLeftSpace = nItalicRightSpace =
00122         nLoAttrFence = nHiAttrFence = 0;
00123     nBorderWidth = 0;
00124 }
00125 
00126 
00127 SmRect::SmRect(const SmRect &rRect)
00128 :       aTopLeft(rRect.aTopLeft),
00129         aSize(rRect.aSize)
00130 {
00131         bHasBaseline  = rRect.bHasBaseline;
00132         nBaseline         = rRect.nBaseline;
00133         nAlignT           = rRect.nAlignT;
00134         nAlignM           = rRect.nAlignM;
00135         nAlignB           = rRect.nAlignB;
00136         nGlyphTop         = rRect.nGlyphTop;
00137         nGlyphBottom  = rRect.nGlyphBottom;
00138         nHiAttrFence  = rRect.nHiAttrFence;
00139         nLoAttrFence  = rRect.nLoAttrFence;
00140         bHasAlignInfo = rRect.bHasAlignInfo;
00141         nItalicLeftSpace  = rRect.nItalicLeftSpace;
00142         nItalicRightSpace = rRect.nItalicRightSpace;
00143     nBorderWidth  = rRect.nBorderWidth;
00144 }
00145 
00146 
00147 void SmRect::CopyAlignInfo(const SmRect &rRect)
00148 {
00149         nBaseline         = rRect.nBaseline;
00150         bHasBaseline  = rRect.bHasBaseline;
00151         nAlignT           =     rRect.nAlignT;
00152         nAlignM           =     rRect.nAlignM;
00153         nAlignB           =     rRect.nAlignB;
00154         bHasAlignInfo = rRect.bHasAlignInfo;
00155         nLoAttrFence  = rRect.nLoAttrFence;
00156         nHiAttrFence  = rRect.nHiAttrFence;
00157 }
00158 
00159 
00160 void SmRect::BuildRect(const OutputDevice &rDev, const SmFormat *pFormat,
00161                        const XubString &rText, USHORT nBorder)
00162 {
00163 #ifndef PRODUCT
00164         if (rDev.GetOutDevType() != OUTDEV_PRINTER)
00165                 DBG_WARNING("Sm :  Referenz-Device ist kein Drucker");
00166 #endif
00167 
00168         DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: Ooops...");
00169 
00170         aSize = Size(rDev.GetTextWidth(rText), rDev.GetTextHeight());
00171 
00172         const FontMetric  aFM (rDev.GetFontMetric());
00173     BOOL              bIsMath  = aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH ) ||
00174                                  aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH2 );
00175         BOOL                      bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
00176         const long                nFontHeight = rDev.GetFont().GetSize().Height();
00177 
00178     nBorderWidth  = nBorder;
00179         bHasAlignInfo = TRUE;
00180         bHasBaseline  = TRUE;
00181         nBaseline         = aFM.GetAscent();
00182         nAlignT           = nBaseline - nFontHeight * 750L / 1000L;
00183         nAlignM           = nBaseline - nFontHeight * 121L / 422L;
00184                 // that's where the horizontal bars of '+', '-', ... are
00185                 // (1/3 of ascent over baseline)
00186                 // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
00187         nAlignB           = nBaseline;
00188 
00189         // workaround for printer fonts with very small (possible 0 or even
00190         // negative(!)) leading
00191         if (aFM.GetIntLeading() < 5  &&  rDev.GetOutDevType() == OUTDEV_PRINTER)
00192         {
00193                 OutputDevice    *pWindow = Application::GetDefaultDevice();
00194 
00195                 pWindow->Push(PUSH_MAPMODE | PUSH_FONT);
00196 
00197                 pWindow->SetMapMode(rDev.GetMapMode());
00198                 pWindow->SetFont(rDev.GetFontMetric());
00199 
00200                 long  nDelta = pWindow->GetFontMetric().GetIntLeading();
00201                 if (nDelta == 0)
00202                 {       // dieser Wert entspricht etwa einem Leading von 80 bei einer
00203             // Fonthoehe von 422 (12pt)
00204                         nDelta = nFontHeight * 8L / 43;
00205                 }
00206                 SetTop(GetTop() - nDelta);
00207 
00208                 pWindow->Pop();
00209         }
00210 
00211         // get GlyphBoundRect
00212         Rectangle  aGlyphRect;
00213 #if OSL_DEBUG_LEVEL > 1
00214     BOOL bSuccess =
00215 #endif
00216                 SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
00217 #if OSL_DEBUG_LEVEL > 1
00218     if (!bSuccess)
00219     {
00220         DBG_ERROR( "Sm : Ooops... (fehlt evtl. der Font?)");
00221     }
00222 #endif
00223 
00224         nItalicLeftSpace  = GetLeft() - aGlyphRect.Left() + nBorderWidth;
00225         nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
00226         if (nItalicLeftSpace  < 0  &&  !bAllowSmaller)
00227                 nItalicLeftSpace  = 0;
00228         if (nItalicRightSpace < 0  &&  !bAllowSmaller)
00229                 nItalicRightSpace = 0;
00230 
00231         long  nDist = 0;
00232         if (pFormat)
00233                 nDist = (rDev.GetFont().GetSize().Height()
00234                                 * pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100L;
00235 
00236         nHiAttrFence = aGlyphRect.TopLeft().Y() - 1 - nBorderWidth - nDist;
00237         nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);
00238 
00239         nGlyphTop    = aGlyphRect.Top() - nBorderWidth;
00240         nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;
00241 
00242         if (bAllowSmaller)
00243         {
00244         // fuer Symbole und Operatoren aus dem StarMath Font passen wir den
00245                 // oberen und unteren Rand dem Zeichen an.
00246                 SetTop(nGlyphTop);
00247                 SetBottom(nGlyphBottom);
00248         }
00249 
00250         if (nHiAttrFence < GetTop())
00251                 nHiAttrFence = GetTop();
00252 
00253         if (nLoAttrFence > GetBottom())
00254                 nLoAttrFence = GetBottom();
00255 
00256         DBG_ASSERT(rText.Len() == 0  ||  !IsEmpty(),
00257                            "Sm: leeres Rechteck erzeugt");
00258 }
00259 
00260 
00261 void SmRect::Init(const OutputDevice &rDev, const SmFormat *pFormat,
00262                   const XubString &rText, USHORT nEBorderWidth)
00263         // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
00264 {
00265     BuildRect(rDev, pFormat, rText, nEBorderWidth);
00266 }
00267 
00268 
00269 SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
00270                const XubString &rText, long nEBorderWidth)
00271 {
00272     DBG_ASSERT( nEBorderWidth >= 0, "BorderWidth negativ" );
00273     if (nEBorderWidth < 0)
00274         nEBorderWidth = 0;
00275     Init(rDev, pFormat, rText, (USHORT) nEBorderWidth);
00276 }
00277 
00278 
00279 SmRect::SmRect(long nWidth, long nHeight)
00280         // this constructor should never be used for anything textlike because
00281         // it will not provide useful values for baseline, AlignT and AlignB!
00282         // It's purpose is to get a 'SmRect' for the horizontal line in fractions
00283         // as used in 'SmBinVerNode'.
00284 :       aSize(nWidth, nHeight)
00285 {
00286         DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: ooops...");
00287 
00288         bHasBaseline  = FALSE;
00289         bHasAlignInfo = TRUE;
00290         nBaseline         = 0;
00291         nAlignT           = GetTop();
00292         nAlignB           = GetBottom();
00293         nAlignM           = (nAlignT + nAlignB) / 2;            // this is the default
00294         nItalicLeftSpace = nItalicRightSpace = 0;
00295         nGlyphTop    = nHiAttrFence  = GetTop();
00296         nGlyphBottom = nLoAttrFence  = GetBottom();
00297     nBorderWidth  = 0;
00298 }
00299 
00300 
00301 void SmRect::SetLeft(long nLeft)
00302 {
00303         if (nLeft <= GetRight())
00304         {       aSize.Width() = GetRight() - nLeft + 1;
00305                 aTopLeft.X()  = nLeft;
00306         }
00307 }
00308 
00309 
00310 void SmRect::SetRight(long nRight)
00311 {
00312         if (nRight >= GetLeft())
00313                 aSize.Width() = nRight - GetLeft() + 1;
00314 }
00315 
00316 
00317 void SmRect::SetBottom(long nBottom)
00318 {
00319         if (nBottom >= GetTop())
00320                 aSize.Height() = nBottom - GetTop() + 1;
00321 }
00322 
00323 
00324 void SmRect::SetTop(long nTop)
00325 {
00326         if (nTop <= GetBottom())
00327         {       aSize.Height()   = GetBottom() - nTop + 1;
00328                 aTopLeft.Y() = nTop;
00329         }
00330 }
00331 
00332 
00333 void SmRect::Move(const Point &rPosition)
00334         // move rectangle by position 'rPosition'.
00335 {
00336         aTopLeft  += rPosition;
00337 
00338         long  nDelta = rPosition.Y();
00339         nBaseline += nDelta;
00340         nAlignT   += nDelta;
00341         nAlignM   += nDelta;
00342         nAlignB   += nDelta;
00343         nGlyphTop    += nDelta;
00344         nGlyphBottom += nDelta;
00345         nHiAttrFence += nDelta;
00346         nLoAttrFence += nDelta;
00347 }
00348 
00349 
00350 const Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
00351                                                         RectHorAlign eHor, RectVerAlign eVer) const
00352 {       Point  aPos (GetTopLeft());
00353                 // will become the topleft point of the new rectangle position
00354 
00355         // set horizontal or vertical new rectangle position depending on
00356         // 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
00357         switch (ePos)
00358         {       case RP_LEFT :
00359                         aPos.X() = rRect.GetItalicLeft() - GetItalicRightSpace()
00360                                            - GetWidth();
00361                         break;
00362                 case RP_RIGHT :
00363                         aPos.X() = rRect.GetItalicRight() + 1 + GetItalicLeftSpace();
00364                         break;
00365                 case RP_TOP :
00366                         aPos.Y() = rRect.GetTop() - GetHeight();
00367                         break;
00368                 case RP_BOTTOM :
00369                         aPos.Y() = rRect.GetBottom() + 1;
00370                         break;
00371                 case RP_ATTRIBUT :
00372                         aPos.X() = rRect.GetItalicCenterX() - GetItalicWidth() / 2
00373                                            + GetItalicLeftSpace();
00374                         break;
00375                 default :
00376                         DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
00377         }
00378 
00379         // check if horizontal position is already set
00380         if (ePos == RP_LEFT  ||  ePos == RP_RIGHT  ||  ePos == RP_ATTRIBUT)
00381                 // correct error in current vertical position
00382                 switch (eVer)
00383                 {       case RVA_TOP :
00384                                 aPos.Y() += rRect.GetAlignT() - GetAlignT();
00385                                 break;
00386                         case RVA_MID :
00387                                 aPos.Y() += rRect.GetAlignM() - GetAlignM();
00388                                 break;
00389                         case RVA_BASELINE :
00390                                 // align baselines if possible else align mid's
00391                                 if (HasBaseline() && rRect.HasBaseline())
00392                                         aPos.Y() += rRect.GetBaseline() - GetBaseline();
00393                                 else
00394                                         aPos.Y() += rRect.GetAlignM() - GetAlignM();
00395                                 break;
00396                         case RVA_BOTTOM :
00397                                 aPos.Y() += rRect.GetAlignB() - GetAlignB();
00398                                 break;
00399                         case RVA_CENTERY :
00400                                 aPos.Y() += rRect.GetCenterY() - GetCenterY();
00401                                 break;
00402                         case RVA_ATTRIBUT_HI:
00403                                 aPos.Y() += rRect.GetHiAttrFence() - GetBottom();
00404                                 break;
00405                         case RVA_ATTRIBUT_MID :
00406                                 aPos.Y() += SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
00407                                                         - GetCenterY();
00408                                 break;
00409                         case RVA_ATTRIBUT_LO :
00410                                 aPos.Y() += rRect.GetLoAttrFence() - GetTop();
00411                                 break;
00412                 default :
00413                                 DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
00414                 }
00415 
00416         // check if vertical position is already set
00417         if (ePos == RP_TOP      ||      ePos == RP_BOTTOM)
00418                 // correct error in current horizontal position
00419                 switch (eHor)
00420                 {       case RHA_LEFT :
00421                                 aPos.X() += rRect.GetItalicLeft() - GetItalicLeft();
00422                                 break;
00423                         case RHA_CENTER :
00424                                 aPos.X() += rRect.GetItalicCenterX() - GetItalicCenterX();
00425                                 break;
00426                         case RHA_RIGHT :
00427                                 aPos.X() += rRect.GetItalicRight() - GetItalicRight();
00428                                 break;
00429                         default :
00430                                 DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
00431                 }
00432 
00433         return aPos;
00434 }
00435 
00436 
00437 SmRect & SmRect::Union(const SmRect &rRect)
00438         // rectangle union of current one with 'rRect'. The result is to be the
00439         // smallest rectangles that covers the space of both rectangles.
00440         // (empty rectangles cover no space)
00442 {
00443         if (rRect.IsEmpty())
00444                 return *this;
00445 
00446         long  nL  = rRect.GetLeft(),
00447                   nR  = rRect.GetRight(),
00448                   nT  = rRect.GetTop(),
00449                   nB  = rRect.GetBottom(),
00450                   nGT = rRect.nGlyphTop,
00451                   nGB = rRect.nGlyphBottom;
00452         if (!IsEmpty())
00453         {       long  nTmp;
00454 
00455                 if ((nTmp = GetLeft()) < nL)
00456                         nL = nTmp;
00457                 if ((nTmp = GetRight()) > nR)
00458                         nR = nTmp;
00459                 if ((nTmp = GetTop()) < nT)
00460                         nT = nTmp;
00461                 if ((nTmp = GetBottom()) > nB)
00462                         nB = nTmp;
00463                 if ((nTmp = nGlyphTop) < nGT)
00464                         nGT = nTmp;
00465                 if ((nTmp = nGlyphBottom) > nGB)
00466                         nGB = nTmp;
00467         }
00468 
00469         SetLeft(nL);
00470         SetRight(nR);
00471         SetTop(nT);
00472         SetBottom(nB);
00473         nGlyphTop    = nGT;
00474         nGlyphBottom = nGB;
00475 
00476         return *this;
00477 }
00478 
00479 
00480 SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode)
00481         // let current rectangle be the union of itself and 'rRect'
00482         // (the smallest rectangle surrounding both). Also adapt values for
00483         // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
00484         // The baseline is set according to 'eCopyMode'.
00485         // If one of the rectangles has no relevant info the other one is copied.
00486 {
00487         // get some values used for (italic) spaces adaption
00488         // ! (need to be done before changing current SmRect) !
00489         long  nL = Min(GetItalicLeft(),  rRect.GetItalicLeft()),
00490                   nR = Max(GetItalicRight(), rRect.GetItalicRight());
00491 
00492         Union(rRect);
00493 
00494         SetItalicSpaces(GetLeft() - nL, nR - GetRight());
00495 
00496         if (!HasAlignInfo())
00497                 CopyAlignInfo(rRect);
00498         else if (rRect.HasAlignInfo())
00499         {       nAlignT = Min(GetAlignT(), rRect.GetAlignT());
00500                 nAlignB = Max(GetAlignB(), rRect.GetAlignB());
00501                 nHiAttrFence = Min(GetHiAttrFence(), rRect.GetHiAttrFence());
00502                 nLoAttrFence = Max(GetLoAttrFence(), rRect.GetLoAttrFence());
00503                 DBG_ASSERT(HasAlignInfo(), "Sm: ooops...");
00504 
00505                 switch (eCopyMode)
00506                 {       case RCP_THIS:
00507                                 // already done
00508                                 break;
00509                         case RCP_ARG:
00510                                 CopyMBL(rRect);
00511                                 break;
00512                         case RCP_NONE:
00513                                 ClearBaseline();
00514                                 nAlignM = (nAlignT + nAlignB) / 2;
00515                                 break;
00516                         case RCP_XOR:
00517                                 if (!HasBaseline())
00518                                         CopyMBL(rRect);
00519                                 break;
00520                         default :
00521                                 DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
00522                 }
00523         }
00524 
00525         return *this;
00526 }
00527 
00528 
00529 SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
00530                                                   long nNewAlignM)
00531         // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
00532         // (this version will be used in 'SmBinVerNode' to provide means to
00533         // align eg "{a over b} over c" correctly where AlignM should not
00534         // be (AlignT + AlignB) / 2)
00535 {
00536         DBG_ASSERT(HasAlignInfo(), "Sm: keine Align Info");
00537 
00538         ExtendBy(rRect, eCopyMode);
00539         nAlignM = nNewAlignM;
00540 
00541         return *this;
00542 }
00543 
00544 
00545 SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
00546                                                   BOOL bKeepVerAlignParams)
00547         // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
00548         // baseline.
00549         // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
00550         // be allowed to modify these values.)
00551 {
00552         long  nOldAlignT   = GetAlignT(),
00553                   nOldAlignM   = GetAlignM(),
00554                   nOldAlignB   = GetAlignB(),
00555                   nOldBaseline = nBaseline;             
00556         BOOL  bOldHasAlignInfo = HasAlignInfo();
00557 
00558         ExtendBy(rRect, eCopyMode);
00559 
00560         if (bKeepVerAlignParams)
00561         {       nAlignT   = nOldAlignT;
00562                 nAlignM   = nOldAlignM;
00563                 nAlignB   = nOldAlignB;
00564                 nBaseline = nOldBaseline;
00565                 bHasAlignInfo = bOldHasAlignInfo;
00566         }
00567 
00568         return *this;
00569 }
00570 
00571 
00572 long SmRect::OrientedDist(const Point &rPoint) const
00573         // return oriented distance of rPoint to the current rectangle,
00574         // especially the return value is <= 0 iff the point is inside the
00575         // rectangle.
00576         // For simplicity the maximum-norm is used.
00577 {
00578         BOOL  bIsInside = IsInsideItalicRect(rPoint);
00579 
00580         // build reference point to define the distance
00581         Point  aRef;
00582         if (bIsInside)
00583         {       Point  aIC (GetItalicCenterX(), GetCenterY());
00584 
00585                 aRef.X() = rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft();
00586                 aRef.Y() = rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop();
00587         }
00588         else
00589         {
00590                 // x-coordinate
00591                 if (rPoint.X() > GetItalicRight())
00592                         aRef.X() = GetItalicRight();
00593                 else if (rPoint.X() < GetItalicLeft())
00594                         aRef.X() = GetItalicLeft();
00595                 else
00596                         aRef.X() = rPoint.X();
00597                 // y-coordinate
00598                 if (rPoint.Y() > GetBottom())
00599                         aRef.Y() = GetBottom();
00600                 else if (rPoint.Y() < GetTop())
00601                         aRef.Y() = GetTop();
00602                 else
00603                         aRef.Y() = rPoint.Y();
00604         }
00605 
00606         // build distance vector
00607         Point  aDist (aRef - rPoint);
00608 
00609         long nAbsX = labs(aDist.X()),
00610                  nAbsY = labs(aDist.Y());
00611 
00612         return bIsInside ? - Min(nAbsX, nAbsY) : Max (nAbsX, nAbsY);
00613 }
00614 
00615 
00616 BOOL SmRect::IsInsideRect(const Point &rPoint) const
00617 {
00618         return     rPoint.Y() >= GetTop()
00619                    &&  rPoint.Y() <= GetBottom()
00620                    &&  rPoint.X() >= GetLeft()
00621                    &&  rPoint.X() <= GetRight();
00622 }
00623 
00624 
00625 BOOL SmRect::IsInsideItalicRect(const Point &rPoint) const
00626 {
00627         return     rPoint.Y() >= GetTop()
00628                    &&  rPoint.Y() <= GetBottom()
00629                    &&  rPoint.X() >= GetItalicLeft()
00630                    &&  rPoint.X() <= GetItalicRight();
00631 }
00632 
00633 SmRect SmRect::AsGlyphRect() const
00634 {
00635         SmRect aRect (*this);
00636         aRect.SetTop(nGlyphTop);
00637         aRect.SetBottom(nGlyphBottom);
00638         return aRect;
00639 }
00640 
00641 
00642 // forward declaration
00643 void SmDrawFrame(OutputDevice &rDev, const Rectangle &rRec,
00644                                  const Color aCol = COL_BLACK);
00645 
00646 void SmRect::Draw(OutputDevice &rDev, const Point &rPosition, int nFlags) const
00647 {
00648         if (IsEmpty())
00649                 return;
00650 
00651         rDev.Push(PUSH_LINECOLOR);
00652 
00653         if (nFlags & SM_RECT_LINES)
00654         {       long   nLeftSpace  = 0,
00655                            nRightSpace = 0;
00656 
00657                 if (nFlags & SM_RECT_ITALIC)
00658                 {       nLeftSpace      = GetItalicLeftSpace();
00659                         nRightSpace = GetItalicRightSpace();
00660                 }
00661 
00662                 long  nLeft  = GetLeft()  - nLeftSpace,
00663                           nRight = GetRight() + nRightSpace;
00664 
00665                 Point aOffset (rPosition - GetTopLeft());
00666 
00667                 rDev.SetLineColor(COL_LIGHTBLUE);
00668                 rDev.DrawLine(Point(nLeft,      GetAlignB()) += aOffset,
00669                                           Point(nRight, GetAlignB()) += aOffset);
00670                 rDev.DrawLine(Point(nLeft,      GetAlignT()) += aOffset,
00671                                           Point(nRight, GetAlignT()) += aOffset);
00672                 if (HasBaseline())
00673                         rDev.DrawLine(Point(nLeft,      GetBaseline()) += aOffset,
00674                                                   Point(nRight, GetBaseline()) += aOffset);
00675 
00676                 rDev.SetLineColor(COL_GRAY);
00677                 rDev.DrawLine(Point(nLeft,      GetHiAttrFence()) += aOffset,
00678                                           Point(nRight, GetHiAttrFence()) += aOffset);
00679         }
00680 
00681         if (nFlags & SM_RECT_MID)
00682         {       Point   aCenter = rPosition
00683                                                   + (Point(GetItalicCenterX(), GetAlignM()) -= GetTopLeft()),
00684                                 aLenX     (GetWidth() / 5, 0),
00685                                 aLenY     (0, GetHeight() / 16);
00686 
00687                 rDev.SetLineColor(COL_LIGHTGREEN);
00688                 rDev.DrawLine(aCenter - aLenX, aCenter + aLenX);
00689                 rDev.DrawLine(aCenter - aLenY, aCenter + aLenY);
00690         }
00691 
00692         if (nFlags & SM_RECT_ITALIC)
00693                 SmDrawFrame(rDev, Rectangle(rPosition - Point(GetItalicLeftSpace(), 0),
00694                                 GetItalicSize()));
00695 
00696         if (nFlags & SM_RECT_CORE)
00697                 SmDrawFrame(rDev, Rectangle(rPosition, GetSize()), COL_LIGHTRED);
00698 
00699         rDev.Pop();
00700 }
00701 
00702 
00703 
00705 // misc functions
00706 //
00707 
00708 
00709 void SmDrawFrame(OutputDevice &rDev, const Rectangle &rRec,
00710                                  const Color aCol)
00711 {
00712         rDev.Push(PUSH_LINECOLOR);
00713 
00714         rDev.SetLineColor(aCol);
00715 
00716         rDev.DrawLine(rRec.TopLeft(),     rRec.BottomLeft());
00717         rDev.DrawLine(rRec.BottomLeft(),  rRec.BottomRight());
00718         rDev.DrawLine(rRec.BottomRight(), rRec.TopRight());
00719         rDev.DrawLine(rRec.TopRight(),    rRec.TopLeft());
00720 
00721         rDev.Pop();
00722 }
00723 
00724 
00725 BOOL SmGetGlyphBoundRect(const OutputDevice &rDev,
00726                                                  const XubString &rText, Rectangle &rRect)
00727     // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
00728         // but with a string as argument.
00729 {
00730         // handle special case first
00731         xub_StrLen nLen = rText.Len();
00732         if (nLen == 0)
00733         {       rRect.SetEmpty();
00734                 return TRUE;
00735         }
00736 
00737     // get a device where 'OutputDevice::GetTextBoundRect' will be successful
00738         OutputDevice *pGlyphDev;
00739         if (rDev.GetOutDevType() != OUTDEV_PRINTER)
00740                 pGlyphDev = (OutputDevice *) &rDev;
00741         else
00742         {
00743         // since we format for the printer (where GetTextBoundRect will fail)
00744                 // we need a virtual device here.
00745         pGlyphDev = &SM_MOD1()->GetDefaultVirtualDev();
00746         }
00747 
00748         const FontMetric  aDevFM (rDev.GetFontMetric());
00749 
00750     pGlyphDev->Push(PUSH_FONT | PUSH_MAPMODE);
00751     Font aFnt(rDev.GetFont());
00752     aFnt.SetAlign(ALIGN_TOP);
00753 
00754     // use scale factor when calling GetTextBoundRect to counter
00755     // negative effects from antialiasing which may otherwise result
00756     // in significant incorrect bounding rectangles for some charcters.
00757         Size aFntSize = aFnt.GetSize();
00758 
00759     // HDU: workaround to avoid HUGE font sizes and resulting problems (#112783#)
00760     long nScaleFactor = 1;
00761     while( aFntSize.Height() > 2000 * nScaleFactor )
00762         nScaleFactor *= 2;
00763     
00764     aFnt.SetSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
00765         pGlyphDev->SetFont(aFnt);
00766 
00767     long nTextWidth = rDev.GetTextWidth(rText);
00768     Point aPoint;
00769     Rectangle   aResult (aPoint, Size(nTextWidth, rDev.GetTextHeight())),
00770                                 aTmp;
00771 
00772     BOOL bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText, 0, 0);
00773     DBG_ASSERT( bSuccess, "GetTextBoundRect failed" );
00774 
00775 
00776     if (!aTmp.IsEmpty())
00777     {
00778         aResult = Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
00779                             aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
00780         if (&rDev != pGlyphDev) /* only when rDev is a printer... */
00781         {
00782             long nGDTextWidth  = pGlyphDev->GetTextWidth(rText);
00783             if (nGDTextWidth != 0  &&
00784                 nTextWidth != nGDTextWidth)
00785             {
00786                 aResult.Right() *= nTextWidth;
00787                 aResult.Right() /= nGDTextWidth * nScaleFactor;
00788             }
00789         }
00790     }
00791 
00792         // move rectangle to match possibly different baselines
00793         // (because of different devices)
00794     long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
00795         aResult.Move(0, nDelta);
00796 
00797         pGlyphDev->Pop();
00798 
00799     rRect = aResult;
00800         return bSuccess;
00801 }
00802 
00803 

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