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