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