Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/starmath/source/rect.cxx
Line
Count
Source
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 <o3tl/sorted_vector.hxx>
22
#include <vcl/metric.hxx>
23
#include <vcl/svapp.hxx>
24
#include <vcl/virdev.hxx>
25
#include <sal/log.hxx>
26
27
#include <format.hxx>
28
#include <rect.hxx>
29
#include <types.hxx>
30
#include <smmod.hxx>
31
32
namespace {
33
34
bool SmGetGlyphBoundRect(const vcl::RenderContext &rDev,
35
                         const OUString &rText, tools::Rectangle &rRect)
36
    // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
37
    // but with a string as argument.
38
0
{
39
    // handle special case first
40
0
    if (rText.isEmpty())
41
0
    {
42
0
        rRect.SetEmpty();
43
0
        return true;
44
0
    }
45
46
    // get a device where 'OutputDevice::GetTextBoundRect' will be successful
47
0
    OutputDevice *pGlyphDev;
48
0
    if (rDev.GetOutDevType() != OUTDEV_PRINTER)
49
0
        pGlyphDev = const_cast<OutputDevice *>(&rDev);
50
0
    else
51
0
    {
52
        // since we format for the printer (where GetTextBoundRect will fail)
53
        // we need a virtual device here.
54
0
        pGlyphDev = &SmModule::get()->GetDefaultVirtualDev();
55
0
    }
56
57
0
    const FontMetric  aDevFM (rDev.GetFontMetric());
58
59
0
    auto popIt = pGlyphDev->ScopedPush(vcl::PushFlags::FONT | vcl::PushFlags::MAPMODE);
60
0
    vcl::Font aFnt(rDev.GetFont());
61
0
    aFnt.SetAlignment(ALIGN_TOP);
62
63
    // use scale factor when calling GetTextBoundRect to counter
64
    // negative effects from antialiasing which may otherwise result
65
    // in significant incorrect bounding rectangles for some characters.
66
0
    Size aFntSize = aFnt.GetFontSize();
67
68
    // Workaround to avoid HUGE font sizes and resulting problems
69
0
    tools::Long nScaleFactor = 1;
70
0
    while( aFntSize.Height() > 2000 * nScaleFactor )
71
0
        nScaleFactor *= 2;
72
73
0
    aFnt.SetFontSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
74
0
    pGlyphDev->SetFont(aFnt);
75
76
0
    tools::Long nTextWidth = rDev.GetTextWidth(rText);
77
0
    tools::Rectangle   aResult (Point(), Size(nTextWidth, rDev.GetTextHeight())),
78
0
                       aTmp;
79
80
0
    bool bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText);
81
0
    OSL_ENSURE( bSuccess, "GetTextBoundRect failed" );
82
83
84
0
    if (!aTmp.IsEmpty())
85
0
    {
86
0
        aResult = tools::Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
87
0
                            aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
88
0
        if (&rDev != pGlyphDev) /* only when rDev is a printer... */
89
0
        {
90
0
            tools::Long nGDTextWidth  = pGlyphDev->GetTextWidth(rText);
91
0
            if (nGDTextWidth != 0  &&
92
0
                nTextWidth != nGDTextWidth)
93
0
            {
94
0
                aResult.SetRight( aResult.Right() * nTextWidth );
95
0
                aResult.SetRight( aResult.Right() / ( nGDTextWidth * nScaleFactor) );
96
0
            }
97
0
        }
98
0
    }
99
100
    // move rectangle to match possibly different baselines
101
    // (because of different devices)
102
0
    tools::Long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
103
0
    aResult.Move(0, nDelta);
104
105
0
    rRect = aResult;
106
0
    return bSuccess;
107
0
}
108
109
bool SmIsMathAlpha(std::u16string_view aText)
110
    // true iff symbol (from StarMath Font) should be treated as letter
111
0
{
112
    // Set of symbols, which should be treated as letters in StarMath Font
113
    // (to get a normal (non-clipped) SmRect in contrast to the other operators
114
    // and symbols).
115
0
    static o3tl::sorted_vector<sal_Unicode> const aMathAlpha({
116
0
        MS_ALEPH,               MS_IM,                  MS_RE,
117
0
        MS_WP,                  u'\xE070',              MS_EMPTYSET,
118
0
        u'\x2113',              u'\xE0D6',              u'\x2107',
119
0
        u'\x2127',              u'\x210A',              MS_HBAR,
120
0
        MS_LAMBDABAR,           MS_SETN,                MS_SETZ,
121
0
        MS_SETQ,                MS_SETR,                MS_SETC,
122
0
        u'\x2373',              u'\xE0A5',              u'\x2112',
123
0
        u'\x2130',              u'\x2131'
124
0
    });
125
126
0
    if (aText.empty())
127
0
        return false;
128
129
0
    OSL_ENSURE(aText.size() == 1, "Sm : string must be exactly one character long");
130
0
    sal_Unicode cChar = aText[0];
131
132
    // is it a greek symbol?
133
0
    if (u'\xE0AC' <= cChar  &&  cChar <= u'\xE0D4')
134
0
        return true;
135
    // or, does it appear in 'aMathAlpha'?
136
0
    return aMathAlpha.find(cChar) != aMathAlpha.end();
137
0
}
138
139
}
140
141
142
SmRect::SmRect()
143
    // constructs empty rectangle at (0, 0) with width and height 0.
144
0
    : aTopLeft(0, 0)
145
0
    , aSize(0, 0)
146
0
    , nBaseline(0)
147
0
    , nAlignT(0)
148
0
    , nAlignM(0)
149
0
    , nAlignB(0)
150
0
    , nGlyphTop(0)
151
0
    , nGlyphBottom(0)
152
0
    , nItalicLeftSpace(0)
153
0
    , nItalicRightSpace(0)
154
0
    , nLoAttrFence(0)
155
0
    , nHiAttrFence(0)
156
0
    , nBorderWidth(0)
157
0
    , bHasBaseline(false)
158
0
    , bHasAlignInfo(false)
159
0
{
160
0
}
161
162
163
void SmRect::CopyAlignInfo(const SmRect &rRect)
164
0
{
165
0
    nBaseline     = rRect.nBaseline;
166
0
    bHasBaseline  = rRect.bHasBaseline;
167
0
    nAlignT       = rRect.nAlignT;
168
0
    nAlignM       = rRect.nAlignM;
169
0
    nAlignB       = rRect.nAlignB;
170
0
    bHasAlignInfo = rRect.bHasAlignInfo;
171
0
    nLoAttrFence  = rRect.nLoAttrFence;
172
0
    nHiAttrFence  = rRect.nHiAttrFence;
173
0
}
174
175
176
SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
177
               const OUString &rText, sal_uInt16 nBorder)
178
    // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
179
0
    : aTopLeft(0, 0)
180
0
    , aSize(rDev.GetTextWidth(rText), rDev.GetTextHeight())
