Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/starmath/inc/visitors.hxx
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
10
/** Visitors are an easy way to automating operations with nodes.
11
 *
12
 * The available visitors are:
13
 * SmVisitor                                base class
14
 *      SmDefaultingVisitor                 default visitor
15
 *      SmDrawingVisitor                    draws formula
16
 *      SmCaretPosGraphBuildingVisitor      position of the node inside starmath code
17
 *      SmCloningVisitor                    duplicate nodes
18
 *      SmNodeToTextVisitor                 create code from nodes
19
 *
20
 */
21
22
#pragma once
23
24
#include <sal/config.h>
25
#include <sal/log.hxx>
26
27
#include "node.hxx"
28
#include "caret.hxx"
29
30
/** Base class for visitors that visits a tree of SmNodes
31
 * @remarks all methods have been left abstract to ensure that implementers
32
 * don't forget to implement one.
33
 */
34
class SmVisitor
35
{
36
public:
37
    virtual void Visit( SmTableNode* pNode ) = 0;
38
    virtual void Visit( SmBraceNode* pNode ) = 0;
39
    virtual void Visit( SmBracebodyNode* pNode ) = 0;
40
    virtual void Visit( SmOperNode* pNode ) = 0;
41
    virtual void Visit( SmAlignNode* pNode ) = 0;
42
    virtual void Visit( SmAttributeNode* pNode ) = 0;
43
    virtual void Visit( SmFontNode* pNode ) = 0;
44
    virtual void Visit( SmUnHorNode* pNode ) = 0;
45
    virtual void Visit( SmBinHorNode* pNode ) = 0;
46
    virtual void Visit( SmBinVerNode* pNode ) = 0;
47
    virtual void Visit( SmBinDiagonalNode* pNode ) = 0;
48
    virtual void Visit( SmSubSupNode* pNode ) = 0;
49
    virtual void Visit( SmMatrixNode* pNode ) = 0;
50
    virtual void Visit( SmPlaceNode* pNode ) = 0;
51
    virtual void Visit( SmTextNode* pNode ) = 0;
52
    virtual void Visit( SmSpecialNode* pNode ) = 0;
53
    virtual void Visit( SmGlyphSpecialNode* pNode ) = 0;
54
    virtual void Visit( SmMathSymbolNode* pNode ) = 0;
55
    virtual void Visit( SmBlankNode* pNode ) = 0;
56
    virtual void Visit( SmErrorNode* pNode ) = 0;
57
    virtual void Visit( SmLineNode* pNode ) = 0;
58
    virtual void Visit( SmExpressionNode* pNode ) = 0;
59
    virtual void Visit( SmPolyLineNode* pNode ) = 0;
60
    virtual void Visit( SmRootNode* pNode ) = 0;
61
    virtual void Visit( SmRootSymbolNode* pNode ) = 0;
62
    virtual void Visit( SmRectangleNode* pNode ) = 0;
63
    virtual void Visit( SmVerticalBraceNode* pNode ) = 0;
64
65
protected:
66
4.07k
    ~SmVisitor() {}
67
};
68
69
// SmDefaultingVisitor
70
71
72
/** Visitor that uses DefaultVisit for handling visits by default
73
 *
74
 * This abstract baseclass is useful for visitors where many methods share the same
75
 * implementation.
76
 */
77
class SmDefaultingVisitor : public SmVisitor
78
{
79
public:
80
    void Visit( SmTableNode* pNode ) override;
81
    void Visit( SmBraceNode* pNode ) override;
82
    void Visit( SmBracebodyNode* pNode ) override;
83
    void Visit( SmOperNode* pNode ) override;
84
    void Visit( SmAlignNode* pNode ) override;
85
    void Visit( SmAttributeNode* pNode ) override;
86
    void Visit( SmFontNode* pNode ) override;
87
    void Visit( SmUnHorNode* pNode ) override;
88
    void Visit( SmBinHorNode* pNode ) override;
89
    void Visit( SmBinVerNode* pNode ) override;
90
    void Visit( SmBinDiagonalNode* pNode ) override;
91
    void Visit( SmSubSupNode* pNode ) override;
92
    void Visit( SmMatrixNode* pNode ) override;
93
    void Visit( SmPlaceNode* pNode ) override;
94
    void Visit( SmTextNode* pNode ) override;
95
    void Visit( SmSpecialNode* pNode ) override;
96
    void Visit( SmGlyphSpecialNode* pNode ) override;
97
    void Visit( SmMathSymbolNode* pNode ) override;
98
    void Visit( SmBlankNode* pNode ) override;
99
    void Visit( SmErrorNode* pNode ) override;
100
    void Visit( SmLineNode* pNode ) override;
101
    void Visit( SmExpressionNode* pNode ) override;
102
    void Visit( SmPolyLineNode* pNode ) override;
103
    void Visit( SmRootNode* pNode ) override;
104
    void Visit( SmRootSymbolNode* pNode ) override;
105
    void Visit( SmRectangleNode* pNode ) override;
106
    void Visit( SmVerticalBraceNode* pNode ) override;
107
protected:
108
0
    ~SmDefaultingVisitor() {}
109
110
    /** Method invoked by Visit methods by default */
111
    virtual void DefaultVisit( SmNode* pNode ) = 0;
112
};
113
114
// SmCaretLinesVisitor: ancestor of caret rectangle enumeration and drawing visitors
115
116
class SmCaretLinesVisitor : public SmDefaultingVisitor
117
{
118
public:
119
    SmCaretLinesVisitor(OutputDevice& rDevice, SmCaretPos position, Point offset);
120
    virtual ~SmCaretLinesVisitor() = default;
121
    void Visit(SmTextNode* pNode) override;
122
    using SmDefaultingVisitor::Visit;
123
124
protected:
125
    void DoIt();
126
127
0
    OutputDevice& getDev() { return mrDev; }
128
    virtual void ProcessCaretLine(Point from, Point to) = 0;
129
    virtual void ProcessUnderline(Point from, Point to) = 0;
130
131
    /** Default method for drawing pNodes */
132
    void DefaultVisit(SmNode* pNode) override;
133
134
private:
135
    OutputDevice& mrDev;
136
    SmCaretPos maPos;
137
    /** Offset to draw from */
138
    Point  maOffset;
139
};
140
141
// SmCaretRectanglesVisitor: obtains the set of rectangles to sent to lok
142
143
class SmCaretRectanglesVisitor final : public SmCaretLinesVisitor
144
{
145
public:
146
    SmCaretRectanglesVisitor(OutputDevice& rDevice, SmCaretPos position);
147
0
    const tools::Rectangle& getCaret() const { return maCaret; }
148
149
protected:
150
    virtual void ProcessCaretLine(Point from, Point to) override;
151
    virtual void ProcessUnderline(Point from, Point to) override;
152
153
private:
154
    tools::Rectangle maCaret;
155
};
156
157
// SmCaretDrawingVisitor
158
159
/** Visitor for drawing a caret position */
160
class SmCaretDrawingVisitor final : public SmCaretLinesVisitor
161
{
162
public:
163
    /** Given position and device this constructor will draw the caret */
164
    SmCaretDrawingVisitor( OutputDevice& rDevice, SmCaretPos position, Point offset, bool caretVisible );
165
166
protected:
167
    virtual void ProcessCaretLine(Point from, Point to) override;
168
    virtual void ProcessUnderline(Point from, Point to) override;
169
170
private:
171
    bool  mbCaretVisible;
172
};
173
174
// SmCaretPos2LineVisitor
175
176
/** Visitor getting a line from a caret position */
177
class SmCaretPos2LineVisitor final : public SmDefaultingVisitor
178
{
179
public:
180
    /** Given position and device this constructor will compute a line for the caret */
181
    SmCaretPos2LineVisitor( OutputDevice *pDevice, SmCaretPos position )
182
0
        : mpDev( pDevice )
183
0
        , maPos( position )
184
0
    {
185
0
        SAL_WARN_IF( !position.IsValid(), "starmath", "Cannot draw invalid position!" );
186
187
0
        maPos.pSelectedNode->Accept( this );
188
0
    }
189
    void Visit( SmTextNode* pNode ) override;
190
    using SmDefaultingVisitor::Visit;
191
0
    const SmCaretLine& GetResult( ) const {
192
0
        return maLine;
193
0
    }
194
private:
195
    SmCaretLine maLine;
196
    VclPtr<OutputDevice> mpDev;
197
    SmCaretPos maPos;
198
199
    /** Default method for computing lines for pNodes */
200
    void DefaultVisit( SmNode* pNode ) override;
201
};
202
203
// SmDrawingVisitor
204
205
/** Visitor for drawing SmNodes to OutputDevice */
206
class SmDrawingVisitor final : public SmVisitor
207
{
208
public:
209
    /** Create an instance of SmDrawingVisitor, and use it to draw a formula
210
     * @param rDevice   Device to draw on
211
     * @param position  Offset on device to draw the formula
212
     * @param pTree     Formula tree to draw
213
     * @param rFormat   Formula formatting settings
214
     * @remarks This constructor will do the drawing, no need to anything more.
215
     */
216
    SmDrawingVisitor( OutputDevice &rDevice, Point position, SmNode* pTree, const SmFormat& rFormat )
217
0
        : mrDev( rDevice )
218
0
        , maPosition( position )
219
0
        , mrFormat( rFormat )
220
0
    {
221
0
        if (mrFormat.IsRightToLeft() && mrDev.GetOutDevType() != OUTDEV_WINDOW)
222
0
            mrDev.ReMirror(maPosition);
223
0
        pTree->Accept( this );
224
0
    }
225
    void Visit( SmTableNode* pNode ) override;
226
    void Visit( SmBraceNode* pNode ) override;
227
    void Visit( SmBracebodyNode* pNode ) override;
228
    void Visit( SmOperNode* pNode ) override;
229
    void Visit( SmAlignNode* pNode ) override;
230
    void Visit( SmAttributeNode* pNode ) override;
231
    void Visit( SmFontNode* pNode ) override;
232
    void Visit( SmUnHorNode* pNode ) override;
233
    void Visit( SmBinHorNode* pNode ) override;
234
    void Visit( SmBinVerNode* pNode ) override;
235
    void Visit( SmBinDiagonalNode* pNode ) override;
236
    void Visit( SmSubSupNode* pNode ) override;
237
    void Visit( SmMatrixNode* pNode ) override;
238
    void Visit( SmPlaceNode* pNode ) override;
239
    void Visit( SmTextNode* pNode ) override;
240
    void Visit( SmSpecialNode* pNode ) override;
241
    void Visit( SmGlyphSpecialNode* pNode ) override;
242
    void Visit( SmMathSymbolNode* pNode ) override;
243
    void Visit( SmBlankNode* pNode ) override;
244
    void Visit( SmErrorNode* pNode ) override;
245
    void Visit( SmLineNode* pNode ) override;
246
    void Visit( SmExpressionNode* pNode ) override;
247
    void Visit( SmPolyLineNode* pNode ) override;
248
    void Visit( SmRootNode* pNode ) override;
249
    void Visit( SmRootSymbolNode* pNode ) override;
250
    void Visit( SmRectangleNode* pNode ) override;
251
    void Visit( SmVerticalBraceNode* pNode ) override;
252
private:
253
    /** Draw the children of a pNode
254
     * This the default method, use by most pNodes
255
     */
256
    void DrawChildren( SmStructureNode* pNode );
257
258
    /** Draw an SmTextNode or a subclass of this */
259
    void DrawTextNode( SmTextNode* pNode );
260
    /** Draw an SmSpecialNode or a subclass of this  */
261
    void DrawSpecialNode( SmSpecialNode* pNode );
262
    /** OutputDevice to draw on */
263
    OutputDevice& mrDev;
264
    /** Position to draw on the mrDev
265
     * @remarks This variable is used to pass parameters in DrawChildren( ), this means
266
                that after a call to DrawChildren( ) the contents of this method is undefined
267
                so if needed cache it locally on the stack.
268
     */
269
    Point maPosition;
270
    const SmFormat& mrFormat;
271
};
272
273
// SmSetSelectionVisitor
274
275
/** Set Selection Visitor
276
 * Sets the IsSelected( ) property on all SmNodes of the tree
277
 */
278
class SmSetSelectionVisitor final : public SmDefaultingVisitor
279
{
280
public:
281
    SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pNode);
282
    void Visit( SmBinHorNode* pNode ) override;
283
    void Visit( SmUnHorNode* pNode ) override;
284
    void Visit( SmFontNode* pNode ) override;
285
    void Visit( SmTextNode* pNode ) override;
286
    void Visit( SmExpressionNode* pNode ) override;
287
    void Visit( SmLineNode* pNode ) override;
288
    void Visit( SmAlignNode* pNode ) override;
289
    using SmDefaultingVisitor::Visit;
290
    /** Set IsSelected on all pNodes of pSubTree */
291
    static void SetSelectedOnAll( SmNode* pSubTree, bool IsSelected = true );
292
private:
293
    /** Visit a selectable pNode
294
     * Can be used to handle pNodes that can be selected, that doesn't have more SmCaretPos'
295
     * than 0 and 1 inside them. SmTextNode should be handle separately!
296
     * Also note that pNodes such as SmBinVerNode cannot be selected, don't this method for
297
     * it.
298
     */
299
    void DefaultVisit( SmNode* pNode ) override;
300
    void VisitCompositionNode( SmStructureNode* pNode );
301
    /** Caret position where the selection starts */
302
    SmCaretPos maStartPos;
303
    /** Caret position where the selection ends */
304
    SmCaretPos maEndPos;
305
    /** The current state of this visitor
306
     * This property changes when the visitor meets either maStartPos
307
     * or maEndPos. This means that anything visited in between will be
308
     * selected.
309
     */
310
    bool mbSelecting;
311
};
312
313
314
// SmCaretPosGraphBuildingVisitor
315
316
317
/** A visitor for building a SmCaretPosGraph
318
 *
319
 * Visit invariant:
320
 * Each pNode, except SmExpressionNode, SmBinHorNode and a few others, constitutes an entry
321
 * in a line. Consider the line entry "H", this entry creates one carat position, here
322
 * denoted by | in "H|".
323
 *
324
 * Parameter variables:
325
 *  The following variables are used to transfer parameters into calls and results out
326
 *  of calls.
327
 *      pRightMost : SmCaretPosGraphEntry*
328
 *
329
 * Prior to a Visit call:
330
 *  pRightMost: A pointer to right most position in front of the current line entry.
331
 *
332
 * After a Visit call:
333
 *  pRightMost: A pointer to the right most position in the called line entry, if no there's
334
 *              no caret positions in called line entry don't change this variable.
335
 */
336
class SmCaretPosGraphBuildingVisitor final : public SmVisitor
337
{
338
public:
339
    /** Builds a caret position graph for pRootNode */
340
    explicit SmCaretPosGraphBuildingVisitor( SmNode* pRootNode );
341
    ~SmCaretPosGraphBuildingVisitor();
342
    void Visit( SmTableNode* pNode ) override;
343
    void Visit( SmBraceNode* pNode ) override;
344
    void Visit( SmBracebodyNode* pNode ) override;
345
    void Visit( SmOperNode* pNode ) override;
346
    void Visit( SmAlignNode* pNode ) override;
347
    void Visit( SmAttributeNode* pNode ) override;
348
    void Visit( SmFontNode* pNode ) override;
349
    void Visit( SmUnHorNode* pNode ) override;
350
    void Visit( SmBinHorNode* pNode ) override;
351
    void Visit( SmBinVerNode* pNode ) override;
352
    void Visit( SmBinDiagonalNode* pNode ) override;
353
    void Visit( SmSubSupNode* pNode ) override;
354
    void Visit( SmMatrixNode* pNode ) override;
355
    void Visit( SmPlaceNode* pNode ) override;
356
    void Visit( SmTextNode* pNode ) override;
357
    void Visit( SmSpecialNode* pNode ) override;
358
    void Visit( SmGlyphSpecialNode* pNode ) override;
359
    void Visit( SmMathSymbolNode* pNode ) override;
360
    void Visit( SmBlankNode* pNode ) override;
361
    void Visit( SmErrorNode* pNode ) override;
362
    void Visit( SmLineNode* pNode ) override;
363
    void Visit( SmExpressionNode* pNode ) override;
364
    void Visit( SmPolyLineNode* pNode ) override;
365
    void Visit( SmRootNode* pNode ) override;
366
    void Visit( SmRootSymbolNode* pNode ) override;
367
    void Visit( SmRectangleNode* pNode ) override;
368
    void Visit( SmVerticalBraceNode* pNode ) override;
369
    SmCaretPosGraph* takeGraph()
370
0
    {
371
0
        return mpGraph.release();
372
0
    }
373
private:
374
    SmCaretPosGraphEntry* mpRightMost;
375
    std::unique_ptr<SmCaretPosGraph> mpGraph;
376
};
377
378
// SmCloningVisitor
379
380
/** Visitor for cloning a pNode
381
 *
382
 * This visitor creates deep clones.
383
 */
384
class SmCloningVisitor final : public SmVisitor
385
{
386
public:
387
    SmCloningVisitor()
388
0
        : mpResult(nullptr)
389
0
    {}
390
    void Visit( SmTableNode* pNode ) override;
391
    void Visit( SmBraceNode* pNode ) override;
392
    void Visit( SmBracebodyNode* pNode ) override;
393
    void Visit( SmOperNode* pNode ) override;
394
    void Visit( SmAlignNode* pNode ) override;
395
    void Visit( SmAttributeNode* pNode ) override;
396
    void Visit( SmFontNode* pNode ) override;
397
    void Visit( SmUnHorNode* pNode ) override;
398
    void Visit( SmBinHorNode* pNode ) override;
399
    void Visit( SmBinVerNode* pNode ) override;
400
    void Visit( SmBinDiagonalNode* pNode ) override;
401
    void Visit( SmSubSupNode* pNode ) override;
402
    void Visit( SmMatrixNode* pNode ) override;
403
    void Visit( SmPlaceNode* pNode ) override;
404
    void Visit( SmTextNode* pNode ) override;
405
    void Visit( SmSpecialNode* pNode ) override;
406
    void Visit( SmGlyphSpecialNode* pNode ) override;
407
    void Visit( SmMathSymbolNode* pNode ) override;
408
    void Visit( SmBlankNode* pNode ) override;
409
    void Visit( SmErrorNode* pNode ) override;
410
    void Visit( SmLineNode* pNode ) override;
411
    void Visit( SmExpressionNode* pNode ) override;
412
    void Visit( SmPolyLineNode* pNode ) override;
413
    void Visit( SmRootNode* pNode ) override;
414
    void Visit( SmRootSymbolNode* pNode ) override;
415
    void Visit( SmRectangleNode* pNode ) override;
416
    void Visit( SmVerticalBraceNode* pNode ) override;
417
    /** Clone a pNode */
418
    SmNode* Clone( SmNode* pNode );
419
private:
420
    SmNode* mpResult;
421
    /** Clone children of pSource and give them to pTarget */
422
    void CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget );
423
    /** Clone attributes on a pNode */
424
    static void CloneNodeAttr( SmNode const * pSource, SmNode* pTarget );
425
};
426
427
428
// SmSelectionRectanglesVisitor: collect selection
429
430
class SmSelectionRectanglesVisitor : public SmDefaultingVisitor
431
{
432
public:
433
    SmSelectionRectanglesVisitor(OutputDevice& rDevice, SmNode* pTree);
434
    virtual ~SmSelectionRectanglesVisitor() = default;
435
    void Visit( SmTextNode* pNode ) override;
436
    using SmDefaultingVisitor::Visit;
437
438
0
    const tools::Rectangle& GetSelection() { return maSelectionArea; }
439
440
private:
441
    /** Reference to drawing device */
442
    OutputDevice& mrDev;
443
    /** The current area that is selected */
444
    tools::Rectangle maSelectionArea;
445
    /** Extend the area that must be selected  */
446
0
    void ExtendSelectionArea(const tools::Rectangle& rArea) { maSelectionArea.Union(rArea); }
447
    /** Default visiting method */
448
    void DefaultVisit( SmNode* pNode ) override;
449
    /** Visit the children of a given pNode */
450
    void VisitChildren( SmNode* pNode );
451
};
452
453
// SmSelectionDrawingVisitor
454
455
class SmSelectionDrawingVisitor final : public SmSelectionRectanglesVisitor
456
{
457
public:
458
    /** Draws a selection on rDevice for the selection on pTree */
459
    SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset );
460
};
461
462
// SmNodeToTextVisitor
463
464
/** Extract command text from pNodes */
465
class SmNodeToTextVisitor final : public SmVisitor
466
{
467
public:
468
    SmNodeToTextVisitor( SmNode* pNode, OUString &rText );
469
470
    void Visit( SmTableNode* pNode ) override;
471
    void Visit( SmBraceNode* pNode ) override;
472
    void Visit( SmBracebodyNode* pNode ) override;
473
    void Visit( SmOperNode* pNode ) override;
474
    void Visit( SmAlignNode* pNode ) override;
475
    void Visit( SmAttributeNode* pNode ) override;
476
    void Visit( SmFontNode* pNode ) override;
477
    void Visit( SmUnHorNode* pNode ) override;
478
    void Visit( SmBinHorNode* pNode ) override;
479
    void Visit( SmBinVerNode* pNode ) override;
480
    void Visit( SmBinDiagonalNode* pNode ) override;
481
    void Visit( SmSubSupNode* pNode ) override;
482
    void Visit( SmMatrixNode* pNode ) override;
483
    void Visit( SmPlaceNode* pNode ) override;
484
    void Visit( SmTextNode* pNode ) override;
485
    void Visit( SmSpecialNode* pNode ) override;
486
    void Visit( SmGlyphSpecialNode* pNode ) override;
487
    void Visit( SmMathSymbolNode* pNode ) override;
488
    void Visit( SmBlankNode* pNode ) override;
489
    void Visit( SmErrorNode* pNode ) override;
490
    void Visit( SmLineNode* pNode ) override;
491
    void Visit( SmExpressionNode* pNode ) override;
492
    void Visit( SmPolyLineNode* pNode ) override;
493
    void Visit( SmRootNode* pNode ) override;
494
    void Visit( SmRootSymbolNode* pNode ) override;
495
    void Visit( SmRectangleNode* pNode ) override;
496
    void Visit( SmVerticalBraceNode* pNode ) override;
497
private:
498
499
    /**
500
      * Extract text from a pNode that constitutes a line.
501
      * @param pNode
502
      * @return
503
      */
504
8.22k
    void LineToText( SmNode* pNode ) {
505
8.22k
        Separate( );
506
8.22k
        if( pNode ) pNode->Accept( this );
507
8.22k
        Separate( );
508
8.22k
    }
509
510
    /**
511
      * Appends rText to the OUStringBuffer ( maCmdText ).
512
      * @param rText
513
      * @return
514
      */
515
20.9k
    void Append( std::u16string_view rText ) {
516
20.9k
        maCmdText.append( rText );
517
20.9k
    }
518
519
    /**
520
     * Append a blank for separation, if needed.
521
     * It is needed if last char is not ' '.
522
     * @return
523
     */
524
43.0k
    void Separate( ){
525
43.0k
        if( !maCmdText.isEmpty() && maCmdText[ maCmdText.getLength() - 1 ] != ' ' )
526
12.0k
            maCmdText.append(' ');
527
43.0k
    }
528
529
    /** Output text generated from the pNodes */
530
    OUStringBuffer maCmdText;
531
};
532
533
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */