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