181
0
{
182
0
    const FontMetric  aFM (rDev.GetFontMetric());
183
0
    bool              bIsMath  = aFM.GetFamilyName().equalsIgnoreAsciiCase( FONTNAME_MATH );
184
0
    bool              bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
185
0
    const tools::Long        nFontHeight = rDev.GetFont().GetFontSize().Height();
186
187
0
    nBorderWidth  = nBorder;
188
0
    bHasAlignInfo = true;
189
0
    bHasBaseline  = true;
190
0
    nBaseline     = aFM.GetAscent();
191
0
    nAlignT       = nBaseline - nFontHeight * 750 / 1000;
192
0
    nAlignM       = nBaseline - nFontHeight * 121 / 422;
193
        // that's where the horizontal bars of '+', '-', ... are
194
        // (1/3 of ascent over baseline)
195
        // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
196
0
    nAlignB       = nBaseline;
197
198
    // workaround for printer fonts with very small (possible 0 or even
199
    // negative(!)) leading
200
0
    if (aFM.GetInternalLeading() < 5  &&  rDev.GetOutDevType() == OUTDEV_PRINTER)
201
0
    {
202
0
        OutputDevice    *pWindow = Application::GetDefaultDevice();
203
204
0
        auto popIt = pWindow->ScopedPush(vcl::PushFlags::MAPMODE | vcl::PushFlags::FONT);
205
206
0
        pWindow->SetMapMode(rDev.GetMapMode());
207
0
        pWindow->SetFont(rDev.GetFontMetric());
208
209
0
        tools::Long  nDelta = pWindow->GetFontMetric().GetInternalLeading();
210
0
        if (nDelta == 0)
211
0
        {   // this value approx. fits a Leading of 80 at a
212
            // Fontheight of 422 (12pt)
213
0
            nDelta = nFontHeight * 8 / 43;
214
0
        }
215
0
        SetTop(GetTop() - nDelta);
216
0
    }
217
218
    // get GlyphBoundRect
219
0
    tools::Rectangle  aGlyphRect;
220
0
    bool bSuccess = SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
221
0
    if (!bSuccess)
222
0
        SAL_WARN("starmath", "Ooops... (Font missing?)");
223
224
0
    nItalicLeftSpace  = GetLeft() - aGlyphRect.Left() + nBorderWidth;
225
0
    nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
226
0
    if (nItalicLeftSpace  < 0  &&  !bAllowSmaller)
227
0
        nItalicLeftSpace  = 0;
228
0
    if (nItalicRightSpace < 0  &&  !bAllowSmaller)
229
0
        nItalicRightSpace = 0;
230
231
0
    tools::Long  nDist = 0;
232
0
    if (pFormat)
233
0
        nDist = (rDev.GetFont().GetFontSize().Height()
234
0
                * pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100;
235
236
0
    nHiAttrFence = aGlyphRect.Top() - 1 - nBorderWidth - nDist;
237
0
    nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);
238
239
0
    nGlyphTop    = aGlyphRect.Top() - nBorderWidth;
240
0
    nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;
241
242
0
    if (bAllowSmaller)
243
0
    {
244
        // for symbols and operators from the StarMath Font
245
        // we adjust upper and lower margin of the symbol
246
0
        SetTop(nGlyphTop);
247
0
        SetBottom(nGlyphBottom);
248
0
    }
249
250
0
    if (nHiAttrFence < GetTop())
251
0
        nHiAttrFence = GetTop();
252
253
0
    if (nLoAttrFence > GetBottom())
254
0
        nLoAttrFence = GetBottom();
255
256
0
    OSL_ENSURE(rText.isEmpty() || !IsEmpty(),
257
0
               "Sm: empty rectangle created");
258
0
}
259
260
261
SmRect::SmRect(tools::Long nWidth, tools::Long nHeight)
262
    // this constructor should never be used for anything textlike because
263
    // it will not provide useful values for baseline, AlignT and AlignB!
264
    // It's purpose is to get a 'SmRect' for the horizontal line in fractions
265
    // as used in 'SmBinVerNode'.
266
0
    : aTopLeft(0, 0)
267
0
    , aSize(nWidth, nHeight)
268
0
    , nBaseline(0)
269
0
    , nItalicLeftSpace(0)
270
0
    , nItalicRightSpace(0)
271
0
    , nBorderWidth(0)
272
0
    , bHasBaseline(false)
273
0
    , bHasAlignInfo(true)
274
0
{
275
0
    nAlignT = nGlyphTop    = nHiAttrFence = GetTop();
276
0
    nAlignB = nGlyphBottom = nLoAttrFence = GetBottom();
277
0
    nAlignM = (nAlignT + nAlignB) / 2;        // this is the default
278
0
}
279
280
281
void SmRect::SetLeft(tools::Long nLeft)
282
0
{
283
0
    if (nLeft <= GetRight())
284
0
    {   aSize.setWidth( GetRight() - nLeft + 1 );
285
0
        aTopLeft.setX( nLeft );
286
0
    }
287
0
}
288
289
290
void SmRect::SetRight(tools::Long nRight)
291
0
{
292
0
    if (nRight >= GetLeft())
293
0
        aSize.setWidth( nRight - GetLeft() + 1 );
294
0
}
295
296
297
void SmRect::SetBottom(tools::Long nBottom)
298
0
{
299
0
    if (nBottom >= GetTop())
300
0
        aSize.setHeight( nBottom - GetTop() + 1 );
301
0
}
302
303
304
void SmRect::SetTop(tools::Long nTop)
305
0
{
306
0
    if (nTop <= GetBottom())
307
0
    {   aSize.setHeight( GetBottom() - nTop + 1 );
308
0
        aTopLeft.setY( nTop );
309
0
    }
310
0
}
311
312
313
void SmRect::Move(const Point &rPosition)
314
    // move rectangle by position 'rPosition'.
