/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
bool SmGetGlyphBoundRect(const vcl::RenderContext &rDev, const OUString &rText, tools::Rectangle &rRect) // basically the same as 'GetTextBoundRect' (in class 'OutputDevice') // but with a string as argument.
{ // handle special case first if (rText.isEmpty())
{
rRect.SetEmpty(); returntrue;
}
// get a device where 'OutputDevice::GetTextBoundRect' will be successful
OutputDevice *pGlyphDev; if (rDev.GetOutDevType() != OUTDEV_PRINTER)
pGlyphDev = const_cast<OutputDevice *>(&rDev); else
{ // since we format for the printer (where GetTextBoundRect will fail) // we need a virtual device here.
pGlyphDev = &SmModule::get()->GetDefaultVirtualDev();
}
// use scale factor when calling GetTextBoundRect to counter // negative effects from antialiasing which may otherwise result // in significant incorrect bounding rectangles for some characters.
Size aFntSize = aFnt.GetFontSize();
// Workaround to avoid HUGE font sizes and resulting problems
tools::Long nScaleFactor = 1; while( aFntSize.Height() > 2000 * nScaleFactor )
nScaleFactor *= 2;
if (!aTmp.IsEmpty())
{
aResult = tools::Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor); if (&rDev != pGlyphDev) /* only when rDev is a printer... */
{
tools::Long nGDTextWidth = pGlyphDev->GetTextWidth(rText); if (nGDTextWidth != 0 &&
nTextWidth != nGDTextWidth)
{
aResult.SetRight( aResult.Right() * nTextWidth );
aResult.SetRight( aResult.Right() / ( nGDTextWidth * nScaleFactor) );
}
}
}
// move rectangle to match possibly different baselines // (because of different devices)
tools::Long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
aResult.Move(0, nDelta);
pGlyphDev->Pop();
rRect = aResult; return bSuccess;
}
bool SmIsMathAlpha(std::u16string_view aText) // true iff symbol (from StarMath Font) should be treated as letter
{ // Set of symbols, which should be treated as letters in StarMath Font // (to get a normal (non-clipped) SmRect in contrast to the other operators // and symbols). static o3tl::sorted_vector<sal_Unicode> const aMathAlpha({
MS_ALEPH, MS_IM, MS_RE,
MS_WP, u'\xE070', MS_EMPTYSET,
u'\x2113', u'\xE0D6', u'\x2107',
u'\x2127', u'\x210A', MS_HBAR,
MS_LAMBDABAR, MS_SETN, MS_SETZ,
MS_SETQ, MS_SETR, MS_SETC,
u'\x2373', u'\xE0A5', u'\x2112',
u'\x2130', u'\x2131'
});
if (aText.empty()) returnfalse;
OSL_ENSURE(aText.size() == 1, "Sm : string must be exactly one character long");
sal_Unicode cChar = aText[0];
// is it a greek symbol? if (u'\xE0AC' <= cChar && cChar <= u'\xE0D4') returntrue; // or, does it appear in 'aMathAlpha'? return aMathAlpha.find(cChar) != aMathAlpha.end();
}
nBorderWidth = nBorder;
bHasAlignInfo = true;
bHasBaseline = true;
nBaseline = aFM.GetAscent();
nAlignT = nBaseline - nFontHeight * 750 / 1000;
nAlignM = nBaseline - nFontHeight * 121 / 422; // that's where the horizontal bars of '+', '-', ... are // (1/3 of ascent over baseline) // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
nAlignB = nBaseline;
// workaround for printer fonts with very small (possible 0 or even // negative(!)) leading if (aFM.GetInternalLeading() < 5 && rDev.GetOutDevType() == OUTDEV_PRINTER)
{
OutputDevice *pWindow = Application::GetDefaultDevice();
tools::Long nDelta = pWindow->GetFontMetric().GetInternalLeading(); if (nDelta == 0)
{ // this value approx. fits a Leading of 80 at a // Fontheight of 422 (12pt)
nDelta = nFontHeight * 8 / 43;
}
SetTop(GetTop() - nDelta);
pWindow->Pop();
}
// get GlyphBoundRect
tools::Rectangle aGlyphRect; bool bSuccess = SmGetGlyphBoundRect(rDev, rText, aGlyphRect); if (!bSuccess)
SAL_WARN("starmath", "Ooops... (Font missing?)");
if (bAllowSmaller)
{ // for symbols and operators from the StarMath Font // we adjust upper and lower margin of the symbol
SetTop(nGlyphTop);
SetBottom(nGlyphBottom);
}
if (nHiAttrFence < GetTop())
nHiAttrFence = GetTop();
if (nLoAttrFence > GetBottom())
nLoAttrFence = GetBottom();
SmRect::SmRect(tools::Long nWidth, tools::Long nHeight) // this constructor should never be used for anything textlike because // it will not provide useful values for baseline, AlignT and AlignB! // It's purpose is to get a 'SmRect' for the horizontal line in fractions // as used in 'SmBinVerNode'.
: aTopLeft(0, 0)
, aSize(nWidth, nHeight)
, nBaseline(0)
, nItalicLeftSpace(0)
, nItalicRightSpace(0)
, nBorderWidth(0)
, bHasBaseline(false)
, bHasAlignInfo(true)
{
nAlignT = nGlyphTop = nHiAttrFence = GetTop();
nAlignB = nGlyphBottom = nLoAttrFence = GetBottom();
nAlignM = (nAlignT + nAlignB) / 2; // this is the default
}
Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
RectHorAlign eHor, RectVerAlign eVer) const
{ Point aPos (GetTopLeft()); // will become the topleft point of the new rectangle position
// set horizontal or vertical new rectangle position depending on ePos switch (ePos)
{ case RectPos::Left:
aPos.setX( rRect.GetItalicLeft() - GetItalicRightSpace()
- GetWidth() ); break; case RectPos::Right:
aPos.setX( rRect.GetItalicRight() + 1 + GetItalicLeftSpace() ); break; case RectPos::Top:
aPos.setY( rRect.GetTop() - GetHeight() ); break; case RectPos::Bottom:
aPos.setY( rRect.GetBottom() + 1 ); break; case RectPos::Attribute:
aPos.setX( rRect.GetItalicCenterX() - GetItalicWidth() / 2
+ GetItalicLeftSpace() ); break; default:
assert(false);
}
// check if horizontal position is already set if (ePos == RectPos::Left || ePos == RectPos::Right || ePos == RectPos::Attribute) // correct error in current vertical position switch (eVer)
{ case RectVerAlign::Top :
aPos.AdjustY(rRect.GetAlignT() - GetAlignT() ); break; case RectVerAlign::Mid :
aPos.AdjustY(rRect.GetAlignM() - GetAlignM() ); break; case RectVerAlign::Baseline : // align baselines if possible else align mid's if (HasBaseline() && rRect.HasBaseline())
aPos.AdjustY(rRect.GetBaseline() - GetBaseline() ); else
aPos.AdjustY(rRect.GetAlignM() - GetAlignM() ); break; case RectVerAlign::Bottom :
aPos.AdjustY(rRect.GetAlignB() - GetAlignB() ); break; case RectVerAlign::CenterY :
aPos.AdjustY(rRect.GetCenterY() - GetCenterY() ); break; case RectVerAlign::AttributeHi:
aPos.AdjustY(rRect.GetHiAttrFence() - GetBottom() ); break; case RectVerAlign::AttributeMid :
aPos.AdjustY(SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
- GetCenterY() ); break; case RectVerAlign::AttributeLo :
aPos.AdjustY(rRect.GetLoAttrFence() - GetTop() ); break; default :
assert(false);
}
// check if vertical position is already set if (ePos == RectPos::Top || ePos == RectPos::Bottom) // correct error in current horizontal position switch (eHor)
{ case RectHorAlign::Left:
aPos.AdjustX(rRect.GetItalicLeft() - GetItalicLeft() ); break; case RectHorAlign::Center:
aPos.AdjustX(rRect.GetItalicCenterX() - GetItalicCenterX() ); break; case RectHorAlign::Right:
aPos.AdjustX(rRect.GetItalicRight() - GetItalicRight() ); break; default:
assert(false);
}
return aPos;
}
void SmRect::Union(const SmRect &rRect) // rectangle union of current one with 'rRect'. The result is to be the // smallest rectangles that covers the space of both rectangles. // (empty rectangles cover no space) //! Italic correction is NOT taken into account here!
{ if (rRect.IsEmpty()) return;
tools::Long nL = rRect.GetLeft(),
nR = rRect.GetRight(),
nT = rRect.GetTop(),
nB = rRect.GetBottom(),
nGT = rRect.nGlyphTop,
nGB = rRect.nGlyphBottom; if (!IsEmpty())
{ tools::Long nTmp;
if ((nTmp = GetLeft()) < nL)
nL = nTmp; if ((nTmp = GetRight()) > nR)
nR = nTmp; if ((nTmp = GetTop()) < nT)
nT = nTmp; if ((nTmp = GetBottom()) > nB)
nB = nTmp; if ((nTmp = nGlyphTop) < nGT)
nGT = nTmp; if ((nTmp = nGlyphBottom) > nGB)
nGB = nTmp;
}
SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode) // let current rectangle be the union of itself and 'rRect' // (the smallest rectangle surrounding both). Also adapt values for // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces. // The baseline is set according to 'eCopyMode'. // If one of the rectangles has no relevant info the other one is copied.
{ // get some values used for (italic) spaces adaptation // ! (need to be done before changing current SmRect) !
tools::Long nL = std::min(GetItalicLeft(), rRect.GetItalicLeft()),
nR = std::max(GetItalicRight(), rRect.GetItalicRight());
switch (eCopyMode)
{ case RectCopyMBL::This: // already done break; case RectCopyMBL::Arg:
CopyMBL(rRect); break; case RectCopyMBL::None:
bHasBaseline = false;
nAlignM = (nAlignT + nAlignB) / 2; break; case RectCopyMBL::Xor: if (!HasBaseline())
CopyMBL(rRect); break; default :
assert(false);
}
}
return *this;
}
void SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
tools::Long nNewAlignM) // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'. // (this version will be used in 'SmBinVerNode' to provide means to // align eg "{a over b} over c" correctly where AlignM should not // be (AlignT + AlignB) / 2)
{
OSL_ENSURE(HasAlignInfo(), "Sm: no align info");
SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode, bool bKeepVerAlignParams) // as 'ExtendBy' but keeps original values for AlignT, -M and -B and // baseline. // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't // be allowed to modify these values.)
{
tools::Long nOldAlignT = GetAlignT(),
nOldAlignM = GetAlignM(),
nOldAlignB = GetAlignB(),
nOldBaseline = nBaseline; //! depends not on 'HasBaseline' bool bOldHasAlignInfo = HasAlignInfo();
tools::Long SmRect::OrientedDist(const Point &rPoint) const // return oriented distance of rPoint to the current rectangle, // especially the return value is <= 0 iff the point is inside the // rectangle. // For simplicity the maximum-norm is used.
{ bool bIsInside = IsInsideItalicRect(rPoint);
// build reference point to define the distance
Point aRef; if (bIsInside)
{ Point aIC (GetItalicCenterX(), GetCenterY());
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.