xref: /aoo41x/main/starmath/source/rect.cxx (revision d107581f)
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