315
0
{
316
0
    aTopLeft  += rPosition;
317
318
0
    tools::Long  nDelta = rPosition.Y();
319
0
    nBaseline += nDelta;
320
0
    nAlignT   += nDelta;
321
0
    nAlignM   += nDelta;
322
0
    nAlignB   += nDelta;
323
0
    nGlyphTop    += nDelta;
324
0
    nGlyphBottom += nDelta;
325
0
    nHiAttrFence += nDelta;
326
0
    nLoAttrFence += nDelta;
327
0
}
328
329
330
Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
331
                            RectHorAlign eHor, RectVerAlign eVer) const
332
0
{   Point  aPos (GetTopLeft());
333
        // will become the topleft point of the new rectangle position
334
335
    // set horizontal or vertical new rectangle position depending on ePos
336
0
    switch (ePos)
337
0
    {   case RectPos::Left:
338
0
            aPos.setX( rRect.GetItalicLeft() - GetItalicRightSpace()
339
0
                       - GetWidth() );
340
0
            break;
341
0
        case RectPos::Right:
342
0
            aPos.setX( rRect.GetItalicRight() + 1 + GetItalicLeftSpace() );
343
0
            break;
344
0
        case RectPos::Top:
345
0
            aPos.setY( rRect.GetTop() - GetHeight() );
346
0
            break;
347
0
        case RectPos::Bottom:
348
0
            aPos.setY( rRect.GetBottom() + 1 );
349
0
            break;
350
0
        case RectPos::Attribute:
351
0
            aPos.setX( rRect.GetItalicCenterX() - GetItalicWidth() / 2
352
0
                       + GetItalicLeftSpace() );
353
0
            break;
354
0
        default:
355
0
            assert(false);
356
0
    }
357
358
    // check if horizontal position is already set
359
0
    if (ePos == RectPos::Left || ePos == RectPos::Right || ePos == RectPos::Attribute)
360
        // correct error in current vertical position
361
0
        switch (eVer)
362
0
        {   case RectVerAlign::Top :
363
0
                aPos.AdjustY(rRect.GetAlignT() - GetAlignT() );
364
0
                break;
365
0
            case RectVerAlign::Mid :
366
0
                aPos.AdjustY(rRect.GetAlignM() - GetAlignM() );
367
0
                break;
368
0
            case RectVerAlign::Baseline :
369
                // align baselines if possible else align mid's
370
0
                if (HasBaseline() && rRect.HasBaseline())
371
0
                    aPos.AdjustY(rRect.GetBaseline() - GetBaseline() );
372
0
                else
373
0
                    aPos.AdjustY(rRect.GetAlignM() - GetAlignM() );
374
0
                break;
375
0
            case RectVerAlign::Bottom :
376
0
                aPos.AdjustY(rRect.GetAlignB() - GetAlignB() );
377
0
                break;
378
0
            case RectVerAlign::CenterY :
379
0
                aPos.AdjustY(rRect.GetCenterY() - GetCenterY() );
380
0
                break;
381
0
            case RectVerAlign::AttributeHi:
382
0
                aPos.AdjustY(rRect.GetHiAttrFence() - GetBottom() );
383
0
                break;
384
0
            case RectVerAlign::AttributeMid :
385
0
                aPos.AdjustY(SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
386
0
                            - GetCenterY() );
387
0
                break;
388
0
            case RectVerAlign::AttributeLo :
389
0
                aPos.AdjustY(rRect.GetLoAttrFence() - GetTop() );
390
0
                break;
391
0
        default :
392
0
                assert(false);
393
0
        }
394
395
    // check if vertical position is already set
396
0
    if (ePos == RectPos::Top || ePos == RectPos::Bottom)
397
        // correct error in current horizontal position
398
0
        switch (eHor)
399
0
        {   case RectHorAlign::Left:
400
0
                aPos.AdjustX(rRect.GetItalicLeft() - GetItalicLeft() );
401
0
                break;
402
0
            case RectHorAlign::Center:
403
0
                aPos.AdjustX(rRect.GetItalicCenterX() - GetItalicCenterX() );
404
0
                break;
405
0
            case RectHorAlign::Right:
406
0
                aPos.AdjustX(rRect.GetItalicRight() - GetItalicRight() );
407
0
                break;
408
0
            default:
409
0
                assert(false);
410
0
        }
411
412
0
    return aPos;
413
0
}
414
415
416
void SmRect::Union(const SmRect &rRect)
417
    // rectangle union of current one with 'rRect'. The result is to be the
418
    // smallest rectangles that covers the space of both rectangles.
419
    // (empty rectangles cover no space)
420
    //! Italic correction is NOT taken into account here!
421
0
{
422
0
    if (rRect.IsEmpty())
423
0
        return;
424
425
0
    tools::Long  nL  = rRect.GetLeft(),
426
0
          nR  = rRect.GetRight(),
427
0
          nT  = rRect.GetTop(),
428
0
          nB  = rRect.GetBottom(),
429
0
          nGT = rRect.nGlyphTop,
430
0
          nGB = rRect.nGlyphBottom;
431
0
    if (!IsEmpty())
432
0
    {   tools::Long  nTmp;
433
434
0
        if ((nTmp = GetLeft()) < nL)
435
0
            nL = nTmp;
436
0
        if ((nTmp = GetRight()) > nR)
437
0
            nR = nTmp;
438
0
        if ((nTmp = GetTop()) < nT)
439
0
            nT = nTmp;
440
0
        if ((nTmp = GetBottom()) > nB)
441
0
            nB = nTmp;
442
0
        if ((nTmp = nGlyphTop) < nGT)
443
0
            nGT = nTmp;
444
0
        if ((nTmp = nGlyphBottom) > nGB)
445
0
            nGB = nTmp;
446
0
    }
447
448
0
    SetLeft(nL);
449
0
    SetRight(nR);
450
0
    SetTop(nT);
451
0
    SetBottom(nB);
452
0
    nGlyphTop    = nGT;
453
0
    nGlyphBottom = nGB;
454
0
}
455
456
457
SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode)
458
    // let current rectangle be the union of itself and 'rRect'
459
    // (the smallest rectangle surrounding both). Also adapt values for
460
    // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
461
    // The baseline is set according to 'eCopyMode'.
462
    // If one of the rectangles has no relevant info the other one is copied.
463
0
{
464
    // get some values used for (italic) spaces adaptation
465
    // ! (need to be done before changing current SmRect) !
466
0
    tools::Long  nL = std::min(GetItalicLeft(),  rRect.GetItalicLeft()),
467
0
          nR = std::max(GetItalicRight(), rRect.GetItalicRight());
468
469
0
    Union(rRect);
470
471
0
    SetItalicSpaces(GetLeft() - nL, nR - GetRight());
472
473
0
    if (!HasAlignInfo())
474
0
        CopyAlignInfo(rRect);
475
0
    else if (rRect.HasAlignInfo())
476
0
    {
477
0
        assert(HasAlignInfo());
478
0
        nAlignT = std::min(GetAlignT(), rRect.GetAlignT());
479
0
        nAlignB = std::max(GetAlignB(), rRect.GetAlignB());
480
0
        nHiAttrFence = std::min(GetHiAttrFence(), rRect.GetHiAttrFence());
481
0
        nLoAttrFence = std::max(GetLoAttrFence(), rRect.GetLoAttrFence());
482
483
0
        switch (eCopyMode)
484
0
        {   case RectCopyMBL::This:
485
                // already done
486
0
                break;
487
0
            case RectCopyMBL::Arg:
488
0
                CopyMBL(rRect);
489
0
                break;
490
0
            case RectCopyMBL::None:
491
0
                bHasBaseline = false;
492
0
                nAlignM = (nAlignT + nAlignB) / 2;
493
0
                break;
494
0
            case RectCopyMBL::Xor:
495
0
                if (!HasBaseline())
496
0
                    CopyMBL(rRect);
497
0
                break;
498
0
            default :
499
0
                assert(false);
500
0
        }
501
0
    }
502
503
0
    return *this;
504
0
}
505
506
507
void SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
508
                          tools::Long nNewAlignM)
509
    // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
510
    // (this version will be used in 'SmBinVerNode' to provide means to
