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 10cdf0e10cSrcweir * 11*d107581fSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 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. 19cdf0e10cSrcweir * 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 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 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 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 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 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 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 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 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 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 282cdf0e10cSrcweir void SmRect::SetRight(long nRight) 283cdf0e10cSrcweir { 284cdf0e10cSrcweir if (nRight >= GetLeft()) 285cdf0e10cSrcweir aSize.Width() = nRight - GetLeft() + 1; 286cdf0e10cSrcweir } 287cdf0e10cSrcweir 288cdf0e10cSrcweir 289cdf0e10cSrcweir void SmRect::SetBottom(long nBottom) 290cdf0e10cSrcweir { 291cdf0e10cSrcweir if (nBottom >= GetTop()) 292cdf0e10cSrcweir aSize.Height() = nBottom - GetTop() + 1; 293cdf0e10cSrcweir } 294cdf0e10cSrcweir 295cdf0e10cSrcweir 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 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 322cdf0e10cSrcweir 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 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 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 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 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 544cdf0e10cSrcweir 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 588cdf0e10cSrcweir 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 597cdf0e10cSrcweir 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 605cdf0e10cSrcweir 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 619cdf0e10cSrcweir 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 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 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