fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / starmath / source / rect.cxx
blob19459867bba649f80771a5e14fd6ba2022ab0a15
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <osl/diagnose.h>
21 #include <vcl/svapp.hxx>
22 #include <vcl/wrkwin.hxx>
23 #include <vcl/virdev.hxx>
26 #include "rect.hxx"
27 #include "types.hxx"
28 #include "utility.hxx"
29 #include "smmod.hxx"
32 ////////////////////////////////////////////////////////////////////////////////
35 // '\0' terminated Array with symbol, which should be treat as letters in
36 // StarMath Font, (to get a normal (non-clipped) SmRect in contrast to the
37 // other operators and symbols).
38 static sal_Unicode const aMathAlpha[] =
40 MS_ALEPH, MS_IM, MS_RE,
41 MS_WP, sal_Unicode(0xE070), MS_EMPTYSET,
42 sal_Unicode(0x2113), sal_Unicode(0xE0D6), sal_Unicode(0x2107),
43 sal_Unicode(0x2127), sal_Unicode(0x210A), MS_HBAR,
44 MS_LAMBDABAR, MS_SETN, MS_SETZ,
45 MS_SETQ, MS_SETR, MS_SETC,
46 sal_Unicode(0x2373), sal_Unicode(0xE0A5), sal_Unicode(0x2112),
47 sal_Unicode(0x2130), sal_Unicode(0x2131),
48 sal_Unicode('\0')
51 bool SmIsMathAlpha(const OUString &rText)
52 // true iff symbol (from StarMath Font) should be treated as letter
54 if (rText.isEmpty())
55 return false;
57 OSL_ENSURE(rText.getLength() == 1, "Sm : string must be exactly one character long");
58 sal_Unicode cChar = rText[0];
60 // is it a greek symbol?
61 if (sal_Unicode(0xE0AC) <= cChar && cChar <= sal_Unicode(0xE0D4))
62 return true;
63 else
65 // appears it in 'aMathAlpha'?
66 const sal_Unicode *pChar = aMathAlpha;
67 while (*pChar && *pChar != cChar)
68 pChar++;
69 return *pChar != sal_Unicode('\0');
74 ////////////////////////////////////////
76 // SmRect members
80 SmRect::SmRect()
81 // constructs empty rectangle at (0, 0) with width and height 0.
83 OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: ooops...");
84 OSL_ENSURE(aSize == Size(0, 0), "Sm: ooops...");
86 bHasBaseline = bHasAlignInfo = false;
87 nBaseline = nAlignT = nAlignM = nAlignB =
88 nGlyphTop = nGlyphBottom =
89 nItalicLeftSpace = nItalicRightSpace =
90 nLoAttrFence = nHiAttrFence = 0;
91 nBorderWidth = 0;
95 SmRect::SmRect(const SmRect &rRect)
96 : aTopLeft(rRect.aTopLeft),
97 aSize(rRect.aSize)
99 bHasBaseline = rRect.bHasBaseline;
100 nBaseline = rRect.nBaseline;
101 nAlignT = rRect.nAlignT;
102 nAlignM = rRect.nAlignM;
103 nAlignB = rRect.nAlignB;
104 nGlyphTop = rRect.nGlyphTop;
105 nGlyphBottom = rRect.nGlyphBottom;
106 nHiAttrFence = rRect.nHiAttrFence;
107 nLoAttrFence = rRect.nLoAttrFence;
108 bHasAlignInfo = rRect.bHasAlignInfo;
109 nItalicLeftSpace = rRect.nItalicLeftSpace;
110 nItalicRightSpace = rRect.nItalicRightSpace;
111 nBorderWidth = rRect.nBorderWidth;
115 void SmRect::CopyAlignInfo(const SmRect &rRect)
117 nBaseline = rRect.nBaseline;
118 bHasBaseline = rRect.bHasBaseline;
119 nAlignT = rRect.nAlignT;
120 nAlignM = rRect.nAlignM;
121 nAlignB = rRect.nAlignB;
122 bHasAlignInfo = rRect.bHasAlignInfo;
123 nLoAttrFence = rRect.nLoAttrFence;
124 nHiAttrFence = rRect.nHiAttrFence;
128 void SmRect::BuildRect(const OutputDevice &rDev, const SmFormat *pFormat,
129 const OUString &rText, sal_uInt16 nBorder)
131 OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: Ooops...");
133 aSize = Size(rDev.GetTextWidth(rText), rDev.GetTextHeight());
135 const FontMetric aFM (rDev.GetFontMetric());
136 bool bIsMath = aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH );
137 bool bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
138 const long nFontHeight = rDev.GetFont().GetSize().Height();
140 nBorderWidth = nBorder;
141 bHasAlignInfo = true;
142 bHasBaseline = true;
143 nBaseline = aFM.GetAscent();
144 nAlignT = nBaseline - nFontHeight * 750L / 1000L;
145 nAlignM = nBaseline - nFontHeight * 121L / 422L;
146 // that's where the horizontal bars of '+', '-', ... are
147 // (1/3 of ascent over baseline)
148 // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
149 nAlignB = nBaseline;
151 // workaround for printer fonts with very small (possible 0 or even
152 // negative(!)) leading
153 if (aFM.GetIntLeading() < 5 && rDev.GetOutDevType() == OUTDEV_PRINTER)
155 OutputDevice *pWindow = Application::GetDefaultDevice();
157 pWindow->Push(PUSH_MAPMODE | PUSH_FONT);
159 pWindow->SetMapMode(rDev.GetMapMode());
160 pWindow->SetFont(rDev.GetFontMetric());
162 long nDelta = pWindow->GetFontMetric().GetIntLeading();
163 if (nDelta == 0)
164 { // this value approx. fits a Leading of 80 at a
165 // Fontheight of 422 (12pt)
166 nDelta = nFontHeight * 8L / 43;
168 SetTop(GetTop() - nDelta);
170 pWindow->Pop();
173 // get GlyphBoundRect
174 Rectangle aGlyphRect;
175 #if OSL_DEBUG_LEVEL > 1
176 bool bSuccess =
177 #endif
178 SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
179 #if OSL_DEBUG_LEVEL > 1
180 if (!bSuccess)
182 OSL_FAIL( "Sm : Ooops... (fehlt evtl. der Font?)");
184 #endif
186 nItalicLeftSpace = GetLeft() - aGlyphRect.Left() + nBorderWidth;
187 nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
188 if (nItalicLeftSpace < 0 && !bAllowSmaller)
189 nItalicLeftSpace = 0;
190 if (nItalicRightSpace < 0 && !bAllowSmaller)
191 nItalicRightSpace = 0;
193 long nDist = 0;
194 if (pFormat)
195 nDist = (rDev.GetFont().GetSize().Height()
196 * pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100L;
198 nHiAttrFence = aGlyphRect.TopLeft().Y() - 1 - nBorderWidth - nDist;
199 nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);
201 nGlyphTop = aGlyphRect.Top() - nBorderWidth;
202 nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;
204 if (bAllowSmaller)
206 // for symbols and operators from the StarMath Font
207 // we adjust upper and lower margin of the symbol
208 SetTop(nGlyphTop);
209 SetBottom(nGlyphBottom);
212 if (nHiAttrFence < GetTop())
213 nHiAttrFence = GetTop();
215 if (nLoAttrFence > GetBottom())
216 nLoAttrFence = GetBottom();
218 OSL_ENSURE(rText.isEmpty() || !IsEmpty(),
219 "Sm: empty rectangle created");
223 void SmRect::Init(const OutputDevice &rDev, const SmFormat *pFormat,
224 const OUString &rText, sal_uInt16 nEBorderWidth)
225 // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
227 BuildRect(rDev, pFormat, rText, nEBorderWidth);
231 SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
232 const OUString &rText, long nEBorderWidth)
234 OSL_ENSURE( nEBorderWidth >= 0, "BorderWidth is negative" );
235 if (nEBorderWidth < 0)
236 nEBorderWidth = 0;
237 Init(rDev, pFormat, rText, (sal_uInt16) nEBorderWidth);
241 SmRect::SmRect(long nWidth, long nHeight)
242 // this constructor should never be used for anything textlike because
243 // it will not provide useful values for baseline, AlignT and AlignB!
244 // It's purpose is to get a 'SmRect' for the horizontal line in fractions
245 // as used in 'SmBinVerNode'.
246 : aSize(nWidth, nHeight)
248 OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: ooops...");
250 bHasBaseline = false;
251 bHasAlignInfo = true;
252 nBaseline = 0;
253 nAlignT = GetTop();
254 nAlignB = GetBottom();
255 nAlignM = (nAlignT + nAlignB) / 2; // this is the default
256 nItalicLeftSpace = nItalicRightSpace = 0;
257 nGlyphTop = nHiAttrFence = GetTop();
258 nGlyphBottom = nLoAttrFence = GetBottom();
259 nBorderWidth = 0;
263 void SmRect::SetLeft(long nLeft)
265 if (nLeft <= GetRight())
266 { aSize.Width() = GetRight() - nLeft + 1;
267 aTopLeft.X() = nLeft;
272 void SmRect::SetRight(long nRight)
274 if (nRight >= GetLeft())
275 aSize.Width() = nRight - GetLeft() + 1;
279 void SmRect::SetBottom(long nBottom)
281 if (nBottom >= GetTop())
282 aSize.Height() = nBottom - GetTop() + 1;
286 void SmRect::SetTop(long nTop)
288 if (nTop <= GetBottom())
289 { aSize.Height() = GetBottom() - nTop + 1;
290 aTopLeft.Y() = nTop;
295 void SmRect::Move(const Point &rPosition)
296 // move rectangle by position 'rPosition'.
298 aTopLeft += rPosition;
300 long nDelta = rPosition.Y();
301 nBaseline += nDelta;
302 nAlignT += nDelta;
303 nAlignM += nDelta;
304 nAlignB += nDelta;
305 nGlyphTop += nDelta;
306 nGlyphBottom += nDelta;
307 nHiAttrFence += nDelta;
308 nLoAttrFence += nDelta;
312 const Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
313 RectHorAlign eHor, RectVerAlign eVer) const
314 { Point aPos (GetTopLeft());
315 // will become the topleft point of the new rectangle position
317 // set horizontal or vertical new rectangle position depending on
318 // 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
319 switch (ePos)
320 { case RP_LEFT :
321 aPos.X() = rRect.GetItalicLeft() - GetItalicRightSpace()
322 - GetWidth();
323 break;
324 case RP_RIGHT :
325 aPos.X() = rRect.GetItalicRight() + 1 + GetItalicLeftSpace();
326 break;
327 case RP_TOP :
328 aPos.Y() = rRect.GetTop() - GetHeight();
329 break;
330 case RP_BOTTOM :
331 aPos.Y() = rRect.GetBottom() + 1;
332 break;
333 case RP_ATTRIBUT :
334 aPos.X() = rRect.GetItalicCenterX() - GetItalicWidth() / 2
335 + GetItalicLeftSpace();
336 break;
337 default :
338 OSL_FAIL("Sm: unknown case");
341 // check if horizontal position is already set
342 if (ePos == RP_LEFT || ePos == RP_RIGHT || ePos == RP_ATTRIBUT)
343 // correct error in current vertical position
344 switch (eVer)
345 { case RVA_TOP :
346 aPos.Y() += rRect.GetAlignT() - GetAlignT();
347 break;
348 case RVA_MID :
349 aPos.Y() += rRect.GetAlignM() - GetAlignM();
350 break;
351 case RVA_BASELINE :
352 // align baselines if possible else align mid's
353 if (HasBaseline() && rRect.HasBaseline())
354 aPos.Y() += rRect.GetBaseline() - GetBaseline();
355 else
356 aPos.Y() += rRect.GetAlignM() - GetAlignM();
357 break;
358 case RVA_BOTTOM :
359 aPos.Y() += rRect.GetAlignB() - GetAlignB();
360 break;
361 case RVA_CENTERY :
362 aPos.Y() += rRect.GetCenterY() - GetCenterY();
363 break;
364 case RVA_ATTRIBUT_HI:
365 aPos.Y() += rRect.GetHiAttrFence() - GetBottom();
366 break;
367 case RVA_ATTRIBUT_MID :
368 aPos.Y() += SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
369 - GetCenterY();
370 break;
371 case RVA_ATTRIBUT_LO :
372 aPos.Y() += rRect.GetLoAttrFence() - GetTop();
373 break;
374 default :
375 OSL_FAIL("Sm: unknown case");
378 // check if vertical position is already set
379 if (ePos == RP_TOP || ePos == RP_BOTTOM)
380 // correct error in current horizontal position
381 switch (eHor)
382 { case RHA_LEFT :
383 aPos.X() += rRect.GetItalicLeft() - GetItalicLeft();
384 break;
385 case RHA_CENTER :
386 aPos.X() += rRect.GetItalicCenterX() - GetItalicCenterX();
387 break;
388 case RHA_RIGHT :
389 aPos.X() += rRect.GetItalicRight() - GetItalicRight();
390 break;
391 default :
392 OSL_FAIL("Sm: unknown case");
395 return aPos;
399 SmRect & SmRect::Union(const SmRect &rRect)
400 // rectangle union of current one with 'rRect'. The result is to be the
401 // smallest rectangles that covers the space of both rectangles.
402 // (empty rectangles cover no space)
403 //! Italic correction is NOT taken into account here!
405 if (rRect.IsEmpty())
406 return *this;
408 long nL = rRect.GetLeft(),
409 nR = rRect.GetRight(),
410 nT = rRect.GetTop(),
411 nB = rRect.GetBottom(),
412 nGT = rRect.nGlyphTop,
413 nGB = rRect.nGlyphBottom;
414 if (!IsEmpty())
415 { long nTmp;
417 if ((nTmp = GetLeft()) < nL)
418 nL = nTmp;
419 if ((nTmp = GetRight()) > nR)
420 nR = nTmp;
421 if ((nTmp = GetTop()) < nT)
422 nT = nTmp;
423 if ((nTmp = GetBottom()) > nB)
424 nB = nTmp;
425 if ((nTmp = nGlyphTop) < nGT)
426 nGT = nTmp;
427 if ((nTmp = nGlyphBottom) > nGB)
428 nGB = nTmp;
431 SetLeft(nL);
432 SetRight(nR);
433 SetTop(nT);
434 SetBottom(nB);
435 nGlyphTop = nGT;
436 nGlyphBottom = nGB;
438 return *this;
442 SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode)
443 // let current rectangle be the union of itself and 'rRect'
444 // (the smallest rectangle surrounding both). Also adapt values for
445 // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
446 // The baseline is set according to 'eCopyMode'.
447 // If one of the rectangles has no relevant info the other one is copied.
449 // get some values used for (italic) spaces adaption
450 // ! (need to be done before changing current SmRect) !
451 long nL = std::min(GetItalicLeft(), rRect.GetItalicLeft()),
452 nR = std::max(GetItalicRight(), rRect.GetItalicRight());
454 Union(rRect);
456 SetItalicSpaces(GetLeft() - nL, nR - GetRight());
458 if (!HasAlignInfo())
459 CopyAlignInfo(rRect);
460 else if (rRect.HasAlignInfo())
461 { nAlignT = std::min(GetAlignT(), rRect.GetAlignT());
462 nAlignB = std::max(GetAlignB(), rRect.GetAlignB());
463 nHiAttrFence = std::min(GetHiAttrFence(), rRect.GetHiAttrFence());
464 nLoAttrFence = std::max(GetLoAttrFence(), rRect.GetLoAttrFence());
465 OSL_ENSURE(HasAlignInfo(), "Sm: ooops...");
467 switch (eCopyMode)
468 { case RCP_THIS:
469 // already done
470 break;
471 case RCP_ARG:
472 CopyMBL(rRect);
473 break;
474 case RCP_NONE:
475 ClearBaseline();
476 nAlignM = (nAlignT + nAlignB) / 2;
477 break;
478 case RCP_XOR:
479 if (!HasBaseline())
480 CopyMBL(rRect);
481 break;
482 default :
483 OSL_FAIL("Sm: unknown case");
487 return *this;
491 SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
492 long nNewAlignM)
493 // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
494 // (this version will be used in 'SmBinVerNode' to provide means to
495 // align eg "{a over b} over c" correctly where AlignM should not
496 // be (AlignT + AlignB) / 2)
498 OSL_ENSURE(HasAlignInfo(), "Sm: no align info");
500 ExtendBy(rRect, eCopyMode);
501 nAlignM = nNewAlignM;
503 return *this;
507 SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
508 bool bKeepVerAlignParams)
509 // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
510 // baseline.
511 // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
512 // be allowed to modify these values.)
514 long nOldAlignT = GetAlignT(),
515 nOldAlignM = GetAlignM(),
516 nOldAlignB = GetAlignB(),
517 nOldBaseline = nBaseline; //! depends not on 'HasBaseline'
518 bool bOldHasAlignInfo = HasAlignInfo();
520 ExtendBy(rRect, eCopyMode);
522 if (bKeepVerAlignParams)
523 { nAlignT = nOldAlignT;
524 nAlignM = nOldAlignM;
525 nAlignB = nOldAlignB;
526 nBaseline = nOldBaseline;
527 bHasAlignInfo = bOldHasAlignInfo;
530 return *this;
534 long SmRect::OrientedDist(const Point &rPoint) const
535 // return oriented distance of rPoint to the current rectangle,
536 // especially the return value is <= 0 iff the point is inside the
537 // rectangle.
538 // For simplicity the maximum-norm is used.
540 bool bIsInside = IsInsideItalicRect(rPoint);
542 // build reference point to define the distance
543 Point aRef;
544 if (bIsInside)
545 { Point aIC (GetItalicCenterX(), GetCenterY());
547 aRef.X() = rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft();
548 aRef.Y() = rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop();
550 else
552 // x-coordinate
553 if (rPoint.X() > GetItalicRight())
554 aRef.X() = GetItalicRight();
555 else if (rPoint.X() < GetItalicLeft())
556 aRef.X() = GetItalicLeft();
557 else
558 aRef.X() = rPoint.X();
559 // y-coordinate
560 if (rPoint.Y() > GetBottom())
561 aRef.Y() = GetBottom();
562 else if (rPoint.Y() < GetTop())
563 aRef.Y() = GetTop();
564 else
565 aRef.Y() = rPoint.Y();
568 // build distance vector
569 Point aDist (aRef - rPoint);
571 long nAbsX = labs(aDist.X()),
572 nAbsY = labs(aDist.Y());
574 return bIsInside ? - std::min(nAbsX, nAbsY) : std::max (nAbsX, nAbsY);
578 bool SmRect::IsInsideRect(const Point &rPoint) const
580 return rPoint.Y() >= GetTop()
581 && rPoint.Y() <= GetBottom()
582 && rPoint.X() >= GetLeft()
583 && rPoint.X() <= GetRight();
587 bool SmRect::IsInsideItalicRect(const Point &rPoint) const
589 return rPoint.Y() >= GetTop()
590 && rPoint.Y() <= GetBottom()
591 && rPoint.X() >= GetItalicLeft()
592 && rPoint.X() <= GetItalicRight();
595 SmRect SmRect::AsGlyphRect() const
597 SmRect aRect (*this);
598 aRect.SetTop(nGlyphTop);
599 aRect.SetBottom(nGlyphBottom);
600 return aRect;
603 bool SmGetGlyphBoundRect(const OutputDevice &rDev,
604 const OUString &rText, Rectangle &rRect)
605 // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
606 // but with a string as argument.
608 // handle special case first
609 if (rText.isEmpty())
611 rRect.SetEmpty();
612 return true;
615 // get a device where 'OutputDevice::GetTextBoundRect' will be successful
616 OutputDevice *pGlyphDev;
617 if (rDev.GetOutDevType() != OUTDEV_PRINTER)
618 pGlyphDev = (OutputDevice *) &rDev;
619 else
621 // since we format for the printer (where GetTextBoundRect will fail)
622 // we need a virtual device here.
623 pGlyphDev = &SM_MOD()->GetDefaultVirtualDev();
626 const FontMetric aDevFM (rDev.GetFontMetric());
628 pGlyphDev->Push(PUSH_FONT | PUSH_MAPMODE);
629 Font aFnt(rDev.GetFont());
630 aFnt.SetAlign(ALIGN_TOP);
632 // use scale factor when calling GetTextBoundRect to counter
633 // negative effects from antialiasing which may otherwise result
634 // in significant incorrect bounding rectangles for some characters.
635 Size aFntSize = aFnt.GetSize();
637 // Workaround to avoid HUGE font sizes and resulting problems
638 long nScaleFactor = 1;
639 while( aFntSize.Height() > 2000 * nScaleFactor )
640 nScaleFactor *= 2;
642 aFnt.SetSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
643 pGlyphDev->SetFont(aFnt);
645 long nTextWidth = rDev.GetTextWidth(rText);
646 Point aPoint;
647 Rectangle aResult (aPoint, Size(nTextWidth, rDev.GetTextHeight())),
648 aTmp;
650 bool bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText, 0, 0);
651 OSL_ENSURE( bSuccess, "GetTextBoundRect failed" );
654 if (!aTmp.IsEmpty())
656 aResult = Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
657 aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
658 if (&rDev != pGlyphDev) /* only when rDev is a printer... */
660 long nGDTextWidth = pGlyphDev->GetTextWidth(rText);
661 if (nGDTextWidth != 0 &&
662 nTextWidth != nGDTextWidth)
664 aResult.Right() *= nTextWidth;
665 aResult.Right() /= nGDTextWidth * nScaleFactor;
670 // move rectangle to match possibly different baselines
671 // (because of different devices)
672 long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
673 aResult.Move(0, nDelta);
675 pGlyphDev->Pop();
677 rRect = aResult;
678 return bSuccess;
682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */