Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/starmath/source/node.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
21
#include <symbol.hxx>
22
#include <smmod.hxx>
23
#include "tmpdevice.hxx"
24
#include <utility>
25
#include <visitors.hxx>
26
#include <tools/UnitConversion.hxx>
27
#include <vcl/metric.hxx>
28
#include <o3tl/safeint.hxx>
29
#include <osl/diagnose.h>
30
#include <basegfx/numeric/ftools.hxx>
31
#include <unicode/uchar.h>
32
#include <unicode/uscript.h>
33
34
namespace {
35
36
template<typename F>
37
void ForEachNonNull(SmNode *pNode, F && f)
38
477M
{
39
477M
    size_t nSize = pNode->GetNumSubNodes();
40
1.10G
    for (size_t i = 0; i < nSize; ++i)
41
630M
    {
42
630M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
630M
        if (pSubNode != nullptr)
44
491M
            f(pSubNode);
45
630M
    }
46
477M
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetPhantom(bool)::$_0>(SmNode*, SmNode::SetPhantom(bool)::$_0&&)
Line
Count
Source
38
142
{
39
142
    size_t nSize = pNode->GetNumSubNodes();
40
284
    for (size_t i = 0; i < nSize; ++i)
41
142
    {
42
142
        SmNode *pSubNode = pNode->GetSubNode(i);
43
142
        if (pSubNode != nullptr)
44
94
            f(pSubNode);
45
142
    }
46
142
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetColor(Color const&)::$_0>(SmNode*, SmNode::SetColor(Color const&)::$_0&&)
Line
Count
Source
38
80.8k
{
39
80.8k
    size_t nSize = pNode->GetNumSubNodes();
40
165k
    for (size_t i = 0; i < nSize; ++i)
41
84.6k
    {
42
84.6k
        SmNode *pSubNode = pNode->GetSubNode(i);
43
84.6k
        if (pSubNode != nullptr)
44
79.4k
            f(pSubNode);
45
84.6k
    }
46
80.8k
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetAttribute(FontAttribute)::$_0>(SmNode*, SmNode::SetAttribute(FontAttribute)::$_0&&)
Line
Count
Source
38
804k
{
39
804k
    size_t nSize = pNode->GetNumSubNodes();
40
1.71M
    for (size_t i = 0; i < nSize; ++i)
41
907k
    {
42
907k
        SmNode *pSubNode = pNode->GetSubNode(i);
43
907k
        if (pSubNode != nullptr)
44
803k
            f(pSubNode);
45
907k
    }
46
804k
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::ClearAttribute(FontAttribute)::$_0>(SmNode*, SmNode::ClearAttribute(FontAttribute)::$_0&&)
Line
Count
Source
38
65.9k
{
39
65.9k
    size_t nSize = pNode->GetNumSubNodes();
40
137k
    for (size_t i = 0; i < nSize; ++i)
41
71.7k
    {
42
71.7k
        SmNode *pSubNode = pNode->GetSubNode(i);
43
71.7k
        if (pSubNode != nullptr)
44
56.5k
            f(pSubNode);
45
71.7k
    }
46
65.9k
}
Unexecuted instantiation: node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetFont(SmFace const&)::$_0>(SmNode*, SmNode::SetFont(SmFace const&)::$_0&&)
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetFontSize(Fraction const&, FontSizeType)::$_0>(SmNode*, SmNode::SetFontSize(Fraction const&, FontSizeType)::$_0&&)
Line
Count
Source
38
12.8M
{
39
12.8M
    size_t nSize = pNode->GetNumSubNodes();
40
26.8M
    for (size_t i = 0; i < nSize; ++i)
41
14.0M
    {
42
14.0M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
14.0M
        if (pSubNode != nullptr)
44
12.7M
            f(pSubNode);
45
14.0M
    }
46
12.8M
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetSize(Fraction const&)::$_0>(SmNode*, SmNode::SetSize(Fraction const&)::$_0&&)
Line
Count
Source
38
98.4M
{
39
98.4M
    size_t nSize = pNode->GetNumSubNodes();
40
208M
    for (size_t i = 0; i < nSize; ++i)
41
110M
    {
42
110M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
110M
        if (pSubNode != nullptr)
44
97.3M
            f(pSubNode);
45
110M
    }
46
98.4M
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::SetRectHorAlign(RectHorAlign, bool)::$_0>(SmNode*, SmNode::SetRectHorAlign(RectHorAlign, bool)::$_0&&)
Line
Count
Source
38
433k
{
39
433k
    size_t nSize = pNode->GetNumSubNodes();
40
720k
    for (size_t i = 0; i < nSize; ++i)
41
287k
    {
42
287k
        SmNode *pSubNode = pNode->GetSubNode(i);
43
287k
        if (pSubNode != nullptr)
44
271k
            f(pSubNode);
45
287k
    }
46
433k
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::Prepare(SmFormat const&, SmDocShell const&, int)::$_0>(SmNode*, SmNode::Prepare(SmFormat const&, SmDocShell const&, int)::$_0&&)
Line
Count
Source
38
6.28M
{
39
6.28M
    size_t nSize = pNode->GetNumSubNodes();
40
12.9M
    for (size_t i = 0; i < nSize; ++i)
41
6.70M
    {
42
6.70M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
6.70M
        if (pSubNode != nullptr)
44
6.27M
            f(pSubNode);
45
6.70M
    }
46
6.28M
}
node.cxx:void (anonymous namespace)::ForEachNonNull<SmNode::Move(Point const&)::$_0>(SmNode*, SmNode::Move(Point const&)::$_0&&)
Line
Count
Source
38
348M
{
39
348M
    size_t nSize = pNode->GetNumSubNodes();
40
732M
    for (size_t i = 0; i < nSize; ++i)
41
383M
    {
42
383M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
383M
        if (pSubNode != nullptr)
44
344M
            f(pSubNode);
45
383M
    }
46
348M
}
node.cxx:void (anonymous namespace)::ForEachNonNull<std::__1::default_delete<SmNode> >(SmNode*, std::__1::default_delete<SmNode>&&)
Line
Count
Source
38
5.91M
{
39
5.91M
    size_t nSize = pNode->GetNumSubNodes();
40
63.7M
    for (size_t i = 0; i < nSize; ++i)
41
57.8M
    {
42
57.8M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
57.8M
        if (pSubNode != nullptr)
44
15.3M
            f(pSubNode);
45
57.8M
    }
46
5.91M
}
Unexecuted instantiation: node.cxx:void (anonymous namespace)::ForEachNonNull<SmStructureNode::GetAccessibleText(rtl::OUStringBuffer&) const::$_0>(SmNode*, SmStructureNode::GetAccessibleText(rtl::OUStringBuffer&) const::$_0&&)
node.cxx:void (anonymous namespace)::ForEachNonNull<SmStructureNode::ClaimPaternity()::$_0>(SmNode*, SmStructureNode::ClaimPaternity()::$_0&&)
Line
Count
Source
38
3.91M
{
39
3.91M
    size_t nSize = pNode->GetNumSubNodes();
40
60.4M
    for (size_t i = 0; i < nSize; ++i)
41
56.5M
    {
42
56.5M
        SmNode *pSubNode = pNode->GetSubNode(i);
43
56.5M
        if (pSubNode != nullptr)
44
13.5M
            f(pSubNode);
45
56.5M
    }
46
3.91M
}
47
48
}
49
50
SmNode::SmNode(SmNodeType eNodeType, SmToken aNodeToken)
51
16.0M
    : maNodeToken(std::move( aNodeToken ))
52
16.0M
    , meType( eNodeType )
53
16.0M
    , meScaleMode( SmScaleMode::None )
54
16.0M
    , meRectHorAlign( RectHorAlign::Left )
55
16.0M
    , mnFlags( FontChangeMask::None )
56
16.0M
    , mnAttributes( FontAttribute::None )
57
16.0M
    , mbIsPhantom( false )
58
16.0M
    , mbIsSelected( false )
59
16.0M
    , mnAccIndex( -1 )
60
16.0M
    , mpParentNode( nullptr )
61
16.0M
{
62
16.0M
}
63
64
SmNode::~SmNode()
65
16.0M
{
66
16.0M
}
67
68
const SmNode * SmNode::GetLeftMost() const
69
    //  returns leftmost node of current subtree.
70
    //! (this assumes the one with index 0 is always the leftmost subnode
71
    //! for the current node).
72
2.71M
{
73
2.71M
    const SmNode *pNode = GetNumSubNodes() > 0 ?
74
1.70M
                        GetSubNode(0) : nullptr;
75
76
2.71M
    return pNode ? pNode->GetLeftMost() : this;
77
2.71M
}
78
79
80
void SmNode::SetPhantom(bool bIsPhantomP)
81
142
{
82
142
    if (! (Flags() & FontChangeMask::Phantom))
83
96
        mbIsPhantom = bIsPhantomP;
84
85
142
    bool b = mbIsPhantom;
86
142
    ForEachNonNull(this, [b](SmNode *pNode){pNode->SetPhantom(b);});
87
142
}
88
89
90
void SmNode::SetColor(const Color& rColor)
91
80.8k
{
92
80.8k
    if (! (Flags() & FontChangeMask::Color))
93
69.4k
        GetFont().SetColor(rColor);
94
95
80.8k
    ForEachNonNull(this, [&rColor](SmNode *pNode){pNode->SetColor(rColor);});
96
80.8k
}
97
98
99
void SmNode::SetAttribute(FontAttribute nAttrib)
100
804k
{
101
804k
    if (
102
804k
        (nAttrib == FontAttribute::Bold && !(Flags() & FontChangeMask::Bold)) ||
103
803k
        (nAttrib == FontAttribute::Italic && !(Flags() & FontChangeMask::Italic))
104
804k
       )
105
552k
    {
106
552k
        mnAttributes |= nAttrib;
107
552k
    }
108
109
804k
    ForEachNonNull(this, [nAttrib](SmNode *pNode){pNode->SetAttribute(nAttrib);});
110
804k
}
111
112
113
void SmNode::ClearAttribute(FontAttribute nAttrib)
114
65.9k
{
115
65.9k
    if (
116
65.9k
        (nAttrib == FontAttribute::Bold && !(Flags() & FontChangeMask::Bold)) ||
117
65.9k
        (nAttrib == FontAttribute::Italic && !(Flags() & FontChangeMask::Italic))
118
65.9k
       )
119
50.1k
    {
120
50.1k
        mnAttributes &= ~nAttrib;
121
50.1k
    }
122
123
65.9k
    ForEachNonNull(this, [nAttrib](SmNode *pNode){pNode->ClearAttribute(nAttrib);});
124
65.9k
}
125
126
127
void SmNode::SetFont(const SmFace &rFace)
128
0
{
129
0
    if (!(Flags() & FontChangeMask::Face))
130
0
        GetFont() = rFace;
131
0
    ForEachNonNull(this, [&rFace](SmNode *pNode){pNode->SetFont(rFace);});
132
0
}
133
134
135
void SmNode::SetFontSize(const Fraction &rSize, FontSizeType nType)
136
    //! 'rSize' is in units of pts
137
12.8M
{
138
12.8M
    Size  aFntSize;
139
140
12.8M
    if (!(Flags() & FontChangeMask::Size))
141
11.2M
    {
142
11.2M
        Fraction aVal(conversionFract(o3tl::Length::pt, SmO3tlLengthUnit()) * rSize);
143
11.2M
        tools::Long      nHeight = static_cast<tools::Long>(aVal);
144
145
11.2M
        aFntSize = GetFont().GetFontSize();
146
11.2M
        aFntSize.setWidth( 0 );
147
11.2M
        switch(nType)
148
11.2M
        {
149
3.22k
            case FontSizeType::ABSOLUT:
150
3.22k
                aFntSize.setHeight( nHeight );
151
3.22k
                break;
152
153
11.1M
            case FontSizeType::PLUS:
154
11.1M
                aFntSize.AdjustHeight(nHeight );
155
11.1M
                break;
156
157
396
            case FontSizeType::MINUS:
158
396
                aFntSize.AdjustHeight( -nHeight );
159
396
                break;
160
161
50.0k
            case FontSizeType::MULTIPLY:
162
50.0k
                aFntSize.setHeight( static_cast<tools::Long>(Fraction(aFntSize.Height()) * rSize) );
163
50.0k
                break;
164
165
19.6k
            case FontSizeType::DIVIDE:
166
19.6k
                if (rSize != Fraction(0))
167
5.50k
                    aFntSize.setHeight( static_cast<tools::Long>(Fraction(aFntSize.Height()) / rSize) );
168
19.6k
                break;
169
0
            default:
170
0
                break;
171
11.2M
        }
172
173
        // check the requested size against maximum value
174
11.2M
        const int nMaxVal = o3tl::convert(128, o3tl::Length::pt, SmO3tlLengthUnit());
175
11.2M
        if (aFntSize.Height() > nMaxVal)
176
1.87M
            aFntSize.setHeight( nMaxVal );
177
178
11.2M
        GetFont().SetSize(aFntSize);
179
11.2M
    }
180
181
12.8M
    ForEachNonNull(this, [&rSize, &nType](SmNode *pNode){pNode->SetFontSize(rSize, nType);});
182
12.8M
}
183
184
185
void SmNode::SetSize(const Fraction &rSize)
186
98.4M
{
187
98.4M
    GetFont() *= rSize;
188
189
98.4M
    ForEachNonNull(this, [&rSize](SmNode *pNode){pNode->SetSize(rSize);});
190
98.4M
}
191
192
193
void SmNode::SetRectHorAlign(RectHorAlign eHorAlign, bool bApplyToSubTree )
194
1.43M
{
195
1.43M
    meRectHorAlign = eHorAlign;
196
197
1.43M
    if (bApplyToSubTree)
198
433k
        ForEachNonNull(this, [eHorAlign](SmNode *pNode){pNode->SetRectHorAlign(eHorAlign);});
199
1.43M
}
200
201
202
void SmNode::PrepareAttributes()
203
3.97M
{
204
3.97M
    GetFont().SetWeight((Attributes() & FontAttribute::Bold)   ? WEIGHT_BOLD   : WEIGHT_NORMAL);
205
3.97M
    GetFont().SetItalic((Attributes() & FontAttribute::Italic) ? ITALIC_NORMAL : ITALIC_NONE);
206
3.97M
}
207
208
209
void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
210
6.28M
{
211
6.28M
    if (nDepth > 1024)
212
1
        throw std::range_error("parser depth limit");
213
214
6.28M
    mbIsPhantom  = false;
215
6.28M
    mnFlags      = FontChangeMask::None;
216
6.28M
    mnAttributes = FontAttribute::None;
217
218
6.28M
    switch (rFormat.GetHorAlign())
219
6.28M
    {   case SmHorAlign::Left:     meRectHorAlign = RectHorAlign::Left;   break;
220
6.28M
        case SmHorAlign::Center:   meRectHorAlign = RectHorAlign::Center; break;
221
0
        case SmHorAlign::Right:    meRectHorAlign = RectHorAlign::Right;  break;
222
6.28M
    }
223
224
6.28M
    GetFont() = rFormat.GetFont(FNT_MATH);
225
6.28M
    OSL_ENSURE( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
226
6.28M
            "unexpected CharSet" );
227
6.28M
    GetFont().SetWeight(WEIGHT_NORMAL);
228
6.28M
    GetFont().SetItalic(ITALIC_NONE);
229
230
6.28M
    ForEachNonNull(this, [&rFormat, &rDocShell, nDepth](SmNode *pNode){pNode->Prepare(rFormat, rDocShell, nDepth + 1);});
231
6.28M
}
232
233
void SmNode::Move(const Point& rVector)
234
348M
{
235
348M
    if (rVector.X() == 0  &&  rVector.Y() == 0)
236
891
        return;
237
238
348M
    SmRect::Move(rVector);
239
240
348M
    ForEachNonNull(this, [&rVector](SmNode *pNode){pNode->Move(rVector);});
241
348M
}
242
243
void SmNode::AdaptToX(OutputDevice &/*rDev*/, tools::Long /*nWidth*/)
244
0
{
245
0
}
246
247
248
void SmNode::AdaptToY(OutputDevice &/*rDev*/, tools::Long /*nHeight*/)
249
4.24k
{
250
4.24k
}
251
252
253
const SmNode * SmNode::FindTokenAt(sal_uInt16 nRow, sal_uInt16 nCol) const
254
    // returns (first) ** visible ** (sub)node with the tokens text at
255
    // position 'nRow', 'nCol'.
256
    //! (there should be exactly one such node if any)
257
0
{
258
0
    if (    IsVisible()
259
0
        &&  nRow == GetSelection().start.nPara
260
0
        &&  nCol >= GetSelection().start.nIndex  &&  nCol <= GetSelection().end.nIndex )
261
0
        return this;
262
0
    else
263
0
    {
264
0
        size_t nNumSubNodes = GetNumSubNodes();
265
0
        for (size_t i = 0;  i < nNumSubNodes; ++i)
266
0
        {
267
0
            const SmNode *pNode = GetSubNode(i);
268
269
0
            if (!pNode)
270
0
                continue;
271
272
0
            const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
273
0
            if (pResult)
274
0
                return pResult;
275
0
        }
276
0
    }
277
278
0
    return nullptr;
279
0
}
280
281
282
const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
283
0
{
284
0
    tools::Long          nDist   = LONG_MAX;
285
0
    const SmNode *pResult = nullptr;
286
287
0
    if (IsVisible())
288
0
        pResult = this;
289
0
    else
290
0
    {
291
0
        size_t nNumSubNodes = GetNumSubNodes();
292
0
        for (size_t i = 0;  i < nNumSubNodes; ++i)
293
0
        {
294
0
            const SmNode *pNode = GetSubNode(i);
295
296
0
            if (!pNode)
297
0
                continue;
298
299
0
            const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
300
0
            if (pFound)
301
0
            {
302
0
                tools::Long nTmp = pFound->OrientedDist(rPoint);
303
0
                if (nTmp < nDist)
304
0
                {
305
0
                    nDist   = nTmp;
306
0
                    pResult = pFound;
307
308
                    // quit immediately if 'rPoint' is inside the *should not
309
                    // overlap with other rectangles* part.
310
                    // This (partly) serves for getting the attributes in eg
311
                    // "bar overstrike a".
312
                    // ('nDist < 0' is used as *quick shot* to avoid evaluation of
313
                    // the following expression, where the result is already determined)
314
0
                    if (nDist < 0  &&  pFound->IsInsideRect(rPoint))
315
0
                        break;
316
0
                }
317
0
            }
318
0
        }
319
0
    }
320
321
0
    return pResult;
322
0
}
323
324
const SmNode * SmNode::FindNodeWithAccessibleIndex(sal_Int32 nAccIdx) const
325
0
{
326
0
    const SmNode *pResult = nullptr;
327
328
0
    sal_Int32 nIdx = GetAccessibleIndex();
329
0
    OUStringBuffer aTxt;
330
0
    if (nIdx >= 0)
331
0
        GetAccessibleText( aTxt );  // get text if used in following 'if' statement
332
333
0
    if (nIdx >= 0
334
0
        &&  nIdx <= nAccIdx  &&  nAccIdx < nIdx + aTxt.getLength())
335
0
        pResult = this;
336
0
    else
337
0
    {
338
0
        size_t nNumSubNodes = GetNumSubNodes();
339
0
        for (size_t i = 0; i < nNumSubNodes; ++i)
340
0
        {
341
0
            const SmNode *pNode = GetSubNode(i);
342
0
            if (!pNode)
343
0
                continue;
344
345
0
            pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
346
0
            if (pResult)
347
0
                return pResult;
348
0
        }
349
0
    }
350
351
0
    return pResult;
352
0
}
353
354
355
SmStructureNode::~SmStructureNode()
356
5.91M
{
357
5.91M
    ForEachNonNull(this, std::default_delete<SmNode>());
358
5.91M
}
359
360
361
void SmStructureNode::ClearSubNodes()
362
19.1k
{
363
19.1k
    maSubNodes.clear();
364
19.1k
}
365
366
void SmStructureNode::SetSubNodes(std::unique_ptr<SmNode> pFirst, std::unique_ptr<SmNode> pSecond, std::unique_ptr<SmNode> pThird)
367
2.56M
{
368
2.56M
    size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0));
369
2.56M
    maSubNodes.resize( nSize );
370
2.56M
    if (pFirst)
371
2.41M
        maSubNodes[0] = pFirst.release();
372
2.56M
    if (pSecond)
373
2.55M
        maSubNodes[1] = pSecond.release();
374
2.56M
    if (pThird)
375
1.76M
        maSubNodes[2] = pThird.release();
376
377
2.56M
    ClaimPaternity();
378
2.56M
}
379
380
void SmStructureNode::SetSubNodes(SmNode* pFirst, SmNode* pSecond, SmNode* pThird)
381
0
{
382
0
    size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0));
383
0
    maSubNodes.resize( nSize );
384
0
    if (pFirst)
385
0
        maSubNodes[0] = pFirst;
386
0
    if (pSecond)
387
0
        maSubNodes[1] = pSecond;
388
0
    if (pThird)
389
0
        maSubNodes[2] = pThird;
390
391
0
    ClaimPaternity();
392
0
}
393
394
void SmStructureNode::SetSubNodesBinMo(std::unique_ptr<SmNode> pFirst, std::unique_ptr<SmNode> pSecond, std::unique_ptr<SmNode> pThird)
395
627k
{
396
627k
    if(GetType()==SmNodeType::BinDiagonal)
397
0
    {
398
0
        size_t nSize = pSecond ? 3 : (pThird ? 2 : (pFirst ? 1 : 0));
399
0
        maSubNodes.resize( nSize );
400
0
        if (pFirst)
401
0
            maSubNodes[0] = pFirst.release();
402
0
        if (pSecond)
403
0
            maSubNodes[2] = pSecond.release();
404
0
        if (pThird)
405
0
            maSubNodes[1] = pThird.release();
406
0
    }
407
627k
    else
408
627k
    {
409
627k
        size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0));
410
627k
        maSubNodes.resize( nSize );
411
627k
        if (pFirst)
412
627k
            maSubNodes[0] = pFirst.release();
413
627k
        if (pSecond)
414
627k
            maSubNodes[1] = pSecond.release();
415
627k
        if (pThird)
416
627k
            maSubNodes[2] = pThird.release();
417
627k
    }
418
627k
    ClaimPaternity();
419
627k
}
420
421
void SmStructureNode::SetSubNodes(SmNodeArray&& rNodeArray)
422
726k
{
423
726k
    maSubNodes = std::move(rNodeArray);
424
726k
    ClaimPaternity();
425
726k
}
426
427
bool SmStructureNode::IsVisible() const
428
0
{
429
0
    return false;
430
0
}
431
432
size_t SmStructureNode::GetNumSubNodes() const
433
195M
{
434
195M
    return maSubNodes.size();
435
195M
}
436
437
SmNode* SmStructureNode::GetSubNode(size_t nIndex)
438
642M
{
439
642M
    return maSubNodes[nIndex];
440
642M
}
441
442
SmNode* SmStructureNode::GetSubNodeBinMo(size_t nIndex) const
443
0
{
444
0
    if(GetType()==SmNodeType::BinDiagonal)
445
0
    {
446
0
        if (nIndex==1)
447
0
            nIndex = 2;
448
0
        else if (nIndex==2)
449
0
            nIndex = 1;
450
0
    }
451
0
    return maSubNodes[nIndex];
452
0
}
453
454
void SmStructureNode::GetAccessibleText( OUStringBuffer &rText ) const
455
0
{
456
0
    ForEachNonNull(const_cast<SmStructureNode *>(this),
457
0
                   [&rText](SmNode *pNode)
458
0
        {
459
0
            if (pNode->IsVisible())
460
0
                pNode->SetAccessibleIndex(rText.getLength());
461
0
            pNode->GetAccessibleText( rText );
462
0
        });
463
0
}
464
465
void SmStructureNode::ClaimPaternity()
466
3.91M
{
467
13.5M
    ForEachNonNull(this, [this](SmNode *pNode){pNode->SetParent(this);});
468
3.91M
}
469
470
int SmStructureNode::IndexOfSubNode(SmNode const * pSubNode)
471
0
{
472
0
    size_t nSize = GetNumSubNodes();
473
0
    for (size_t i = 0; i < nSize; i++)
474
0
        if (pSubNode == GetSubNode(i))
475
0
            return i;
476
0
    return -1;
477
0
}
478
479
void SmStructureNode::SetSubNode(size_t nIndex, SmNode* pNode)
480
1.85M
{
481
1.85M
    size_t size = maSubNodes.size();
482
1.85M
    if (size <= nIndex)
483
1.85M
    {
484
        //Resize subnodes array
485
1.85M
        maSubNodes.resize(nIndex + 1);
486
        //Set new slots to NULL except at nIndex
487
1.85M
        for (size_t i = size; i < nIndex; i++)
488
0
            maSubNodes[i] = nullptr;
489
1.85M
    }
490
1.85M
    maSubNodes[nIndex] = pNode;
491
1.85M
    if (pNode)
492
1.85M
        pNode->SetParent(this);
493
1.85M
}
494
495
bool SmVisibleNode::IsVisible() const
496
0
{
497
0
    return true;
498
0
}
499
500
size_t SmVisibleNode::GetNumSubNodes() const
501
286M
{
502
286M
    return 0;
503
286M
}
504
505
SmNode * SmVisibleNode::GetSubNode(size_t /*nIndex*/)
506
0
{
507
0
    return nullptr;
508
0
}
509
510
void SmGraphicNode::GetAccessibleText( OUStringBuffer &rText ) const
511
0
{
512
0
    rText.append(GetToken().aText);
513
0
}
514
515
void SmTableNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
516
    // arranges all subnodes in one column
517
5.17k
{
518
5.17k
    SmNode *pNode;
519
5.17k
    size_t nSize = GetNumSubNodes();
520
521
    // make distance depend on font size
522
5.17k
    tools::Long  nDist = +(rFormat.GetDistance(DIS_VERTICAL)
523
5.17k
                    * GetFont().GetFontSize().Height()) / 100;
524
525
5.17k
    if (nSize < 1)
526
0
        return;
527
528
    // arrange subnodes and get maximum width of them
529
5.17k
    tools::Long  nMaxWidth = 0,
530
5.17k
          nTmp;
531
14.5k
    for (size_t i = 0; i < nSize; ++i)
532
9.34k
    {
533
9.34k
        if (nullptr != (pNode = GetSubNode(i)))
534
9.34k
        {   pNode->Arrange(rDev, rFormat);
535
9.34k
            if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
536
5.47k
                nMaxWidth = nTmp;
537
9.34k
        }
538
9.34k
    }
539
540
5.17k
    Point  aPos;
541
5.17k
    SmRect::operator = (SmRect(nMaxWidth, 1));
542
14.5k
    for (size_t i = 0; i < nSize; ++i)
543
9.34k
    {
544
9.34k
        if (nullptr != (pNode = GetSubNode(i)))
545
9.34k
        {   const SmRect &rNodeRect = pNode->GetRect();
546
9.34k
            const SmNode *pCoNode   = pNode->GetLeftMost();
547
9.34k
            RectHorAlign  eHorAlign = pCoNode->GetRectHorAlign();
548
549
9.34k
            aPos = rNodeRect.AlignTo(*this, RectPos::Bottom,
550
9.34k
                        eHorAlign, RectVerAlign::Baseline);
551
9.34k
            if (i)
552
4.16k
                aPos.AdjustY(nDist );
553
9.34k
            pNode->MoveTo(aPos);
554
9.34k
            ExtendBy(rNodeRect, nSize > 1 ? RectCopyMBL::None : RectCopyMBL::Arg);
555
9.34k
        }
556
9.34k
    }
557
    // #i972#
558
5.17k
    if (HasBaseline())
559
4.90k
        mnFormulaBaseline = GetBaseline();
560
271
    else
561
271
    {
562
271
        SmTmpDevice aTmpDev (rDev, true);
563
271
        aTmpDev.SetFont(GetFont());
564
565
271
        SmRect aRect(aTmpDev, &rFormat, u"a"_ustr, GetFont().GetBorderWidth());
566
271
        mnFormulaBaseline = GetAlignM();
567
        // move from middle position by constant - distance
568
        // between middle and baseline for single letter
569
271
        mnFormulaBaseline += aRect.GetBaseline() - aRect.GetAlignM();
570
271
    }
571
5.17k
}
572
573
const SmNode * SmTableNode::GetLeftMost() const
574
0
{
575
0
    return this;
576
0
}
577
578
579
tools::Long SmTableNode::GetFormulaBaseline() const
580
0
{
581
0
    return mnFormulaBaseline;
582
0
}
583
584
585
/**************************************************************************/
586
587
588
void SmLineNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
589
1.00M
{
590
1.00M
    SmNode::Prepare(rFormat, rDocShell, nDepth);
591
592
    // Here we use the 'FNT_VARIABLE' font since it's ascent and descent in general fit better
593
    // to the rest of the formula compared to the 'FNT_MATH' font.
594
1.00M
    GetFont() = rFormat.GetFont(FNT_VARIABLE);
595
1.00M
    Flags() |= FontChangeMask::Face;
596
1.00M
}
597
598
599
/**************************************************************************/
600
601
602
void SmLineNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
603
    // arranges all subnodes in one row with some extra space between
604
1.00M
{
605
1.00M
    SmNode *pNode;
606
1.00M
    size_t nSize = GetNumSubNodes();
607
3.81M
    for (size_t i = 0; i < nSize; ++i)
608
2.80M
    {
609
2.80M
        if (nullptr != (pNode = GetSubNode(i)))
610
2.80M
            pNode->Arrange(rDev, rFormat);
611
2.80M
    }
612
613
1.00M
    SmTmpDevice aTmpDev (rDev, true);
614
1.00M
    aTmpDev.SetFont(GetFont());
615
616
1.00M
    if (nSize < 1)
617
1.50k
    {
618
        // provide an empty rectangle with alignment parameters for the "current"
619
        // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
620
        // same sub-/supscript positions.)
621
        //! be sure to use a character that has explicitly defined HiAttribut
622
        //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
623
        //! 'vec {a}'.
624
1.50k
        SmRect::operator = (SmRect(aTmpDev, &rFormat, u"a"_ustr,
625
1.50k
                            GetFont().GetBorderWidth()));
626
        // make sure that the rectangle occupies (almost) no space
627
1.50k
        SetWidth(1);
628
1.50k
        SetItalicSpaces(0, 0);
629
1.50k
        return;
630
1.50k
    }
631
632
    // make distance depend on font size
633
1.00M
    tools::Long nDist = (rFormat.GetDistance(DIS_HORIZONTAL) * GetFont().GetFontSize().Height()) / 100;
634
1.00M
    if (!IsUseExtraSpaces())
635
0
        nDist = 0;
636
637
1.00M
    Point   aPos;
638
    // copy the first node into LineNode and extend by the others
639
1.00M
    if (nullptr != (pNode = GetSubNode(0)))
640
1.00M
        SmRect::operator = (pNode->GetRect());
641
642
2.80M
    for (size_t i = 1;  i < nSize; ++i)
643
1.80M
    {
644
1.80M
        if (nullptr != (pNode = GetSubNode(i)))
645
1.80M
        {
646
1.80M
            aPos = pNode->AlignTo(*this, RectPos::Right, RectHorAlign::Center, RectVerAlign::Baseline);
647
648
            // add horizontal space to the left for each but the first sub node
649
1.80M
            aPos.AdjustX(nDist );
650
651
1.80M
            pNode->MoveTo(aPos);
652
1.80M
            ExtendBy( *pNode, RectCopyMBL::Xor );
653
1.80M
        }
654
1.80M
    }
655
1.00M
}
656
657
658
/**************************************************************************/
659
660
661
void SmExpressionNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
662
    // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
663
997k
{
664
997k
    SmLineNode::Arrange(rDev, rFormat);
665
666
    //  copy alignment of leftmost subnode if any
667
997k
    const SmNode *pNode = GetLeftMost();
668
997k
    if (pNode)
669
997k
        SetRectHorAlign(pNode->GetRectHorAlign(), false);
670
997k
}
671
672
673
/**************************************************************************/
674
675
676
void SmUnHorNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
677
130k
{
678
130k
    bool  bIsPostfix = GetToken().eType == TFACT;
679
680
130k
    SmNode *pNode0 = GetSubNode(0),
681
130k
           *pNode1 = GetSubNode(1);
682
130k
    SmNode *pOper = bIsPostfix ? pNode1 : pNode0,
683
130k
           *pBody = bIsPostfix ? pNode0 : pNode1;
684
130k
    assert(pOper);
685
130k
    assert(pBody);
686
687
130k
    pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
688
130k
    pOper->Arrange(rDev, rFormat);
689
130k
    pBody->Arrange(rDev, rFormat);
690
691
130k
    tools::Long nDist = (pOper->GetRect().GetWidth() * rFormat.GetDistance(DIS_HORIZONTAL)) / 100;
692
693
130k
    SmRect::operator = (*pNode0);
694
695
130k
    Point aPos = pNode1->AlignTo(*this, RectPos::Right, RectHorAlign::Center, RectVerAlign::Baseline);
696
130k
    aPos.AdjustX(nDist );
697
130k
    pNode1->MoveTo(aPos);
698
130k
    ExtendBy(*pNode1, RectCopyMBL::Xor);
699
130k
}
700
701
702
/**************************************************************************/
703
704
namespace {
705
706
void lcl_GetHeightVerOffset(const SmRect &rRect,
707
                                    tools::Long &rHeight, tools::Long &rVerOffset)
708
    // calculate height and vertical offset of root sign suitable for 'rRect'
709
12.4k
{
710
12.4k
    rVerOffset = (rRect.GetBottom() - rRect.GetAlignB()) / 2;
711
12.4k
    rHeight    = rRect.GetHeight() - rVerOffset;
712
713
12.4k
    OSL_ENSURE(rHeight    >= 0, "Sm : Ooops...");
714
12.4k
    OSL_ENSURE(rVerOffset >= 0, "Sm : Ooops...");
715
12.4k
}
716
717
718
Point lcl_GetExtraPos(const SmRect &rRootSymbol,
719
                              const SmRect &rExtra)
720
1.86k
{
721
1.86k
    const Size &rSymSize = rRootSymbol.GetSize();
722
723
1.86k
    Point  aPos = rRootSymbol.GetTopLeft()
724
1.86k
            + Point((rSymSize.Width()  * 70) / 100,
725
1.86k
                    (rSymSize.Height() * 52) / 100);
726
727
    // from this calculate topleft edge of 'rExtra'
728
1.86k
    aPos.AdjustX( -(rExtra.GetWidth() + rExtra.GetItalicRightSpace()) );
729
1.86k
    aPos.AdjustY( -(rExtra.GetHeight()) );
730
    // if there's enough space move a bit less to the right
731
    // examples: "nroot i a", "nroot j a"
732
    // (it looks better if we don't use italic-spaces here)
733
1.86k
    tools::Long  nX = rRootSymbol.GetLeft() + (rSymSize.Width() * 30) / 100;
734
1.86k
    if (aPos.X() > nX)
735
680
        aPos.setX( nX );
736
737
1.86k
    return aPos;
738
1.86k
}
739
740
}
741
742
void SmRootNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
743
12.4k
{
744
    //! pExtra needs to have the smaller index than pRootSym in order to
745
    //! not to get the root symbol but the pExtra when clicking on it in the
746
    //! GraphicWindow. (That is because of the simplicity of the algorithm
747
    //! that finds the node corresponding to a mouseclick in the window.)
748
12.4k
    SmNode *pExtra   = GetSubNode(0),
749
12.4k
           *pRootSym = GetSubNode(1),
750
12.4k
           *pBody    = GetSubNode(2);
751
12.4k
    assert(pRootSym);
752
12.4k
    assert(pBody);
753
754
12.4k
    pBody->Arrange(rDev, rFormat);
755
756
12.4k
    tools::Long  nHeight,
757
12.4k
          nVerOffset;
758
12.4k
    lcl_GetHeightVerOffset(*pBody, nHeight, nVerOffset);
759
12.4k
    nHeight += rFormat.GetDistance(DIS_ROOT)
760
12.4k
               * GetFont().GetFontSize().Height() / 100;
761
762
12.4k
    if (nHeight < 0)
763
7
    {
764
7
        SAL_WARN("starmath", "negative height");
765
7
        nHeight = 0;
766
7
    }
767
768
    // font specialist advised to change the width first
769
12.4k
    pRootSym->AdaptToY(rDev, nHeight);
770
12.4k
    pRootSym->AdaptToX(rDev, pBody->GetItalicWidth());
771
772
12.4k
    pRootSym->Arrange(rDev, rFormat);
773
774
    // Set the top and bottom of the root symbol to the top and bottom of its glyph bounding rect,
775
    // to get accurate position of the root symbol.
776
12.4k
    SmRect rRootSymRect = pRootSym->AsGlyphRect();
777
12.4k
    pRootSym->SetTop(rRootSymRect.GetTop());
778
12.4k
    pRootSym->SetBottom(rRootSymRect.GetBottom());
779
780
12.4k
    Point  aPos = pRootSym->AlignTo(*pBody, RectPos::Left, RectHorAlign::Center, RectVerAlign::Baseline);
781
    //! override calculated vertical position
782
12.4k
    aPos.setY( pRootSym->GetTop() + pBody->GetBottom() - pRootSym->GetBottom() );
783
12.4k
    aPos.AdjustY( -nVerOffset );
784
12.4k
    pRootSym->MoveTo(aPos);
785
786
12.4k
    if (pExtra)
787
1.86k
    {   pExtra->SetSize(Fraction(rFormat.GetRelSize(SIZ_INDEX), 100));
788
1.86k
        pExtra->Arrange(rDev, rFormat);
789
790
1.86k
        aPos = lcl_GetExtraPos(*pRootSym, *pExtra);
791
1.86k
        pExtra->MoveTo(aPos);
792
1.86k
    }
793
794
12.4k
    SmRect::operator = (*pBody);
795
12.4k
    ExtendBy(*pRootSym, RectCopyMBL::This);
796
12.4k
    if (pExtra)
797
1.86k
        ExtendBy(*pExtra, RectCopyMBL::This, true);
798
12.4k
}
799
800
/**************************************************************************/
801
802
803
void SmBinHorNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
804
946k
{
805
946k
    SmNode *pLeft  = LeftOperand(),
806
946k
           *pOper  = Symbol(),
807
946k
           *pRight = RightOperand();
808
946k
    assert(pLeft);
809
946k
    assert(pOper);
810
946k
    assert(pRight);
811
812
946k
    pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
813
814
946k
    pLeft ->Arrange(rDev, rFormat);
815
946k
    pOper ->Arrange(rDev, rFormat);
816
946k
    pRight->Arrange(rDev, rFormat);
817
818
946k
    const SmRect &rOpRect = pOper->GetRect();
819
820
946k
    tools::Long nMul;
821
946k
    if (o3tl::checked_multiply<tools::Long>(rOpRect.GetWidth(), rFormat.GetDistance(DIS_HORIZONTAL), nMul))
822
2
    {
823
2
        SAL_WARN("starmath", "integer overflow");
824
2
        return;
825
2
    }
826
827
946k
    tools::Long nDist = nMul / 100;
828
829
946k
    SmRect::operator = (*pLeft);
830
831
946k
    Point aPos;
832
946k
    aPos = pOper->AlignTo(*this, RectPos::Right, RectHorAlign::Center, RectVerAlign::Baseline);
833
946k
    aPos.AdjustX(nDist );
834
946k
    pOper->MoveTo(aPos);
835
946k
    ExtendBy(*pOper, RectCopyMBL::Xor);
836
837
946k
    aPos = pRight->AlignTo(*this, RectPos::Right, RectHorAlign::Center, RectVerAlign::Baseline);
838
946k
    aPos.AdjustX(nDist );
839
840
946k
    pRight->MoveTo(aPos);
841
946k
    ExtendBy(*pRight, RectCopyMBL::Xor);
842
946k
}
843
844
845
/**************************************************************************/
846
847
848
void SmBinVerNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
849
5.42k
{
850
5.42k
    SmNode *pNum   = GetSubNode(0),
851
5.42k
           *pLine  = GetSubNode(1),
852
5.42k
           *pDenom = GetSubNode(2);
853
5.42k
    assert(pNum);
854
5.42k
    assert(pLine);
855
5.42k
    assert(pDenom);
856
857
5.42k
    bool  bIsTextmode = rFormat.IsTextmode();
858
5.42k
    if (bIsTextmode)
859
0
    {
860
0
        Fraction  aFraction(rFormat.GetRelSize(SIZ_INDEX), 100);
861
0
        pNum  ->SetSize(aFraction);
862
0
        pLine ->SetSize(aFraction);
863
0
        pDenom->SetSize(aFraction);
864
0
    }
865
866
5.42k
    pNum  ->Arrange(rDev, rFormat);
867
5.42k
    pDenom->Arrange(rDev, rFormat);
868
869
5.42k
    tools::Long  nFontHeight = GetFont().GetFontSize().Height(),
870
5.42k
          nExtLen     = nFontHeight * rFormat.GetDistance(DIS_FRACTION) / 100,
871
5.42k
          nThick      = nFontHeight * rFormat.GetDistance(DIS_STROKEWIDTH) / 100,
872
5.42k
          nWidth      = std::max(pNum->GetItalicWidth(), pDenom->GetItalicWidth()),
873
5.42k
          nNumDist    = bIsTextmode ? 0 :
874
5.42k
                            nFontHeight * rFormat.GetDistance(DIS_NUMERATOR)   / 100,
875
5.42k
          nDenomDist  = bIsTextmode ? 0 :
876
5.42k
                            nFontHeight * rFormat.GetDistance(DIS_DENOMINATOR) / 100;
877
878
    // font specialist advised to change the width first
879
5.42k
    pLine->AdaptToY(rDev, nThick);
880
5.42k
    pLine->AdaptToX(rDev, nWidth + 2 * nExtLen);
881
5.42k
    pLine->Arrange(rDev, rFormat);
882
883
    // get horizontal alignment for numerator
884
5.42k
    const SmNode *pLM       = pNum->GetLeftMost();
885
5.42k
    RectHorAlign  eHorAlign = pLM->GetRectHorAlign();
886
887
    // move numerator to its position
888
5.42k
    Point  aPos = pNum->AlignTo(*pLine, RectPos::Top, eHorAlign, RectVerAlign::Baseline);
889
5.42k
    aPos.AdjustY( -nNumDist );
890
5.42k
    pNum->MoveTo(aPos);
891
892
    // get horizontal alignment for denominator
893
5.42k
    pLM       = pDenom->GetLeftMost();
894
5.42k
    eHorAlign = pLM->GetRectHorAlign();
895
896
    // move denominator to its position
897
5.42k
    aPos = pDenom->AlignTo(*pLine, RectPos::Bottom, eHorAlign, RectVerAlign::Baseline);
898
5.42k
    aPos.AdjustY(nDenomDist );
899
5.42k
    pDenom->MoveTo(aPos);
900
901
5.42k
    SmRect::operator = (*pNum);
902
5.42k
    ExtendBy(*pDenom, RectCopyMBL::None).ExtendBy(*pLine, RectCopyMBL::None, pLine->GetCenterY());
903
5.42k
}
904
905
const SmNode * SmBinVerNode::GetLeftMost() const
906
1.38k
{
907
1.38k
    return this;
908
1.38k
}
909
910
911
namespace {
912
913
/// @return value of the determinant formed by the two points
914
double Det(const Point &rHeading1, const Point &rHeading2)
915
0
{
916
0
    return rHeading1.X() * rHeading2.Y() - rHeading1.Y() * rHeading2.X();
917
0
}
918
919
920
/// Is true iff the point 'rPoint1' belongs to the straight line through 'rPoint2'
921
/// and has the direction vector 'rHeading2'
922
bool IsPointInLine(const Point &rPoint1,
923
                   const Point &rPoint2, const Point &rHeading2)
924
0
{
925
0
    assert(rHeading2 != Point());
926
927
0
    bool bRes = false;
928
0
    static const double eps = 5.0 * DBL_EPSILON;
929
930
0
    double fLambda;
931
0
    if (std::abs(rHeading2.X()) > std::abs(rHeading2.Y()))
932
0
    {
933
0
        fLambda = (rPoint1.X() - rPoint2.X()) / static_cast<double>(rHeading2.X());
934
0
        bRes = fabs(rPoint1.Y() - (rPoint2.Y() + fLambda * rHeading2.Y())) < eps;
935
0
    }
936
0
    else
937
0
    {
938
0
        fLambda = (rPoint1.Y() - rPoint2.Y()) / static_cast<double>(rHeading2.Y());
939
0
        bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
940
0
    }
941
942
0
    return bRes;
943
0
}
944
945
946
sal_uInt16 GetLineIntersectionPoint(Point &rResult,
947
                                const Point& rPoint1, const Point &rHeading1,
948
                                const Point& rPoint2, const Point &rHeading2)
949
0
{
950
0
    assert(rHeading1 != Point());
951
0
    assert(rHeading2 != Point());
952
953
0
    sal_uInt16 nRes = 1;
954
0
    static const double eps = 5.0 * DBL_EPSILON;
955
956
    // are the direction vectors linearly dependent?
957
0
    double  fDet = Det(rHeading1, rHeading2);
958
0
    if (fabs(fDet) < eps)
959
0
    {
960
0
        nRes    = IsPointInLine(rPoint1, rPoint2, rHeading2) ? USHRT_MAX : 0;
961
0
        rResult = nRes ? rPoint1 : Point();
962
0
    }
963
0
    else
964
0
    {
965
        // here we do not pay attention to the computational accuracy
966
        // (that would be more complicated and is not really worth it in this case)
967
0
        double fLambda = (    (rPoint1.Y() - rPoint2.Y()) * rHeading2.X()
968
0
                            - (rPoint1.X() - rPoint2.X()) * rHeading2.Y())
969
0
                         / fDet;
970
0
        rResult = Point(rPoint1.X() + static_cast<tools::Long>(fLambda * rHeading1.X()),
971
0
                        rPoint1.Y() + static_cast<tools::Long>(fLambda * rHeading1.Y()));
972
0
    }
973
974
0
    return nRes;
975
0
}
976
977
}
978
979
980
/// @return position and size of the diagonal line
981
/// premise: SmRect of the node defines the limitation(!) consequently it has to be known upfront
982
void SmBinDiagonalNode::GetOperPosSize(Point &rPos, Size &rSize,
983
                        const Point &rDiagPoint, double fAngleDeg) const
984
985
0
{
986
0
    double  fAngleRad   = basegfx::deg2rad(fAngleDeg);
987
0
    tools::Long    nRectLeft   = GetItalicLeft(),
988
0
            nRectRight  = GetItalicRight(),
989
0
            nRectTop    = GetTop(),
990
0
            nRectBottom = GetBottom();
991
0
    Point   aRightHdg     (100, 0),
992
0
            aDownHdg      (0, 100),
993
0
            aDiagHdg      ( static_cast<tools::Long>(100.0 * cos(fAngleRad)),
994
0
                            static_cast<tools::Long>(-100.0 * sin(fAngleRad)) );
995
996
0
    tools::Long  nLeft, nRight, nTop, nBottom;     // margins of the rectangle for the diagonal
997
0
    Point aPoint;
998
0
    if (IsAscending())
999
0
    {
1000
        // determine top right corner
1001
0
        GetLineIntersectionPoint(aPoint,
1002
0
            Point(nRectLeft, nRectTop), aRightHdg,
1003
0
            rDiagPoint, aDiagHdg);
1004
        // is there a point of intersection with the top border?
1005
0
        if (aPoint.X() <= nRectRight)
1006
0
        {
1007
0
            nRight = aPoint.X();
1008
0
            nTop   = nRectTop;
1009
0
        }
1010
0
        else
1011
0
        {
1012
            // there has to be a point of intersection with the right border!
1013
0
            GetLineIntersectionPoint(aPoint,
1014
0
                Point(nRectRight, nRectTop), aDownHdg,
1015
0
                rDiagPoint, aDiagHdg);
1016
1017
0
            nRight = nRectRight;
1018
0
            nTop   = aPoint.Y();
1019
0
        }
1020
1021
        // determine bottom left corner
1022
0
        GetLineIntersectionPoint(aPoint,
1023
0
            Point(nRectLeft, nRectBottom), aRightHdg,
1024
0
            rDiagPoint, aDiagHdg);
1025
        // is there a point of intersection with the bottom border?
1026
0
        if (aPoint.X() >= nRectLeft)
1027
0
        {
1028
0
            nLeft   = aPoint.X();
1029
0
            nBottom = nRectBottom;
1030
0
        }
1031
0
        else
1032
0
        {
1033
            // there has to be a point of intersection with the left border!
1034
0
            GetLineIntersectionPoint(aPoint,
1035
0
                Point(nRectLeft, nRectTop), aDownHdg,
1036
0
                rDiagPoint, aDiagHdg);
1037
1038
0
            nLeft   = nRectLeft;
1039
0
            nBottom = aPoint.Y();
1040
0
        }
1041
0
    }
1042
0
    else
1043
0
    {
1044
        // determine top left corner
1045
0
        GetLineIntersectionPoint(aPoint,
1046
0
            Point(nRectLeft, nRectTop), aRightHdg,
1047
0
            rDiagPoint, aDiagHdg);
1048
        // is there a point of intersection with the top border?
1049
0
        if (aPoint.X() >= nRectLeft)
1050
0
        {
1051
0
            nLeft = aPoint.X();
1052
0
            nTop  = nRectTop;
1053
0
        }
1054
0
        else
1055
0
        {
1056
            // there has to be a point of intersection with the left border!
1057
0
            GetLineIntersectionPoint(aPoint,
1058
0
                Point(nRectLeft, nRectTop), aDownHdg,
1059
0
                rDiagPoint, aDiagHdg);
1060
1061
0
            nLeft = nRectLeft;
1062
0
            nTop  = aPoint.Y();
1063
0
        }
1064
1065
        // determine bottom right corner
1066
0
        GetLineIntersectionPoint(aPoint,
1067
0
            Point(nRectLeft, nRectBottom), aRightHdg,
1068
0
            rDiagPoint, aDiagHdg);
1069
        // is there a point of intersection with the bottom border?
1070
0
        if (aPoint.X() <= nRectRight)
1071
0
        {
1072
0
            nRight  = aPoint.X();
1073
0
            nBottom = nRectBottom;
1074
0
        }
1075
0
        else
1076
0
        {
1077
            // there has to be a point of intersection with the right border!
1078
0
            GetLineIntersectionPoint(aPoint,
1079
0
                Point(nRectRight, nRectTop), aDownHdg,
1080
0
                rDiagPoint, aDiagHdg);
1081
1082
0
            nRight  = nRectRight;
1083
0
            nBottom = aPoint.Y();
1084
0
        }
1085
0
    }
1086
1087
0
    rSize = Size(nRight - nLeft + 1, nBottom - nTop + 1);
1088
0
    rPos.setX( nLeft );
1089
0
    rPos.setY( nTop );
1090
0
}
1091
1092
1093
void SmBinDiagonalNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1094
0
{
1095
    // Both arguments have to get into the SubNodes before the Operator so that clicking
1096
    // within the GraphicWindow sets the FormulaCursor correctly (cf. SmRootNode)
1097
0
    SmNode *pLeft  = GetSubNode(0),
1098
0
           *pRight = GetSubNode(1),
1099
0
           *pLine  = GetSubNode(2);
1100
0
    assert(pLeft);
1101
0
    assert(pRight);
1102
0
    assert(pLine && pLine->GetType() == SmNodeType::PolyLine);
1103
1104
0
    SmPolyLineNode *pOper = static_cast<SmPolyLineNode *>(pLine);
1105
0
    assert(pOper);
1106
1107
    //! some routines being called extract some info from the OutputDevice's
1108
    //! font (eg the space to be used for borders OR the font name(!!)).
1109
    //! Thus the font should reflect the needs and has to be set!
1110
0
    SmTmpDevice aTmpDev (rDev, true);
1111
0
    aTmpDev.SetFont(GetFont());
1112
1113
0
    pLeft->Arrange(aTmpDev, rFormat);
1114
0
    pRight->Arrange(aTmpDev, rFormat);
1115
1116
    // determine implicitly the values (incl. the margin) of the diagonal line
1117
0
    pOper->Arrange(aTmpDev, rFormat);
1118
1119
0
    tools::Long nDelta = pOper->GetWidth() * 8 / 10;
1120
1121
    // determine TopLeft position from the right argument
1122
0
    Point aPos;
1123
0
    aPos.setX( pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace() );
1124
0
    if (IsAscending())
1125
0
        aPos.setY( pLeft->GetBottom() + nDelta );
1126
0
    else
1127
0
        aPos.setY( pLeft->GetTop() - nDelta - pRight->GetHeight() );
1128
1129
0
    pRight->MoveTo(aPos);
1130
1131
    // determine new baseline
1132
0
    tools::Long nTmpBaseline = IsAscending() ? (pLeft->GetBottom() + pRight->GetTop()) / 2
1133
0
                        : (pLeft->GetTop() + pRight->GetBottom()) / 2;
1134
0
    Point  aLogCenter ((pLeft->GetItalicRight() + pRight->GetItalicLeft()) / 2,
1135
0
                       nTmpBaseline);
1136
1137
0
    SmRect::operator = (*pLeft);
1138
0
    ExtendBy(*pRight, RectCopyMBL::None);
1139
1140
1141
    // determine position and size of diagonal line
1142
0
    Size  aTmpSize;
1143
0
    GetOperPosSize(aPos, aTmpSize, aLogCenter, IsAscending() ? 60.0 : -60.0);
1144
1145
    // font specialist advised to change the width first
1146
0
    pOper->AdaptToY(aTmpDev, aTmpSize.Height());
1147
0
    pOper->AdaptToX(aTmpDev, aTmpSize.Width());
1148
    // and make it active
1149
0
    pOper->Arrange(aTmpDev, rFormat);
1150
1151
0
    pOper->MoveTo(aPos);
1152
1153
0
    ExtendBy(*pOper, RectCopyMBL::None, nTmpBaseline);
1154
0
}
1155
1156
1157
/**************************************************************************/
1158
1159
1160
void SmSubSupNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1161
78.1k
{
1162
78.1k
    OSL_ENSURE(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES,
1163
78.1k
               "Sm: wrong number of subnodes");
1164
1165
78.1k
    SmNode *pBody = GetBody();
1166
78.1k
    assert(pBody);
1167
1168
78.1k
    tools::Long  nOrigHeight = pBody->GetFont().GetFontSize().Height();
1169
1170
78.1k
    pBody->Arrange(rDev, rFormat);
1171
1172
78.1k
    const SmRect &rBodyRect = pBody->GetRect();
1173
78.1k
    SmRect::operator = (rBodyRect);
1174
1175
    // line that separates sub- and supscript rectangles
1176
78.1k
    tools::Long  nDelimLine = SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1177
1178
78.1k
    Point  aPos;
1179
78.1k
    tools::Long   nDelta, nDist;
1180
1181
    // iterate over all possible sub-/supscripts
1182
78.1k
    SmRect  aTmpRect (rBodyRect);
1183
547k
    for (int i = 0;  i < SUBSUP_NUM_ENTRIES;  i++)
1184
469k
    {
1185
469k
        SmSubSup eSubSup = static_cast<SmSubSup>(i);
1186
469k
        SmNode *pSubSup = GetSubSup(eSubSup);
1187
1188
469k
        if (!pSubSup)
1189
390k
            continue;
1190
1191
        // switch position of limits if we are in textmode
1192
78.2k
        if (rFormat.IsTextmode()  &&  (GetToken().nGroup & TG::Limit))
1193
0
            switch (eSubSup)
1194
0
            {   case CSUB:  eSubSup = RSUB;     break;
1195
0
                case CSUP:  eSubSup = RSUP;     break;
1196
0
                default:
1197
0
                    break;
1198
0
            }
1199
1200
        // prevent sub-/supscripts from diminishing in size
1201
        // (as would be in "a_{1_{2_{3_4}}}")
1202
78.2k
        if (GetFont().GetFontSize().Height() > rFormat.GetBaseSize().Height() / 3)
1203
55.1k
        {
1204
55.1k
            sal_uInt16 nIndex = (eSubSup == CSUB  ||  eSubSup == CSUP) ?
1205
54.3k
                                    SIZ_LIMITS : SIZ_INDEX;
1206
55.1k
            Fraction  aFraction ( rFormat.GetRelSize(nIndex), 100 );
1207
55.1k
            pSubSup->SetSize(aFraction);
1208
55.1k
        }
1209
1210
78.2k
        pSubSup->Arrange(rDev, rFormat);
1211
1212
78.2k
        bool  bIsTextmode = rFormat.IsTextmode();
1213
78.2k
        nDist = 0;
1214
1215
        //! be sure that CSUB, CSUP are handled before the other cases!
1216
78.2k
        switch (eSubSup)
1217
78.2k
        {   case RSUB :
1218
29.5k
            case LSUB :
1219
29.5k
                if (!bIsTextmode)
1220
29.5k
                    nDist = nOrigHeight
1221
29.5k
                            * rFormat.GetDistance(DIS_SUBSCRIPT) / 100;
1222
29.5k
                aPos  = pSubSup->GetRect().AlignTo(aTmpRect,
1223
29.5k
                                eSubSup == LSUB ? RectPos::Left : RectPos::Right,
1224
29.5k
                                RectHorAlign::Center, RectVerAlign::Bottom);
1225
29.5k
                aPos.AdjustY(nDist );
1226
29.5k
                nDelta = nDelimLine - aPos.Y();
1227
29.5k
                if (nDelta > 0)
1228
10.5k
                    aPos.AdjustY(nDelta );
1229
29.5k
                break;
1230
47.9k
            case RSUP :
1231
47.9k
            case LSUP :
1232
47.9k
                if (!bIsTextmode)
1233
47.9k
                    nDist = nOrigHeight
1234
47.9k
                            * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100;
1235
47.9k
                aPos  = pSubSup->GetRect().AlignTo(aTmpRect,
1236
47.9k
                                eSubSup == LSUP ? RectPos::Left : RectPos::Right,
1237
47.9k
                                RectHorAlign::Center, RectVerAlign::Top);
1238
47.9k
                aPos.AdjustY( -nDist );
1239
47.9k
                nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
1240
47.9k
                if (nDelta > 0)
1241
28.5k
                    aPos.AdjustY( -nDelta );
1242
47.9k
                break;
1243
272
            case CSUB :
1244
272
                if (!bIsTextmode)
1245
272
                    nDist = nOrigHeight
1246
272
                            * rFormat.GetDistance(DIS_LOWERLIMIT) / 100;
1247
272
                aPos = pSubSup->GetRect().AlignTo(rBodyRect, RectPos::Bottom,
1248
272
                                RectHorAlign::Center, RectVerAlign::Baseline);
1249
272
                aPos.AdjustY(nDist );
1250
272
                break;
1251
512
            case CSUP :
1252
512
                if (!bIsTextmode)
1253
512
                    nDist = nOrigHeight
1254
512
                            * rFormat.GetDistance(DIS_UPPERLIMIT) / 100;
1255
512
                aPos = pSubSup->GetRect().AlignTo(rBodyRect, RectPos::Top,
1256
512
                                RectHorAlign::Center, RectVerAlign::Baseline);
1257
512
                aPos.AdjustY( -nDist );
1258
512
                break;
1259
78.2k
        }
1260
1261
78.2k
        pSubSup->MoveTo(aPos);
1262
78.2k
        ExtendBy(*pSubSup, RectCopyMBL::This, true);
1263
1264
        // update rectangle to which  RSUB, RSUP, LSUB, LSUP
1265
        // will be aligned to
1266
78.2k
        if (eSubSup == CSUB  ||  eSubSup == CSUP)
1267
784
            aTmpRect = *this;
1268
78.2k
    }
1269
78.1k
}
1270
1271
/**************************************************************************/
1272
1273
void SmBraceNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1274
21.4k
{
1275
21.4k
    SmNode *pLeft  = OpeningBrace(),
1276
21.4k
           *pBody  = Body(),
1277
21.4k
           *pRight = ClosingBrace();
1278
21.4k
    assert(pLeft);
1279
21.4k
    assert(pBody);
1280
21.4k
    assert(pRight);
1281
1282
21.4k
    pBody->Arrange(rDev, rFormat);
1283
1284
21.4k
    bool  bIsScaleNormal = rFormat.IsScaleNormalBrackets(),
1285
21.4k
          bScale         = pBody->GetHeight() > 0  &&
1286
19.6k
                           (GetScaleMode() == SmScaleMode::Height  ||  bIsScaleNormal),
1287
21.4k
          bIsABS         = GetToken().eType == TABS;
1288
1289
21.4k
    tools::Long  nFaceHeight = GetFont().GetFontSize().Height();
1290
1291
    // determine oversize in %
1292
21.4k
    sal_uInt16  nPerc = 0;
1293
21.4k
    if (!bIsABS && bScale)
1294
110
    {   // in case of oversize braces...
1295
110
        sal_uInt16 nIndex = GetScaleMode() == SmScaleMode::Height ?
1296
110
                            DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1297
110
        nPerc = rFormat.GetDistance(nIndex);
1298
110
    }
1299
1300
    // determine the height for the braces
1301
21.4k
    tools::Long  nBraceHeight;
1302
21.4k
    if (bScale)
1303
1.60k
    {
1304
1.60k
        nBraceHeight = pBody->GetType() == SmNodeType::Bracebody ?
1305
110
                              static_cast<SmBracebodyNode *>(pBody)->GetBodyHeight()
1306
1.60k
                            : pBody->GetHeight();
1307
1.60k
        nBraceHeight += 2 * (nBraceHeight * nPerc / 100);
1308
1.60k
    }
1309
19.8k
    else
1310
19.8k
        nBraceHeight = nFaceHeight;
1311
1312
    // distance to the argument
1313
21.4k
    nPerc = bIsABS ? 0 : rFormat.GetDistance(DIS_BRACKETSPACE);
1314
21.4k
    tools::Long  nDist = nFaceHeight * nPerc / 100;
1315
1316
    // if wanted, scale the braces to the wanted size
1317
21.4k
    if (bScale)
1318
1.60k
    {
1319
1.60k
        Size  aTmpSize (pLeft->GetFont().GetFontSize());
1320
1.60k
        OSL_ENSURE(pRight->GetFont().GetFontSize() == aTmpSize,
1321
1.60k
                    "Sm : different font sizes");
1322
1.60k
        aTmpSize.setWidth( std::min(nBraceHeight * 60 / 100,
1323
1.60k
                            rFormat.GetBaseSize().Height() * 3 / 2) );
1324
        // correction factor since change from StarMath to OpenSymbol font
1325
        // because of the different font width in the FontMetric
1326
1.60k
        aTmpSize.setWidth( aTmpSize.Width() * 182 );
1327
1.60k
        aTmpSize.setWidth( aTmpSize.Width() / 267 );
1328
1329
1.60k
        sal_Unicode cChar = pLeft->GetToken().cMathChar[0];
1330
1.60k
        if (cChar != MS_LINE  &&  cChar != MS_DLINE &&
1331
1.60k
            cChar != MS_VERTLINE  &&  cChar != MS_DVERTLINE)
1332
110
            pLeft ->GetFont().SetSize(aTmpSize);
1333
1334
1.60k
        cChar = pRight->GetToken().cMathChar[0];
1335
1.60k
        if (cChar != MS_LINE  &&  cChar != MS_DLINE &&
1336
1.60k
            cChar != MS_VERTLINE  &&  cChar != MS_DVERTLINE)
1337
110
            pRight->GetFont().SetSize(aTmpSize);
1338
1339
1.60k
        pLeft ->AdaptToY(rDev, nBraceHeight);
1340
1.60k
        pRight->AdaptToY(rDev, nBraceHeight);
1341
1.60k
    }
1342
1343
21.4k
    pLeft ->Arrange(rDev, rFormat);
1344
21.4k
    pRight->Arrange(rDev, rFormat);
1345
1346
    // required in order to make "\(a\) - (a) - left ( a right )" look alright
1347
21.4k
    RectVerAlign  eVerAlign = bScale ? RectVerAlign::CenterY : RectVerAlign::Baseline;
1348
1349
21.4k
    Point         aPos;
1350
21.4k
    aPos = pLeft->AlignTo(*pBody, RectPos::Left, RectHorAlign::Center, eVerAlign);
1351
21.4k
    aPos.AdjustX( -nDist );
1352
21.4k
    pLeft->MoveTo(aPos);
1353
1354
21.4k
    aPos = pRight->AlignTo(*pBody, RectPos::Right, RectHorAlign::Center, eVerAlign);
1355
21.4k
    aPos.AdjustX(nDist );
1356
21.4k
    pRight->MoveTo(aPos);
1357
1358
21.4k
    SmRect::operator = (*pBody);
1359
21.4k
    ExtendBy(*pLeft, RectCopyMBL::This).ExtendBy(*pRight, RectCopyMBL::This);
1360
21.4k
}
1361
1362
1363
/**************************************************************************/
1364
1365
1366
void SmBracebodyNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1367
19.9k
{
1368
19.9k
    size_t nNumSubNodes = GetNumSubNodes();
1369
19.9k
    if (nNumSubNodes == 0)
1370
1.75k
        return;
1371
1372
    // arrange arguments
1373
40.5k
    for (size_t i = 0;  i < nNumSubNodes; i += 2)
1374
22.4k
        GetSubNode(i)->Arrange(rDev, rFormat);
1375
1376
    // build reference rectangle with necessary info for vertical alignment
1377
18.1k
    SmRect  aRefRect (*GetSubNode(0));
1378
40.5k
    for (size_t i = 0;  i < nNumSubNodes; i += 2)
1379
22.4k
    {
1380
22.4k
        SmRect aTmpRect (*GetSubNode(i));
1381
22.4k
        Point  aPos = aTmpRect.AlignTo(aRefRect, RectPos::Right, RectHorAlign::Center, RectVerAlign::Baseline);
1382
22.4k
        aTmpRect.MoveTo(aPos);
1383
22.4k
        aRefRect.ExtendBy(aTmpRect, RectCopyMBL::Xor);
1384
22.4k
    }
1385
1386
18.1k
    mnBodyHeight = aRefRect.GetHeight();
1387
1388
    // scale separators to required height and arrange them
1389
18.1k
    bool bScale  = GetScaleMode() == SmScaleMode::Height  ||  rFormat.IsScaleNormalBrackets();
1390
18.1k
    tools::Long nHeight = bScale ? aRefRect.GetHeight() : GetFont().GetFontSize().Height();
1391
18.1k
    sal_uInt16 nIndex  = GetScaleMode() == SmScaleMode::Height ?
1392
18.0k
                        DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1393
18.1k
    sal_uInt16 nPerc   = rFormat.GetDistance(nIndex);
1394
18.1k
    if (bScale)
1395
110
        nHeight += 2 * (nHeight * nPerc / 100);
1396
22.4k
    for (size_t i = 1; i < nNumSubNodes; i += 2)
1397
4.30k
    {
1398
4.30k
        SmNode *pNode = GetSubNode(i);
1399
4.30k
        pNode->AdaptToY(rDev, nHeight);
1400
4.30k
        pNode->Arrange(rDev, rFormat);
1401
4.30k
    }
1402
1403
    // horizontal distance between argument and brackets or separators
1404
18.1k
    tools::Long  nDist = GetFont().GetFontSize().Height()
1405
18.1k
                  * rFormat.GetDistance(DIS_BRACKETSPACE) / 100;
1406
1407
18.1k
    SmNode *pLeft = GetSubNode(0);
1408
18.1k
    SmRect::operator = (*pLeft);
1409
26.7k
    for (size_t i = 1; i < nNumSubNodes; ++i)
1410
8.54k
    {
1411
8.54k
        bool          bIsSeparator = i % 2 != 0;
1412
8.54k
        RectVerAlign  eVerAlign    = bIsSeparator ? RectVerAlign::CenterY : RectVerAlign::Baseline;
1413
1414
8.54k
        SmNode *pRight = GetSubNode(i);
1415
8.54k
        Point  aPosX = pRight->AlignTo(*pLeft,   RectPos::Right, RectHorAlign::Center, eVerAlign),
1416
8.54k
               aPosY = pRight->AlignTo(aRefRect, RectPos::Right, RectHorAlign::Center, eVerAlign);
1417
8.54k
        aPosX.AdjustX(nDist );
1418
1419
8.54k
        pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
1420
8.54k
        ExtendBy(*pRight, bIsSeparator ? RectCopyMBL::This : RectCopyMBL::Xor);
1421
1422
8.54k
        pLeft = pRight;
1423
8.54k
    }
1424
18.1k
}
1425
1426
1427
/**************************************************************************/
1428
1429
1430
void SmVerticalBraceNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1431
0
{
1432
0
    SmNode *pBody   = Body(),
1433
0
           *pBrace  = Brace(),
1434
0
           *pScript = Script();
1435
0
    assert(pBody);
1436
0
    assert(pBrace);
1437
0
    assert(pScript);
1438
1439
0
    SmTmpDevice aTmpDev (rDev, true);
1440
0
    aTmpDev.SetFont(GetFont());
1441
1442
0
    pBody->Arrange(aTmpDev, rFormat);
1443
1444
    // size is the same as for limits for this part
1445
0
    pScript->SetSize( Fraction( rFormat.GetRelSize(SIZ_LIMITS), 100 ) );
1446
    // braces are a bit taller than usually
1447
0
    pBrace ->SetSize( Fraction(3, 2) );
1448
1449
0
    tools::Long  nItalicWidth = pBody->GetItalicWidth();
1450
0
    if (nItalicWidth > 0)
1451
0
        pBrace->AdaptToX(aTmpDev, nItalicWidth);
1452
1453
0
    pBrace ->Arrange(aTmpDev, rFormat);
1454
0
    pScript->Arrange(aTmpDev, rFormat);
1455
1456
    // determine the relative position and the distances between each other
1457
0
    RectPos  eRectPos;
1458
0
    tools::Long nFontHeight = pBody->GetFont().GetFontSize().Height();
1459
0
    tools::Long nDistBody   = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
1460
0
         nDistScript = nFontHeight;
1461
0
    if (GetToken().eType == TOVERBRACE)
1462
0
    {
1463
0
        eRectPos = RectPos::Top;
1464
0
        nDistBody    = - nDistBody;
1465
0
        nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
1466
0
    }
1467
0
    else // TUNDERBRACE
1468
0
    {
1469
0
        eRectPos = RectPos::Bottom;
1470
0
        nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
1471
0
    }
1472
0
    nDistBody   /= 100;
1473
0
    nDistScript /= 100;
1474
1475
0
    Point  aPos = pBrace->AlignTo(*pBody, eRectPos, RectHorAlign::Center, RectVerAlign::Baseline);
1476
0
    aPos.AdjustY(nDistBody );
1477
0
    pBrace->MoveTo(aPos);
1478
1479
0
    aPos = pScript->AlignTo(*pBrace, eRectPos, RectHorAlign::Center, RectVerAlign::Baseline);
1480
0
    aPos.AdjustY(nDistScript );
1481
0
    pScript->MoveTo(aPos);
1482
1483
0
    SmRect::operator = (*pBody);
1484
0
    ExtendBy(*pBrace, RectCopyMBL::This).ExtendBy(*pScript, RectCopyMBL::This);
1485
0
}
1486
1487
1488
/**************************************************************************/
1489
1490
1491
SmNode * SmOperNode::GetSymbol()
1492
11.5k
{
1493
11.5k
    SmNode *pNode = GetSubNode(0);
1494
11.5k
    assert(pNode);
1495
1496
11.5k
    if (pNode->GetType() == SmNodeType::SubSup)
1497
3.69k
        pNode = static_cast<SmSubSupNode *>(pNode)->GetBody();
1498
1499
11.5k
    OSL_ENSURE(pNode, "Sm: NULL pointer!");
1500
11.5k
    return pNode;
1501
11.5k
}
1502
1503
1504
tools::Long SmOperNode::CalcSymbolHeight(const SmNode &rSymbol,
1505
                                  const SmFormat &rFormat) const
1506
    // returns the font height to be used for operator-symbol
1507
11.5k
{
1508
11.5k
    tools::Long  nHeight = GetFont().GetFontSize().Height();
1509
1510
11.5k
    SmTokenType  eTmpType = GetToken().eType;
1511
11.5k
    if (eTmpType == TLIM  ||  eTmpType == TLIMINF  ||  eTmpType == TLIMSUP)
1512
5.70k
        return nHeight;
1513
1514
5.80k
    if (!rFormat.IsTextmode())
1515
5.80k
    {
1516
        // set minimum size ()
1517
5.80k
        nHeight += (nHeight * 20) / 100;
1518
1519
5.80k
        nHeight += nHeight
1520
5.80k
                   * rFormat.GetDistance(DIS_OPERATORSIZE) / 100;
1521
5.80k
        nHeight = nHeight * 686 / 845;
1522
5.80k
    }
1523
1524
    // correct user-defined symbols to match height of sum from used font
1525
5.80k
    if (rSymbol.GetToken().eType == TSPECIAL)
1526
0
        nHeight = nHeight * 845 / 686;
1527
1528
5.80k
    return nHeight;
1529
11.5k
}
1530
1531
1532
void SmOperNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1533
11.5k
{
1534
11.5k
    SmNode *pOper = GetSubNode(0);
1535
11.5k
    SmNode *pBody = GetSubNode(1);
1536
1537
11.5k
    assert(pOper);
1538
11.5k
    assert(pBody);
1539
1540
11.5k
    SmNode *pSymbol = GetSymbol();
1541
11.5k
    pSymbol->SetSize(Fraction(CalcSymbolHeight(*pSymbol, rFormat),
1542
11.5k
                              pSymbol->GetFont().GetFontSize().Height()));
1543
1544
11.5k
    pBody->Arrange(rDev, rFormat);
1545
11.5k
    bool bDynamicallySized = false;
1546
11.5k
    if (pSymbol->GetToken().eType == TINTD)
1547
7
    {
1548
7
        tools::Long nBodyHeight = pBody->GetHeight();
1549
7
        tools::Long nFontHeight = pSymbol->GetFont().GetFontSize().Height();
1550
7
        if (nFontHeight < nBodyHeight)
1551
0
        {
1552
0
            pSymbol->SetSize(Fraction(nBodyHeight, nFontHeight));
1553
0
            bDynamicallySized = true;
1554
0
        }
1555
7
    }
1556
11.5k
    pOper->Arrange(rDev, rFormat);
1557
1558
11.5k
    tools::Long  nOrigHeight = GetFont().GetFontSize().Height(),
1559
11.5k
          nDist = nOrigHeight
1560
11.5k
                  * rFormat.GetDistance(DIS_OPERATORSPACE) / 100;
1561
1562
11.5k
    Point aPos = pOper->AlignTo(*pBody, RectPos::Left, RectHorAlign::Center, bDynamicallySized ? RectVerAlign::CenterY : RectVerAlign::Mid);
1563
11.5k
    aPos.AdjustX( -nDist );
1564
11.5k
    pOper->MoveTo(aPos);
1565
1566
11.5k
    SmRect::operator = (*pBody);
1567
11.5k
    ExtendBy(*pOper, RectCopyMBL::This);
1568
11.5k
}
1569
1570
1571
/**************************************************************************/
1572
1573
1574
void SmAlignNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1575
    // set alignment within the entire subtree (including current node)
1576
176
{
1577
176
    assert(GetNumSubNodes() == 1);
1578
1579
176
    SmNode  *pNode = GetSubNode(0);
1580
176
    assert(pNode);
1581
1582
176
    RectHorAlign  eHorAlign = RectHorAlign::Center;
1583
176
    switch (GetToken().eType)
1584
176
    {
1585
170
        case TALIGNL:   eHorAlign = RectHorAlign::Left;   break;
1586
1
        case TALIGNC:   eHorAlign = RectHorAlign::Center; break;
1587
5
        case TALIGNR:   eHorAlign = RectHorAlign::Right;  break;
1588
0
        default:
1589
0
            break;
1590
176
    }
1591
176
    SetRectHorAlign(eHorAlign);
1592
1593
176
    pNode->Arrange(rDev, rFormat);
1594
1595
176
    SmRect::operator = (pNode->GetRect());
1596
176
}
1597
1598
1599
/**************************************************************************/
1600
1601
1602
void SmAttributeNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1603
3.55k
{
1604
3.55k
    SmNode *pAttr = Attribute(),
1605
3.55k
           *pBody = Body();
1606
3.55k
    assert(pBody);
1607
3.55k
    assert(pAttr);
1608
1609
3.55k
    pBody->Arrange(rDev, rFormat);
1610
1611
3.55k
    if (GetScaleMode() == SmScaleMode::Width)
1612
962
        pAttr->AdaptToX(rDev, pBody->GetItalicWidth());
1613
3.55k
    pAttr->Arrange(rDev, rFormat);
1614
1615
    // get relative position of attribute
1616
3.55k
    RectVerAlign  eVerAlign;
1617
3.55k
    tools::Long          nDist = 0;
1618
3.55k
    switch (GetToken().eType)
1619
3.55k
    {   case TUNDERLINE :
1620
911
            eVerAlign = RectVerAlign::AttributeLo;
1621
911
            break;
1622
0
        case TOVERSTRIKE :
1623
0
            eVerAlign = RectVerAlign::AttributeMid;
1624
0
            break;
1625
2.64k
        default :
1626
2.64k
            eVerAlign = RectVerAlign::AttributeHi;
1627
2.64k
            if (pBody->GetType() == SmNodeType::Attribute)
1628
0
                nDist = GetFont().GetFontSize().Height()
1629
0
                        * rFormat.GetDistance(DIS_ORNAMENTSPACE) / 100;
1630
3.55k
    }
1631
3.55k
    Point  aPos = pAttr->AlignTo(*pBody, RectPos::Attribute, RectHorAlign::Center, eVerAlign);
1632
3.55k
    aPos.AdjustY( -nDist );
1633
3.55k
    pAttr->MoveTo(aPos);
1634
1635
3.55k
    SmRect::operator = (*pBody);
1636
3.55k
    ExtendBy(*pAttr, RectCopyMBL::This, true);
1637
3.55k
}
1638
1639
void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
1640
26.8k
{
1641
    //! prepare subnodes first
1642
26.8k
    SmNode::Prepare(rFormat, rDocShell, nDepth);
1643
1644
26.8k
    int  nFnt = -1;
1645
26.8k
    switch (GetToken().eType)
1646
26.8k
    {
1647
0
        case TFIXED:    nFnt = FNT_FIXED;   break;
1648
0
        case TSANS:     nFnt = FNT_SANS;    break;
1649
0
        case TSERIF:    nFnt = FNT_SERIF;   break;
1650
26.8k
        default:
1651
26.8k
            break;
1652
26.8k
    }
1653
26.8k
    if (nFnt != -1)
1654
0
    {   GetFont() = rFormat.GetFont( sal::static_int_cast< sal_uInt16 >(nFnt) );
1655
0
        SetFont(GetFont());
1656
0
    }
1657
1658
    //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
1659
    //! other font nodes (those with lower depth in the tree)
1660
26.8k
    Flags() |= FontChangeMask::Face;
1661
26.8k
}
1662
1663
void SmFontNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1664
26.8k
{
1665
26.8k
    SmNode *pNode = GetSubNode(1);
1666
26.8k
    assert(pNode);
1667
26.8k
    sal_uInt32 nc;
1668
1669
26.8k
    switch (GetToken().eType)
1670
26.8k
    {   case TSIZE :
1671
14.2k
            pNode->SetFontSize(maFontSize, meSizeType);
1672
14.2k
            break;
1673
0
        case TSANS :
1674
0
        case TSERIF :
1675
0
        case TFIXED :
1676
0
            pNode->SetFont(GetFont());
1677
0
            break;
1678
0
        case TUNKNOWN : break;  // no assertion on "font <?> <?>"
1679
1680
48
        case TPHANTOM : SetPhantom(true);               break;
1681
570
        case TBOLD :    SetAttribute(FontAttribute::Bold);     break;
1682
1.18k
        case TITALIC :  SetAttribute(FontAttribute::Italic);   break;
1683
0
        case TNBOLD :   ClearAttribute(FontAttribute::Bold);   break;
1684
9.39k
        case TNITALIC : ClearAttribute(FontAttribute::Italic); break;
1685
1686
        // Using HTML CSS Level 1 standard
1687
0
        case TRGB :
1688
0
        case TRGBA :
1689
0
        case THTMLCOL :
1690
0
        case TMATHMLCOL :
1691
0
        case TDVIPSNAMESCOL:
1692
532
        case TICONICCOL :
1693
1.43k
        case THEX :
1694
1.43k
            nc = GetToken().cMathChar.toUInt32(16);
1695
1.43k
            SetColor(Color(ColorTransparency, nc));
1696
1.43k
            break;
1697
1698
0
        default:
1699
0
            SAL_WARN("starmath", "unknown case");
1700
26.8k
    }
1701
1702
26.8k
    pNode->Arrange(rDev, rFormat);
1703
1704
26.8k
    SmRect::operator = (pNode->GetRect());
1705
26.8k
}
1706
1707
/**************************************************************************/
1708
1709
1710
SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
1711
0
    : SmGraphicNode(SmNodeType::PolyLine, rNodeToken)
1712
0
    , maPoly(2)
1713
0
    , mnWidth(0)
1714
0
{
1715
0
}
1716
1717
1718
void SmPolyLineNode::AdaptToX(OutputDevice &/*rDev*/, tools::Long nNewWidth)
1719
0
{
1720
0
    maToSize.setWidth( nNewWidth );
1721
0
}
1722
1723
1724
void SmPolyLineNode::AdaptToY(OutputDevice &/*rDev*/, tools::Long nNewHeight)
1725
0
{
1726
0
    GetFont().FreezeBorderWidth();
1727
0
    maToSize.setHeight( nNewHeight );
1728
0
}
1729
1730
1731
void SmPolyLineNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1732
0
{
1733
    //! some routines being called extract some info from the OutputDevice's
1734
    //! font (eg the space to be used for borders OR the font name(!!)).
1735
    //! Thus the font should reflect the needs and has to be set!
1736
0
    SmTmpDevice aTmpDev (rDev, true);
1737
0
    aTmpDev.SetFont(GetFont());
1738
1739
0
    tools::Long  nBorderwidth = GetFont().GetBorderWidth();
1740
1741
    // create polygon using both endpoints
1742
0
    assert(maPoly.GetSize() == 2);
1743
0
    Point  aPointA, aPointB;
1744
0
    if (GetToken().eType == TWIDESLASH)
1745
0
    {
1746
0
        aPointA.setX( nBorderwidth );
1747
0
        aPointA.setY( maToSize.Height() - nBorderwidth );
1748
0
        aPointB.setX( maToSize.Width() - nBorderwidth );
1749
0
        aPointB.setY( nBorderwidth );
1750
0
    }
1751
0
    else
1752
0
    {
1753
0
        OSL_ENSURE(GetToken().eType == TWIDEBACKSLASH, "Sm : unexpected token");
1754
0
        aPointA.setX( nBorderwidth );
1755
0
        aPointA.setY( nBorderwidth );
1756
0
        aPointB.setX( maToSize.Width() - nBorderwidth );
1757
0
        aPointB.setY( maToSize.Height() - nBorderwidth );
1758
0
    }
1759
0
    maPoly.SetPoint(aPointA, 0);
1760
0
    maPoly.SetPoint(aPointB, 1);
1761
1762
0
    tools::Long  nThick       = GetFont().GetFontSize().Height()
1763
0
                            * rFormat.GetDistance(DIS_STROKEWIDTH) / 100;
1764
0
    mnWidth = nThick + 2 * nBorderwidth;
1765
1766
0
    SmRect::operator = (SmRect(maToSize.Width(), maToSize.Height()));
1767
0
}
1768
1769
1770
/**************************************************************************/
1771
1772
void SmRootSymbolNode::AdaptToX(OutputDevice &/*rDev*/, tools::Long nWidth)
1773
12.4k
{
1774
12.4k
    mnBodyWidth = nWidth;
1775
12.4k
}
1776
1777
1778
void SmRootSymbolNode::AdaptToY(OutputDevice &rDev, tools::Long nHeight)
1779
12.4k
{
1780
    // some additional length so that the horizontal
1781
    // bar will be positioned above the argument
1782
12.4k
    SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / 10);
1783
12.4k
}
1784
1785
1786
/**************************************************************************/
1787
1788
1789
void SmRectangleNode::AdaptToX(OutputDevice &/*rDev*/, tools::Long nWidth)
1790
6.38k
{
1791
6.38k
    maToSize.setWidth( nWidth );
1792
6.38k
}
1793
1794
1795
void SmRectangleNode::AdaptToY(OutputDevice &/*rDev*/, tools::Long nHeight)
1796
5.42k
{
1797
5.42k
    GetFont().FreezeBorderWidth();
1798
5.42k
    maToSize.setHeight( nHeight );
1799
5.42k
}
1800
1801
1802
void SmRectangleNode::Arrange(OutputDevice &rDev, const SmFormat &/*rFormat*/)
1803
6.38k
{
1804
6.38k
    tools::Long  nFontHeight = GetFont().GetFontSize().Height();
1805
6.38k
    tools::Long  nWidth  = maToSize.Width(),
1806
6.38k
          nHeight = maToSize.Height();
1807
6.38k
    if (nHeight == 0)
1808
962
        nHeight = nFontHeight / 30;
1809
6.38k
    if (nWidth == 0)
1810
0
        nWidth  = nFontHeight / 3;
1811
1812
6.38k
    SmTmpDevice aTmpDev (rDev, true);
1813
6.38k
    aTmpDev.SetFont(GetFont());
1814
1815
    // add some borderspace
1816
6.38k
    tools::Long  nTmpBorderWidth = GetFont().GetBorderWidth();
1817
6.38k
    nHeight += 2 * nTmpBorderWidth;
1818
1819
    //! use this method in order to have 'SmRect::HasAlignInfo() == true'
1820
    //! and thus having the attribute-fences updated in 'SmRect::ExtendBy'
1821
6.38k
    SmRect::operator = (SmRect(nWidth, nHeight));
1822
6.38k
}
1823
1824
1825
/**************************************************************************/
1826
1827
1828
SmTextNode::SmTextNode( SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 nFontDescP )
1829
4.78M
    : SmVisibleNode(eNodeType, rNodeToken)
1830
4.78M
    , mnFontDesc(nFontDescP)
1831
4.78M
    , mnSelectionStart(0)
1832
4.78M
    , mnSelectionEnd(0)
1833
4.78M
{
1834
4.78M
}
1835
1836
SmTextNode::SmTextNode( const SmToken &rNodeToken, sal_uInt16 nFontDescP )
1837
5.25M
    : SmVisibleNode(SmNodeType::Text, rNodeToken)
1838
5.25M
    , mnFontDesc(nFontDescP)
1839
5.25M
    , mnSelectionStart(0)
1840
5.25M
    , mnSelectionEnd(0)
1841
5.25M
{
1842
5.25M
}
1843
1844
0
void SmTextNode::ChangeText(const OUString &rText) {
1845
0
    maText = rText;
1846
0
    GetToken().aText = rText;
1847
0
    AdjustFontDesc();
1848
0
}
1849
1850
void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
1851
2.11M
{
1852
2.11M
    SmNode::Prepare(rFormat, rDocShell, nDepth);
1853
1854
    // default setting for horizontal alignment of nodes with TTEXT
1855
    // content is as alignl (cannot be done in Arrange since it would
1856
    // override the settings made by an SmAlignNode before)
1857
2.11M
    if (TTEXT == GetToken().eType)
1858
161k
        SetRectHorAlign( RectHorAlign::Left );
1859
1860
2.11M
    maText = GetToken().aText;
1861
2.11M
    GetFont() = rFormat.GetFont(GetFontDesc());
1862
1863
2.11M
    if (IsItalic( GetFont() ))
1864
0
        Attributes() |= FontAttribute::Italic;
1865
2.11M
    if (IsBold( GetFont() ))
1866
0
        Attributes() |= FontAttribute::Bold;
1867
1868
    // special handling for ':' where it is a token on its own and is likely
1869
    // to be used for mathematical notations. (E.g. a:b = 2:3)
1870
    // In that case it should not be displayed in italic.
1871
2.11M
    if (maText.getLength() == 1 && GetToken().aText[0] == ':')
1872
85.0k
        Attributes() &= ~FontAttribute::Italic;
1873
1874
    // Arabic text should not be italic, so we check for any character in Arabic script and
1875
    // remove italic attribute.
1876
2.11M
    if (!maText.isEmpty())
1877
2.10M
    {
1878
2.10M
        sal_Int32 nIndex = 0;
1879
17.8M
        while (nIndex < maText.getLength())
1880
15.7M
        {
1881
15.7M
            sal_uInt32 cChar = maText.iterateCodePoints(&nIndex);
1882
15.7M
            if (u_getIntPropertyValue(cChar, UCHAR_SCRIPT) == USCRIPT_ARABIC)
1883
3.43k
            {
1884
3.43k
                Attributes() &= ~FontAttribute::Italic;
1885
3.43k
                break;
1886
3.43k
            }
1887
15.7M
        }
1888
2.10M
    }
1889
2.11M
};
1890
1891
1892
void SmTextNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1893
2.11M
{
1894
2.11M
    PrepareAttributes();
1895
1896
2.11M
    sal_uInt16  nSizeDesc = GetFontDesc() == FNT_FUNCTION ?
1897
2.10M
                            SIZ_FUNCTION : SIZ_TEXT;
1898
2.11M
    GetFont() *= Fraction (rFormat.GetRelSize(nSizeDesc), 100);
1899
1900
2.11M
    SmTmpDevice aTmpDev (rDev, true);
1901
2.11M
    aTmpDev.SetFont(GetFont());
1902
1903
2.11M
    SmRect::operator = (SmRect(aTmpDev, &rFormat, maText, GetFont().GetBorderWidth()));
1904
2.11M
}
1905
1906
void SmTextNode::GetAccessibleText( OUStringBuffer &rText ) const
1907
0
{
1908
0
    rText.append(maText);
1909
0
}
1910
1911
void SmTextNode::AdjustFontDesc()
1912
0
{
1913
0
    if (GetToken().nGroup == TG::Function) mnFontDesc = FNT_FUNCTION;
1914
0
    else if (GetToken().eType == TTEXT) mnFontDesc = FNT_TEXT;
1915
0
    else {
1916
0
        sal_Unicode firstChar = maText[0];
1917
0
        if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',')
1918
0
            mnFontDesc = FNT_NUMBER;
1919
0
        else mnFontDesc = FNT_VARIABLE;
1920
0
    }
1921
0
}
1922
1923
sal_Unicode SmTextNode::ConvertSymbolToUnicode(sal_Unicode nIn)
1924
0
{
1925
    //Find the best match in accepted unicode for our private area symbols
1926
0
    static const sal_Unicode aStarMathPrivateToUnicode[] =
1927
0
    {
1928
0
        0x2030, 0xF613, 0xF612, 0x002B, 0x003C, 0x003E, 0xE425, 0xE421, 0xE088, 0x2208,
1929
0
        0x0192, 0x2026, 0x2192, 0x221A, 0x221A, 0x221A, 0xE090, 0x005E, 0x02C7, 0x02D8,
1930
0
        0x00B4, 0x0060, 0x02DC, 0x00AF, 0x0362, 0xE099, 0xE09A, 0x20DB, 0xE09C, 0xE09D,
1931
0
        0x0028, 0x0029, 0x2220, 0x22AF, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7,
1932
0
        0x002F, 0x005C, 0x274F, 0xE0AB, 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03A0,
1933
0
        0x03a3, 0x03a5, 0x03a6, 0x03a8, 0x03A9, 0x03B1, 0x03B2, 0x03b3, 0x03b4, 0x03b5,
1934
0
        0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
1935
0
        0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03b5,
1936
0
        0x03d1, 0x03d6, 0xE0D2, 0x03db, 0x2118, 0x2202, 0x2129, 0xE0D7, 0xE0D8, 0x22A4,
1937
0
        0xE0DA, 0x2190, 0x2191, 0x2193
1938
0
    };
1939
0
    if ((nIn >= 0xE080) && (nIn <= 0xE0DD))
1940
0
        nIn = aStarMathPrivateToUnicode[nIn-0xE080];
1941
1942
    //For whatever unicode glyph that equation editor doesn't ship with that
1943
    //we have a possible match we can munge it to.
1944
0
    switch (nIn)
1945
0
    {
1946
0
        case 0x2223:
1947
0
            nIn = '|';
1948
0
            break;
1949
0
        default:
1950
0
            break;
1951
0
    }
1952
1953
0
    return nIn;
1954
0
}
1955
1956
/**************************************************************************/
1957
1958
void SmMatrixNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
1959
1.35k
{
1960
1.35k
    SmNode *pNode;
1961
1962
    // initialize array that is to hold the maximum widths of all
1963
    // elements (subnodes) in that column.
1964
1.35k
    std::vector<tools::Long> aColWidth(mnNumCols);
1965
1966
    // arrange subnodes and calculate the above arrays contents
1967
1.35k
    size_t nNodes = GetNumSubNodes();
1968
10.6k
    for (size_t i = 0; i < nNodes; ++i)
1969
9.31k
    {
1970
9.31k
        size_t nIdx = nNodes - 1 - i;
1971
9.31k
        if (nullptr != (pNode = GetSubNode(nIdx)))
1972
9.31k
        {
1973
9.31k
            pNode->Arrange(rDev, rFormat);
1974
9.31k
            int  nCol = nIdx % mnNumCols;
1975
9.31k
            aColWidth[nCol] = std::max(aColWidth[nCol], pNode->GetItalicWidth());
1976
9.31k
        }
1977
9.31k
    }
1978
1979
    // norm distance from which the following two are calculated
1980
1.35k
    const tools::Long  nNormDist = 3 * GetFont().GetFontSize().Height();
1981
1982
    // define horizontal and vertical minimal distances that separate
1983
    // the elements
1984
1.35k
    tools::Long  nHorDist = nNormDist * rFormat.GetDistance(DIS_MATRIXCOL) / 100,
1985
1.35k
          nVerDist = nNormDist * rFormat.GetDistance(DIS_MATRIXROW) / 100;
1986
1987
    // build array that holds the leftmost position for each column
1988
1.35k
    std::vector<tools::Long> aColLeft(mnNumCols);
1989
1.35k
    tools::Long  nX = 0;
1990
3.84k
    for (size_t j = 0; j < mnNumCols; ++j)
1991
2.49k
    {
1992
2.49k
        aColLeft[j] = nX;
1993
2.49k
        nX += aColWidth[j] + nHorDist;
1994
2.49k
    }
1995
1996
1.35k
    SmRect::operator = (SmRect());
1997
6.77k
    for (size_t i = 0;  i < mnNumRows; ++i)
1998
5.41k
    {
1999
5.41k
        Point aPos;
2000
5.41k
        SmRect aLineRect;
2001
14.7k
        for (size_t j = 0;  j < mnNumCols; ++j)
2002
9.31k
        {
2003
9.31k
            SmNode *pTmpNode = GetSubNode(i * mnNumCols + j);
2004
9.31k
            assert(pTmpNode);
2005
2006
9.31k
            const SmRect &rNodeRect = pTmpNode->GetRect();
2007
2008
            // align all baselines in that row if possible
2009
9.31k
            aPos = rNodeRect.AlignTo(aLineRect, RectPos::Right, RectHorAlign::Center, RectVerAlign::Baseline);
2010
2011
            // get horizontal alignment
2012
9.31k
            const SmNode *pCoNode   = pTmpNode->GetLeftMost();
2013
9.31k
            RectHorAlign  eHorAlign = pCoNode->GetRectHorAlign();
2014
2015
            // calculate horizontal position of element depending on column
2016
            // and horizontal alignment
2017
9.31k
            switch (eHorAlign)
2018
9.31k
            {   case RectHorAlign::Left:
2019
596
                    aPos.setX( aColLeft[j] );
2020
596
                    break;
2021
8.72k
                case RectHorAlign::Center:
2022
8.72k
                    aPos.setX( rNodeRect.GetLeft() + aColLeft[j]
2023
8.72k
                               + aColWidth[j] / 2
2024
8.72k
                               - rNodeRect.GetItalicCenterX() );
2025
8.72k
                    break;
2026
0
                case RectHorAlign::Right:
2027
0
                    aPos.setX( aColLeft[j]
2028
0
                               + aColWidth[j] - rNodeRect.GetItalicWidth() );
2029
0
                    break;
2030
0
                default:
2031
0
                    assert(false);
2032
9.31k
            }
2033
2034
9.31k
            pTmpNode->MoveTo(aPos);
2035
9.31k
            aLineRect.ExtendBy(rNodeRect, RectCopyMBL::Xor);
2036
9.31k
        }
2037
2038
5.41k
        aPos = aLineRect.AlignTo(*this, RectPos::Bottom, RectHorAlign::Center, RectVerAlign::Baseline);
2039
5.41k
        if (i > 0)
2040
4.06k
            aPos.AdjustY(nVerDist );
2041
2042
        // move 'aLineRect' and rectangles in that line to final position
2043
5.41k
        Point aDelta(0, // since horizontal alignment is already done
2044
5.41k
                     aPos.Y() - aLineRect.GetTop());
2045
5.41k
        aLineRect.Move(aDelta);
2046
14.7k
        for (size_t j = 0;  j < mnNumCols; ++j)
2047
9.31k
        {
2048
9.31k
            if (nullptr != (pNode = GetSubNode(i * mnNumCols + j)))
2049
9.31k
                pNode->Move(aDelta);
2050
9.31k
        }
2051
2052
5.41k
        ExtendBy(aLineRect, RectCopyMBL::None);
2053
5.41k
    }
2054
1.35k
}
2055
2056
const SmNode * SmMatrixNode::GetLeftMost() const
2057
146
{
2058
146
    return this;
2059
146
}
2060
2061
2062
/**************************************************************************/
2063
2064
2065
SmMathSymbolNode::SmMathSymbolNode(const SmToken &rNodeToken)
2066
2.85M
:   SmSpecialNode(SmNodeType::Math, rNodeToken, FNT_MATH)
2067
2.85M
{
2068
2.85M
    SetText(GetToken().cMathChar);
2069
2.85M
}
2070
2071
void SmMathSymbolNode::AdaptToX(OutputDevice &rDev, tools::Long nWidth)
2072
0
{
2073
    // Since there is no function to do this, we try to approximate it:
2074
0
    Size  aFntSize (GetFont().GetFontSize());
2075
2076
    //! however the result is a bit better with 'nWidth' as initial font width
2077
0
    aFntSize.setWidth( nWidth );
2078
0
    GetFont().SetSize(aFntSize);
2079
2080
0
    SmTmpDevice aTmpDev (rDev, true);
2081
0
    aTmpDev.SetFont(GetFont());
2082
2083
    // get denominator of error factor for width
2084
0
    tools::Long nTmpBorderWidth = GetFont().GetBorderWidth();
2085
0
    tools::Long nDenom = SmRect(aTmpDev, nullptr, GetText(), nTmpBorderWidth).GetItalicWidth();
2086
2087
    // scale fontwidth with this error factor
2088
0
    aFntSize.setWidth( aFntSize.Width() * nWidth );
2089
0
    aFntSize.setWidth( aFntSize.Width() / ( nDenom ? nDenom : 1) );
2090
2091
0
    GetFont().SetSize(aFntSize);
2092
0
}
2093
2094
void SmMathSymbolNode::AdaptToY(OutputDevice &rDev, tools::Long nHeight)
2095
15.7k
{
2096
15.7k
    GetFont().FreezeBorderWidth();
2097
15.7k
    Size  aFntSize (GetFont().GetFontSize());
2098
2099
    // Since we only want to scale the height, we might have
2100
    // to determine the font width in order to keep it
2101
15.7k
    if (aFntSize.Width() == 0)
2102
15.4k
    {
2103
15.4k
        auto popIt = rDev.ScopedPush(vcl::PushFlags::FONT | vcl::PushFlags::MAPMODE);
2104
15.4k
        rDev.SetFont(GetFont());
2105
15.4k
        aFntSize.setWidth( rDev.GetFontMetric().GetFontSize().Width() );
2106
15.4k
    }
2107
15.7k
    OSL_ENSURE(aFntSize.Width() != 0, "Sm: ");
2108
2109
    //! however the result is a bit better with 'nHeight' as initial
2110
    //! font height
2111
15.7k
    aFntSize.setHeight( nHeight );
2112
15.7k
    GetFont().SetSize(aFntSize);
2113
2114
15.7k
    SmTmpDevice aTmpDev (rDev, true);
2115
15.7k
    aTmpDev.SetFont(GetFont());
2116
2117
    // get denominator of error factor for height
2118
15.7k
    tools::Long nTmpBorderWidth = GetFont().GetBorderWidth();
2119
15.7k
    tools::Long nDenom = 0;
2120
15.7k
    if (!GetText().isEmpty())
2121
15.7k
        nDenom = SmRect(aTmpDev, nullptr, GetText(), nTmpBorderWidth).GetHeight();
2122
2123
    // scale fontwidth with this error factor
2124
15.7k
    aFntSize.setHeight( aFntSize.Height() * nHeight );
2125
15.7k
    aFntSize.setHeight( aFntSize.Height() / ( nDenom ? nDenom : 1) );
2126
2127
15.7k
    GetFont().SetSize(aFntSize);
2128
15.7k
}
2129
2130
2131
void SmMathSymbolNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
2132
1.15M
{
2133
1.15M
    SmNode::Prepare(rFormat, rDocShell, nDepth);
2134
2135
1.15M
    GetFont() = rFormat.GetFont(GetFontDesc());
2136
    // use same font size as is used for variables
2137
1.15M
    GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetFontSize() );
2138
2139
1.15M
    OSL_ENSURE(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL  ||
2140
1.15M
               GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
2141
1.15M
        "wrong charset for character from StarMath/OpenSymbol font");
2142
2143
1.15M
    Flags() |= FontChangeMask::Face | FontChangeMask::Italic;
2144
1.15M
};
2145
2146
2147
void SmMathSymbolNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
2148
1.14M
{
2149
1.14M
    const OUString &rText = GetText();
2150
2151
1.14M
    if (rText.isEmpty() || rText[0] == '\0')
2152
6.83k
    {   SmRect::operator = (SmRect());
2153
6.83k
        return;
2154
6.83k
    }
2155
2156
1.14M
    PrepareAttributes();
2157
2158
1.14M
    GetFont() *= Fraction (rFormat.GetRelSize(SIZ_TEXT), 100);
2159
2160
1.14M
    SmTmpDevice aTmpDev (rDev, true);
2161
1.14M
    aTmpDev.SetFont(GetFont());
2162
2163
1.14M
    SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
2164
1.14M
}
2165
2166
/**************************************************************************/
2167
2168
SmSpecialNode::SmSpecialNode(SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 _nFontDesc)
2169
4.74M
    : SmTextNode(eNodeType, rNodeToken, _nFontDesc)
2170
4.74M
{
2171
4.74M
}
2172
2173
2174
SmSpecialNode::SmSpecialNode(const SmToken &rNodeToken)
2175
36.5k
    : SmTextNode(SmNodeType::Special, rNodeToken, FNT_VARIABLE)  // default Font isn't always correct!
2176
36.5k
{
2177
36.5k
}
2178
2179
2180
void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
2181
16.9k
{
2182
16.9k
    SmNode::Prepare(rFormat, rDocShell, nDepth);
2183
2184
16.9k
    const SmSym* pSym
2185
16.9k
        = GetToken().aText.isEmpty()
2186
16.9k
              ? nullptr
2187
16.9k
              : SmModule::get()->GetSymbolManager().GetSymbolByName(GetToken().aText.subView(1));
2188
2189
16.9k
    bool bIsGreekSymbol = false;
2190
16.9k
    bool bIsSpecialSymbol = false;
2191
16.9k
    bool bIsArabic = false;
2192
2193
16.9k
    if (pSym)
2194
0
    {
2195
0
        sal_UCS4 cChar = pSym->GetCharacter();
2196
0
        OUString aTmp( &cChar, 1 );
2197
0
        SetText( aTmp );
2198
0
        GetFont() = SmFace(pSym->GetFace(&rFormat));
2199
2200
0
        OUString aSymbolSetName = SmLocalizedSymbolData::GetExportSymbolSetName(pSym->GetSymbolSetName());
2201
0
        if (aSymbolSetName == "Greek")
2202
0
            bIsGreekSymbol = true;
2203
0
        else if (aSymbolSetName == "Special")
2204
0
            bIsSpecialSymbol = true;
2205
0
        else if (aSymbolSetName == "Arabic")
2206
0
            bIsArabic = true;
2207
0
    }
2208
16.9k
    else
2209
16.9k
    {
2210
16.9k
        SetText( GetToken().aText );
2211
16.9k
        GetFont() = rFormat.GetFont(FNT_VARIABLE);
2212
16.9k
    }
2213
    // use same font size as is used for variables
2214
16.9k
    GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetFontSize() );
2215
2216
    // Actually only WEIGHT_NORMAL and WEIGHT_BOLD should occur... However, the sms-file also
2217
    // contains e.g. 'WEIGHT_ULTRALIGHT'. Consequently, compare here with '>' instead of '!='.
2218
    // (In the long term the necessity for 'PrepareAttribut' and thus also for this here should be dropped)
2219
2220
    //! see also SmFontStyles::GetStyleName
2221
16.9k
    if (IsItalic( GetFont() ))
2222
0
        SetAttribute(FontAttribute::Italic);
2223
16.9k
    if (IsBold( GetFont() ))
2224
0
        SetAttribute(FontAttribute::Bold);
2225
2226
16.9k
    Flags() |= FontChangeMask::Face;
2227
2228
16.9k
    sal_uInt32 cChar = 0;
2229
16.9k
    if (!GetText().isEmpty())
2230
16.9k
    {
2231
16.9k
        sal_Int32 nIndex = 0;
2232
16.9k
        cChar = GetText().iterateCodePoints(&nIndex);
2233
16.9k
        if (!bIsArabic)
2234
16.9k
            bIsArabic = u_getIntPropertyValue(cChar, UCHAR_SCRIPT) == USCRIPT_ARABIC;
2235
16.9k
    }
2236
2237
16.9k
    if (!bIsGreekSymbol && !bIsSpecialSymbol && !bIsArabic)
2238
16.9k
        return;
2239
2240
    // Arabic and special symbols should not be italic,
2241
    // Greek is italic only in some cases.
2242
0
    bool bItalic = false;
2243
0
    if (bIsGreekSymbol)
2244
0
    {
2245
0
        sal_Int16 nStyle = rFormat.GetGreekCharStyle();
2246
0
        OSL_ENSURE( nStyle >= 0 && nStyle <= 2, "unexpected value for GreekCharStyle" );
2247
0
        if (nStyle == 1)
2248
0
            bItalic = true;
2249
0
        else if (nStyle == 2)
2250
0
        {
2251
0
            static const sal_Unicode cUppercaseAlpha = 0x0391;
2252
0
            static const sal_Unicode cUppercaseOmega = 0x03A9;
2253
            // uppercase letters should be straight and lowercase letters italic
2254
0
            bItalic = cUppercaseAlpha > cChar || cChar > cUppercaseOmega;
2255
0
        }
2256
0
    }
2257
2258
0
    if (bItalic)
2259
0
        Attributes() |= FontAttribute::Italic;
2260
0
    else
2261
0
        Attributes() &= ~FontAttribute::Italic;
2262
0
};
2263
2264
2265
void SmSpecialNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
2266
15.2k
{
2267
15.2k
    PrepareAttributes();
2268
2269
15.2k
    SmTmpDevice aTmpDev (rDev, true);
2270
15.2k
    aTmpDev.SetFont(GetFont());
2271
2272
15.2k
    SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
2273
15.2k
}
2274
2275
/**************************************************************************/
2276
2277
2278
void SmGlyphSpecialNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
2279
1.65k
{
2280
1.65k
    PrepareAttributes();
2281
2282
1.65k
    SmTmpDevice aTmpDev (rDev, true);
2283
1.65k
    aTmpDev.SetFont(GetFont());
2284
2285
1.65k
    SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(),
2286
1.65k
                               GetFont().GetBorderWidth()).AsGlyphRect());
2287
1.65k
}
2288
2289
2290
/**************************************************************************/
2291
2292
2293
void SmPlaceNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
2294
508
{
2295
508
    SmNode::Prepare(rFormat, rDocShell, nDepth);
2296
2297
508
    GetFont().SetColor(COL_GRAY);
2298
508
    Flags() |= FontChangeMask::Color | FontChangeMask::Face | FontChangeMask::Italic;
2299
508
};
2300
2301
2302
void SmPlaceNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
2303
508
{
2304
508
    PrepareAttributes();
2305
2306
508
    SmTmpDevice aTmpDev (rDev, true);
2307
508
    aTmpDev.SetFont(GetFont());
2308
2309
508
    SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
2310
508
}
2311
2312
2313
/**************************************************************************/
2314
2315
2316
void SmErrorNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
2317
707k
{
2318
707k
    SmNode::Prepare(rFormat, rDocShell, nDepth);
2319
2320
707k
    GetFont().SetColor(COL_RED);
2321
707k
    Flags() |= FontChangeMask::Phantom | FontChangeMask::Bold | FontChangeMask::Italic
2322
707k
               | FontChangeMask::Color | FontChangeMask::Face | FontChangeMask::Size;
2323
707k
}
2324
2325
2326
void SmErrorNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
2327
707k
{
2328
707k
    PrepareAttributes();
2329
2330
707k
    SmTmpDevice aTmpDev (rDev, true);
2331
707k
    aTmpDev.SetFont(GetFont());
2332
2333
707k
    const OUString &rText = GetText();
2334
707k
    SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
2335
707k
}
2336
2337
/**************************************************************************/
2338
2339
void SmBlankNode::IncreaseBy(const SmToken &rToken, sal_uInt32 nMultiplyBy)
2340
61.7k
{
2341
61.7k
    switch(rToken.eType)
2342
61.7k
    {
2343
20.8k
        case TBLANK:  mnNum += (4 * nMultiplyBy); break;
2344
40.8k
        case TSBLANK: mnNum += (1 * nMultiplyBy); break;
2345
0
        default:
2346
0
            break;
2347
61.7k
    }
2348
61.7k
}
2349
2350
void SmBlankNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell, int nDepth)
2351
16.9k
{
2352
16.9k
    SmNode::Prepare(rFormat, rDocShell, nDepth);
2353
2354
    // Here it need/should not be the StarMath font, so that for the character
2355
    // used in Arrange a normal (non-clipped) rectangle is generated
2356
16.9k
    GetFont() = rFormat.GetFont(FNT_VARIABLE);
2357
2358
16.9k
    Flags() |= FontChangeMask::Face | FontChangeMask::Bold | FontChangeMask::Italic;
2359
16.9k
}
2360
2361
2362
void SmBlankNode::Arrange(OutputDevice &rDev, const SmFormat &rFormat)
2363
16.9k
{
2364
16.9k
    SmTmpDevice aTmpDev (rDev, true);
2365
16.9k
    aTmpDev.SetFont(GetFont());
2366
2367
    // make distance depend on the font height
2368
    // (so that it increases when scaling (e.g. size *2 {a ~ b})
2369
16.9k
    tools::Long  nDist  = GetFont().GetFontSize().Height() / 10,
2370
16.9k
          nSpace = mnNum * nDist;
2371
2372
    // get a SmRect with Baseline and all the bells and whistles
2373
16.9k
    SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString(' '),
2374
16.9k
                               GetFont().GetBorderWidth()));
2375
2376
    // and resize it to the requested size
2377
16.9k
    SetItalicSpaces(0, 0);
2378
16.9k
    SetWidth(nSpace);
2379
16.9k
}
2380
2381
/**************************************************************************/
2382
//Implementation of all accept methods for SmVisitor
2383
2384
5.25k
void SmTableNode::Accept(SmVisitor* pVisitor) {
2385
5.25k
    pVisitor->Visit(this);
2386
5.25k
}
2387
2388
127
void SmBraceNode::Accept(SmVisitor* pVisitor) {
2389
127
    pVisitor->Visit(this);
2390
127
}
2391
2392
0
void SmBracebodyNode::Accept(SmVisitor* pVisitor) {
2393
0
    pVisitor->Visit(this);
2394
0
}
2395
2396
0
void SmOperNode::Accept(SmVisitor* pVisitor) {
2397
0
    pVisitor->Visit(this);
2398
0
}
2399
2400
0
void SmAlignNode::Accept(SmVisitor* pVisitor) {
2401
0
    pVisitor->Visit(this);
2402
0
}
2403
2404
68
void SmAttributeNode::Accept(SmVisitor* pVisitor) {
2405
68
    pVisitor->Visit(this);
2406
68
}
2407
2408
11.3k
void SmFontNode::Accept(SmVisitor* pVisitor) {
2409
11.3k
    pVisitor->Visit(this);
2410
11.3k
}
2411
2412
0
void SmUnHorNode::Accept(SmVisitor* pVisitor) {
2413
0
    pVisitor->Visit(this);
2414
0
}
2415
2416
0
void SmBinHorNode::Accept(SmVisitor* pVisitor) {
2417
0
    pVisitor->Visit(this);
2418
0
}
2419
2420
58
void SmBinVerNode::Accept(SmVisitor* pVisitor) {
2421
58
    pVisitor->Visit(this);
2422
58
}
2423
2424
0
void SmBinDiagonalNode::Accept(SmVisitor* pVisitor) {
2425
0
    pVisitor->Visit(this);
2426
0
}
2427
2428
1.00k
void SmSubSupNode::Accept(SmVisitor* pVisitor) {
2429
1.00k
    pVisitor->Visit(this);
2430
1.00k
}
2431
2432
227
void SmMatrixNode::Accept(SmVisitor* pVisitor) {
2433
227
    pVisitor->Visit(this);
2434
227
}
2435
2436
0
void SmPlaceNode::Accept(SmVisitor* pVisitor) {
2437
0
    pVisitor->Visit(this);
2438
0
}
2439
2440
13.0k
void SmTextNode::Accept(SmVisitor* pVisitor) {
2441
13.0k
    pVisitor->Visit(this);
2442
13.0k
}
2443
2444
0
void SmSpecialNode::Accept(SmVisitor* pVisitor) {
2445
0
    pVisitor->Visit(this);
2446
0
}
2447
2448
1
void SmGlyphSpecialNode::Accept(SmVisitor* pVisitor) {
2449
1
    pVisitor->Visit(this);
2450
1
}
2451
2452
1.69k
void SmMathSymbolNode::Accept(SmVisitor* pVisitor) {
2453
1.69k
    pVisitor->Visit(this);
2454
1.69k
}
2455
2456
158
void SmBlankNode::Accept(SmVisitor* pVisitor) {
2457
158
    pVisitor->Visit(this);
2458
158
}
2459
2460
0
void SmErrorNode::Accept(SmVisitor* pVisitor) {
2461
0
    pVisitor->Visit(this);
2462
0
}
2463
2464
5.39k
void SmLineNode::Accept(SmVisitor* pVisitor) {
2465
5.39k
    pVisitor->Visit(this);
2466
5.39k
}
2467
2468
1.89k
void SmExpressionNode::Accept(SmVisitor* pVisitor) {
2469
1.89k
    pVisitor->Visit(this);
2470
1.89k
}
2471
2472
0
void SmPolyLineNode::Accept(SmVisitor* pVisitor) {
2473
0
    pVisitor->Visit(this);
2474
0
}
2475
2476
328
void SmRootNode::Accept(SmVisitor* pVisitor) {
2477
328
    pVisitor->Visit(this);
2478
328
}
2479
2480
0
void SmRootSymbolNode::Accept(SmVisitor* pVisitor) {
2481
0
    pVisitor->Visit(this);
2482
0
}
2483
2484
0
void SmRectangleNode::Accept(SmVisitor* pVisitor) {
2485
0
    pVisitor->Visit(this);
2486
0
}
2487
2488
0
void SmVerticalBraceNode::Accept(SmVisitor* pVisitor) {
2489
0
    pVisitor->Visit(this);
2490
0
}
2491
2492
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */