LCOV - code coverage report
Current view: top level - libreoffice/starmath/source - rect.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 276 327 84.4 %
Date: 2012-12-17 Functions: 19 23 82.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include <osl/diagnose.h>
      21             : #include <vcl/svapp.hxx>
      22             : #include <vcl/wrkwin.hxx>
      23             : #include <vcl/virdev.hxx>
      24             : 
      25             : 
      26             : #include "rect.hxx"
      27             : #include "types.hxx"
      28             : #include "utility.hxx"
      29             : #include "smmod.hxx"
      30             : 
      31             : 
      32             : ////////////////////////////////////////////////////////////////////////////////
      33             : 
      34             : 
      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[] =
      39             : {
      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')
      49             : };
      50             : 
      51        4250 : bool SmIsMathAlpha(const rtl::OUString &rText)
      52             :     // true iff symbol (from StarMath Font) should be treated as letter
      53             : {
      54        4250 :     if (rText.isEmpty())
      55          12 :         return false;
      56             : 
      57             :     OSL_ENSURE(rText.getLength() == 1, "Sm : string must be exactly one character long");
      58        4238 :     sal_Unicode cChar = rText[0];
      59             : 
      60             :     // is it a greek symbol?
      61        4238 :     if (sal_Unicode(0xE0AC) <= cChar  &&  cChar <= sal_Unicode(0xE0D4))
      62           0 :         return true;
      63             :     else
      64             :     {
      65             :         // appears it in 'aMathAlpha'?
      66        4238 :         const sal_Unicode *pChar = aMathAlpha;
      67      105950 :         while (*pChar  &&  *pChar != cChar)
      68       97474 :             pChar++;
      69        4238 :         return *pChar != sal_Unicode('\0');
      70             :     }
      71             : }
      72             : 
      73             : 
      74             : ////////////////////////////////////////
      75             : //
      76             : // SmRect members
      77             : //
      78             : 
      79             : 
      80       23862 : SmRect::SmRect()
      81             :     // constructs empty rectangle at (0, 0) with width and height 0.
      82             : {
      83             :     OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: ooops...");
      84             :     OSL_ENSURE(aSize == Size(0, 0), "Sm: ooops...");
      85             : 
      86       23862 :     bHasBaseline = bHasAlignInfo = false;
      87             :     nBaseline = nAlignT = nAlignM = nAlignB =
      88             :     nGlyphTop = nGlyphBottom =
      89             :     nItalicLeftSpace = nItalicRightSpace =
      90       23862 :     nLoAttrFence = nHiAttrFence = 0;
      91       23862 :     nBorderWidth = 0;
      92       23862 : }
      93             : 
      94             : 
      95       20804 : SmRect::SmRect(const SmRect &rRect)
      96             : :   aTopLeft(rRect.aTopLeft),
      97       20804 :     aSize(rRect.aSize)
      98             : {
      99       20804 :     bHasBaseline  = rRect.bHasBaseline;
     100       20804 :     nBaseline     = rRect.nBaseline;
     101       20804 :     nAlignT       = rRect.nAlignT;
     102       20804 :     nAlignM       = rRect.nAlignM;
     103       20804 :     nAlignB       = rRect.nAlignB;
     104       20804 :     nGlyphTop     = rRect.nGlyphTop;
     105       20804 :     nGlyphBottom  = rRect.nGlyphBottom;
     106       20804 :     nHiAttrFence  = rRect.nHiAttrFence;
     107       20804 :     nLoAttrFence  = rRect.nLoAttrFence;
     108       20804 :     bHasAlignInfo = rRect.bHasAlignInfo;
     109       20804 :     nItalicLeftSpace  = rRect.nItalicLeftSpace;
     110       20804 :     nItalicRightSpace = rRect.nItalicRightSpace;
     111       20804 :     nBorderWidth  = rRect.nBorderWidth;
     112       20804 : }
     113             : 
     114             : 
     115         120 : void SmRect::CopyAlignInfo(const SmRect &rRect)
     116             : {
     117         120 :     nBaseline     = rRect.nBaseline;
     118         120 :     bHasBaseline  = rRect.bHasBaseline;
     119         120 :     nAlignT       = rRect.nAlignT;
     120         120 :     nAlignM       = rRect.nAlignM;
     121         120 :     nAlignB       = rRect.nAlignB;
     122         120 :     bHasAlignInfo = rRect.bHasAlignInfo;
     123         120 :     nLoAttrFence  = rRect.nLoAttrFence;
     124         120 :     nHiAttrFence  = rRect.nHiAttrFence;
     125         120 : }
     126             : 
     127             : 
     128        9360 : void SmRect::BuildRect(const OutputDevice &rDev, const SmFormat *pFormat,
     129             :                        const rtl::OUString &rText, sal_uInt16 nBorder)
     130             : {
     131             :     OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: Ooops...");
     132             : 
     133        9360 :     aSize = Size(rDev.GetTextWidth(rText), rDev.GetTextHeight());
     134             : 
     135        9360 :     const FontMetric  aFM (rDev.GetFontMetric());
     136        9360 :     bool              bIsMath  = aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH );
     137        9360 :     bool              bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
     138        9360 :     const long        nFontHeight = rDev.GetFont().GetSize().Height();
     139             : 
     140        9360 :     nBorderWidth  = nBorder;
     141        9360 :     bHasAlignInfo = true;
     142        9360 :     bHasBaseline  = true;
     143        9360 :     nBaseline     = aFM.GetAscent();
     144        9360 :     nAlignT       = nBaseline - nFontHeight * 750L / 1000L;
     145        9360 :     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        9360 :     nAlignB       = nBaseline;
     150             : 
     151             :     // workaround for printer fonts with very small (possible 0 or even
     152             :     // negative(!)) leading
     153        9360 :     if (aFM.GetIntLeading() < 5  &&  rDev.GetOutDevType() == OUTDEV_PRINTER)
     154             :     {
     155           0 :         OutputDevice    *pWindow = Application::GetDefaultDevice();
     156             : 
     157           0 :         pWindow->Push(PUSH_MAPMODE | PUSH_FONT);
     158             : 
     159           0 :         pWindow->SetMapMode(rDev.GetMapMode());
     160           0 :         pWindow->SetFont(rDev.GetFontMetric());
     161             : 
     162           0 :         long  nDelta = pWindow->GetFontMetric().GetIntLeading();
     163           0 :         if (nDelta == 0)
     164             :         {   // this value approx. fits a Leading of 80 at a
     165             :             // Fontheight of 422 (12pt)
     166           0 :             nDelta = nFontHeight * 8L / 43;
     167             :         }
     168           0 :         SetTop(GetTop() - nDelta);
     169             : 
     170           0 :         pWindow->Pop();
     171             :     }
     172             : 
     173             :     // get GlyphBoundRect
     174        9360 :     Rectangle  aGlyphRect;
     175             : #if OSL_DEBUG_LEVEL > 1
     176             :     bool bSuccess =
     177             : #endif
     178        9360 :                 SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
     179             : #if OSL_DEBUG_LEVEL > 1
     180             :     if (!bSuccess)
     181             :     {
     182             :         OSL_FAIL( "Sm : Ooops... (fehlt evtl. der Font?)");
     183             :     }
     184             : #endif
     185             : 
     186        9360 :     nItalicLeftSpace  = GetLeft() - aGlyphRect.Left() + nBorderWidth;
     187        9360 :     nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
     188        9360 :     if (nItalicLeftSpace  < 0  &&  !bAllowSmaller)
     189         744 :         nItalicLeftSpace  = 0;
     190        9360 :     if (nItalicRightSpace < 0  &&  !bAllowSmaller)
     191        1212 :         nItalicRightSpace = 0;
     192             : 
     193        9360 :     long  nDist = 0;
     194        9360 :     if (pFormat)
     195        8040 :         nDist = (rDev.GetFont().GetSize().Height()
     196        8040 :                 * pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100L;
     197             : 
     198        9360 :     nHiAttrFence = aGlyphRect.TopLeft().Y() - 1 - nBorderWidth - nDist;
     199        9360 :     nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);
     200             : 
     201        9360 :     nGlyphTop    = aGlyphRect.Top() - nBorderWidth;
     202        9360 :     nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;
     203             : 
     204        9360 :     if (bAllowSmaller)
     205             :     {
     206             :         // for symbols and operators from the StarMath Font
     207             :         // we adjust upper and lower margin of the symbol
     208        4250 :         SetTop(nGlyphTop);
     209        4250 :         SetBottom(nGlyphBottom);
     210             :     }
     211             : 
     212        9360 :     if (nHiAttrFence < GetTop())
     213        4274 :         nHiAttrFence = GetTop();
     214             : 
     215        9360 :     if (nLoAttrFence > GetBottom())
     216        1164 :         nLoAttrFence = GetBottom();
     217             : 
     218             :     OSL_ENSURE(rText.isEmpty() || !IsEmpty(),
     219        9360 :                "Sm: empty rectangle created");
     220        9360 : }
     221             : 
     222             : 
     223        9360 : void SmRect::Init(const OutputDevice &rDev, const SmFormat *pFormat,
     224             :                   const rtl::OUString &rText, sal_uInt16 nEBorderWidth)
     225             :     // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
     226             : {
     227        9360 :     BuildRect(rDev, pFormat, rText, nEBorderWidth);
     228        9360 : }
     229             : 
     230             : 
     231        9360 : SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
     232        9360 :                const rtl::OUString &rText, long nEBorderWidth)
     233             : {
     234             :     OSL_ENSURE( nEBorderWidth >= 0, "BorderWidth is negative" );
     235        9360 :     if (nEBorderWidth < 0)
     236           0 :         nEBorderWidth = 0;
     237        9360 :     Init(rDev, pFormat, rText, (sal_uInt16) nEBorderWidth);
     238        9360 : }
     239             : 
     240             : 
     241        1394 : 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        1394 : :   aSize(nWidth, nHeight)
     247             : {
     248             :     OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: ooops...");
     249             : 
     250        1394 :     bHasBaseline  = false;
     251        1394 :     bHasAlignInfo = true;
     252        1394 :     nBaseline     = 0;
     253        1394 :     nAlignT       = GetTop();
     254        1394 :     nAlignB       = GetBottom();
     255        1394 :     nAlignM       = (nAlignT + nAlignB) / 2;        // this is the default
     256        1394 :     nItalicLeftSpace = nItalicRightSpace = 0;
     257        1394 :     nGlyphTop    = nHiAttrFence  = GetTop();
     258        1394 :     nGlyphBottom = nLoAttrFence  = GetBottom();
     259        1394 :     nBorderWidth  = 0;
     260        1394 : }
     261             : 
     262             : 
     263        8736 : void SmRect::SetLeft(long nLeft)
     264             : {
     265        8736 :     if (nLeft <= GetRight())
     266        8664 :     {   aSize.Width() = GetRight() - nLeft + 1;
     267        8664 :         aTopLeft.X()  = nLeft;
     268             :     }
     269        8736 : }
     270             : 
     271             : 
     272        8736 : void SmRect::SetRight(long nRight)
     273             : {
     274        8736 :     if (nRight >= GetLeft())
     275        8736 :         aSize.Width() = nRight - GetLeft() + 1;
     276        8736 : }
     277             : 
     278             : 
     279       12998 : void SmRect::SetBottom(long nBottom)
     280             : {
     281       12998 :     if (nBottom >= GetTop())
     282       12986 :         aSize.Height() = nBottom - GetTop() + 1;
     283       12998 : }
     284             : 
     285             : 
     286       12986 : void SmRect::SetTop(long nTop)
     287             : {
     288       12986 :     if (nTop <= GetBottom())
     289       12962 :     {   aSize.Height()   = GetBottom() - nTop + 1;
     290       12962 :         aTopLeft.Y() = nTop;
     291             :     }
     292       12986 : }
     293             : 
     294             : 
     295       44912 : void SmRect::Move(const Point &rPosition)
     296             :     // move rectangle by position 'rPosition'.
     297             : {
     298       44912 :     aTopLeft  += rPosition;
     299             : 
     300       44912 :     long  nDelta = rPosition.Y();
     301       44912 :     nBaseline += nDelta;
     302       44912 :     nAlignT   += nDelta;
     303       44912 :     nAlignM   += nDelta;
     304       44912 :     nAlignB   += nDelta;
     305       44912 :     nGlyphTop    += nDelta;
     306       44912 :     nGlyphBottom += nDelta;
     307       44912 :     nHiAttrFence += nDelta;
     308       44912 :     nLoAttrFence += nDelta;
     309       44912 : }
     310             : 
     311             : 
     312        9132 : const Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
     313             :                             RectHorAlign eHor, RectVerAlign eVer) const
     314        9132 : {   Point  aPos (GetTopLeft());
     315             :         // will become the topleft point of the new rectangle position
     316             : 
     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        9132 :     switch (ePos)
     320             :     {   case RP_LEFT :
     321         888 :             aPos.X() = rRect.GetItalicLeft() - GetItalicRightSpace()
     322         888 :                        - GetWidth();
     323         888 :             break;
     324             :         case RP_RIGHT :
     325        5648 :             aPos.X() = rRect.GetItalicRight() + 1 + GetItalicLeftSpace();
     326        5648 :             break;
     327             :         case RP_TOP :
     328         530 :             aPos.Y() = rRect.GetTop() - GetHeight();
     329         530 :             break;
     330             :         case RP_BOTTOM :
     331        1730 :             aPos.Y() = rRect.GetBottom() + 1;
     332        1730 :             break;
     333             :         case RP_ATTRIBUT :
     334         336 :             aPos.X() = rRect.GetItalicCenterX() - GetItalicWidth() / 2
     335         336 :                        + GetItalicLeftSpace();
     336         336 :             break;
     337             :         default :
     338             :             OSL_FAIL("Sm: unknown case");
     339             :     }
     340             : 
     341             :     // check if horizontal position is already set
     342        9132 :     if (ePos == RP_LEFT  ||  ePos == RP_RIGHT  ||  ePos == RP_ATTRIBUT)
     343             :         // correct error in current vertical position
     344        6872 :         switch (eVer)
     345             :         {   case RVA_TOP :
     346         492 :                 aPos.Y() += rRect.GetAlignT() - GetAlignT();
     347         492 :                 break;
     348             :             case RVA_MID :
     349         168 :                 aPos.Y() += rRect.GetAlignM() - GetAlignM();
     350         168 :                 break;
     351             :             case RVA_BASELINE :
     352             :                 // align baselines if possible else align mid's
     353        4556 :                 if (HasBaseline() && rRect.HasBaseline())
     354        3992 :                     aPos.Y() += rRect.GetBaseline() - GetBaseline();
     355             :                 else
     356         564 :                     aPos.Y() += rRect.GetAlignM() - GetAlignM();
     357        4556 :                 break;
     358             :             case RVA_BOTTOM :
     359         192 :                 aPos.Y() += rRect.GetAlignB() - GetAlignB();
     360         192 :                 break;
     361             :             case RVA_CENTERY :
     362        1128 :                 aPos.Y() += rRect.GetCenterY() - GetCenterY();
     363        1128 :                 break;
     364             :             case RVA_ATTRIBUT_HI:
     365         288 :                 aPos.Y() += rRect.GetHiAttrFence() - GetBottom();
     366         288 :                 break;
     367             :             case RVA_ATTRIBUT_MID :
     368          48 :                 aPos.Y() += SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
     369          48 :                             - GetCenterY();
     370          24 :                 break;
     371             :             case RVA_ATTRIBUT_LO :
     372          24 :                 aPos.Y() += rRect.GetLoAttrFence() - GetTop();
     373          24 :                 break;
     374             :         default :
     375             :                 OSL_FAIL("Sm: unknown case");
     376             :         }
     377             : 
     378             :     // check if vertical position is already set
     379        9132 :     if (ePos == RP_TOP  ||  ePos == RP_BOTTOM)
     380             :         // correct error in current horizontal position
     381        2260 :         switch (eHor)
     382             :         {   case RHA_LEFT :
     383           0 :                 aPos.X() += rRect.GetItalicLeft() - GetItalicLeft();
     384           0 :                 break;
     385             :             case RHA_CENTER :
     386        2260 :                 aPos.X() += rRect.GetItalicCenterX() - GetItalicCenterX();
     387        2260 :                 break;
     388             :             case RHA_RIGHT :
     389           0 :                 aPos.X() += rRect.GetItalicRight() - GetItalicRight();
     390           0 :                 break;
     391             :             default :
     392             :                 OSL_FAIL("Sm: unknown case");
     393             :         }
     394             : 
     395        9132 :     return aPos;
     396             : }
     397             : 
     398             : 
     399        9012 : 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!
     404             : {
     405        9012 :     if (rRect.IsEmpty())
     406         276 :         return *this;
     407             : 
     408        8736 :     long  nL  = rRect.GetLeft(),
     409        8736 :           nR  = rRect.GetRight(),
     410        8736 :           nT  = rRect.GetTop(),
     411        8736 :           nB  = rRect.GetBottom(),
     412        8736 :           nGT = rRect.nGlyphTop,
     413        8736 :           nGB = rRect.nGlyphBottom;
     414        8736 :     if (!IsEmpty())
     415             :     {   long  nTmp;
     416             : 
     417        8616 :         if ((nTmp = GetLeft()) < nL)
     418        7044 :             nL = nTmp;
     419        8616 :         if ((nTmp = GetRight()) > nR)
     420        2178 :             nR = nTmp;
     421        8616 :         if ((nTmp = GetTop()) < nT)
     422        4300 :             nT = nTmp;
     423        8616 :         if ((nTmp = GetBottom()) > nB)
     424        3038 :             nB = nTmp;
     425        8616 :         if ((nTmp = nGlyphTop) < nGT)
     426        4672 :             nGT = nTmp;
     427        8616 :         if ((nTmp = nGlyphBottom) > nGB)
     428        3510 :             nGB = nTmp;
     429             :     }
     430             : 
     431        8736 :     SetLeft(nL);
     432        8736 :     SetRight(nR);
     433        8736 :     SetTop(nT);
     434        8736 :     SetBottom(nB);
     435        8736 :     nGlyphTop    = nGT;
     436        8736 :     nGlyphBottom = nGB;
     437             : 
     438        8736 :     return *this;
     439             : }
     440             : 
     441             : 
     442        9012 : 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.
     448             : {
     449             :     // get some values used for (italic) spaces adaption
     450             :     // ! (need to be done before changing current SmRect) !
     451        9012 :     long  nL = Min(GetItalicLeft(),  rRect.GetItalicLeft()),
     452        9012 :           nR = Max(GetItalicRight(), rRect.GetItalicRight());
     453             : 
     454        9012 :     Union(rRect);
     455             : 
     456        9012 :     SetItalicSpaces(GetLeft() - nL, nR - GetRight());
     457             : 
     458        9012 :     if (!HasAlignInfo())
     459         120 :         CopyAlignInfo(rRect);
     460        8892 :     else if (rRect.HasAlignInfo())
     461        8880 :     {   nAlignT = Min(GetAlignT(), rRect.GetAlignT());
     462        8880 :         nAlignB = Max(GetAlignB(), rRect.GetAlignB());
     463        8880 :         nHiAttrFence = Min(GetHiAttrFence(), rRect.GetHiAttrFence());
     464        8880 :         nLoAttrFence = Max(GetLoAttrFence(), rRect.GetLoAttrFence());
     465             :         OSL_ENSURE(HasAlignInfo(), "Sm: ooops...");
     466             : 
     467        8880 :         switch (eCopyMode)
     468             :         {   case RCP_THIS:
     469             :                 // already done
     470        2784 :                 break;
     471             :             case RCP_ARG:
     472         900 :                 CopyMBL(rRect);
     473         900 :                 break;
     474             :             case RCP_NONE:
     475         928 :                 ClearBaseline();
     476         928 :                 nAlignM = (nAlignT + nAlignB) / 2;
     477         928 :                 break;
     478             :             case RCP_XOR:
     479        4268 :                 if (!HasBaseline())
     480         180 :                     CopyMBL(rRect);
     481        4268 :                 break;
     482             :             default :
     483             :                 OSL_FAIL("Sm: unknown case");
     484             :         }
     485             :     }
     486             : 
     487        9012 :     return *this;
     488             : }
     489             : 
     490             : 
     491         338 : 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)
     497             : {
     498             :     OSL_ENSURE(HasAlignInfo(), "Sm: no align info");
     499             : 
     500         338 :     ExtendBy(rRect, eCopyMode);
     501         338 :     nAlignM = nNewAlignM;
     502             : 
     503         338 :     return *this;
     504             : }
     505             : 
     506             : 
     507        1356 : 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.)
     513             : {
     514        1356 :     long  nOldAlignT   = GetAlignT(),
     515        1356 :           nOldAlignM   = GetAlignM(),
     516        1356 :           nOldAlignB   = GetAlignB(),
     517        1356 :           nOldBaseline = nBaseline;     //! depends not on 'HasBaseline'
     518        1356 :     bool  bOldHasAlignInfo = HasAlignInfo();
     519             : 
     520        1356 :     ExtendBy(rRect, eCopyMode);
     521             : 
     522        1356 :     if (bKeepVerAlignParams)
     523        1356 :     {   nAlignT   = nOldAlignT;
     524        1356 :         nAlignM   = nOldAlignM;
     525        1356 :         nAlignB   = nOldAlignB;
     526        1356 :         nBaseline = nOldBaseline;
     527        1356 :         bHasAlignInfo = bOldHasAlignInfo;
     528             :     }
     529             : 
     530        1356 :     return *this;
     531             : }
     532             : 
     533             : 
     534           0 : 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.
     539             : {
     540           0 :     bool  bIsInside = IsInsideItalicRect(rPoint);
     541             : 
     542             :     // build reference point to define the distance
     543           0 :     Point  aRef;
     544           0 :     if (bIsInside)
     545           0 :     {   Point  aIC (GetItalicCenterX(), GetCenterY());
     546             : 
     547           0 :         aRef.X() = rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft();
     548           0 :         aRef.Y() = rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop();
     549             :     }
     550             :     else
     551             :     {
     552             :         // x-coordinate
     553           0 :         if (rPoint.X() > GetItalicRight())
     554           0 :             aRef.X() = GetItalicRight();
     555           0 :         else if (rPoint.X() < GetItalicLeft())
     556           0 :             aRef.X() = GetItalicLeft();
     557             :         else
     558           0 :             aRef.X() = rPoint.X();
     559             :         // y-coordinate
     560           0 :         if (rPoint.Y() > GetBottom())
     561           0 :             aRef.Y() = GetBottom();
     562           0 :         else if (rPoint.Y() < GetTop())
     563           0 :             aRef.Y() = GetTop();
     564             :         else
     565           0 :             aRef.Y() = rPoint.Y();
     566             :     }
     567             : 
     568             :     // build distance vector
     569           0 :     Point  aDist (aRef - rPoint);
     570             : 
     571           0 :     long nAbsX = labs(aDist.X()),
     572           0 :          nAbsY = labs(aDist.Y());
     573             : 
     574           0 :     return bIsInside ? - Min(nAbsX, nAbsY) : Max (nAbsX, nAbsY);
     575             : }
     576             : 
     577             : 
     578           0 : bool SmRect::IsInsideRect(const Point &rPoint) const
     579             : {
     580           0 :     return     rPoint.Y() >= GetTop()
     581           0 :            &&  rPoint.Y() <= GetBottom()
     582           0 :            &&  rPoint.X() >= GetLeft()
     583           0 :            &&  rPoint.X() <= GetRight();
     584             : }
     585             : 
     586             : 
     587           0 : bool SmRect::IsInsideItalicRect(const Point &rPoint) const
     588             : {
     589           0 :     return     rPoint.Y() >= GetTop()
     590           0 :            &&  rPoint.Y() <= GetBottom()
     591           0 :            &&  rPoint.X() >= GetItalicLeft()
     592           0 :            &&  rPoint.X() <= GetItalicRight();
     593             : }
     594             : 
     595           0 : SmRect SmRect::AsGlyphRect() const
     596             : {
     597           0 :     SmRect aRect (*this);
     598           0 :     aRect.SetTop(nGlyphTop);
     599           0 :     aRect.SetBottom(nGlyphBottom);
     600           0 :     return aRect;
     601             : }
     602             : 
     603        9360 : bool SmGetGlyphBoundRect(const OutputDevice &rDev,
     604             :                          const rtl::OUString &rText, Rectangle &rRect)
     605             :     // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
     606             :     // but with a string as argument.
     607             : {
     608             :     // handle special case first
     609        9360 :     if (rText.isEmpty())
     610             :     {
     611          12 :         rRect.SetEmpty();
     612          12 :         return true;
     613             :     }
     614             : 
     615             :     // get a device where 'OutputDevice::GetTextBoundRect' will be successful
     616             :     OutputDevice *pGlyphDev;
     617        9348 :     if (rDev.GetOutDevType() != OUTDEV_PRINTER)
     618        9320 :         pGlyphDev = (OutputDevice *) &rDev;
     619             :     else
     620             :     {
     621             :         // since we format for the printer (where GetTextBoundRect will fail)
     622             :         // we need a virtual device here.
     623          28 :         pGlyphDev = &SM_MOD()->GetDefaultVirtualDev();
     624             :     }
     625             : 
     626        9348 :     const FontMetric  aDevFM (rDev.GetFontMetric());
     627             : 
     628        9348 :     pGlyphDev->Push(PUSH_FONT | PUSH_MAPMODE);
     629        9348 :     Font aFnt(rDev.GetFont());
     630        9348 :     aFnt.SetAlign(ALIGN_TOP);
     631             : 
     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 charcters.
     635        9348 :     Size aFntSize = aFnt.GetSize();
     636             : 
     637             :     // Workaround to avoid HUGE font sizes and resulting problems
     638        9348 :     long nScaleFactor = 1;
     639       18780 :     while( aFntSize.Height() > 2000 * nScaleFactor )
     640          84 :         nScaleFactor *= 2;
     641             : 
     642        9348 :     aFnt.SetSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
     643        9348 :     pGlyphDev->SetFont(aFnt);
     644             : 
     645        9348 :     long nTextWidth = rDev.GetTextWidth(rText);
     646        9348 :     Point aPoint;
     647        9348 :     Rectangle   aResult (aPoint, Size(nTextWidth, rDev.GetTextHeight())),
     648        9348 :                 aTmp;
     649             : 
     650        9348 :     bool bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText, 0, 0);
     651             :     OSL_ENSURE( bSuccess, "GetTextBoundRect failed" );
     652             : 
     653             : 
     654        9348 :     if (!aTmp.IsEmpty())
     655             :     {
     656       15480 :         aResult = Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
     657       23220 :                             aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
     658        7740 :         if (&rDev != pGlyphDev) /* only when rDev is a printer... */
     659             :         {
     660          28 :             long nGDTextWidth  = pGlyphDev->GetTextWidth(rText);
     661          28 :             if (nGDTextWidth != 0  &&
     662             :                 nTextWidth != nGDTextWidth)
     663             :             {
     664          28 :                 aResult.Right() *= nTextWidth;
     665          28 :                 aResult.Right() /= nGDTextWidth * nScaleFactor;
     666             :             }
     667             :         }
     668             :     }
     669             : 
     670             :     // move rectangle to match possibly different baselines
     671             :     // (because of different devices)
     672        9348 :     long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
     673        9348 :     aResult.Move(0, nDelta);
     674             : 
     675        9348 :     pGlyphDev->Pop();
     676             : 
     677        9348 :     rRect = aResult;
     678        9348 :     return bSuccess;
     679             : }
     680             : 
     681             : 
     682             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10