1*d107581fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*d107581fSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*d107581fSAndrew Rist * or more contributor license agreements. See the NOTICE file
5*d107581fSAndrew Rist * distributed with this work for additional information
6*d107581fSAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*d107581fSAndrew Rist * to you under the Apache License, Version 2.0 (the
8*d107581fSAndrew Rist * "License"); you may not use this file except in compliance
9*d107581fSAndrew Rist * with the License. You may obtain a copy of the License at
10*d107581fSAndrew Rist *
11*d107581fSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*d107581fSAndrew Rist *
13*d107581fSAndrew Rist * Unless required by applicable law or agreed to in writing,
14*d107581fSAndrew Rist * software distributed under the License is distributed on an
15*d107581fSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*d107581fSAndrew Rist * KIND, either express or implied. See the License for the
17*d107581fSAndrew Rist * specific language governing permissions and limitations
18*d107581fSAndrew Rist * under the License.
19*d107581fSAndrew Rist *
20*d107581fSAndrew Rist *************************************************************/
21*d107581fSAndrew Rist
22*d107581fSAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_starmath.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir
28cdf0e10cSrcweir #include <tools/string.hxx>
29cdf0e10cSrcweir #include <tools/debug.hxx>
30cdf0e10cSrcweir #include <vcl/svapp.hxx>
31cdf0e10cSrcweir #include <vcl/wrkwin.hxx>
32cdf0e10cSrcweir #include <vcl/virdev.hxx>
33cdf0e10cSrcweir
34cdf0e10cSrcweir
35cdf0e10cSrcweir #include "rect.hxx"
36cdf0e10cSrcweir #include "types.hxx"
37cdf0e10cSrcweir #include "utility.hxx"
38cdf0e10cSrcweir #include "smmod.hxx"
39cdf0e10cSrcweir
40cdf0e10cSrcweir
41cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////////
42cdf0e10cSrcweir
43cdf0e10cSrcweir
44cdf0e10cSrcweir // '\0' terminiertes Array mit Zeichen, die im StarMath Font als Buchstaben
45cdf0e10cSrcweir // betrachtet werden sollen, (um im Gegensatz zu den anderen Operatoren
46cdf0e10cSrcweir // und Symbolen ein "normales"(ungecliptes) SmRect zu erhalten).
47cdf0e10cSrcweir static xub_Unicode __READONLY_DATA aMathAlpha[] =
48cdf0e10cSrcweir {
49cdf0e10cSrcweir MS_ALEPH, MS_IM, MS_RE,
50cdf0e10cSrcweir MS_WP, xub_Unicode(0xE070), MS_EMPTYSET,
51cdf0e10cSrcweir xub_Unicode(0x2113), xub_Unicode(0xE0D6), xub_Unicode(0x2107),
52cdf0e10cSrcweir xub_Unicode(0x2127), xub_Unicode(0x210A), MS_HBAR,
53cdf0e10cSrcweir MS_LAMBDABAR, MS_SETN, MS_SETZ,
54cdf0e10cSrcweir MS_SETQ, MS_SETR, MS_SETC,
55cdf0e10cSrcweir xub_Unicode(0x2373), xub_Unicode(0xE0A5), xub_Unicode(0x2112),
56cdf0e10cSrcweir xub_Unicode(0x2130), xub_Unicode(0x2131),
57cdf0e10cSrcweir xub_Unicode('\0')
58cdf0e10cSrcweir };
59cdf0e10cSrcweir
SmIsMathAlpha(const XubString & rText)60cdf0e10cSrcweir sal_Bool SmIsMathAlpha(const XubString &rText)
61cdf0e10cSrcweir // ergibt genau dann sal_True, wenn das Zeichen (aus dem StarMath Font) wie ein
62cdf0e10cSrcweir // Buchstabe behandelt werden soll.
63cdf0e10cSrcweir {
64cdf0e10cSrcweir if (rText.Len() == 0)
65cdf0e10cSrcweir return sal_False;
66cdf0e10cSrcweir
67cdf0e10cSrcweir DBG_ASSERT(rText.Len() == 1, "Sm : String enthaelt nicht genau ein Zeichen");
68cdf0e10cSrcweir xub_Unicode cChar = rText.GetChar(0);
69cdf0e10cSrcweir
70cdf0e10cSrcweir // ist es ein griechisches Zeichen ?
71cdf0e10cSrcweir if (xub_Unicode(0xE0AC) <= cChar && cChar <= xub_Unicode(0xE0D4))
72cdf0e10cSrcweir return sal_True;
73cdf0e10cSrcweir else
74cdf0e10cSrcweir {
75cdf0e10cSrcweir // kommt es in 'aMathAlpha' vor ?
76cdf0e10cSrcweir const xub_Unicode *pChar = aMathAlpha;
77cdf0e10cSrcweir while (*pChar && *pChar != cChar)
78cdf0e10cSrcweir pChar++;
79cdf0e10cSrcweir return *pChar != xub_Unicode('\0');
80cdf0e10cSrcweir }
81cdf0e10cSrcweir }
82cdf0e10cSrcweir
83cdf0e10cSrcweir
84cdf0e10cSrcweir ////////////////////////////////////////
85cdf0e10cSrcweir //
86cdf0e10cSrcweir // SmRect members
87cdf0e10cSrcweir //
88cdf0e10cSrcweir
89cdf0e10cSrcweir
SmRect()90cdf0e10cSrcweir SmRect::SmRect()
91cdf0e10cSrcweir // constructs empty rectangle at (0, 0) with width and height 0.
92cdf0e10cSrcweir {
93cdf0e10cSrcweir DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: ooops...");
94cdf0e10cSrcweir DBG_ASSERT(aSize == Size(0, 0), "Sm: ooops...");
95cdf0e10cSrcweir
96cdf0e10cSrcweir bHasBaseline = bHasAlignInfo = sal_False;
97cdf0e10cSrcweir nBaseline = nAlignT = nAlignM = nAlignB =
98cdf0e10cSrcweir nGlyphTop = nGlyphBottom =
99cdf0e10cSrcweir nItalicLeftSpace = nItalicRightSpace =
100cdf0e10cSrcweir nLoAttrFence = nHiAttrFence = 0;
101cdf0e10cSrcweir nBorderWidth = 0;
102cdf0e10cSrcweir }
103cdf0e10cSrcweir
104cdf0e10cSrcweir
SmRect(const SmRect & rRect)105cdf0e10cSrcweir SmRect::SmRect(const SmRect &rRect)
106cdf0e10cSrcweir : aTopLeft(rRect.aTopLeft),
107cdf0e10cSrcweir aSize(rRect.aSize)
108cdf0e10cSrcweir {
109cdf0e10cSrcweir bHasBaseline = rRect.bHasBaseline;
110cdf0e10cSrcweir nBaseline = rRect.nBaseline;
111cdf0e10cSrcweir nAlignT = rRect.nAlignT;
112cdf0e10cSrcweir nAlignM = rRect.nAlignM;
113cdf0e10cSrcweir nAlignB = rRect.nAlignB;
114cdf0e10cSrcweir nGlyphTop = rRect.nGlyphTop;
115cdf0e10cSrcweir nGlyphBottom = rRect.nGlyphBottom;
116cdf0e10cSrcweir nHiAttrFence = rRect.nHiAttrFence;
117cdf0e10cSrcweir nLoAttrFence = rRect.nLoAttrFence;
118cdf0e10cSrcweir bHasAlignInfo = rRect.bHasAlignInfo;
119cdf0e10cSrcweir nItalicLeftSpace = rRect.nItalicLeftSpace;
120cdf0e10cSrcweir nItalicRightSpace = rRect.nItalicRightSpace;
121cdf0e10cSrcweir nBorderWidth = rRect.nBorderWidth;
122cdf0e10cSrcweir }
123cdf0e10cSrcweir
124cdf0e10cSrcweir
CopyAlignInfo(const SmRect & rRect)125cdf0e10cSrcweir void SmRect::CopyAlignInfo(const SmRect &rRect)
126cdf0e10cSrcweir {
127cdf0e10cSrcweir nBaseline = rRect.nBaseline;
128cdf0e10cSrcweir bHasBaseline = rRect.bHasBaseline;
129cdf0e10cSrcweir nAlignT = rRect.nAlignT;
130cdf0e10cSrcweir nAlignM = rRect.nAlignM;
131cdf0e10cSrcweir nAlignB = rRect.nAlignB;
132cdf0e10cSrcweir bHasAlignInfo = rRect.bHasAlignInfo;
133cdf0e10cSrcweir nLoAttrFence = rRect.nLoAttrFence;
134cdf0e10cSrcweir nHiAttrFence = rRect.nHiAttrFence;
135cdf0e10cSrcweir }
136cdf0e10cSrcweir
137cdf0e10cSrcweir
BuildRect(const OutputDevice & rDev,const SmFormat * pFormat,const XubString & rText,sal_uInt16 nBorder)138cdf0e10cSrcweir void SmRect::BuildRect(const OutputDevice &rDev, const SmFormat *pFormat,
139cdf0e10cSrcweir const XubString &rText, sal_uInt16 nBorder)
140cdf0e10cSrcweir {
141cdf0e10cSrcweir DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: Ooops...");
142cdf0e10cSrcweir
143cdf0e10cSrcweir aSize = Size(rDev.GetTextWidth(rText), rDev.GetTextHeight());
144cdf0e10cSrcweir
145cdf0e10cSrcweir const FontMetric aFM (rDev.GetFontMetric());
146cdf0e10cSrcweir sal_Bool bIsMath = aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH );
147cdf0e10cSrcweir sal_Bool bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
148cdf0e10cSrcweir const long nFontHeight = rDev.GetFont().GetSize().Height();
149cdf0e10cSrcweir
150cdf0e10cSrcweir nBorderWidth = nBorder;
151cdf0e10cSrcweir bHasAlignInfo = sal_True;
152cdf0e10cSrcweir bHasBaseline = sal_True;
153cdf0e10cSrcweir nBaseline = aFM.GetAscent();
154cdf0e10cSrcweir nAlignT = nBaseline - nFontHeight * 750L / 1000L;
155cdf0e10cSrcweir nAlignM = nBaseline - nFontHeight * 121L / 422L;
156cdf0e10cSrcweir // that's where the horizontal bars of '+', '-', ... are
157cdf0e10cSrcweir // (1/3 of ascent over baseline)
158cdf0e10cSrcweir // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
159cdf0e10cSrcweir nAlignB = nBaseline;
160cdf0e10cSrcweir
161cdf0e10cSrcweir // workaround for printer fonts with very small (possible 0 or even
162cdf0e10cSrcweir // negative(!)) leading
163cdf0e10cSrcweir if (aFM.GetIntLeading() < 5 && rDev.GetOutDevType() == OUTDEV_PRINTER)
164cdf0e10cSrcweir {
165cdf0e10cSrcweir OutputDevice *pWindow = Application::GetDefaultDevice();
166cdf0e10cSrcweir
167cdf0e10cSrcweir pWindow->Push(PUSH_MAPMODE | PUSH_FONT);
168cdf0e10cSrcweir
169cdf0e10cSrcweir pWindow->SetMapMode(rDev.GetMapMode());
170cdf0e10cSrcweir pWindow->SetFont(rDev.GetFontMetric());
171cdf0e10cSrcweir
172cdf0e10cSrcweir long nDelta = pWindow->GetFontMetric().GetIntLeading();
173cdf0e10cSrcweir if (nDelta == 0)
174cdf0e10cSrcweir { // dieser Wert entspricht etwa einem Leading von 80 bei einer
175cdf0e10cSrcweir // Fonthoehe von 422 (12pt)
176cdf0e10cSrcweir nDelta = nFontHeight * 8L / 43;
177cdf0e10cSrcweir }
178cdf0e10cSrcweir SetTop(GetTop() - nDelta);
179cdf0e10cSrcweir
180cdf0e10cSrcweir pWindow->Pop();
181cdf0e10cSrcweir }
182cdf0e10cSrcweir
183cdf0e10cSrcweir // get GlyphBoundRect
184cdf0e10cSrcweir Rectangle aGlyphRect;
185cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
186cdf0e10cSrcweir sal_Bool bSuccess =
187cdf0e10cSrcweir #endif
188cdf0e10cSrcweir SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
189cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
190cdf0e10cSrcweir if (!bSuccess)
191cdf0e10cSrcweir {
192cdf0e10cSrcweir DBG_ERROR( "Sm : Ooops... (fehlt evtl. der Font?)");
193cdf0e10cSrcweir }
194cdf0e10cSrcweir #endif
195cdf0e10cSrcweir
196cdf0e10cSrcweir nItalicLeftSpace = GetLeft() - aGlyphRect.Left() + nBorderWidth;
197cdf0e10cSrcweir nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
198cdf0e10cSrcweir if (nItalicLeftSpace < 0 && !bAllowSmaller)
199cdf0e10cSrcweir nItalicLeftSpace = 0;
200cdf0e10cSrcweir if (nItalicRightSpace < 0 && !bAllowSmaller)
201cdf0e10cSrcweir nItalicRightSpace = 0;
202cdf0e10cSrcweir
203cdf0e10cSrcweir long nDist = 0;
204cdf0e10cSrcweir if (pFormat)
205cdf0e10cSrcweir nDist = (rDev.GetFont().GetSize().Height()
206cdf0e10cSrcweir * pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100L;
207cdf0e10cSrcweir
208cdf0e10cSrcweir nHiAttrFence = aGlyphRect.TopLeft().Y() - 1 - nBorderWidth - nDist;
209cdf0e10cSrcweir nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);
210cdf0e10cSrcweir
211cdf0e10cSrcweir nGlyphTop = aGlyphRect.Top() - nBorderWidth;
212cdf0e10cSrcweir nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;
213cdf0e10cSrcweir
214cdf0e10cSrcweir if (bAllowSmaller)
215cdf0e10cSrcweir {
216cdf0e10cSrcweir // fuer Symbole und Operatoren aus dem StarMath Font passen wir den
217cdf0e10cSrcweir // oberen und unteren Rand dem Zeichen an.
218cdf0e10cSrcweir SetTop(nGlyphTop);
219cdf0e10cSrcweir SetBottom(nGlyphBottom);
220cdf0e10cSrcweir }
221cdf0e10cSrcweir
222cdf0e10cSrcweir if (nHiAttrFence < GetTop())
223cdf0e10cSrcweir nHiAttrFence = GetTop();
224cdf0e10cSrcweir
225cdf0e10cSrcweir if (nLoAttrFence > GetBottom())
226cdf0e10cSrcweir nLoAttrFence = GetBottom();
227cdf0e10cSrcweir
228cdf0e10cSrcweir DBG_ASSERT(rText.Len() == 0 || !IsEmpty(),
229cdf0e10cSrcweir "Sm: leeres Rechteck erzeugt");
230cdf0e10cSrcweir }
231cdf0e10cSrcweir
232cdf0e10cSrcweir
Init(const OutputDevice & rDev,const SmFormat * pFormat,const XubString & rText,sal_uInt16 nEBorderWidth)233cdf0e10cSrcweir void SmRect::Init(const OutputDevice &rDev, const SmFormat *pFormat,
234cdf0e10cSrcweir const XubString &rText, sal_uInt16 nEBorderWidth)
235cdf0e10cSrcweir // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
236cdf0e10cSrcweir {
237cdf0e10cSrcweir BuildRect(rDev, pFormat, rText, nEBorderWidth);
238cdf0e10cSrcweir }
239cdf0e10cSrcweir
240cdf0e10cSrcweir
SmRect(const OutputDevice & rDev,const SmFormat * pFormat,const XubString & rText,long nEBorderWidth)241cdf0e10cSrcweir SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
242cdf0e10cSrcweir const XubString &rText, long nEBorderWidth)
243cdf0e10cSrcweir {
244cdf0e10cSrcweir DBG_ASSERT( nEBorderWidth >= 0, "BorderWidth negativ" );
245cdf0e10cSrcweir if (nEBorderWidth < 0)
246cdf0e10cSrcweir nEBorderWidth = 0;
247cdf0e10cSrcweir Init(rDev, pFormat, rText, (sal_uInt16) nEBorderWidth);
248cdf0e10cSrcweir }
249cdf0e10cSrcweir
250cdf0e10cSrcweir
SmRect(long nWidth,long nHeight)251cdf0e10cSrcweir SmRect::SmRect(long nWidth, long nHeight)
252cdf0e10cSrcweir // this constructor should never be used for anything textlike because
253cdf0e10cSrcweir // it will not provide useful values for baseline, AlignT and AlignB!
254cdf0e10cSrcweir // It's purpose is to get a 'SmRect' for the horizontal line in fractions
255cdf0e10cSrcweir // as used in 'SmBinVerNode'.
256cdf0e10cSrcweir : aSize(nWidth, nHeight)
257cdf0e10cSrcweir {
258cdf0e10cSrcweir DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: ooops...");
259cdf0e10cSrcweir
260cdf0e10cSrcweir bHasBaseline = sal_False;
261cdf0e10cSrcweir bHasAlignInfo = sal_True;
262cdf0e10cSrcweir nBaseline = 0;
263cdf0e10cSrcweir nAlignT = GetTop();
264cdf0e10cSrcweir nAlignB = GetBottom();
265cdf0e10cSrcweir nAlignM = (nAlignT + nAlignB) / 2; // this is the default
266cdf0e10cSrcweir nItalicLeftSpace = nItalicRightSpace = 0;
267cdf0e10cSrcweir nGlyphTop = nHiAttrFence = GetTop();
268cdf0e10cSrcweir nGlyphBottom = nLoAttrFence = GetBottom();
269cdf0e10cSrcweir nBorderWidth = 0;
270cdf0e10cSrcweir }
271cdf0e10cSrcweir
272cdf0e10cSrcweir
SetLeft(long nLeft)273cdf0e10cSrcweir void SmRect::SetLeft(long nLeft)
274cdf0e10cSrcweir {
275cdf0e10cSrcweir if (nLeft <= GetRight())
276cdf0e10cSrcweir { aSize.Width() = GetRight() - nLeft + 1;
277cdf0e10cSrcweir aTopLeft.X() = nLeft;
278cdf0e10cSrcweir }
279cdf0e10cSrcweir }
280cdf0e10cSrcweir
281cdf0e10cSrcweir
SetRight(long nRight)282cdf0e10cSrcweir void SmRect::SetRight(long nRight)
283cdf0e10cSrcweir {
284cdf0e10cSrcweir if (nRight >= GetLeft())
285cdf0e10cSrcweir aSize.Width() = nRight - GetLeft() + 1;
286cdf0e10cSrcweir }
287cdf0e10cSrcweir
288cdf0e10cSrcweir
SetBottom(long nBottom)289cdf0e10cSrcweir void SmRect::SetBottom(long nBottom)
290cdf0e10cSrcweir {
291cdf0e10cSrcweir if (nBottom >= GetTop())
292cdf0e10cSrcweir aSize.Height() = nBottom - GetTop() + 1;
293cdf0e10cSrcweir }
294cdf0e10cSrcweir
295cdf0e10cSrcweir
SetTop(long nTop)296cdf0e10cSrcweir void SmRect::SetTop(long nTop)
297cdf0e10cSrcweir {
298cdf0e10cSrcweir if (nTop <= GetBottom())
299cdf0e10cSrcweir { aSize.Height() = GetBottom() - nTop + 1;
300cdf0e10cSrcweir aTopLeft.Y() = nTop;
301cdf0e10cSrcweir }
302cdf0e10cSrcweir }
303cdf0e10cSrcweir
304cdf0e10cSrcweir
Move(const Point & rPosition)305cdf0e10cSrcweir void SmRect::Move(const Point &rPosition)
306cdf0e10cSrcweir // move rectangle by position 'rPosition'.
307cdf0e10cSrcweir {
308cdf0e10cSrcweir aTopLeft += rPosition;
309cdf0e10cSrcweir
310cdf0e10cSrcweir long nDelta = rPosition.Y();
311cdf0e10cSrcweir nBaseline += nDelta;
312cdf0e10cSrcweir nAlignT += nDelta;
313cdf0e10cSrcweir nAlignM += nDelta;
314cdf0e10cSrcweir nAlignB += nDelta;
315cdf0e10cSrcweir nGlyphTop += nDelta;
316cdf0e10cSrcweir nGlyphBottom += nDelta;
317cdf0e10cSrcweir nHiAttrFence += nDelta;
318cdf0e10cSrcweir nLoAttrFence += nDelta;
319cdf0e10cSrcweir }
320cdf0e10cSrcweir
321cdf0e10cSrcweir
AlignTo(const SmRect & rRect,RectPos ePos,RectHorAlign eHor,RectVerAlign eVer) const322cdf0e10cSrcweir const Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
323cdf0e10cSrcweir RectHorAlign eHor, RectVerAlign eVer) const
324cdf0e10cSrcweir { Point aPos (GetTopLeft());
325cdf0e10cSrcweir // will become the topleft point of the new rectangle position
326cdf0e10cSrcweir
327cdf0e10cSrcweir // set horizontal or vertical new rectangle position depending on
328cdf0e10cSrcweir // 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
329cdf0e10cSrcweir switch (ePos)
330cdf0e10cSrcweir { case RP_LEFT :
331cdf0e10cSrcweir aPos.X() = rRect.GetItalicLeft() - GetItalicRightSpace()
332cdf0e10cSrcweir - GetWidth();
333cdf0e10cSrcweir break;
334cdf0e10cSrcweir case RP_RIGHT :
335cdf0e10cSrcweir aPos.X() = rRect.GetItalicRight() + 1 + GetItalicLeftSpace();
336cdf0e10cSrcweir break;
337cdf0e10cSrcweir case RP_TOP :
338cdf0e10cSrcweir aPos.Y() = rRect.GetTop() - GetHeight();
339cdf0e10cSrcweir break;
340cdf0e10cSrcweir case RP_BOTTOM :
341cdf0e10cSrcweir aPos.Y() = rRect.GetBottom() + 1;
342cdf0e10cSrcweir break;
343cdf0e10cSrcweir case RP_ATTRIBUT :
344cdf0e10cSrcweir aPos.X() = rRect.GetItalicCenterX() - GetItalicWidth() / 2
345cdf0e10cSrcweir + GetItalicLeftSpace();
346cdf0e10cSrcweir break;
347cdf0e10cSrcweir default :
348cdf0e10cSrcweir DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
349cdf0e10cSrcweir }
350cdf0e10cSrcweir
351cdf0e10cSrcweir // check if horizontal position is already set
352cdf0e10cSrcweir if (ePos == RP_LEFT || ePos == RP_RIGHT || ePos == RP_ATTRIBUT)
353cdf0e10cSrcweir // correct error in current vertical position
354cdf0e10cSrcweir switch (eVer)
355cdf0e10cSrcweir { case RVA_TOP :
356cdf0e10cSrcweir aPos.Y() += rRect.GetAlignT() - GetAlignT();
357cdf0e10cSrcweir break;
358cdf0e10cSrcweir case RVA_MID :
359cdf0e10cSrcweir aPos.Y() += rRect.GetAlignM() - GetAlignM();
360cdf0e10cSrcweir break;
361cdf0e10cSrcweir case RVA_BASELINE :
362cdf0e10cSrcweir // align baselines if possible else align mid's
363cdf0e10cSrcweir if (HasBaseline() && rRect.HasBaseline())
364cdf0e10cSrcweir aPos.Y() += rRect.GetBaseline() - GetBaseline();
365cdf0e10cSrcweir else
366cdf0e10cSrcweir aPos.Y() += rRect.GetAlignM() - GetAlignM();
367cdf0e10cSrcweir break;
368cdf0e10cSrcweir case RVA_BOTTOM :
369cdf0e10cSrcweir aPos.Y() += rRect.GetAlignB() - GetAlignB();
370cdf0e10cSrcweir break;
371cdf0e10cSrcweir case RVA_CENTERY :
372cdf0e10cSrcweir aPos.Y() += rRect.GetCenterY() - GetCenterY();
373cdf0e10cSrcweir break;
374cdf0e10cSrcweir case RVA_ATTRIBUT_HI:
375cdf0e10cSrcweir aPos.Y() += rRect.GetHiAttrFence() - GetBottom();
376cdf0e10cSrcweir break;
377cdf0e10cSrcweir case RVA_ATTRIBUT_MID :
378cdf0e10cSrcweir aPos.Y() += SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
379cdf0e10cSrcweir - GetCenterY();
380cdf0e10cSrcweir break;
381cdf0e10cSrcweir case RVA_ATTRIBUT_LO :
382cdf0e10cSrcweir aPos.Y() += rRect.GetLoAttrFence() - GetTop();
383cdf0e10cSrcweir break;
384cdf0e10cSrcweir default :
385cdf0e10cSrcweir DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
386cdf0e10cSrcweir }
387cdf0e10cSrcweir
388cdf0e10cSrcweir // check if vertical position is already set
389cdf0e10cSrcweir if (ePos == RP_TOP || ePos == RP_BOTTOM)
390cdf0e10cSrcweir // correct error in current horizontal position
391cdf0e10cSrcweir switch (eHor)
392cdf0e10cSrcweir { case RHA_LEFT :
393cdf0e10cSrcweir aPos.X() += rRect.GetItalicLeft() - GetItalicLeft();
394cdf0e10cSrcweir break;
395cdf0e10cSrcweir case RHA_CENTER :
396cdf0e10cSrcweir aPos.X() += rRect.GetItalicCenterX() - GetItalicCenterX();
397cdf0e10cSrcweir break;
398cdf0e10cSrcweir case RHA_RIGHT :
399cdf0e10cSrcweir aPos.X() += rRect.GetItalicRight() - GetItalicRight();
400cdf0e10cSrcweir break;
401cdf0e10cSrcweir default :
402cdf0e10cSrcweir DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
403cdf0e10cSrcweir }
404cdf0e10cSrcweir
405cdf0e10cSrcweir return aPos;
406cdf0e10cSrcweir }
407cdf0e10cSrcweir
408cdf0e10cSrcweir
Union(const SmRect & rRect)409cdf0e10cSrcweir SmRect & SmRect::Union(const SmRect &rRect)
410cdf0e10cSrcweir // rectangle union of current one with 'rRect'. The result is to be the
411cdf0e10cSrcweir // smallest rectangles that covers the space of both rectangles.
412cdf0e10cSrcweir // (empty rectangles cover no space)
413cdf0e10cSrcweir //! Italic correction is NOT taken into account here!
414cdf0e10cSrcweir {
415cdf0e10cSrcweir if (rRect.IsEmpty())
416cdf0e10cSrcweir return *this;
417cdf0e10cSrcweir
418cdf0e10cSrcweir long nL = rRect.GetLeft(),
419cdf0e10cSrcweir nR = rRect.GetRight(),
420cdf0e10cSrcweir nT = rRect.GetTop(),
421cdf0e10cSrcweir nB = rRect.GetBottom(),
422cdf0e10cSrcweir nGT = rRect.nGlyphTop,
423cdf0e10cSrcweir nGB = rRect.nGlyphBottom;
424cdf0e10cSrcweir if (!IsEmpty())
425cdf0e10cSrcweir { long nTmp;
426cdf0e10cSrcweir
427cdf0e10cSrcweir if ((nTmp = GetLeft()) < nL)
428cdf0e10cSrcweir nL = nTmp;
429cdf0e10cSrcweir if ((nTmp = GetRight()) > nR)
430cdf0e10cSrcweir nR = nTmp;
431cdf0e10cSrcweir if ((nTmp = GetTop()) < nT)
432cdf0e10cSrcweir nT = nTmp;
433cdf0e10cSrcweir if ((nTmp = GetBottom()) > nB)
434cdf0e10cSrcweir nB = nTmp;
435cdf0e10cSrcweir if ((nTmp = nGlyphTop) < nGT)
436cdf0e10cSrcweir nGT = nTmp;
437cdf0e10cSrcweir if ((nTmp = nGlyphBottom) > nGB)
438cdf0e10cSrcweir nGB = nTmp;
439cdf0e10cSrcweir }
440cdf0e10cSrcweir
441cdf0e10cSrcweir SetLeft(nL);
442cdf0e10cSrcweir SetRight(nR);
443cdf0e10cSrcweir SetTop(nT);
444cdf0e10cSrcweir SetBottom(nB);
445cdf0e10cSrcweir nGlyphTop = nGT;
446cdf0e10cSrcweir nGlyphBottom = nGB;
447cdf0e10cSrcweir
448cdf0e10cSrcweir return *this;
449cdf0e10cSrcweir }
450cdf0e10cSrcweir
451cdf0e10cSrcweir
ExtendBy(const SmRect & rRect,RectCopyMBL eCopyMode)452cdf0e10cSrcweir SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode)
453cdf0e10cSrcweir // let current rectangle be the union of itself and 'rRect'
454cdf0e10cSrcweir // (the smallest rectangle surrounding both). Also adapt values for
455cdf0e10cSrcweir // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
456cdf0e10cSrcweir // The baseline is set according to 'eCopyMode'.
457cdf0e10cSrcweir // If one of the rectangles has no relevant info the other one is copied.
458cdf0e10cSrcweir {
459cdf0e10cSrcweir // get some values used for (italic) spaces adaption
460cdf0e10cSrcweir // ! (need to be done before changing current SmRect) !
461cdf0e10cSrcweir long nL = Min(GetItalicLeft(), rRect.GetItalicLeft()),
462cdf0e10cSrcweir nR = Max(GetItalicRight(), rRect.GetItalicRight());
463cdf0e10cSrcweir
464cdf0e10cSrcweir Union(rRect);
465cdf0e10cSrcweir
466cdf0e10cSrcweir SetItalicSpaces(GetLeft() - nL, nR - GetRight());
467cdf0e10cSrcweir
468cdf0e10cSrcweir if (!HasAlignInfo())
469cdf0e10cSrcweir CopyAlignInfo(rRect);
470cdf0e10cSrcweir else if (rRect.HasAlignInfo())
471cdf0e10cSrcweir { nAlignT = Min(GetAlignT(), rRect.GetAlignT());
472cdf0e10cSrcweir nAlignB = Max(GetAlignB(), rRect.GetAlignB());
473cdf0e10cSrcweir nHiAttrFence = Min(GetHiAttrFence(), rRect.GetHiAttrFence());
474cdf0e10cSrcweir nLoAttrFence = Max(GetLoAttrFence(), rRect.GetLoAttrFence());
475cdf0e10cSrcweir DBG_ASSERT(HasAlignInfo(), "Sm: ooops...");
476cdf0e10cSrcweir
477cdf0e10cSrcweir switch (eCopyMode)
478cdf0e10cSrcweir { case RCP_THIS:
479cdf0e10cSrcweir // already done
480cdf0e10cSrcweir break;
481cdf0e10cSrcweir case RCP_ARG:
482cdf0e10cSrcweir CopyMBL(rRect);
483cdf0e10cSrcweir break;
484cdf0e10cSrcweir case RCP_NONE:
485cdf0e10cSrcweir ClearBaseline();
486cdf0e10cSrcweir nAlignM = (nAlignT + nAlignB) / 2;
487cdf0e10cSrcweir break;
488cdf0e10cSrcweir case RCP_XOR:
489cdf0e10cSrcweir if (!HasBaseline())
490cdf0e10cSrcweir CopyMBL(rRect);
491cdf0e10cSrcweir break;
492cdf0e10cSrcweir default :
493cdf0e10cSrcweir DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
494cdf0e10cSrcweir }
495cdf0e10cSrcweir }
496cdf0e10cSrcweir
497cdf0e10cSrcweir return *this;
498cdf0e10cSrcweir }
499cdf0e10cSrcweir
500cdf0e10cSrcweir
ExtendBy(const SmRect & rRect,RectCopyMBL eCopyMode,long nNewAlignM)501cdf0e10cSrcweir SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
502cdf0e10cSrcweir long nNewAlignM)
503cdf0e10cSrcweir // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
504cdf0e10cSrcweir // (this version will be used in 'SmBinVerNode' to provide means to
505cdf0e10cSrcweir // align eg "{a over b} over c" correctly where AlignM should not
506cdf0e10cSrcweir // be (AlignT + AlignB) / 2)
507cdf0e10cSrcweir {
508cdf0e10cSrcweir DBG_ASSERT(HasAlignInfo(), "Sm: keine Align Info");
509cdf0e10cSrcweir
510cdf0e10cSrcweir ExtendBy(rRect, eCopyMode);
511cdf0e10cSrcweir nAlignM = nNewAlignM;
512cdf0e10cSrcweir
513cdf0e10cSrcweir return *this;
514cdf0e10cSrcweir }
515cdf0e10cSrcweir
516cdf0e10cSrcweir
ExtendBy(const SmRect & rRect,RectCopyMBL eCopyMode,sal_Bool bKeepVerAlignParams)517cdf0e10cSrcweir SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
518cdf0e10cSrcweir sal_Bool bKeepVerAlignParams)
519cdf0e10cSrcweir // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
520cdf0e10cSrcweir // baseline.
521cdf0e10cSrcweir // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
522cdf0e10cSrcweir // be allowed to modify these values.)
523cdf0e10cSrcweir {
524cdf0e10cSrcweir long nOldAlignT = GetAlignT(),
525cdf0e10cSrcweir nOldAlignM = GetAlignM(),
526cdf0e10cSrcweir nOldAlignB = GetAlignB(),
527cdf0e10cSrcweir nOldBaseline = nBaseline; //! depends not on 'HasBaseline'
528cdf0e10cSrcweir sal_Bool bOldHasAlignInfo = HasAlignInfo();
529cdf0e10cSrcweir
530cdf0e10cSrcweir ExtendBy(rRect, eCopyMode);
531cdf0e10cSrcweir
532cdf0e10cSrcweir if (bKeepVerAlignParams)
533cdf0e10cSrcweir { nAlignT = nOldAlignT;
534cdf0e10cSrcweir nAlignM = nOldAlignM;
535cdf0e10cSrcweir nAlignB = nOldAlignB;
536cdf0e10cSrcweir nBaseline = nOldBaseline;
537cdf0e10cSrcweir bHasAlignInfo = bOldHasAlignInfo;
538cdf0e10cSrcweir }
539cdf0e10cSrcweir
540cdf0e10cSrcweir return *this;
541cdf0e10cSrcweir }
542cdf0e10cSrcweir
543cdf0e10cSrcweir
OrientedDist(const Point & rPoint) const544cdf0e10cSrcweir long SmRect::OrientedDist(const Point &rPoint) const
545cdf0e10cSrcweir // return oriented distance of rPoint to the current rectangle,
546cdf0e10cSrcweir // especially the return value is <= 0 iff the point is inside the
547cdf0e10cSrcweir // rectangle.
548cdf0e10cSrcweir // For simplicity the maximum-norm is used.
549cdf0e10cSrcweir {
550cdf0e10cSrcweir sal_Bool bIsInside = IsInsideItalicRect(rPoint);
551cdf0e10cSrcweir
552cdf0e10cSrcweir // build reference point to define the distance
553cdf0e10cSrcweir Point aRef;
554cdf0e10cSrcweir if (bIsInside)
555cdf0e10cSrcweir { Point aIC (GetItalicCenterX(), GetCenterY());
556cdf0e10cSrcweir
557cdf0e10cSrcweir aRef.X() = rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft();
558cdf0e10cSrcweir aRef.Y() = rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop();
559cdf0e10cSrcweir }
560cdf0e10cSrcweir else
561cdf0e10cSrcweir {
562cdf0e10cSrcweir // x-coordinate
563cdf0e10cSrcweir if (rPoint.X() > GetItalicRight())
564cdf0e10cSrcweir aRef.X() = GetItalicRight();
565cdf0e10cSrcweir else if (rPoint.X() < GetItalicLeft())
566cdf0e10cSrcweir aRef.X() = GetItalicLeft();
567cdf0e10cSrcweir else
568cdf0e10cSrcweir aRef.X() = rPoint.X();
569cdf0e10cSrcweir // y-coordinate
570cdf0e10cSrcweir if (rPoint.Y() > GetBottom())
571cdf0e10cSrcweir aRef.Y() = GetBottom();
572cdf0e10cSrcweir else if (rPoint.Y() < GetTop())
573cdf0e10cSrcweir aRef.Y() = GetTop();
574cdf0e10cSrcweir else
575cdf0e10cSrcweir aRef.Y() = rPoint.Y();
576cdf0e10cSrcweir }
577cdf0e10cSrcweir
578cdf0e10cSrcweir // build distance vector
579cdf0e10cSrcweir Point aDist (aRef - rPoint);
580cdf0e10cSrcweir
581cdf0e10cSrcweir long nAbsX = labs(aDist.X()),
582cdf0e10cSrcweir nAbsY = labs(aDist.Y());
583cdf0e10cSrcweir
584cdf0e10cSrcweir return bIsInside ? - Min(nAbsX, nAbsY) : Max (nAbsX, nAbsY);
585cdf0e10cSrcweir }
586cdf0e10cSrcweir
587cdf0e10cSrcweir
IsInsideRect(const Point & rPoint) const588cdf0e10cSrcweir sal_Bool SmRect::IsInsideRect(const Point &rPoint) const
589cdf0e10cSrcweir {
590cdf0e10cSrcweir return rPoint.Y() >= GetTop()
591cdf0e10cSrcweir && rPoint.Y() <= GetBottom()
592cdf0e10cSrcweir && rPoint.X() >= GetLeft()
593cdf0e10cSrcweir && rPoint.X() <= GetRight();
594cdf0e10cSrcweir }
595cdf0e10cSrcweir
596cdf0e10cSrcweir
IsInsideItalicRect(const Point & rPoint) const597cdf0e10cSrcweir sal_Bool SmRect::IsInsideItalicRect(const Point &rPoint) const
598cdf0e10cSrcweir {
599cdf0e10cSrcweir return rPoint.Y() >= GetTop()
600cdf0e10cSrcweir && rPoint.Y() <= GetBottom()
601cdf0e10cSrcweir && rPoint.X() >= GetItalicLeft()
602cdf0e10cSrcweir && rPoint.X() <= GetItalicRight();
603cdf0e10cSrcweir }
604cdf0e10cSrcweir
AsGlyphRect() const605cdf0e10cSrcweir SmRect SmRect::AsGlyphRect() const
606cdf0e10cSrcweir {
607cdf0e10cSrcweir SmRect aRect (*this);
608cdf0e10cSrcweir aRect.SetTop(nGlyphTop);
609cdf0e10cSrcweir aRect.SetBottom(nGlyphBottom);
610cdf0e10cSrcweir return aRect;
611cdf0e10cSrcweir }
612cdf0e10cSrcweir
613cdf0e10cSrcweir #ifdef SM_RECT_DEBUG
614cdf0e10cSrcweir
615cdf0e10cSrcweir // forward declaration
616cdf0e10cSrcweir void SmDrawFrame(OutputDevice &rDev, const Rectangle &rRec,
617cdf0e10cSrcweir const Color aCol = COL_BLACK);
618cdf0e10cSrcweir
Draw(OutputDevice & rDev,const Point & rPosition,int nFlags) const619cdf0e10cSrcweir void SmRect::Draw(OutputDevice &rDev, const Point &rPosition, int nFlags) const
620cdf0e10cSrcweir {
621cdf0e10cSrcweir if (IsEmpty())
622cdf0e10cSrcweir return;
623cdf0e10cSrcweir
624cdf0e10cSrcweir rDev.Push(PUSH_LINECOLOR);
625cdf0e10cSrcweir
626cdf0e10cSrcweir if (nFlags & SM_RECT_LINES)
627cdf0e10cSrcweir { long nLeftSpace = 0,
628cdf0e10cSrcweir nRightSpace = 0;
629cdf0e10cSrcweir
630cdf0e10cSrcweir if (nFlags & SM_RECT_ITALIC)
631cdf0e10cSrcweir { nLeftSpace = GetItalicLeftSpace();
632cdf0e10cSrcweir nRightSpace = GetItalicRightSpace();
633cdf0e10cSrcweir }
634cdf0e10cSrcweir
635cdf0e10cSrcweir long nLeft = GetLeft() - nLeftSpace,
636cdf0e10cSrcweir nRight = GetRight() + nRightSpace;
637cdf0e10cSrcweir
638cdf0e10cSrcweir Point aOffset (rPosition - GetTopLeft());
639cdf0e10cSrcweir
640cdf0e10cSrcweir rDev.SetLineColor(COL_LIGHTBLUE);
641cdf0e10cSrcweir rDev.DrawLine(Point(nLeft, GetAlignB()) += aOffset,
642cdf0e10cSrcweir Point(nRight, GetAlignB()) += aOffset);
643cdf0e10cSrcweir rDev.DrawLine(Point(nLeft, GetAlignT()) += aOffset,
644cdf0e10cSrcweir Point(nRight, GetAlignT()) += aOffset);
645cdf0e10cSrcweir if (HasBaseline())
646cdf0e10cSrcweir rDev.DrawLine(Point(nLeft, GetBaseline()) += aOffset,
647cdf0e10cSrcweir Point(nRight, GetBaseline()) += aOffset);
648cdf0e10cSrcweir
649cdf0e10cSrcweir rDev.SetLineColor(COL_GRAY);
650cdf0e10cSrcweir rDev.DrawLine(Point(nLeft, GetHiAttrFence()) += aOffset,
651cdf0e10cSrcweir Point(nRight, GetHiAttrFence()) += aOffset);
652cdf0e10cSrcweir }
653cdf0e10cSrcweir
654cdf0e10cSrcweir if (nFlags & SM_RECT_MID)
655cdf0e10cSrcweir { Point aCenter = rPosition
656cdf0e10cSrcweir + (Point(GetItalicCenterX(), GetAlignM()) -= GetTopLeft()),
657cdf0e10cSrcweir aLenX (GetWidth() / 5, 0),
658cdf0e10cSrcweir aLenY (0, GetHeight() / 16);
659cdf0e10cSrcweir
660cdf0e10cSrcweir rDev.SetLineColor(COL_LIGHTGREEN);
661cdf0e10cSrcweir rDev.DrawLine(aCenter - aLenX, aCenter + aLenX);
662cdf0e10cSrcweir rDev.DrawLine(aCenter - aLenY, aCenter + aLenY);
663cdf0e10cSrcweir }
664cdf0e10cSrcweir
665cdf0e10cSrcweir if (nFlags & SM_RECT_ITALIC)
666cdf0e10cSrcweir SmDrawFrame(rDev, Rectangle(rPosition - Point(GetItalicLeftSpace(), 0),
667cdf0e10cSrcweir GetItalicSize()));
668cdf0e10cSrcweir
669cdf0e10cSrcweir if (nFlags & SM_RECT_CORE)
670cdf0e10cSrcweir SmDrawFrame(rDev, Rectangle(rPosition, GetSize()), COL_LIGHTRED);
671cdf0e10cSrcweir
672cdf0e10cSrcweir rDev.Pop();
673cdf0e10cSrcweir }
674cdf0e10cSrcweir
675cdf0e10cSrcweir
SmDrawFrame(OutputDevice & rDev,const Rectangle & rRec,const Color aCol)676cdf0e10cSrcweir void SmDrawFrame(OutputDevice &rDev, const Rectangle &rRec,
677cdf0e10cSrcweir const Color aCol)
678cdf0e10cSrcweir {
679cdf0e10cSrcweir rDev.Push(PUSH_LINECOLOR);
680cdf0e10cSrcweir
681cdf0e10cSrcweir rDev.SetLineColor(aCol);
682cdf0e10cSrcweir
683cdf0e10cSrcweir rDev.DrawLine(rRec.TopLeft(), rRec.BottomLeft());
684cdf0e10cSrcweir rDev.DrawLine(rRec.BottomLeft(), rRec.BottomRight());
685cdf0e10cSrcweir rDev.DrawLine(rRec.BottomRight(), rRec.TopRight());
686cdf0e10cSrcweir rDev.DrawLine(rRec.TopRight(), rRec.TopLeft());
687cdf0e10cSrcweir
688cdf0e10cSrcweir rDev.Pop();
689cdf0e10cSrcweir }
690cdf0e10cSrcweir
691cdf0e10cSrcweir #endif //SM_RECT_DEBUG
692cdf0e10cSrcweir
693cdf0e10cSrcweir
SmGetGlyphBoundRect(const OutputDevice & rDev,const XubString & rText,Rectangle & rRect)694cdf0e10cSrcweir sal_Bool SmGetGlyphBoundRect(const OutputDevice &rDev,
695cdf0e10cSrcweir const XubString &rText, Rectangle &rRect)
696cdf0e10cSrcweir // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
697cdf0e10cSrcweir // but with a string as argument.
698cdf0e10cSrcweir {
699cdf0e10cSrcweir // handle special case first
700cdf0e10cSrcweir xub_StrLen nLen = rText.Len();
701cdf0e10cSrcweir if (nLen == 0)
702cdf0e10cSrcweir { rRect.SetEmpty();
703cdf0e10cSrcweir return sal_True;
704cdf0e10cSrcweir }
705cdf0e10cSrcweir
706cdf0e10cSrcweir // get a device where 'OutputDevice::GetTextBoundRect' will be successful
707cdf0e10cSrcweir OutputDevice *pGlyphDev;
708cdf0e10cSrcweir if (rDev.GetOutDevType() != OUTDEV_PRINTER)
709cdf0e10cSrcweir pGlyphDev = (OutputDevice *) &rDev;
710cdf0e10cSrcweir else
711cdf0e10cSrcweir {
712cdf0e10cSrcweir // since we format for the printer (where GetTextBoundRect will fail)
713cdf0e10cSrcweir // we need a virtual device here.
714cdf0e10cSrcweir pGlyphDev = &SM_MOD()->GetDefaultVirtualDev();
715cdf0e10cSrcweir }
716cdf0e10cSrcweir
717cdf0e10cSrcweir const FontMetric aDevFM (rDev.GetFontMetric());
718cdf0e10cSrcweir
719cdf0e10cSrcweir pGlyphDev->Push(PUSH_FONT | PUSH_MAPMODE);
720cdf0e10cSrcweir Font aFnt(rDev.GetFont());
721cdf0e10cSrcweir aFnt.SetAlign(ALIGN_TOP);
722cdf0e10cSrcweir
723cdf0e10cSrcweir // use scale factor when calling GetTextBoundRect to counter
724cdf0e10cSrcweir // negative effects from antialiasing which may otherwise result
725cdf0e10cSrcweir // in significant incorrect bounding rectangles for some charcters.
726cdf0e10cSrcweir Size aFntSize = aFnt.GetSize();
727cdf0e10cSrcweir
728cdf0e10cSrcweir // HDU: workaround to avoid HUGE font sizes and resulting problems (#112783#)
729cdf0e10cSrcweir long nScaleFactor = 1;
730cdf0e10cSrcweir while( aFntSize.Height() > 2000 * nScaleFactor )
731cdf0e10cSrcweir nScaleFactor *= 2;
732cdf0e10cSrcweir
733cdf0e10cSrcweir aFnt.SetSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
734cdf0e10cSrcweir pGlyphDev->SetFont(aFnt);
735cdf0e10cSrcweir
736cdf0e10cSrcweir long nTextWidth = rDev.GetTextWidth(rText);
737cdf0e10cSrcweir Point aPoint;
738cdf0e10cSrcweir Rectangle aResult (aPoint, Size(nTextWidth, rDev.GetTextHeight())),
739cdf0e10cSrcweir aTmp;
740cdf0e10cSrcweir
741cdf0e10cSrcweir sal_Bool bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText, 0, 0);
742cdf0e10cSrcweir DBG_ASSERT( bSuccess, "GetTextBoundRect failed" );
743cdf0e10cSrcweir
744cdf0e10cSrcweir
745cdf0e10cSrcweir if (!aTmp.IsEmpty())
746cdf0e10cSrcweir {
747cdf0e10cSrcweir aResult = Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
748cdf0e10cSrcweir aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
749cdf0e10cSrcweir if (&rDev != pGlyphDev) /* only when rDev is a printer... */
750cdf0e10cSrcweir {
751cdf0e10cSrcweir long nGDTextWidth = pGlyphDev->GetTextWidth(rText);
752cdf0e10cSrcweir if (nGDTextWidth != 0 &&
753cdf0e10cSrcweir nTextWidth != nGDTextWidth)
754cdf0e10cSrcweir {
755cdf0e10cSrcweir aResult.Right() *= nTextWidth;
756cdf0e10cSrcweir aResult.Right() /= nGDTextWidth * nScaleFactor;
757cdf0e10cSrcweir }
758cdf0e10cSrcweir }
759cdf0e10cSrcweir }
760cdf0e10cSrcweir
761cdf0e10cSrcweir // move rectangle to match possibly different baselines
762cdf0e10cSrcweir // (because of different devices)
763cdf0e10cSrcweir long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
764cdf0e10cSrcweir aResult.Move(0, nDelta);
765cdf0e10cSrcweir
766cdf0e10cSrcweir pGlyphDev->Pop();
767cdf0e10cSrcweir
768cdf0e10cSrcweir rRect = aResult;
769cdf0e10cSrcweir return bSuccess;
770cdf0e10cSrcweir }
771cdf0e10cSrcweir
772cdf0e10cSrcweir
773