1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_starmath.hxx"
32 #include <tools/string.hxx>
33 #include <tools/debug.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/wrkwin.hxx>
36 #include <vcl/virdev.hxx>
41 #include "utility.hxx"
45 ////////////////////////////////////////////////////////////////////////////////
48 // '\0' terminiertes Array mit Zeichen, die im StarMath Font als Buchstaben
49 // betrachtet werden sollen, (um im Gegensatz zu den anderen Operatoren
50 // und Symbolen ein "normales"(ungecliptes) SmRect zu erhalten).
51 static xub_Unicode __READONLY_DATA aMathAlpha
[] =
53 MS_ALEPH
, MS_IM
, MS_RE
,
54 MS_WP
, xub_Unicode(0xE070), MS_EMPTYSET
,
55 xub_Unicode(0x2113), xub_Unicode(0xE0D6), xub_Unicode(0x2107),
56 xub_Unicode(0x2127), xub_Unicode(0x210A), MS_HBAR
,
57 MS_LAMBDABAR
, MS_SETN
, MS_SETZ
,
58 MS_SETQ
, MS_SETR
, MS_SETC
,
59 xub_Unicode(0x2373), xub_Unicode(0xE0A5), xub_Unicode(0x2112),
60 xub_Unicode(0x2130), xub_Unicode(0x2131),
64 BOOL
SmIsMathAlpha(const XubString
&rText
)
65 // ergibt genau dann TRUE, wenn das Zeichen (aus dem StarMath Font) wie ein
66 // Buchstabe behandelt werden soll.
71 DBG_ASSERT(rText
.Len() == 1, "Sm : String enthaelt nicht genau ein Zeichen");
72 xub_Unicode cChar
= rText
.GetChar(0);
74 // ist es ein griechisches Zeichen ?
75 if (xub_Unicode(0xE0AC) <= cChar
&& cChar
<= xub_Unicode(0xE0D4))
79 // kommt es in 'aMathAlpha' vor ?
80 const xub_Unicode
*pChar
= aMathAlpha
;
81 while (*pChar
&& *pChar
!= cChar
)
83 return *pChar
!= xub_Unicode('\0');
88 ////////////////////////////////////////
95 // constructs empty rectangle at (0, 0) with width and height 0.
97 DBG_ASSERT(aTopLeft
== Point(0, 0), "Sm: ooops...");
98 DBG_ASSERT(aSize
== Size(0, 0), "Sm: ooops...");
100 bHasBaseline
= bHasAlignInfo
= FALSE
;
101 nBaseline
= nAlignT
= nAlignM
= nAlignB
=
102 nGlyphTop
= nGlyphBottom
=
103 nItalicLeftSpace
= nItalicRightSpace
=
104 nLoAttrFence
= nHiAttrFence
= 0;
109 SmRect::SmRect(const SmRect
&rRect
)
110 : aTopLeft(rRect
.aTopLeft
),
113 bHasBaseline
= rRect
.bHasBaseline
;
114 nBaseline
= rRect
.nBaseline
;
115 nAlignT
= rRect
.nAlignT
;
116 nAlignM
= rRect
.nAlignM
;
117 nAlignB
= rRect
.nAlignB
;
118 nGlyphTop
= rRect
.nGlyphTop
;
119 nGlyphBottom
= rRect
.nGlyphBottom
;
120 nHiAttrFence
= rRect
.nHiAttrFence
;
121 nLoAttrFence
= rRect
.nLoAttrFence
;
122 bHasAlignInfo
= rRect
.bHasAlignInfo
;
123 nItalicLeftSpace
= rRect
.nItalicLeftSpace
;
124 nItalicRightSpace
= rRect
.nItalicRightSpace
;
125 nBorderWidth
= rRect
.nBorderWidth
;
129 void SmRect::CopyAlignInfo(const SmRect
&rRect
)
131 nBaseline
= rRect
.nBaseline
;
132 bHasBaseline
= rRect
.bHasBaseline
;
133 nAlignT
= rRect
.nAlignT
;
134 nAlignM
= rRect
.nAlignM
;
135 nAlignB
= rRect
.nAlignB
;
136 bHasAlignInfo
= rRect
.bHasAlignInfo
;
137 nLoAttrFence
= rRect
.nLoAttrFence
;
138 nHiAttrFence
= rRect
.nHiAttrFence
;
142 void SmRect::BuildRect(const OutputDevice
&rDev
, const SmFormat
*pFormat
,
143 const XubString
&rText
, USHORT nBorder
)
145 DBG_ASSERT(aTopLeft
== Point(0, 0), "Sm: Ooops...");
147 aSize
= Size(rDev
.GetTextWidth(rText
), rDev
.GetTextHeight());
149 const FontMetric
aFM (rDev
.GetFontMetric());
150 BOOL bIsMath
= aFM
.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH
);
151 BOOL bAllowSmaller
= bIsMath
&& !SmIsMathAlpha(rText
);
152 const long nFontHeight
= rDev
.GetFont().GetSize().Height();
154 nBorderWidth
= nBorder
;
155 bHasAlignInfo
= TRUE
;
157 nBaseline
= aFM
.GetAscent();
158 nAlignT
= nBaseline
- nFontHeight
* 750L / 1000L;
159 nAlignM
= nBaseline
- nFontHeight
* 121L / 422L;
160 // that's where the horizontal bars of '+', '-', ... are
161 // (1/3 of ascent over baseline)
162 // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
165 // workaround for printer fonts with very small (possible 0 or even
166 // negative(!)) leading
167 if (aFM
.GetIntLeading() < 5 && rDev
.GetOutDevType() == OUTDEV_PRINTER
)
169 OutputDevice
*pWindow
= Application::GetDefaultDevice();
171 pWindow
->Push(PUSH_MAPMODE
| PUSH_FONT
);
173 pWindow
->SetMapMode(rDev
.GetMapMode());
174 pWindow
->SetFont(rDev
.GetFontMetric());
176 long nDelta
= pWindow
->GetFontMetric().GetIntLeading();
178 { // dieser Wert entspricht etwa einem Leading von 80 bei einer
179 // Fonthoehe von 422 (12pt)
180 nDelta
= nFontHeight
* 8L / 43;
182 SetTop(GetTop() - nDelta
);
187 // get GlyphBoundRect
188 Rectangle aGlyphRect
;
189 #if OSL_DEBUG_LEVEL > 1
192 SmGetGlyphBoundRect(rDev
, rText
, aGlyphRect
);
193 #if OSL_DEBUG_LEVEL > 1
196 DBG_ERROR( "Sm : Ooops... (fehlt evtl. der Font?)");
200 nItalicLeftSpace
= GetLeft() - aGlyphRect
.Left() + nBorderWidth
;
201 nItalicRightSpace
= aGlyphRect
.Right() - GetRight() + nBorderWidth
;
202 if (nItalicLeftSpace
< 0 && !bAllowSmaller
)
203 nItalicLeftSpace
= 0;
204 if (nItalicRightSpace
< 0 && !bAllowSmaller
)
205 nItalicRightSpace
= 0;
209 nDist
= (rDev
.GetFont().GetSize().Height()
210 * pFormat
->GetDistance(DIS_ORNAMENTSIZE
)) / 100L;
212 nHiAttrFence
= aGlyphRect
.TopLeft().Y() - 1 - nBorderWidth
- nDist
;
213 nLoAttrFence
= SmFromTo(GetAlignB(), GetBottom(), 0.0);
215 nGlyphTop
= aGlyphRect
.Top() - nBorderWidth
;
216 nGlyphBottom
= aGlyphRect
.Bottom() + nBorderWidth
;
220 // fuer Symbole und Operatoren aus dem StarMath Font passen wir den
221 // oberen und unteren Rand dem Zeichen an.
223 SetBottom(nGlyphBottom
);
226 if (nHiAttrFence
< GetTop())
227 nHiAttrFence
= GetTop();
229 if (nLoAttrFence
> GetBottom())
230 nLoAttrFence
= GetBottom();
232 DBG_ASSERT(rText
.Len() == 0 || !IsEmpty(),
233 "Sm: leeres Rechteck erzeugt");
237 void SmRect::Init(const OutputDevice
&rDev
, const SmFormat
*pFormat
,
238 const XubString
&rText
, USHORT nEBorderWidth
)
239 // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
241 BuildRect(rDev
, pFormat
, rText
, nEBorderWidth
);
245 SmRect::SmRect(const OutputDevice
&rDev
, const SmFormat
*pFormat
,
246 const XubString
&rText
, long nEBorderWidth
)
248 DBG_ASSERT( nEBorderWidth
>= 0, "BorderWidth negativ" );
249 if (nEBorderWidth
< 0)
251 Init(rDev
, pFormat
, rText
, (USHORT
) nEBorderWidth
);
255 SmRect::SmRect(long nWidth
, long nHeight
)
256 // this constructor should never be used for anything textlike because
257 // it will not provide useful values for baseline, AlignT and AlignB!
258 // It's purpose is to get a 'SmRect' for the horizontal line in fractions
259 // as used in 'SmBinVerNode'.
260 : aSize(nWidth
, nHeight
)
262 DBG_ASSERT(aTopLeft
== Point(0, 0), "Sm: ooops...");
264 bHasBaseline
= FALSE
;
265 bHasAlignInfo
= TRUE
;
268 nAlignB
= GetBottom();
269 nAlignM
= (nAlignT
+ nAlignB
) / 2; // this is the default
270 nItalicLeftSpace
= nItalicRightSpace
= 0;
271 nGlyphTop
= nHiAttrFence
= GetTop();
272 nGlyphBottom
= nLoAttrFence
= GetBottom();
277 void SmRect::SetLeft(long nLeft
)
279 if (nLeft
<= GetRight())
280 { aSize
.Width() = GetRight() - nLeft
+ 1;
281 aTopLeft
.X() = nLeft
;
286 void SmRect::SetRight(long nRight
)
288 if (nRight
>= GetLeft())
289 aSize
.Width() = nRight
- GetLeft() + 1;
293 void SmRect::SetBottom(long nBottom
)
295 if (nBottom
>= GetTop())
296 aSize
.Height() = nBottom
- GetTop() + 1;
300 void SmRect::SetTop(long nTop
)
302 if (nTop
<= GetBottom())
303 { aSize
.Height() = GetBottom() - nTop
+ 1;
309 void SmRect::Move(const Point
&rPosition
)
310 // move rectangle by position 'rPosition'.
312 aTopLeft
+= rPosition
;
314 long nDelta
= rPosition
.Y();
320 nGlyphBottom
+= nDelta
;
321 nHiAttrFence
+= nDelta
;
322 nLoAttrFence
+= nDelta
;
326 const Point
SmRect::AlignTo(const SmRect
&rRect
, RectPos ePos
,
327 RectHorAlign eHor
, RectVerAlign eVer
) const
328 { Point
aPos (GetTopLeft());
329 // will become the topleft point of the new rectangle position
331 // set horizontal or vertical new rectangle position depending on
332 // 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
335 aPos
.X() = rRect
.GetItalicLeft() - GetItalicRightSpace()
339 aPos
.X() = rRect
.GetItalicRight() + 1 + GetItalicLeftSpace();
342 aPos
.Y() = rRect
.GetTop() - GetHeight();
345 aPos
.Y() = rRect
.GetBottom() + 1;
348 aPos
.X() = rRect
.GetItalicCenterX() - GetItalicWidth() / 2
349 + GetItalicLeftSpace();
352 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
355 // check if horizontal position is already set
356 if (ePos
== RP_LEFT
|| ePos
== RP_RIGHT
|| ePos
== RP_ATTRIBUT
)
357 // correct error in current vertical position
360 aPos
.Y() += rRect
.GetAlignT() - GetAlignT();
363 aPos
.Y() += rRect
.GetAlignM() - GetAlignM();
366 // align baselines if possible else align mid's
367 if (HasBaseline() && rRect
.HasBaseline())
368 aPos
.Y() += rRect
.GetBaseline() - GetBaseline();
370 aPos
.Y() += rRect
.GetAlignM() - GetAlignM();
373 aPos
.Y() += rRect
.GetAlignB() - GetAlignB();
376 aPos
.Y() += rRect
.GetCenterY() - GetCenterY();
378 case RVA_ATTRIBUT_HI
:
379 aPos
.Y() += rRect
.GetHiAttrFence() - GetBottom();
381 case RVA_ATTRIBUT_MID
:
382 aPos
.Y() += SmFromTo(rRect
.GetAlignB(), rRect
.GetAlignT(), 0.4)
385 case RVA_ATTRIBUT_LO
:
386 aPos
.Y() += rRect
.GetLoAttrFence() - GetTop();
389 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
392 // check if vertical position is already set
393 if (ePos
== RP_TOP
|| ePos
== RP_BOTTOM
)
394 // correct error in current horizontal position
397 aPos
.X() += rRect
.GetItalicLeft() - GetItalicLeft();
400 aPos
.X() += rRect
.GetItalicCenterX() - GetItalicCenterX();
403 aPos
.X() += rRect
.GetItalicRight() - GetItalicRight();
406 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
413 SmRect
& SmRect::Union(const SmRect
&rRect
)
414 // rectangle union of current one with 'rRect'. The result is to be the
415 // smallest rectangles that covers the space of both rectangles.
416 // (empty rectangles cover no space)
417 //! Italic correction is NOT taken into account here!
422 long nL
= rRect
.GetLeft(),
423 nR
= rRect
.GetRight(),
425 nB
= rRect
.GetBottom(),
426 nGT
= rRect
.nGlyphTop
,
427 nGB
= rRect
.nGlyphBottom
;
431 if ((nTmp
= GetLeft()) < nL
)
433 if ((nTmp
= GetRight()) > nR
)
435 if ((nTmp
= GetTop()) < nT
)
437 if ((nTmp
= GetBottom()) > nB
)
439 if ((nTmp
= nGlyphTop
) < nGT
)
441 if ((nTmp
= nGlyphBottom
) > nGB
)
456 SmRect
& SmRect::ExtendBy(const SmRect
&rRect
, RectCopyMBL eCopyMode
)
457 // let current rectangle be the union of itself and 'rRect'
458 // (the smallest rectangle surrounding both). Also adapt values for
459 // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
460 // The baseline is set according to 'eCopyMode'.
461 // If one of the rectangles has no relevant info the other one is copied.
463 // get some values used for (italic) spaces adaption
464 // ! (need to be done before changing current SmRect) !
465 long nL
= Min(GetItalicLeft(), rRect
.GetItalicLeft()),
466 nR
= Max(GetItalicRight(), rRect
.GetItalicRight());
470 SetItalicSpaces(GetLeft() - nL
, nR
- GetRight());
473 CopyAlignInfo(rRect
);
474 else if (rRect
.HasAlignInfo())
475 { nAlignT
= Min(GetAlignT(), rRect
.GetAlignT());
476 nAlignB
= Max(GetAlignB(), rRect
.GetAlignB());
477 nHiAttrFence
= Min(GetHiAttrFence(), rRect
.GetHiAttrFence());
478 nLoAttrFence
= Max(GetLoAttrFence(), rRect
.GetLoAttrFence());
479 DBG_ASSERT(HasAlignInfo(), "Sm: ooops...");
490 nAlignM
= (nAlignT
+ nAlignB
) / 2;
497 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
505 SmRect
& SmRect::ExtendBy(const SmRect
&rRect
, RectCopyMBL eCopyMode
,
507 // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
508 // (this version will be used in 'SmBinVerNode' to provide means to
509 // align eg "{a over b} over c" correctly where AlignM should not
510 // be (AlignT + AlignB) / 2)
512 DBG_ASSERT(HasAlignInfo(), "Sm: keine Align Info");
514 ExtendBy(rRect
, eCopyMode
);
515 nAlignM
= nNewAlignM
;
521 SmRect
& SmRect::ExtendBy(const SmRect
&rRect
, RectCopyMBL eCopyMode
,
522 BOOL bKeepVerAlignParams
)
523 // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
525 // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
526 // be allowed to modify these values.)
528 long nOldAlignT
= GetAlignT(),
529 nOldAlignM
= GetAlignM(),
530 nOldAlignB
= GetAlignB(),
531 nOldBaseline
= nBaseline
; //! depends not on 'HasBaseline'
532 BOOL bOldHasAlignInfo
= HasAlignInfo();
534 ExtendBy(rRect
, eCopyMode
);
536 if (bKeepVerAlignParams
)
537 { nAlignT
= nOldAlignT
;
538 nAlignM
= nOldAlignM
;
539 nAlignB
= nOldAlignB
;
540 nBaseline
= nOldBaseline
;
541 bHasAlignInfo
= bOldHasAlignInfo
;
548 long SmRect::OrientedDist(const Point
&rPoint
) const
549 // return oriented distance of rPoint to the current rectangle,
550 // especially the return value is <= 0 iff the point is inside the
552 // For simplicity the maximum-norm is used.
554 BOOL bIsInside
= IsInsideItalicRect(rPoint
);
556 // build reference point to define the distance
559 { Point
aIC (GetItalicCenterX(), GetCenterY());
561 aRef
.X() = rPoint
.X() >= aIC
.X() ? GetItalicRight() : GetItalicLeft();
562 aRef
.Y() = rPoint
.Y() >= aIC
.Y() ? GetBottom() : GetTop();
567 if (rPoint
.X() > GetItalicRight())
568 aRef
.X() = GetItalicRight();
569 else if (rPoint
.X() < GetItalicLeft())
570 aRef
.X() = GetItalicLeft();
572 aRef
.X() = rPoint
.X();
574 if (rPoint
.Y() > GetBottom())
575 aRef
.Y() = GetBottom();
576 else if (rPoint
.Y() < GetTop())
579 aRef
.Y() = rPoint
.Y();
582 // build distance vector
583 Point
aDist (aRef
- rPoint
);
585 long nAbsX
= labs(aDist
.X()),
586 nAbsY
= labs(aDist
.Y());
588 return bIsInside
? - Min(nAbsX
, nAbsY
) : Max (nAbsX
, nAbsY
);
592 BOOL
SmRect::IsInsideRect(const Point
&rPoint
) const
594 return rPoint
.Y() >= GetTop()
595 && rPoint
.Y() <= GetBottom()
596 && rPoint
.X() >= GetLeft()
597 && rPoint
.X() <= GetRight();
601 BOOL
SmRect::IsInsideItalicRect(const Point
&rPoint
) const
603 return rPoint
.Y() >= GetTop()
604 && rPoint
.Y() <= GetBottom()
605 && rPoint
.X() >= GetItalicLeft()
606 && rPoint
.X() <= GetItalicRight();
609 SmRect
SmRect::AsGlyphRect() const
611 SmRect
aRect (*this);
612 aRect
.SetTop(nGlyphTop
);
613 aRect
.SetBottom(nGlyphBottom
);
619 // forward declaration
620 void SmDrawFrame(OutputDevice
&rDev
, const Rectangle
&rRec
,
621 const Color aCol
= COL_BLACK
);
623 void SmRect::Draw(OutputDevice
&rDev
, const Point
&rPosition
, int nFlags
) const
628 rDev
.Push(PUSH_LINECOLOR
);
630 if (nFlags
& SM_RECT_LINES
)
631 { long nLeftSpace
= 0,
634 if (nFlags
& SM_RECT_ITALIC
)
635 { nLeftSpace
= GetItalicLeftSpace();
636 nRightSpace
= GetItalicRightSpace();
639 long nLeft
= GetLeft() - nLeftSpace
,
640 nRight
= GetRight() + nRightSpace
;
642 Point
aOffset (rPosition
- GetTopLeft());
644 rDev
.SetLineColor(COL_LIGHTBLUE
);
645 rDev
.DrawLine(Point(nLeft
, GetAlignB()) += aOffset
,
646 Point(nRight
, GetAlignB()) += aOffset
);
647 rDev
.DrawLine(Point(nLeft
, GetAlignT()) += aOffset
,
648 Point(nRight
, GetAlignT()) += aOffset
);
650 rDev
.DrawLine(Point(nLeft
, GetBaseline()) += aOffset
,
651 Point(nRight
, GetBaseline()) += aOffset
);
653 rDev
.SetLineColor(COL_GRAY
);
654 rDev
.DrawLine(Point(nLeft
, GetHiAttrFence()) += aOffset
,
655 Point(nRight
, GetHiAttrFence()) += aOffset
);
658 if (nFlags
& SM_RECT_MID
)
659 { Point aCenter
= rPosition
660 + (Point(GetItalicCenterX(), GetAlignM()) -= GetTopLeft()),
661 aLenX (GetWidth() / 5, 0),
662 aLenY (0, GetHeight() / 16);
664 rDev
.SetLineColor(COL_LIGHTGREEN
);
665 rDev
.DrawLine(aCenter
- aLenX
, aCenter
+ aLenX
);
666 rDev
.DrawLine(aCenter
- aLenY
, aCenter
+ aLenY
);
669 if (nFlags
& SM_RECT_ITALIC
)
670 SmDrawFrame(rDev
, Rectangle(rPosition
- Point(GetItalicLeftSpace(), 0),
673 if (nFlags
& SM_RECT_CORE
)
674 SmDrawFrame(rDev
, Rectangle(rPosition
, GetSize()), COL_LIGHTRED
);
680 void SmDrawFrame(OutputDevice
&rDev
, const Rectangle
&rRec
,
683 rDev
.Push(PUSH_LINECOLOR
);
685 rDev
.SetLineColor(aCol
);
687 rDev
.DrawLine(rRec
.TopLeft(), rRec
.BottomLeft());
688 rDev
.DrawLine(rRec
.BottomLeft(), rRec
.BottomRight());
689 rDev
.DrawLine(rRec
.BottomRight(), rRec
.TopRight());
690 rDev
.DrawLine(rRec
.TopRight(), rRec
.TopLeft());
695 #endif //SM_RECT_DEBUG
698 BOOL
SmGetGlyphBoundRect(const OutputDevice
&rDev
,
699 const XubString
&rText
, Rectangle
&rRect
)
700 // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
701 // but with a string as argument.
703 // handle special case first
704 xub_StrLen nLen
= rText
.Len();
710 // get a device where 'OutputDevice::GetTextBoundRect' will be successful
711 OutputDevice
*pGlyphDev
;
712 if (rDev
.GetOutDevType() != OUTDEV_PRINTER
)
713 pGlyphDev
= (OutputDevice
*) &rDev
;
716 // since we format for the printer (where GetTextBoundRect will fail)
717 // we need a virtual device here.
718 pGlyphDev
= &SM_MOD()->GetDefaultVirtualDev();
721 const FontMetric
aDevFM (rDev
.GetFontMetric());
723 pGlyphDev
->Push(PUSH_FONT
| PUSH_MAPMODE
);
724 Font
aFnt(rDev
.GetFont());
725 aFnt
.SetAlign(ALIGN_TOP
);
727 // use scale factor when calling GetTextBoundRect to counter
728 // negative effects from antialiasing which may otherwise result
729 // in significant incorrect bounding rectangles for some charcters.
730 Size aFntSize
= aFnt
.GetSize();
732 // HDU: workaround to avoid HUGE font sizes and resulting problems (#112783#)
733 long nScaleFactor
= 1;
734 while( aFntSize
.Height() > 2000 * nScaleFactor
)
737 aFnt
.SetSize( Size( aFntSize
.Width() / nScaleFactor
, aFntSize
.Height() / nScaleFactor
) );
738 pGlyphDev
->SetFont(aFnt
);
740 long nTextWidth
= rDev
.GetTextWidth(rText
);
742 Rectangle
aResult (aPoint
, Size(nTextWidth
, rDev
.GetTextHeight())),
745 BOOL bSuccess
= pGlyphDev
->GetTextBoundRect(aTmp
, rText
, 0, 0);
746 DBG_ASSERT( bSuccess
, "GetTextBoundRect failed" );
751 aResult
= Rectangle(aTmp
.Left() * nScaleFactor
, aTmp
.Top() * nScaleFactor
,
752 aTmp
.Right() * nScaleFactor
, aTmp
.Bottom() * nScaleFactor
);
753 if (&rDev
!= pGlyphDev
) /* only when rDev is a printer... */
755 long nGDTextWidth
= pGlyphDev
->GetTextWidth(rText
);
756 if (nGDTextWidth
!= 0 &&
757 nTextWidth
!= nGDTextWidth
)
759 aResult
.Right() *= nTextWidth
;
760 aResult
.Right() /= nGDTextWidth
* nScaleFactor
;
765 // move rectangle to match possibly different baselines
766 // (because of different devices)
767 long nDelta
= aDevFM
.GetAscent() - pGlyphDev
->GetFontMetric().GetAscent() * nScaleFactor
;
768 aResult
.Move(0, nDelta
);