1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rect.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_starmath.hxx"
35 #include <tools/string.hxx>
36 #include <tools/debug.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/wrkwin.hxx>
39 #include <vcl/virdev.hxx>
44 #include "utility.hxx"
48 ////////////////////////////////////////////////////////////////////////////////
51 // '\0' terminiertes Array mit Zeichen, die im StarMath Font als Buchstaben
52 // betrachtet werden sollen, (um im Gegensatz zu den anderen Operatoren
53 // und Symbolen ein "normales"(ungecliptes) SmRect zu erhalten).
54 static xub_Unicode __READONLY_DATA aMathAlpha
[] =
56 MS_ALEPH
, MS_IM
, MS_RE
,
57 MS_WP
, xub_Unicode(0xE070), MS_EMPTYSET
,
58 xub_Unicode(0x2113), xub_Unicode(0xE0D6), xub_Unicode(0x2107),
59 xub_Unicode(0x2127), xub_Unicode(0x210A), MS_HBAR
,
60 MS_LAMBDABAR
, MS_SETN
, MS_SETZ
,
61 MS_SETQ
, MS_SETR
, MS_SETC
,
62 xub_Unicode(0x2373), xub_Unicode(0xE0A5), xub_Unicode(0x2112),
63 xub_Unicode(0x2130), xub_Unicode(0x2131),
67 BOOL
SmIsMathAlpha(const XubString
&rText
)
68 // ergibt genau dann TRUE, wenn das Zeichen (aus dem StarMath Font) wie ein
69 // Buchstabe behandelt werden soll.
74 DBG_ASSERT(rText
.Len() == 1, "Sm : String enthaelt nicht genau ein Zeichen");
75 xub_Unicode cChar
= rText
.GetChar(0);
77 // ist es ein griechisches Zeichen ?
78 if (xub_Unicode(0xE0AC) <= cChar
&& cChar
<= xub_Unicode(0xE0D4))
82 // kommt es in 'aMathAlpha' vor ?
83 const xub_Unicode
*pChar
= aMathAlpha
;
84 while (*pChar
&& *pChar
!= cChar
)
86 return *pChar
!= xub_Unicode('\0');
91 ////////////////////////////////////////
98 // constructs empty rectangle at (0, 0) with width and height 0.
100 DBG_ASSERT(aTopLeft
== Point(0, 0), "Sm: ooops...");
101 DBG_ASSERT(aSize
== Size(0, 0), "Sm: ooops...");
103 bHasBaseline
= bHasAlignInfo
= FALSE
;
104 nBaseline
= nAlignT
= nAlignM
= nAlignB
=
105 nGlyphTop
= nGlyphBottom
=
106 nItalicLeftSpace
= nItalicRightSpace
=
107 nLoAttrFence
= nHiAttrFence
= 0;
112 SmRect::SmRect(const SmRect
&rRect
)
113 : aTopLeft(rRect
.aTopLeft
),
116 bHasBaseline
= rRect
.bHasBaseline
;
117 nBaseline
= rRect
.nBaseline
;
118 nAlignT
= rRect
.nAlignT
;
119 nAlignM
= rRect
.nAlignM
;
120 nAlignB
= rRect
.nAlignB
;
121 nGlyphTop
= rRect
.nGlyphTop
;
122 nGlyphBottom
= rRect
.nGlyphBottom
;
123 nHiAttrFence
= rRect
.nHiAttrFence
;
124 nLoAttrFence
= rRect
.nLoAttrFence
;
125 bHasAlignInfo
= rRect
.bHasAlignInfo
;
126 nItalicLeftSpace
= rRect
.nItalicLeftSpace
;
127 nItalicRightSpace
= rRect
.nItalicRightSpace
;
128 nBorderWidth
= rRect
.nBorderWidth
;
132 void SmRect::CopyAlignInfo(const SmRect
&rRect
)
134 nBaseline
= rRect
.nBaseline
;
135 bHasBaseline
= rRect
.bHasBaseline
;
136 nAlignT
= rRect
.nAlignT
;
137 nAlignM
= rRect
.nAlignM
;
138 nAlignB
= rRect
.nAlignB
;
139 bHasAlignInfo
= rRect
.bHasAlignInfo
;
140 nLoAttrFence
= rRect
.nLoAttrFence
;
141 nHiAttrFence
= rRect
.nHiAttrFence
;
145 void SmRect::BuildRect(const OutputDevice
&rDev
, const SmFormat
*pFormat
,
146 const XubString
&rText
, USHORT nBorder
)
148 DBG_ASSERT(aTopLeft
== Point(0, 0), "Sm: Ooops...");
150 aSize
= Size(rDev
.GetTextWidth(rText
), rDev
.GetTextHeight());
152 const FontMetric
aFM (rDev
.GetFontMetric());
153 BOOL bIsMath
= aFM
.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH
) ||
154 aFM
.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH2
);
155 BOOL bAllowSmaller
= bIsMath
&& !SmIsMathAlpha(rText
);
156 const long nFontHeight
= rDev
.GetFont().GetSize().Height();
158 nBorderWidth
= nBorder
;
159 bHasAlignInfo
= TRUE
;
161 nBaseline
= aFM
.GetAscent();
162 nAlignT
= nBaseline
- nFontHeight
* 750L / 1000L;
163 nAlignM
= nBaseline
- nFontHeight
* 121L / 422L;
164 // that's where the horizontal bars of '+', '-', ... are
165 // (1/3 of ascent over baseline)
166 // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
169 // workaround for printer fonts with very small (possible 0 or even
170 // negative(!)) leading
171 if (aFM
.GetIntLeading() < 5 && rDev
.GetOutDevType() == OUTDEV_PRINTER
)
173 OutputDevice
*pWindow
= Application::GetDefaultDevice();
175 pWindow
->Push(PUSH_MAPMODE
| PUSH_FONT
);
177 pWindow
->SetMapMode(rDev
.GetMapMode());
178 pWindow
->SetFont(rDev
.GetFontMetric());
180 long nDelta
= pWindow
->GetFontMetric().GetIntLeading();
182 { // dieser Wert entspricht etwa einem Leading von 80 bei einer
183 // Fonthoehe von 422 (12pt)
184 nDelta
= nFontHeight
* 8L / 43;
186 SetTop(GetTop() - nDelta
);
191 // get GlyphBoundRect
192 Rectangle aGlyphRect
;
193 #if OSL_DEBUG_LEVEL > 1
196 SmGetGlyphBoundRect(rDev
, rText
, aGlyphRect
);
197 #if OSL_DEBUG_LEVEL > 1
200 DBG_ERROR( "Sm : Ooops... (fehlt evtl. der Font?)");
204 nItalicLeftSpace
= GetLeft() - aGlyphRect
.Left() + nBorderWidth
;
205 nItalicRightSpace
= aGlyphRect
.Right() - GetRight() + nBorderWidth
;
206 if (nItalicLeftSpace
< 0 && !bAllowSmaller
)
207 nItalicLeftSpace
= 0;
208 if (nItalicRightSpace
< 0 && !bAllowSmaller
)
209 nItalicRightSpace
= 0;
213 nDist
= (rDev
.GetFont().GetSize().Height()
214 * pFormat
->GetDistance(DIS_ORNAMENTSIZE
)) / 100L;
216 nHiAttrFence
= aGlyphRect
.TopLeft().Y() - 1 - nBorderWidth
- nDist
;
217 nLoAttrFence
= SmFromTo(GetAlignB(), GetBottom(), 0.0);
219 nGlyphTop
= aGlyphRect
.Top() - nBorderWidth
;
220 nGlyphBottom
= aGlyphRect
.Bottom() + nBorderWidth
;
224 // fuer Symbole und Operatoren aus dem StarMath Font passen wir den
225 // oberen und unteren Rand dem Zeichen an.
227 SetBottom(nGlyphBottom
);
230 if (nHiAttrFence
< GetTop())
231 nHiAttrFence
= GetTop();
233 if (nLoAttrFence
> GetBottom())
234 nLoAttrFence
= GetBottom();
236 DBG_ASSERT(rText
.Len() == 0 || !IsEmpty(),
237 "Sm: leeres Rechteck erzeugt");
241 void SmRect::Init(const OutputDevice
&rDev
, const SmFormat
*pFormat
,
242 const XubString
&rText
, USHORT nEBorderWidth
)
243 // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
245 BuildRect(rDev
, pFormat
, rText
, nEBorderWidth
);
249 SmRect::SmRect(const OutputDevice
&rDev
, const SmFormat
*pFormat
,
250 const XubString
&rText
, long nEBorderWidth
)
252 DBG_ASSERT( nEBorderWidth
>= 0, "BorderWidth negativ" );
253 if (nEBorderWidth
< 0)
255 Init(rDev
, pFormat
, rText
, (USHORT
) nEBorderWidth
);
259 SmRect::SmRect(long nWidth
, long nHeight
)
260 // this constructor should never be used for anything textlike because
261 // it will not provide useful values for baseline, AlignT and AlignB!
262 // It's purpose is to get a 'SmRect' for the horizontal line in fractions
263 // as used in 'SmBinVerNode'.
264 : aSize(nWidth
, nHeight
)
266 DBG_ASSERT(aTopLeft
== Point(0, 0), "Sm: ooops...");
268 bHasBaseline
= FALSE
;
269 bHasAlignInfo
= TRUE
;
272 nAlignB
= GetBottom();
273 nAlignM
= (nAlignT
+ nAlignB
) / 2; // this is the default
274 nItalicLeftSpace
= nItalicRightSpace
= 0;
275 nGlyphTop
= nHiAttrFence
= GetTop();
276 nGlyphBottom
= nLoAttrFence
= GetBottom();
281 void SmRect::SetLeft(long nLeft
)
283 if (nLeft
<= GetRight())
284 { aSize
.Width() = GetRight() - nLeft
+ 1;
285 aTopLeft
.X() = nLeft
;
290 void SmRect::SetRight(long nRight
)
292 if (nRight
>= GetLeft())
293 aSize
.Width() = nRight
- GetLeft() + 1;
297 void SmRect::SetBottom(long nBottom
)
299 if (nBottom
>= GetTop())
300 aSize
.Height() = nBottom
- GetTop() + 1;
304 void SmRect::SetTop(long nTop
)
306 if (nTop
<= GetBottom())
307 { aSize
.Height() = GetBottom() - nTop
+ 1;
313 void SmRect::Move(const Point
&rPosition
)
314 // move rectangle by position 'rPosition'.
316 aTopLeft
+= rPosition
;
318 long nDelta
= rPosition
.Y();
324 nGlyphBottom
+= nDelta
;
325 nHiAttrFence
+= nDelta
;
326 nLoAttrFence
+= nDelta
;
330 const Point
SmRect::AlignTo(const SmRect
&rRect
, RectPos ePos
,
331 RectHorAlign eHor
, RectVerAlign eVer
) const
332 { Point
aPos (GetTopLeft());
333 // will become the topleft point of the new rectangle position
335 // set horizontal or vertical new rectangle position depending on
336 // 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
339 aPos
.X() = rRect
.GetItalicLeft() - GetItalicRightSpace()
343 aPos
.X() = rRect
.GetItalicRight() + 1 + GetItalicLeftSpace();
346 aPos
.Y() = rRect
.GetTop() - GetHeight();
349 aPos
.Y() = rRect
.GetBottom() + 1;
352 aPos
.X() = rRect
.GetItalicCenterX() - GetItalicWidth() / 2
353 + GetItalicLeftSpace();
356 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
359 // check if horizontal position is already set
360 if (ePos
== RP_LEFT
|| ePos
== RP_RIGHT
|| ePos
== RP_ATTRIBUT
)
361 // correct error in current vertical position
364 aPos
.Y() += rRect
.GetAlignT() - GetAlignT();
367 aPos
.Y() += rRect
.GetAlignM() - GetAlignM();
370 // align baselines if possible else align mid's
371 if (HasBaseline() && rRect
.HasBaseline())
372 aPos
.Y() += rRect
.GetBaseline() - GetBaseline();
374 aPos
.Y() += rRect
.GetAlignM() - GetAlignM();
377 aPos
.Y() += rRect
.GetAlignB() - GetAlignB();
380 aPos
.Y() += rRect
.GetCenterY() - GetCenterY();
382 case RVA_ATTRIBUT_HI
:
383 aPos
.Y() += rRect
.GetHiAttrFence() - GetBottom();
385 case RVA_ATTRIBUT_MID
:
386 aPos
.Y() += SmFromTo(rRect
.GetAlignB(), rRect
.GetAlignT(), 0.4)
389 case RVA_ATTRIBUT_LO
:
390 aPos
.Y() += rRect
.GetLoAttrFence() - GetTop();
393 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
396 // check if vertical position is already set
397 if (ePos
== RP_TOP
|| ePos
== RP_BOTTOM
)
398 // correct error in current horizontal position
401 aPos
.X() += rRect
.GetItalicLeft() - GetItalicLeft();
404 aPos
.X() += rRect
.GetItalicCenterX() - GetItalicCenterX();
407 aPos
.X() += rRect
.GetItalicRight() - GetItalicRight();
410 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
417 SmRect
& SmRect::Union(const SmRect
&rRect
)
418 // rectangle union of current one with 'rRect'. The result is to be the
419 // smallest rectangles that covers the space of both rectangles.
420 // (empty rectangles cover no space)
421 //! Italic correction is NOT taken into account here!
426 long nL
= rRect
.GetLeft(),
427 nR
= rRect
.GetRight(),
429 nB
= rRect
.GetBottom(),
430 nGT
= rRect
.nGlyphTop
,
431 nGB
= rRect
.nGlyphBottom
;
435 if ((nTmp
= GetLeft()) < nL
)
437 if ((nTmp
= GetRight()) > nR
)
439 if ((nTmp
= GetTop()) < nT
)
441 if ((nTmp
= GetBottom()) > nB
)
443 if ((nTmp
= nGlyphTop
) < nGT
)
445 if ((nTmp
= nGlyphBottom
) > nGB
)
460 SmRect
& SmRect::ExtendBy(const SmRect
&rRect
, RectCopyMBL eCopyMode
)
461 // let current rectangle be the union of itself and 'rRect'
462 // (the smallest rectangle surrounding both). Also adapt values for
463 // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
464 // The baseline is set according to 'eCopyMode'.
465 // If one of the rectangles has no relevant info the other one is copied.
467 // get some values used for (italic) spaces adaption
468 // ! (need to be done before changing current SmRect) !
469 long nL
= Min(GetItalicLeft(), rRect
.GetItalicLeft()),
470 nR
= Max(GetItalicRight(), rRect
.GetItalicRight());
474 SetItalicSpaces(GetLeft() - nL
, nR
- GetRight());
477 CopyAlignInfo(rRect
);
478 else if (rRect
.HasAlignInfo())
479 { nAlignT
= Min(GetAlignT(), rRect
.GetAlignT());
480 nAlignB
= Max(GetAlignB(), rRect
.GetAlignB());
481 nHiAttrFence
= Min(GetHiAttrFence(), rRect
.GetHiAttrFence());
482 nLoAttrFence
= Max(GetLoAttrFence(), rRect
.GetLoAttrFence());
483 DBG_ASSERT(HasAlignInfo(), "Sm: ooops...");
494 nAlignM
= (nAlignT
+ nAlignB
) / 2;
501 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
509 SmRect
& SmRect::ExtendBy(const SmRect
&rRect
, RectCopyMBL eCopyMode
,
511 // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
512 // (this version will be used in 'SmBinVerNode' to provide means to
513 // align eg "{a over b} over c" correctly where AlignM should not
514 // be (AlignT + AlignB) / 2)
516 DBG_ASSERT(HasAlignInfo(), "Sm: keine Align Info");
518 ExtendBy(rRect
, eCopyMode
);
519 nAlignM
= nNewAlignM
;
525 SmRect
& SmRect::ExtendBy(const SmRect
&rRect
, RectCopyMBL eCopyMode
,
526 BOOL bKeepVerAlignParams
)
527 // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
529 // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
530 // be allowed to modify these values.)
532 long nOldAlignT
= GetAlignT(),
533 nOldAlignM
= GetAlignM(),
534 nOldAlignB
= GetAlignB(),
535 nOldBaseline
= nBaseline
; //! depends not on 'HasBaseline'
536 BOOL bOldHasAlignInfo
= HasAlignInfo();
538 ExtendBy(rRect
, eCopyMode
);
540 if (bKeepVerAlignParams
)
541 { nAlignT
= nOldAlignT
;
542 nAlignM
= nOldAlignM
;
543 nAlignB
= nOldAlignB
;
544 nBaseline
= nOldBaseline
;
545 bHasAlignInfo
= bOldHasAlignInfo
;
552 long SmRect::OrientedDist(const Point
&rPoint
) const
553 // return oriented distance of rPoint to the current rectangle,
554 // especially the return value is <= 0 iff the point is inside the
556 // For simplicity the maximum-norm is used.
558 BOOL bIsInside
= IsInsideItalicRect(rPoint
);
560 // build reference point to define the distance
563 { Point
aIC (GetItalicCenterX(), GetCenterY());
565 aRef
.X() = rPoint
.X() >= aIC
.X() ? GetItalicRight() : GetItalicLeft();
566 aRef
.Y() = rPoint
.Y() >= aIC
.Y() ? GetBottom() : GetTop();
571 if (rPoint
.X() > GetItalicRight())
572 aRef
.X() = GetItalicRight();
573 else if (rPoint
.X() < GetItalicLeft())
574 aRef
.X() = GetItalicLeft();
576 aRef
.X() = rPoint
.X();
578 if (rPoint
.Y() > GetBottom())
579 aRef
.Y() = GetBottom();
580 else if (rPoint
.Y() < GetTop())
583 aRef
.Y() = rPoint
.Y();
586 // build distance vector
587 Point
aDist (aRef
- rPoint
);
589 long nAbsX
= labs(aDist
.X()),
590 nAbsY
= labs(aDist
.Y());
592 return bIsInside
? - Min(nAbsX
, nAbsY
) : Max (nAbsX
, nAbsY
);
596 BOOL
SmRect::IsInsideRect(const Point
&rPoint
) const
598 return rPoint
.Y() >= GetTop()
599 && rPoint
.Y() <= GetBottom()
600 && rPoint
.X() >= GetLeft()
601 && rPoint
.X() <= GetRight();
605 BOOL
SmRect::IsInsideItalicRect(const Point
&rPoint
) const
607 return rPoint
.Y() >= GetTop()
608 && rPoint
.Y() <= GetBottom()
609 && rPoint
.X() >= GetItalicLeft()
610 && rPoint
.X() <= GetItalicRight();
613 SmRect
SmRect::AsGlyphRect() const
615 SmRect
aRect (*this);
616 aRect
.SetTop(nGlyphTop
);
617 aRect
.SetBottom(nGlyphBottom
);
623 // forward declaration
624 void SmDrawFrame(OutputDevice
&rDev
, const Rectangle
&rRec
,
625 const Color aCol
= COL_BLACK
);
627 void SmRect::Draw(OutputDevice
&rDev
, const Point
&rPosition
, int nFlags
) const
632 rDev
.Push(PUSH_LINECOLOR
);
634 if (nFlags
& SM_RECT_LINES
)
635 { long nLeftSpace
= 0,
638 if (nFlags
& SM_RECT_ITALIC
)
639 { nLeftSpace
= GetItalicLeftSpace();
640 nRightSpace
= GetItalicRightSpace();
643 long nLeft
= GetLeft() - nLeftSpace
,
644 nRight
= GetRight() + nRightSpace
;
646 Point
aOffset (rPosition
- GetTopLeft());
648 rDev
.SetLineColor(COL_LIGHTBLUE
);
649 rDev
.DrawLine(Point(nLeft
, GetAlignB()) += aOffset
,
650 Point(nRight
, GetAlignB()) += aOffset
);
651 rDev
.DrawLine(Point(nLeft
, GetAlignT()) += aOffset
,
652 Point(nRight
, GetAlignT()) += aOffset
);
654 rDev
.DrawLine(Point(nLeft
, GetBaseline()) += aOffset
,
655 Point(nRight
, GetBaseline()) += aOffset
);
657 rDev
.SetLineColor(COL_GRAY
);
658 rDev
.DrawLine(Point(nLeft
, GetHiAttrFence()) += aOffset
,
659 Point(nRight
, GetHiAttrFence()) += aOffset
);
662 if (nFlags
& SM_RECT_MID
)
663 { Point aCenter
= rPosition
664 + (Point(GetItalicCenterX(), GetAlignM()) -= GetTopLeft()),
665 aLenX (GetWidth() / 5, 0),
666 aLenY (0, GetHeight() / 16);
668 rDev
.SetLineColor(COL_LIGHTGREEN
);
669 rDev
.DrawLine(aCenter
- aLenX
, aCenter
+ aLenX
);
670 rDev
.DrawLine(aCenter
- aLenY
, aCenter
+ aLenY
);
673 if (nFlags
& SM_RECT_ITALIC
)
674 SmDrawFrame(rDev
, Rectangle(rPosition
- Point(GetItalicLeftSpace(), 0),
677 if (nFlags
& SM_RECT_CORE
)
678 SmDrawFrame(rDev
, Rectangle(rPosition
, GetSize()), COL_LIGHTRED
);
684 void SmDrawFrame(OutputDevice
&rDev
, const Rectangle
&rRec
,
687 rDev
.Push(PUSH_LINECOLOR
);
689 rDev
.SetLineColor(aCol
);
691 rDev
.DrawLine(rRec
.TopLeft(), rRec
.BottomLeft());
692 rDev
.DrawLine(rRec
.BottomLeft(), rRec
.BottomRight());
693 rDev
.DrawLine(rRec
.BottomRight(), rRec
.TopRight());
694 rDev
.DrawLine(rRec
.TopRight(), rRec
.TopLeft());
699 #endif //SM_RECT_DEBUG
702 BOOL
SmGetGlyphBoundRect(const OutputDevice
&rDev
,
703 const XubString
&rText
, Rectangle
&rRect
)
704 // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
705 // but with a string as argument.
707 // handle special case first
708 xub_StrLen nLen
= rText
.Len();
714 // get a device where 'OutputDevice::GetTextBoundRect' will be successful
715 OutputDevice
*pGlyphDev
;
716 if (rDev
.GetOutDevType() != OUTDEV_PRINTER
)
717 pGlyphDev
= (OutputDevice
*) &rDev
;
720 // since we format for the printer (where GetTextBoundRect will fail)
721 // we need a virtual device here.
722 pGlyphDev
= &SM_MOD1()->GetDefaultVirtualDev();
725 const FontMetric
aDevFM (rDev
.GetFontMetric());
727 pGlyphDev
->Push(PUSH_FONT
| PUSH_MAPMODE
);
728 Font
aFnt(rDev
.GetFont());
729 aFnt
.SetAlign(ALIGN_TOP
);
731 // use scale factor when calling GetTextBoundRect to counter
732 // negative effects from antialiasing which may otherwise result
733 // in significant incorrect bounding rectangles for some charcters.
734 Size aFntSize
= aFnt
.GetSize();
736 // HDU: workaround to avoid HUGE font sizes and resulting problems (#112783#)
737 long nScaleFactor
= 1;
738 while( aFntSize
.Height() > 2000 * nScaleFactor
)
741 aFnt
.SetSize( Size( aFntSize
.Width() / nScaleFactor
, aFntSize
.Height() / nScaleFactor
) );
742 pGlyphDev
->SetFont(aFnt
);
744 long nTextWidth
= rDev
.GetTextWidth(rText
);
746 Rectangle
aResult (aPoint
, Size(nTextWidth
, rDev
.GetTextHeight())),
749 BOOL bSuccess
= pGlyphDev
->GetTextBoundRect(aTmp
, rText
, 0, 0);
750 DBG_ASSERT( bSuccess
, "GetTextBoundRect failed" );
755 aResult
= Rectangle(aTmp
.Left() * nScaleFactor
, aTmp
.Top() * nScaleFactor
,
756 aTmp
.Right() * nScaleFactor
, aTmp
.Bottom() * nScaleFactor
);
757 if (&rDev
!= pGlyphDev
) /* only when rDev is a printer... */
759 long nGDTextWidth
= pGlyphDev
->GetTextWidth(rText
);
760 if (nGDTextWidth
!= 0 &&
761 nTextWidth
!= nGDTextWidth
)
763 aResult
.Right() *= nTextWidth
;
764 aResult
.Right() /= nGDTextWidth
* nScaleFactor
;
769 // move rectangle to match possibly different baselines
770 // (because of different devices)
771 long nDelta
= aDevFM
.GetAscent() - pGlyphDev
->GetFontMetric().GetAscent() * nScaleFactor
;
772 aResult
.Move(0, nDelta
);