/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_starmath.hxx"


#include <tools/string.hxx>
#include <tools/debug.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/virdev.hxx>


#include "rect.hxx"
#include "types.hxx"
#include "utility.hxx"
#include "smmod.hxx"


////////////////////////////////////////////////////////////////////////////////


// '\0' terminiertes Array mit Zeichen, die im StarMath Font als Buchstaben
// betrachtet werden sollen, (um im Gegensatz zu den anderen Operatoren
// und Symbolen ein "normales"(ungecliptes) SmRect zu erhalten).
static xub_Unicode __READONLY_DATA aMathAlpha[] =
{
    MS_ALEPH,               MS_IM,                  MS_RE,
    MS_WP,                  xub_Unicode(0xE070),    MS_EMPTYSET,
    xub_Unicode(0x2113),    xub_Unicode(0xE0D6),    xub_Unicode(0x2107),
    xub_Unicode(0x2127),    xub_Unicode(0x210A),    MS_HBAR,
    MS_LAMBDABAR,           MS_SETN,                MS_SETZ,
    MS_SETQ,                MS_SETR,                MS_SETC,
    xub_Unicode(0x2373),    xub_Unicode(0xE0A5),    xub_Unicode(0x2112),
    xub_Unicode(0x2130),    xub_Unicode(0x2131),
	xub_Unicode('\0')
};

sal_Bool SmIsMathAlpha(const XubString &rText)
	// ergibt genau dann sal_True, wenn das Zeichen (aus dem StarMath Font) wie ein
	// Buchstabe behandelt werden soll.
{
	if (rText.Len() == 0)
		return sal_False;

    DBG_ASSERT(rText.Len() == 1, "Sm : String enthaelt nicht genau ein Zeichen");
	xub_Unicode cChar = rText.GetChar(0);

	// ist es ein griechisches Zeichen ?
    if (xub_Unicode(0xE0AC) <= cChar  &&  cChar <= xub_Unicode(0xE0D4))
		return sal_True;
	else
	{
		// kommt es in 'aMathAlpha' vor ?
		const xub_Unicode *pChar = aMathAlpha;
		while (*pChar  &&  *pChar != cChar)
			pChar++;
		return *pChar != xub_Unicode('\0');
	}
}


////////////////////////////////////////
//
// SmRect members
//


SmRect::SmRect()
	// constructs empty rectangle at (0, 0) with width and height 0.
{
	DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: ooops...");
	DBG_ASSERT(aSize == Size(0, 0), "Sm: ooops...");

	bHasBaseline = bHasAlignInfo = sal_False;
	nBaseline = nAlignT = nAlignM = nAlignB =
	nGlyphTop = nGlyphBottom =
	nItalicLeftSpace = nItalicRightSpace =
	nLoAttrFence = nHiAttrFence = 0;
    nBorderWidth = 0;
}


SmRect::SmRect(const SmRect &rRect)
:	aTopLeft(rRect.aTopLeft),
	aSize(rRect.aSize)
{
	bHasBaseline  = rRect.bHasBaseline;
	nBaseline	  = rRect.nBaseline;
	nAlignT		  = rRect.nAlignT;
	nAlignM		  = rRect.nAlignM;
	nAlignB		  = rRect.nAlignB;
	nGlyphTop	  = rRect.nGlyphTop;
	nGlyphBottom  = rRect.nGlyphBottom;
	nHiAttrFence  = rRect.nHiAttrFence;
	nLoAttrFence  = rRect.nLoAttrFence;
	bHasAlignInfo = rRect.bHasAlignInfo;
	nItalicLeftSpace  = rRect.nItalicLeftSpace;
	nItalicRightSpace = rRect.nItalicRightSpace;
    nBorderWidth  = rRect.nBorderWidth;
}


void SmRect::CopyAlignInfo(const SmRect &rRect)
{
	nBaseline	  = rRect.nBaseline;
	bHasBaseline  =	rRect.bHasBaseline;
	nAlignT		  =	rRect.nAlignT;
	nAlignM		  =	rRect.nAlignM;
	nAlignB		  =	rRect.nAlignB;
	bHasAlignInfo = rRect.bHasAlignInfo;
	nLoAttrFence  =	rRect.nLoAttrFence;
	nHiAttrFence  =	rRect.nHiAttrFence;
}


void SmRect::BuildRect(const OutputDevice &rDev, const SmFormat *pFormat,
                       const XubString &rText, sal_uInt16 nBorder)
{
	DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: Ooops...");

	aSize = Size(rDev.GetTextWidth(rText), rDev.GetTextHeight());

	const FontMetric  aFM (rDev.GetFontMetric());
    sal_Bool              bIsMath  = aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH );
	sal_Bool			  bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
	const long		  nFontHeight = rDev.GetFont().GetSize().Height();

    nBorderWidth  = nBorder;
	bHasAlignInfo = sal_True;
	bHasBaseline  = sal_True;
	nBaseline	  = aFM.GetAscent();
	nAlignT		  = nBaseline - nFontHeight * 750L / 1000L;
	nAlignM 	  = nBaseline - nFontHeight * 121L / 422L;
		// that's where the horizontal bars of '+', '-', ... are
		// (1/3 of ascent over baseline)
		// (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
	nAlignB		  = nBaseline;

	// workaround for printer fonts with very small (possible 0 or even
	// negative(!)) leading
	if (aFM.GetIntLeading() < 5  &&  rDev.GetOutDevType() == OUTDEV_PRINTER)
	{
		OutputDevice	*pWindow = Application::GetDefaultDevice();

		pWindow->Push(PUSH_MAPMODE | PUSH_FONT);

		pWindow->SetMapMode(rDev.GetMapMode());
		pWindow->SetFont(rDev.GetFontMetric());

		long  nDelta = pWindow->GetFontMetric().GetIntLeading();
		if (nDelta == 0)
		{ 	// dieser Wert entspricht etwa einem Leading von 80 bei einer
            // Fonthoehe von 422 (12pt)
			nDelta = nFontHeight * 8L / 43;
		}
		SetTop(GetTop() - nDelta);

		pWindow->Pop();
	}

	// get GlyphBoundRect
	Rectangle  aGlyphRect;
#if OSL_DEBUG_LEVEL > 1
    sal_Bool bSuccess =
#endif
                SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
#if OSL_DEBUG_LEVEL > 1
    if (!bSuccess)
    {
        DBG_ERROR( "Sm : Ooops... (fehlt evtl. der Font?)");
    }
#endif

	nItalicLeftSpace  = GetLeft() - aGlyphRect.Left() + nBorderWidth;
	nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
	if (nItalicLeftSpace  < 0  &&  !bAllowSmaller)
		nItalicLeftSpace  = 0;
	if (nItalicRightSpace < 0  &&  !bAllowSmaller)
		nItalicRightSpace = 0;

	long  nDist = 0;
	if (pFormat)
		nDist = (rDev.GetFont().GetSize().Height()
				* pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100L;

	nHiAttrFence = aGlyphRect.TopLeft().Y() - 1 - nBorderWidth - nDist;
	nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);

	nGlyphTop    = aGlyphRect.Top() - nBorderWidth;
	nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;

	if (bAllowSmaller)
	{
        // fuer Symbole und Operatoren aus dem StarMath Font passen wir den
		// oberen und unteren Rand dem Zeichen an.
		SetTop(nGlyphTop);
		SetBottom(nGlyphBottom);
	}

	if (nHiAttrFence < GetTop())
		nHiAttrFence = GetTop();

	if (nLoAttrFence > GetBottom())
		nLoAttrFence = GetBottom();

	DBG_ASSERT(rText.Len() == 0  ||  !IsEmpty(),
			   "Sm: leeres Rechteck erzeugt");
}


void SmRect::Init(const OutputDevice &rDev, const SmFormat *pFormat,
                  const XubString &rText, sal_uInt16 nEBorderWidth)
	// get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
{
    BuildRect(rDev, pFormat, rText, nEBorderWidth);
}


SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
               const XubString &rText, long nEBorderWidth)
{
    DBG_ASSERT( nEBorderWidth >= 0, "BorderWidth negativ" );
    if (nEBorderWidth < 0)
        nEBorderWidth = 0;
    Init(rDev, pFormat, rText, (sal_uInt16) nEBorderWidth);
}


SmRect::SmRect(long nWidth, long nHeight)
	// this constructor should never be used for anything textlike because
	// it will not provide useful values for baseline, AlignT and AlignB!
	// It's purpose is to get a 'SmRect' for the horizontal line in fractions
	// as used in 'SmBinVerNode'.
:	aSize(nWidth, nHeight)
{
	DBG_ASSERT(aTopLeft == Point(0, 0), "Sm: ooops...");

	bHasBaseline  = sal_False;
	bHasAlignInfo = sal_True;
	nBaseline	  = 0;
	nAlignT		  = GetTop();
	nAlignB		  = GetBottom();
	nAlignM		  = (nAlignT + nAlignB) / 2;		// this is the default
	nItalicLeftSpace = nItalicRightSpace = 0;
	nGlyphTop    = nHiAttrFence  = GetTop();
	nGlyphBottom = nLoAttrFence  = GetBottom();
    nBorderWidth  = 0;
}


void SmRect::SetLeft(long nLeft)
{
	if (nLeft <= GetRight())
	{	aSize.Width() = GetRight() - nLeft + 1;
		aTopLeft.X()  = nLeft;
	}
}


void SmRect::SetRight(long nRight)
{
	if (nRight >= GetLeft())
		aSize.Width() = nRight - GetLeft() + 1;
}


void SmRect::SetBottom(long nBottom)
{
	if (nBottom >= GetTop())
		aSize.Height() = nBottom - GetTop() + 1;
}


void SmRect::SetTop(long nTop)
{
	if (nTop <= GetBottom())
	{	aSize.Height()	 = GetBottom() - nTop + 1;
		aTopLeft.Y() = nTop;
	}
}


void SmRect::Move(const Point &rPosition)
	// move rectangle by position 'rPosition'.
{
	aTopLeft  += rPosition;

	long  nDelta = rPosition.Y();
	nBaseline += nDelta;
	nAlignT   += nDelta;
	nAlignM	  += nDelta;
	nAlignB   += nDelta;
	nGlyphTop    += nDelta;
	nGlyphBottom += nDelta;
	nHiAttrFence += nDelta;
	nLoAttrFence += nDelta;
}


const Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
							RectHorAlign eHor, RectVerAlign eVer) const
{	Point  aPos (GetTopLeft());
		// will become the topleft point of the new rectangle position

	// set horizontal or vertical new rectangle position depending on
	// 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
	switch (ePos)
	{	case RP_LEFT :
			aPos.X() = rRect.GetItalicLeft() - GetItalicRightSpace()
					   - GetWidth();
			break;
		case RP_RIGHT :
			aPos.X() = rRect.GetItalicRight() + 1 + GetItalicLeftSpace();
			break;
		case RP_TOP :
			aPos.Y() = rRect.GetTop() - GetHeight();
			break;
		case RP_BOTTOM :
			aPos.Y() = rRect.GetBottom() + 1;
			break;
		case RP_ATTRIBUT :
			aPos.X() = rRect.GetItalicCenterX() - GetItalicWidth() / 2
					   + GetItalicLeftSpace();
			break;
		default :
			DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
	}

	// check if horizontal position is already set
	if (ePos == RP_LEFT  ||  ePos == RP_RIGHT  ||  ePos == RP_ATTRIBUT)
		// correct error in current vertical position
		switch (eVer)
		{	case RVA_TOP :
				aPos.Y() += rRect.GetAlignT() - GetAlignT();
				break;
			case RVA_MID :
				aPos.Y() += rRect.GetAlignM() - GetAlignM();
				break;
			case RVA_BASELINE :
				// align baselines if possible else align mid's
				if (HasBaseline() && rRect.HasBaseline())
					aPos.Y() += rRect.GetBaseline() - GetBaseline();
				else
					aPos.Y() += rRect.GetAlignM() - GetAlignM();
				break;
			case RVA_BOTTOM :
				aPos.Y() += rRect.GetAlignB() - GetAlignB();
				break;
			case RVA_CENTERY :
				aPos.Y() += rRect.GetCenterY() - GetCenterY();
				break;
			case RVA_ATTRIBUT_HI:
				aPos.Y() += rRect.GetHiAttrFence() - GetBottom();
				break;
			case RVA_ATTRIBUT_MID :
				aPos.Y() += SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
							- GetCenterY();
				break;
			case RVA_ATTRIBUT_LO :
				aPos.Y() += rRect.GetLoAttrFence() - GetTop();
				break;
		default :
				DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
		}

	// check if vertical position is already set
	if (ePos == RP_TOP	||	ePos == RP_BOTTOM)
		// correct error in current horizontal position
		switch (eHor)
		{	case RHA_LEFT :
				aPos.X() += rRect.GetItalicLeft() - GetItalicLeft();
				break;
			case RHA_CENTER :
				aPos.X() += rRect.GetItalicCenterX() - GetItalicCenterX();
				break;
			case RHA_RIGHT :
				aPos.X() += rRect.GetItalicRight() - GetItalicRight();
				break;
			default :
				DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
		}

	return aPos;
}


SmRect & SmRect::Union(const SmRect &rRect)
	// rectangle union of current one with 'rRect'. The result is to be the
	// smallest rectangles that covers the space of both rectangles.
	// (empty rectangles cover no space)
	//! Italic correction is NOT taken into account here!
{
	if (rRect.IsEmpty())
		return *this;

	long  nL  = rRect.GetLeft(),
		  nR  = rRect.GetRight(),
		  nT  = rRect.GetTop(),
		  nB  = rRect.GetBottom(),
		  nGT = rRect.nGlyphTop,
		  nGB = rRect.nGlyphBottom;
	if (!IsEmpty())
	{	long  nTmp;

		if ((nTmp = GetLeft()) < nL)
			nL = nTmp;
		if ((nTmp = GetRight()) > nR)
			nR = nTmp;
		if ((nTmp = GetTop()) < nT)
			nT = nTmp;
		if ((nTmp = GetBottom()) > nB)
			nB = nTmp;
		if ((nTmp = nGlyphTop) < nGT)
			nGT = nTmp;
		if ((nTmp = nGlyphBottom) > nGB)
			nGB = nTmp;
	}

	SetLeft(nL);
	SetRight(nR);
	SetTop(nT);
	SetBottom(nB);
	nGlyphTop    = nGT;
	nGlyphBottom = nGB;

	return *this;
}


SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode)
	// let current rectangle be the union of itself and 'rRect'
	// (the smallest rectangle surrounding both). Also adapt values for
	// 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
	// The baseline is set according to 'eCopyMode'.
	// If one of the rectangles has no relevant info the other one is copied.
{
	// get some values used for (italic) spaces adaption
	// ! (need to be done before changing current SmRect) !
	long  nL = Min(GetItalicLeft(),  rRect.GetItalicLeft()),
		  nR = Max(GetItalicRight(), rRect.GetItalicRight());

	Union(rRect);

	SetItalicSpaces(GetLeft() - nL, nR - GetRight());

	if (!HasAlignInfo())
		CopyAlignInfo(rRect);
	else if (rRect.HasAlignInfo())
	{	nAlignT = Min(GetAlignT(), rRect.GetAlignT());
		nAlignB = Max(GetAlignB(), rRect.GetAlignB());
		nHiAttrFence = Min(GetHiAttrFence(), rRect.GetHiAttrFence());
		nLoAttrFence = Max(GetLoAttrFence(), rRect.GetLoAttrFence());
		DBG_ASSERT(HasAlignInfo(), "Sm: ooops...");

		switch (eCopyMode)
		{	case RCP_THIS:
				// already done
				break;
			case RCP_ARG:
				CopyMBL(rRect);
				break;
			case RCP_NONE:
				ClearBaseline();
				nAlignM = (nAlignT + nAlignB) / 2;
				break;
			case RCP_XOR:
				if (!HasBaseline())
					CopyMBL(rRect);
				break;
			default :
				DBG_ASSERT(sal_False, "Sm: unbekannter Fall");
		}
	}

	return *this;
}


SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
						  long nNewAlignM)
	// as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
	// (this version will be used in 'SmBinVerNode' to provide means to
	// align eg "{a over b} over c" correctly where AlignM should not
	// be (AlignT + AlignB) / 2)
{
	DBG_ASSERT(HasAlignInfo(), "Sm: keine Align Info");

	ExtendBy(rRect, eCopyMode);
	nAlignM = nNewAlignM;

	return *this;
}


SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
						  sal_Bool bKeepVerAlignParams)
	// as 'ExtendBy' but keeps original values for AlignT, -M and -B and
	// baseline.
	// (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
	// be allowed to modify these values.)
{
	long  nOldAlignT   = GetAlignT(),
		  nOldAlignM   = GetAlignM(),
		  nOldAlignB   = GetAlignB(),
		  nOldBaseline = nBaseline;		//! depends not on 'HasBaseline'
	sal_Bool  bOldHasAlignInfo = HasAlignInfo();

	ExtendBy(rRect, eCopyMode);

	if (bKeepVerAlignParams)
	{	nAlignT	  = nOldAlignT;
		nAlignM	  = nOldAlignM;
		nAlignB	  = nOldAlignB;
		nBaseline = nOldBaseline;
		bHasAlignInfo = bOldHasAlignInfo;
	}

	return *this;
}


long SmRect::OrientedDist(const Point &rPoint) const
	// return oriented distance of rPoint to the current rectangle,
	// especially the return value is <= 0 iff the point is inside the
	// rectangle.
	// For simplicity the maximum-norm is used.
{
	sal_Bool  bIsInside = IsInsideItalicRect(rPoint);

	// build reference point to define the distance
	Point  aRef;
	if (bIsInside)
	{	Point  aIC (GetItalicCenterX(), GetCenterY());

		aRef.X() = rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft();
		aRef.Y() = rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop();
	}
	else
	{
		// x-coordinate
		if (rPoint.X() > GetItalicRight())
			aRef.X() = GetItalicRight();
		else if (rPoint.X() < GetItalicLeft())
			aRef.X() = GetItalicLeft();
		else
			aRef.X() = rPoint.X();
		// y-coordinate
		if (rPoint.Y() > GetBottom())
			aRef.Y() = GetBottom();
		else if (rPoint.Y() < GetTop())
			aRef.Y() = GetTop();
		else
			aRef.Y() = rPoint.Y();
	}

	// build distance vector
	Point  aDist (aRef - rPoint);

	long nAbsX = labs(aDist.X()),
		 nAbsY = labs(aDist.Y());

	return bIsInside ? - Min(nAbsX, nAbsY) : Max (nAbsX, nAbsY);
}


sal_Bool SmRect::IsInsideRect(const Point &rPoint) const
{
	return	   rPoint.Y() >= GetTop()
		   &&  rPoint.Y() <= GetBottom()
		   &&  rPoint.X() >= GetLeft()
		   &&  rPoint.X() <= GetRight();
}


sal_Bool SmRect::IsInsideItalicRect(const Point &rPoint) const
{
	return	   rPoint.Y() >= GetTop()
		   &&  rPoint.Y() <= GetBottom()
		   &&  rPoint.X() >= GetItalicLeft()
		   &&  rPoint.X() <= GetItalicRight();
}

SmRect SmRect::AsGlyphRect() const
{
	SmRect aRect (*this);
	aRect.SetTop(nGlyphTop);
	aRect.SetBottom(nGlyphBottom);
	return aRect;
}

#ifdef SM_RECT_DEBUG

// forward declaration
void SmDrawFrame(OutputDevice &rDev, const Rectangle &rRec,
				 const Color aCol = COL_BLACK);

void SmRect::Draw(OutputDevice &rDev, const Point &rPosition, int nFlags) const
{
	if (IsEmpty())
		return;

	rDev.Push(PUSH_LINECOLOR);

	if (nFlags & SM_RECT_LINES)
	{	long   nLeftSpace  = 0,
			   nRightSpace = 0;

		if (nFlags & SM_RECT_ITALIC)
		{	nLeftSpace	= GetItalicLeftSpace();
			nRightSpace = GetItalicRightSpace();
		}

		long  nLeft  = GetLeft()  - nLeftSpace,
			  nRight = GetRight() + nRightSpace;

		Point aOffset (rPosition - GetTopLeft());

		rDev.SetLineColor(COL_LIGHTBLUE);
		rDev.DrawLine(Point(nLeft,	GetAlignB()) += aOffset,
					  Point(nRight, GetAlignB()) += aOffset);
		rDev.DrawLine(Point(nLeft,	GetAlignT()) += aOffset,
					  Point(nRight, GetAlignT()) += aOffset);
		if (HasBaseline())
			rDev.DrawLine(Point(nLeft,	GetBaseline()) += aOffset,
						  Point(nRight, GetBaseline()) += aOffset);

		rDev.SetLineColor(COL_GRAY);
		rDev.DrawLine(Point(nLeft,	GetHiAttrFence()) += aOffset,
					  Point(nRight, GetHiAttrFence()) += aOffset);
	}

	if (nFlags & SM_RECT_MID)
	{	Point	aCenter = rPosition
						  + (Point(GetItalicCenterX(), GetAlignM()) -= GetTopLeft()),
				aLenX	  (GetWidth() / 5, 0),
				aLenY	  (0, GetHeight() / 16);

		rDev.SetLineColor(COL_LIGHTGREEN);
		rDev.DrawLine(aCenter - aLenX, aCenter + aLenX);
		rDev.DrawLine(aCenter - aLenY, aCenter + aLenY);
	}

	if (nFlags & SM_RECT_ITALIC)
		SmDrawFrame(rDev, Rectangle(rPosition - Point(GetItalicLeftSpace(), 0),
				GetItalicSize()));

	if (nFlags & SM_RECT_CORE)
		SmDrawFrame(rDev, Rectangle(rPosition, GetSize()), COL_LIGHTRED);

	rDev.Pop();
}


void SmDrawFrame(OutputDevice &rDev, const Rectangle &rRec,
				 const Color aCol)
{
	rDev.Push(PUSH_LINECOLOR);

	rDev.SetLineColor(aCol);

	rDev.DrawLine(rRec.TopLeft(),	  rRec.BottomLeft());
	rDev.DrawLine(rRec.BottomLeft(),  rRec.BottomRight());
	rDev.DrawLine(rRec.BottomRight(), rRec.TopRight());
	rDev.DrawLine(rRec.TopRight(),	  rRec.TopLeft());

	rDev.Pop();
}

#endif //SM_RECT_DEBUG


sal_Bool SmGetGlyphBoundRect(const OutputDevice &rDev,
						 const XubString &rText, Rectangle &rRect)
    // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
	// but with a string as argument.
{
	// handle special case first
	xub_StrLen nLen = rText.Len();
	if (nLen == 0)
	{	rRect.SetEmpty();
		return sal_True;
	}

    // get a device where 'OutputDevice::GetTextBoundRect' will be successful
	OutputDevice *pGlyphDev;
	if (rDev.GetOutDevType() != OUTDEV_PRINTER)
		pGlyphDev = (OutputDevice *) &rDev;
	else
	{
        // since we format for the printer (where GetTextBoundRect will fail)
		// we need a virtual device here.
        pGlyphDev = &SM_MOD()->GetDefaultVirtualDev();
	}

	const FontMetric  aDevFM (rDev.GetFontMetric());

    pGlyphDev->Push(PUSH_FONT | PUSH_MAPMODE);
    Font aFnt(rDev.GetFont());
    aFnt.SetAlign(ALIGN_TOP);

    // use scale factor when calling GetTextBoundRect to counter
    // negative effects from antialiasing which may otherwise result
    // in significant incorrect bounding rectangles for some charcters.
	Size aFntSize = aFnt.GetSize();

    // HDU: workaround to avoid HUGE font sizes and resulting problems (#112783#)
    long nScaleFactor = 1;
    while( aFntSize.Height() > 2000 * nScaleFactor )
        nScaleFactor *= 2;
    
    aFnt.SetSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
	pGlyphDev->SetFont(aFnt);

    long nTextWidth = rDev.GetTextWidth(rText);
    Point aPoint;
    Rectangle   aResult (aPoint, Size(nTextWidth, rDev.GetTextHeight())),
				aTmp;

    sal_Bool bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText, 0, 0);
    DBG_ASSERT( bSuccess, "GetTextBoundRect failed" );


    if (!aTmp.IsEmpty())
    {
        aResult = Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
                            aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
        if (&rDev != pGlyphDev) /* only when rDev is a printer... */
        {
            long nGDTextWidth  = pGlyphDev->GetTextWidth(rText);
            if (nGDTextWidth != 0  &&
                nTextWidth != nGDTextWidth)
            {
                aResult.Right() *= nTextWidth;
                aResult.Right() /= nGDTextWidth * nScaleFactor;
            }
        }
    }

	// move rectangle to match possibly different baselines
	// (because of different devices)
    long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
	aResult.Move(0, nDelta);

	pGlyphDev->Pop();

    rRect = aResult;
	return bSuccess;
}


