00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
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
00067
00068
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
00084
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
00093 if (xub_Unicode(0xE0AC) <= cChar && cChar <= xub_Unicode(0xE0D4))
00094 return TRUE;
00095 else
00096 {
00097
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
00109
00110
00111
00112 SmRect::SmRect()
00113
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
00185
00186
00187 nAlignB = nBaseline;
00188
00189
00190
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 {
00203
00204 nDelta = nFontHeight * 8L / 43;
00205 }
00206 SetTop(GetTop() - nDelta);
00207
00208 pWindow->Pop();
00209 }
00210
00211
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
00245
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
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
00281
00282
00283
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;
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
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
00354
00355
00356
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
00380 if (ePos == RP_LEFT || ePos == RP_RIGHT || ePos == RP_ATTRIBUT)
00381
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
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
00417 if (ePos == RP_TOP || ePos == RP_BOTTOM)
00418
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
00439
00440
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
00482
00483
00484
00485
00486 {
00487
00488
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
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
00532
00533
00534
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
00548
00549
00550
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
00574
00575
00576
00577 {
00578 BOOL bIsInside = IsInsideItalicRect(rPoint);
00579
00580
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
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
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
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
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
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
00728
00729 {
00730
00731 xub_StrLen nLen = rText.Len();
00732 if (nLen == 0)
00733 { rRect.SetEmpty();
00734 return TRUE;
00735 }
00736
00737
00738 OutputDevice *pGlyphDev;
00739 if (rDev.GetOutDevType() != OUTDEV_PRINTER)
00740 pGlyphDev = (OutputDevice *) &rDev;
00741 else
00742 {
00743
00744
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
00755
00756
00757 Size aFntSize = aFnt.GetSize();
00758
00759
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)
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
00793
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