511
    // align eg "{a over b} over c" correctly where AlignM should not
512
    // be (AlignT + AlignB) / 2)
513
0
{
514
0
    OSL_ENSURE(HasAlignInfo(), "Sm: no align info");
515
516
0
    ExtendBy(rRect, eCopyMode);
517
0
    nAlignM = nNewAlignM;
518
0
}
519
520
521
SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
522
                          bool bKeepVerAlignParams)
523
    // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
524
    // baseline.
525
    // (this is used in 'SmSupSubNode' where the sub-/superscripts shouldn't
526
    // be allowed to modify these values.)
527
0
{
528
0
    tools::Long  nOldAlignT   = GetAlignT(),
529
0
          nOldAlignM   = GetAlignM(),
530
0
          nOldAlignB   = GetAlignB(),
531
0
          nOldBaseline = nBaseline;     //! depends not on 'HasBaseline'
532
0
    bool  bOldHasAlignInfo = HasAlignInfo();
533
534
0
    ExtendBy(rRect, eCopyMode);
535
536
0
    if (bKeepVerAlignParams)
537
0
    {   nAlignT   = nOldAlignT;
538
0
        nAlignM   = nOldAlignM;
539
0
        nAlignB   = nOldAlignB;
540
0
        nBaseline = nOldBaseline;
541
0
        bHasAlignInfo = bOldHasAlignInfo;
542
0
    }
543
544
0
    return *this;
545
0
}
546
547
548
tools::Long SmRect::OrientedDist(const Point &rPoint) const
549
    // return oriented distance of rPoint to the current rectangle,
550
    // especially the return value is <= 0 iff the point is inside the
551
    // rectangle.
552
    // For simplicity the maximum-norm is used.
553
0
{
554
0
    bool  bIsInside = IsInsideItalicRect(rPoint);
555
556
    // build reference point to define the distance
557
0
    Point  aRef;
558
0
    if (bIsInside)
559
0
    {   Point  aIC (GetItalicCenterX(), GetCenterY());
560
561
0
        aRef.setX( rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft() );
562
0
        aRef.setY( rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop() );
563
0
    }
564
0
    else
565
0
    {
566
        // x-coordinate
567
0
        if (rPoint.X() > GetItalicRight())
568
0
            aRef.setX( GetItalicRight() );
569
0
        else if (rPoint.X() < GetItalicLeft())
570
0
            aRef.setX( GetItalicLeft() );
571
0
        else
572
0
            aRef.setX( rPoint.X() );
573
        // y-coordinate
574
0
        if (rPoint.Y() > GetBottom())
575
0
            aRef.setY( GetBottom() );
576
0
        else if (rPoint.Y() < GetTop())
577
0
            aRef.setY( GetTop() );
578
0
        else
579
0
            aRef.setY( rPoint.Y() );
580
0
    }
581
582
    // build distance vector
583
0
    Point  aDist (aRef - rPoint);
584
585
0
    tools::Long nAbsX = std::abs(aDist.X()),
586
0
         nAbsY = std::abs(aDist.Y());
587
588
0
    return bIsInside ? - std::min(nAbsX, nAbsY) : std::max (nAbsX, nAbsY);
589
0
}
590
591
592
bool SmRect::IsInsideRect(const Point &rPoint) const
593
0
{
594
0
    return     rPoint.Y() >= GetTop()
595
0
           &&  rPoint.Y() <= GetBottom()
596
0
           &&  rPoint.X() >= GetLeft()
597
0
           &&  rPoint.X() <= GetRight();
598
0
}
599
600
601
bool SmRect::IsInsideItalicRect(const Point &rPoint) const
602
0
{
603
0
    return     rPoint.Y() >= GetTop()
604
0
           &&  rPoint.Y() <= GetBottom()
605
0
           &&  rPoint.X() >= GetItalicLeft()
606
0
           &&  rPoint.X() <= GetItalicRight();
607
0
}
608
609
SmRect SmRect::AsGlyphRect() const
610
0
{
611
0
    SmRect aRect (*this);
612
0
    aRect.SetTop(nGlyphTop);
613
0
    aRect.SetBottom(nGlyphBottom);
614
0
    return aRect;
615
0
}
616
617
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */