Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/edit/textdata.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <sal/config.h>
21
#include <sal/log.hxx>
22
#include <osl/diagnose.h>
23
24
#include <algorithm>
25
#include <cstddef>
26
27
#include <utility>
28
#include <vcl/textdata.hxx>
29
30
#include "TextLine.hxx"
31
#include "textdat2.hxx"
32
33
TextSelection::TextSelection()
34
0
{
35
0
}
36
37
TextSelection::TextSelection( const TextPaM& rPaM ) :
38
0
    maStartPaM( rPaM ), maEndPaM( rPaM )
39
0
{
40
0
}
41
42
TextSelection::TextSelection( const TextPaM& rStart, const TextPaM& rEnd ) :
43
0
    maStartPaM( rStart ), maEndPaM( rEnd )
44
0
{
45
0
}
46
47
void TextSelection::Justify()
48
0
{
49
0
    if ( maEndPaM < maStartPaM )
50
0
    {
51
0
        TextPaM aTemp( maStartPaM );
52
0
        maStartPaM = maEndPaM;
53
0
        maEndPaM = aTemp;
54
0
    }
55
0
}
56
57
TETextPortionList::TETextPortionList()
58
0
{
59
0
}
60
61
TETextPortionList::~TETextPortionList()
62
0
{
63
0
    Reset();
64
0
}
65
66
TETextPortion& TETextPortionList::operator[]( std::size_t nPos )
67
0
{
68
0
    return maPortions[ nPos ];
69
0
}
70
71
std::vector<TETextPortion>::iterator TETextPortionList::begin()
72
0
{
73
0
    return maPortions.begin();
74
0
}
75
76
std::vector<TETextPortion>::const_iterator TETextPortionList::begin() const
77
0
{
78
0
    return maPortions.begin();
79
0
}
80
81
std::vector<TETextPortion>::iterator TETextPortionList::end()
82
0
{
83
0
    return maPortions.end();
84
0
}
85
86
std::vector<TETextPortion>::const_iterator TETextPortionList::end() const
87
0
{
88
0
    return maPortions.end();
89
0
}
90
91
bool TETextPortionList::empty() const
92
0
{
93
0
    return maPortions.empty();
94
0
}
95
96
std::size_t TETextPortionList::size() const
97
0
{
98
0
    return maPortions.size();
99
0
}
100
101
std::vector<TETextPortion>::iterator TETextPortionList::erase( const std::vector<TETextPortion>::iterator& aIter )
102
0
{
103
0
    return maPortions.erase( aIter );
104
0
}
105
106
std::vector<TETextPortion>::iterator TETextPortionList::insert( const std::vector<TETextPortion>::iterator& aIter,
107
                                                                 const TETextPortion& rTP )
108
0
{
109
0
    return maPortions.insert( aIter, rTP );
110
0
}
111
112
void TETextPortionList::push_back( const TETextPortion& rTP )
113
0
{
114
0
    maPortions.push_back( rTP );
115
0
}
116
117
void TETextPortionList::Reset()
118
0
{
119
0
    maPortions.clear();
120
0
}
121
122
void TETextPortionList::DeleteFromPortion( std::size_t nDelFrom )
123
0
{
124
0
    SAL_WARN_IF( ( nDelFrom >= maPortions.size() ) && ( (nDelFrom != 0) || (!maPortions.empty()) ), "vcl", "DeleteFromPortion: Out of range" );
125
0
    maPortions.erase( maPortions.begin() + nDelFrom, maPortions.end() );
126
0
}
127
128
std::size_t TETextPortionList::FindPortion( sal_Int32 nCharPos, sal_Int32& nPortionStart, bool bPreferStartingPortion )
129
0
{
130
    // find left portion at nCharPos at portion border
131
0
    sal_Int32 nTmpPos = 0;
132
0
    for ( std::size_t nPortion = 0; nPortion < maPortions.size(); nPortion++ )
133
0
    {
134
0
        TETextPortion& rPortion = maPortions[ nPortion ];
135
0
        nTmpPos += rPortion.GetLen();
136
0
        if ( nTmpPos >= nCharPos )
137
0
        {
138
            // take this one if we don't prefer the starting portion, or if it's the last one
139
0
            if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == maPortions.size() - 1 ) )
140
0
            {
141
0
                nPortionStart = nTmpPos - rPortion.GetLen();
142
0
                return nPortion;
143
0
            }
144
0
        }
145
0
    }
146
0
    OSL_FAIL( "FindPortion: Not found!" );
147
0
    return ( maPortions.size() - 1 );
148
0
}
149
150
TEParaPortion::TEParaPortion( TextNode* pN )
151
0
    : mpNode {pN}
152
0
    , mnInvalidPosStart {0}
153
0
    , mnInvalidDiff {0}
154
0
    , mbInvalid {true}
155
0
    , mbSimple {false}
156
0
{
157
0
}
158
159
TEParaPortion::~TEParaPortion()
160
0
{
161
0
}
162
163
void TEParaPortion::MarkInvalid( sal_Int32 nStart, sal_Int32 nDiff )
164
0
{
165
0
    if ( !mbInvalid )
166
0
    {
167
0
        mnInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff );
168
0
        mnInvalidDiff = nDiff;
169
0
    }
170
0
    else
171
0
    {
172
        // simple consecutive typing
173
0
        if ( ( nDiff > 0 ) && ( mnInvalidDiff > 0 ) &&
174
0
             ( ( mnInvalidPosStart+mnInvalidDiff ) == nStart ) )
175
0
        {
176
0
            mnInvalidDiff = mnInvalidDiff + nDiff;
177
0
        }
178
        // simple consecutive deleting
179
0
        else if ( ( nDiff < 0 ) && ( mnInvalidDiff < 0 ) && ( mnInvalidPosStart == nStart ) )
180
0
        {
181
0
            mnInvalidPosStart = mnInvalidPosStart + nDiff;
182
0
            mnInvalidDiff = mnInvalidDiff + nDiff;
183
0
        }
184
0
        else
185
0
        {
186
0
            SAL_WARN_IF( ( nDiff < 0 ) && ( (nStart+nDiff) < 0 ), "vcl", "MarkInvalid: Diff out of Range" );
187
0
            mnInvalidPosStart = std::min( mnInvalidPosStart, nDiff < 0 ? nStart+nDiff : nDiff );
188
0
            mnInvalidDiff = 0;
189
0
            mbSimple = false;
190
0
        }
191
0
    }
192
193
0
    maWritingDirectionInfos.clear();
194
195
0
    mbInvalid = true;
196
0
}
197
198
void TEParaPortion::MarkSelectionInvalid( sal_Int32 nStart )
199
0
{
200
0
    if ( !mbInvalid )
201
0
    {
202
0
        mnInvalidPosStart = nStart;
203
0
    }
204
0
    else
205
0
    {
206
0
        mnInvalidPosStart = std::min( mnInvalidPosStart, nStart );
207
0
    }
208
209
0
    maWritingDirectionInfos.clear();
210
211
0
    mnInvalidDiff = 0;
212
0
    mbInvalid = true;
213
0
    mbSimple = false;
214
0
}
215
216
std::vector<TextLine>::size_type TEParaPortion::GetLineNumber( sal_Int32 nChar, bool bInclEnd )
217
0
{
218
0
    for ( std::vector<TextLine>::size_type nLine = 0; nLine < maLines.size(); nLine++ )
219
0
    {
220
0
        TextLine& rLine = maLines[ nLine ];
221
0
        if ( ( bInclEnd && ( rLine.GetEnd() >= nChar ) ) ||
222
0
             ( rLine.GetEnd() > nChar ) )
223
0
        {
224
0
            return nLine;
225
0
        }
226
0
    }
227
228
    // Then it should be at the end of the last line
229
0
    OSL_ENSURE(nChar == maLines.back().GetEnd(), "wrong Index");
230
0
    OSL_ENSURE(!bInclEnd, "Line not found: FindLine");
231
0
    return ( maLines.size() - 1 );
232
0
}
233
234
void TEParaPortion::CorrectValuesBehindLastFormattedLine( sal_uInt16 nLastFormattedLine )
235
0
{
236
0
    sal_uInt16 nLines = maLines.size();
237
0
    SAL_WARN_IF( !nLines, "vcl", "CorrectPortionNumbersFromLine: Empty portion?" );
238
0
    if ( nLastFormattedLine >= ( nLines - 1 ) )
239
0
        return;
240
241
0
    const TextLine& rLastFormatted = maLines[ nLastFormattedLine ];
242
0
    const TextLine& rUnformatted = maLines[ nLastFormattedLine+1 ];
243
0
    std::ptrdiff_t nPortionDiff = rUnformatted.GetStartPortion() - rLastFormatted.GetEndPortion();
244
0
    sal_Int32 nTextDiff = rUnformatted.GetStart() - rLastFormatted.GetEnd();
245
0
    nTextDiff++;    // LastFormatted.GetEnd() was inclusive => subtracted one too much!
246
247
    // The first unformatted one has to start exactly one portion past the last
248
    // formatted one.
249
    // If a portion got split in the changed row, nLastEnd could be > nNextStart!
250
0
    std::ptrdiff_t nPDiff = -( nPortionDiff-1 );
251
0
    const sal_Int32 nTDiff = -( nTextDiff-1 );
252
0
    if ( !(nPDiff || nTDiff) )
253
0
        return;
254
255
0
    for ( sal_uInt16 nL = nLastFormattedLine+1; nL < nLines; nL++ )
256
0
    {
257
0
        TextLine& rLine = maLines[ nL ];
258
259
0
        rLine.SetStartPortion(rLine.GetStartPortion() + nPDiff);
260
0
        rLine.SetEndPortion(rLine.GetEndPortion() + nPDiff);
261
262
0
        rLine.SetStart(rLine.GetStart() + nTDiff);
263
0
        rLine.SetEnd(rLine.GetEnd() + nTDiff);
264
265
0
        rLine.SetValid();
266
0
    }
267
0
}
268
269
TEParaPortions::~TEParaPortions()
270
0
{
271
0
}
272
273
0
TextHint::TextHint( SfxHintId Id ) : SfxHint( Id ), mnValue(0)
274
0
{
275
0
}
276
277
0
TextHint::TextHint( SfxHintId Id, sal_Int32 nValue ) : SfxHint( Id ), mnValue(nValue)
278
0
{
279
0
}
280
281
TEIMEInfos::TEIMEInfos( const TextPaM& rPos, OUString _aOldTextAfterStartPos )
282
0
    : aOldTextAfterStartPos(std::move(_aOldTextAfterStartPos))
283
0
    , aPos(rPos)
284
0
    , nLen(0)
285
0
    , bWasCursorOverwrite(false)
286
0
{
287
0
}
288
289
TEIMEInfos::~TEIMEInfos()
290
0
{
291
0
}
292
293
void TEIMEInfos::CopyAttribs(const ExtTextInputAttr* pA, sal_Int32 nL)
294
0
{
295
0
    nLen = nL;
296
0
    pAttribs.reset( new ExtTextInputAttr[ nL ] );
297
0
    std::copy_n(pA, nL, pAttribs.get());
298
0
}
299
300
void TEIMEInfos::DestroyAttribs()
301
0
{
302
0
    pAttribs.reset();
303
0
    nLen = 0;
304
0
}
305
306
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */