Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/editeng/source/misc/txtrange.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 <editeng/txtrange.hxx>
22
#include <tools/poly.hxx>
23
#include <tools/debug.hxx>
24
#include <basegfx/polygon/b2dpolygon.hxx>
25
#include <basegfx/polygon/b2dpolypolygon.hxx>
26
27
#include <vector>
28
29
TextRanger::TextRanger( const basegfx::B2DPolyPolygon& rPolyPolygon,
30
                        const basegfx::B2DPolyPolygon* pLinePolyPolygon,
31
                        sal_uInt16 nCacheSz, sal_uInt16 nLft, sal_uInt16 nRght,
32
                        bool bSimpl, bool bInnr, bool bVert ) :
33
0
    maPolyPolygon( rPolyPolygon.count() ),
34
0
    nCacheSize( nCacheSz ),
35
0
    nRight( nRght ),
36
0
    nLeft( nLft ),
37
0
    nUpper( 0 ),
38
0
    nLower( 0 ),
39
0
    nPointCount( 0 ),
40
0
    bSimple( bSimpl ),
41
0
    bInner( bInnr ),
42
0
    bVertical( bVert )
43
0
{
44
0
    sal_uInt32 nCount(rPolyPolygon.count());
45
46
0
    for(sal_uInt32 i(0); i < nCount; i++)
47
0
    {
48
0
        const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(i).getDefaultAdaptiveSubdivision());
49
0
        nPointCount += aCandidate.count();
50
0
        maPolyPolygon.Insert( tools::Polygon(aCandidate), static_cast<sal_uInt16>(i) );
51
0
    }
52
53
0
    if( pLinePolyPolygon )
54
0
    {
55
0
        nCount = pLinePolyPolygon->count();
56
0
        mpLinePolyPolygon = tools::PolyPolygon(nCount);
57
58
0
        for(sal_uInt32 i(0); i < nCount; i++)
59
0
        {
60
0
            const basegfx::B2DPolygon aCandidate(pLinePolyPolygon->getB2DPolygon(i).getDefaultAdaptiveSubdivision());
61
0
            nPointCount += aCandidate.count();
62
0
            mpLinePolyPolygon->Insert( tools::Polygon(aCandidate), static_cast<sal_uInt16>(i) );
63
0
        }
64
0
    }
65
0
    else
66
0
        mpLinePolyPolygon.reset();
67
0
}
68
69
70
TextRanger::~TextRanger()
71
0
{
72
0
    mRangeCache.clear();
73
0
}
74
75
/* TextRanger::SetVertical(..)
76
   If there's is a change in the writing direction,
77
   the cache has to be cleared.
78
*/
79
void TextRanger::SetVertical( bool bNew )
80
0
{
81
0
    if( IsVertical() != bNew )
82
0
    {
83
0
        bVertical = bNew;
84
0
        mRangeCache.clear();
85
0
    }
86
0
}
87
88
namespace {
89
90
//! SvxBoundArgs is used to perform temporary calculations on a range array.
91
//! Temporary instances are created in TextRanger::GetTextRanges()
92
class SvxBoundArgs
93
{
94
    std::vector<bool> aBoolArr;
95
    std::deque<tools::Long>* pLongArr;
96
    TextRanger *pTextRanger;
97
    tools::Long nMin;
98
    tools::Long nMax;
99
    tools::Long nTop;
100
    tools::Long nBottom;
101
    tools::Long nUpDiff;
102
    tools::Long nLowDiff;
103
    tools::Long nUpper;
104
    tools::Long nLower;
105
    tools::Long nStart;
106
    tools::Long nEnd;
107
    sal_uInt16 nCut;
108
    sal_uInt16 nLast;
109
    sal_uInt16 nNext;
110
    sal_uInt8 nAct;
111
    sal_uInt8 nFirst;
112
    bool bClosed : 1;
113
    bool bInner : 1;
114
    bool bMultiple : 1;
115
    bool bConcat : 1;
116
    bool bRotate : 1;
117
    void NoteRange( bool bToggle );
118
    tools::Long Cut( tools::Long nY, const Point& rPt1, const Point& rPt2 );
119
    void Add();
120
    void NoteFarPoint_( tools::Long nPx, tools::Long nPyDiff, tools::Long nDiff );
121
    void NoteFarPoint( tools::Long nPx, tools::Long nPyDiff, tools::Long nDiff )
122
0
        { if( nDiff ) NoteFarPoint_( nPx, nPyDiff, nDiff ); }
123
    tools::Long CalcMax( const Point& rPt1, const Point& rPt2, tools::Long nRange, tools::Long nFar );
124
    void CheckCut( const Point& rLst, const Point& rNxt );
125
0
    tools::Long A( const Point& rP ) const { return bRotate ? rP.Y() : rP.X(); }
126
0
    tools::Long B( const Point& rP ) const { return bRotate ? rP.X() : rP.Y(); }
127
public:
128
    SvxBoundArgs( TextRanger* pRanger, std::deque<tools::Long>* pLong, const Range& rRange );
129
0
    void NotePoint( const tools::Long nA ) { NoteMargin( nA - nStart, nA + nEnd ); }
130
    void NoteMargin( const tools::Long nL, const tools::Long nR )
131
0
        { if( nMin > nL ) nMin = nL; if( nMax < nR ) nMax = nR; }
132
    sal_uInt16 Area( const Point& rPt );
133
    void NoteUpLow( tools::Long nA, const sal_uInt8 nArea );
134
    void Calc( const tools::PolyPolygon& rPoly );
135
    void Concat( const tools::PolyPolygon* pPoly );
136
    // inlines
137
0
    void NoteLast() { if( bMultiple ) NoteRange( nAct == nFirst ); }
138
0
    void SetConcat( const bool bNew ){ bConcat = bNew; }
139
0
    bool IsConcat() const { return bConcat; }
140
};
141
142
}
143
144
SvxBoundArgs::SvxBoundArgs( TextRanger* pRanger, std::deque<tools::Long>* pLong,
145
    const Range& rRange )
146
0
    : pLongArr(pLong)
147
0
    , pTextRanger(pRanger)
148
0
    , nMin(0)
149
0
    , nMax(0)
150
0
    , nTop(rRange.Min())
151
0
    , nBottom(rRange.Max())
152
0
    , nCut(0)
153
0
    , nLast(0)
154
0
    , nNext(0)
155
0
    , nAct(0)
156
0
    , nFirst(0)
157
0
    , bClosed(false)
158
0
    , bInner(pRanger->IsInner())
159
0
    , bMultiple(bInner || !pRanger->IsSimple())
160
0
    , bConcat(false)
161
0
    , bRotate(pRanger->IsVertical())
162
0
{
163
0
    if( bRotate )
164
0
    {
165
0
        nStart = pRanger->GetUpper();
166
0
        nEnd = pRanger->GetLower();
167
0
        nLowDiff = pRanger->GetLeft();
168
0
        nUpDiff = pRanger->GetRight();
169
0
    }
170
0
    else
171
0
    {
172
0
        nStart = pRanger->GetLeft();
173
0
        nEnd = pRanger->GetRight();
174
0
        nLowDiff = pRanger->GetUpper();
175
0
        nUpDiff = pRanger->GetLower();
176
0
    }
177
0
    nUpper = nTop - nUpDiff;
178
0
    nLower = nBottom + nLowDiff;
179
0
    pLongArr->clear();
180
0
}
181
182
tools::Long SvxBoundArgs::CalcMax( const Point& rPt1, const Point& rPt2,
183
    tools::Long nRange, tools::Long nFarRange )
184
0
{
185
0
    double nDa = Cut( nRange, rPt1, rPt2 ) - Cut( nFarRange, rPt1, rPt2 );
186
0
    double nB;
187
0
    if( nDa < 0 )
188
0
    {
189
0
        nDa = -nDa;
190
0
        nB = nEnd;
191
0
    }
192
0
    else
193
0
        nB = nStart;
194
195
0
    nB = std::hypot(nB, nDa);
196
197
0
    if (nB == 0) // avoid div / 0
198
0
        return 0;
199
200
0
    nB = nRange + nDa * ( nFarRange - nRange ) / nB;
201
202
0
    bool bNote;
203
0
    if( nB < B(rPt2) )
204
0
        bNote = nB > B(rPt1);
205
0
    else
206
0
        bNote = nB < B(rPt1);
207
0
    if( bNote )
208
0
        return( tools::Long( nB ) );
209
0
    return 0;
210
0
}
211
212
void SvxBoundArgs::CheckCut( const Point& rLst, const Point& rNxt )
213
0
{
214
0
    if( nCut & 1 )
215
0
        NotePoint( Cut( nBottom, rLst, rNxt ) );
216
0
    if( nCut & 2 )
217
0
        NotePoint( Cut( nTop, rLst, rNxt ) );
218
0
    if( rLst.X() == rNxt.X() || rLst.Y() == rNxt.Y() )
219
0
        return;
220
221
0
    tools::Long nYps;
222
0
    if( nLowDiff && ( ( nCut & 1 ) || nLast == 1 || nNext == 1 ) )
223
0
    {
224
0
        nYps = CalcMax( rLst, rNxt, nBottom, nLower );
225
0
        if( nYps )
226
0
            NoteFarPoint_( Cut( nYps, rLst, rNxt ), nLower-nYps, nLowDiff );
227
0
    }
228
0
    if( nUpDiff && ( ( nCut & 2 ) || nLast == 2 || nNext == 2 ) )
229
0
    {
230
0
        nYps = CalcMax( rLst, rNxt, nTop, nUpper );
231
0
        if( nYps )
232
0
            NoteFarPoint_( Cut( nYps, rLst, rNxt ), nYps-nUpper, nUpDiff );
233
0
    }
234
0
}
235
236
void SvxBoundArgs::NoteFarPoint_( tools::Long nPa, tools::Long nPbDiff, tools::Long nDiff )
237
0
{
238
0
    tools::Long nTmpA;
239
0
    double nQuot = 2 * nDiff - nPbDiff;
240
0
    nQuot *= nPbDiff;
241
0
    nQuot = sqrt( nQuot );
242
0
    nQuot /= nDiff;
243
0
    nTmpA = nPa - tools::Long( nStart * nQuot );
244
0
    nPbDiff = nPa + tools::Long( nEnd * nQuot );
245
0
    NoteMargin( nTmpA, nPbDiff );
246
0
}
247
248
void SvxBoundArgs::NoteRange( bool bToggle )
249
0
{
250
0
    DBG_ASSERT( nMax >= nMin || bInner, "NoteRange: Min > Max?");
251
0
    if( nMax < nMin )
252
0
        return;
253
0
    if( !bClosed )
254
0
        bToggle = false;
255
0
    sal_uInt16 nIdx = 0;
256
0
    sal_uInt16 nCount = pLongArr->size();
257
0
    DBG_ASSERT( nCount == 2 * aBoolArr.size(), "NoteRange: Incompatible Sizes" );
258
0
    while( nIdx < nCount && (*pLongArr)[ nIdx ] < nMin )
259
0
        ++nIdx;
260
0
    bool bOdd = (nIdx % 2) != 0;
261
    // No overlap with existing intervals?
262
0
    if( nIdx == nCount || ( !bOdd && nMax < (*pLongArr)[ nIdx ] ) )
263
0
    {   // Then a new one is inserted ...
264
0
        pLongArr->insert( pLongArr->begin() + nIdx, nMin );
265
0
        pLongArr->insert( pLongArr->begin() + nIdx + 1, nMax );
266
0
        aBoolArr.insert( aBoolArr.begin() + (nIdx/2), bToggle );
267
0
    }
268
0
    else
269
0
    {   // expand an existing interval ...
270
0
        sal_uInt16 nMaxIdx = nIdx;
271
        // If we end up on a left interval boundary, it must be reduced to nMin.
272
0
        if( bOdd )
273
0
            --nIdx;
274
0
        else
275
0
            (*pLongArr)[ nIdx ] = nMin;
276
0
        while( nMaxIdx < nCount && (*pLongArr)[ nMaxIdx ] < nMax )
277
0
            ++nMaxIdx;
278
0
        DBG_ASSERT( nMaxIdx > nIdx || nMin == nMax, "NoteRange: Funny Situation." );
279
0
        if( nMaxIdx )
280
0
            --nMaxIdx;
281
0
        if( nMaxIdx < nIdx )
282
0
            nMaxIdx = nIdx;
283
        // If we end up on a right interval boundary, it must be raised to nMax.
284
0
        if( nMaxIdx % 2 )
285
0
            (*pLongArr)[ nMaxIdx-- ] = nMax;
286
        // Possible merge of intervals.
287
0
        sal_uInt16 nDiff = nMaxIdx - nIdx;
288
0
        nMaxIdx = nIdx / 2; // From here on is nMaxIdx the Index in BoolArray.
289
0
        if( nDiff )
290
0
        {
291
0
            pLongArr->erase( pLongArr->begin() + nIdx + 1, pLongArr->begin() + nIdx + 1 + nDiff );
292
0
            nDiff /= 2;
293
0
            sal_uInt16 nStop = nMaxIdx + nDiff;
294
0
            for( sal_uInt16 i = nMaxIdx; i < nStop; ++i )
295
0
                bToggle ^= aBoolArr[ i ];
296
0
            aBoolArr.erase( aBoolArr.begin() + nMaxIdx, aBoolArr.begin() + (nMaxIdx + nDiff) );
297
0
        }
298
0
        DBG_ASSERT( nMaxIdx < aBoolArr.size(), "NoteRange: Too much deleted" );
299
0
        aBoolArr[ nMaxIdx ] = aBoolArr[ nMaxIdx ] != bToggle;
300
0
    }
301
0
}
302
303
void SvxBoundArgs::Calc( const tools::PolyPolygon& rPoly )
304
0
{
305
0
    sal_uInt16 nCount;
306
0
    nAct = 0;
307
0
    for( auto const& rPol : rPoly )
308
0
    {
309
0
        nCount = rPol.GetSize();
310
0
        if( nCount )
311
0
        {
312
0
            const Point& rNull = rPol[ 0 ];
313
0
            bClosed = IsConcat() || ( rNull == rPol[ nCount - 1 ] );
314
0
            nLast = Area( rNull );
315
0
            if( nLast & 12 )
316
0
            {
317
0
                nFirst = 3;
318
0
                if( bMultiple )
319
0
                    nAct = 0;
320
0
            }
321
0
            else
322
0
            {
323
                // The first point of the polygon is within the line.
324
0
                if( nLast )
325
0
                {
326
0
                    if( bMultiple || !nAct )
327
0
                    {
328
0
                        nMin = USHRT_MAX;
329
0
                        nMax = 0;
330
0
                    }
331
0
                    if( nLast & 1 )
332
0
                        NoteFarPoint( A(rNull), nLower - B(rNull), nLowDiff );
333
0
                    else
334
0
                        NoteFarPoint( A(rNull), B(rNull) - nUpper, nUpDiff );
335
0
                }
336
0
                else
337
0
                {
338
0
                    if( bMultiple || !nAct )
339
0
                    {
340
0
                        nMin = A(rNull);
341
0
                        nMax = nMin + nEnd;
342
0
                        nMin -= nStart;
343
0
                    }
344
0
                    else
345
0
                        NotePoint( A(rNull) );
346
0
                }
347
0
                nFirst = 0; // leaving the line in which direction?
348
0
                nAct = 3;   // we are within the line at the moment.
349
0
            }
350
0
            if( nCount > 1 )
351
0
            {
352
0
                sal_uInt16 nIdx = 1;
353
0
                while( true )
354
0
                {
355
0
                    const Point& rLast = rPol[ nIdx - 1 ];
356
0
                    if( nIdx == nCount )
357
0
                        nIdx = 0;
358
0
                    const Point& rNext = rPol[ nIdx ];
359
0
                    nNext = Area( rNext );
360
0
                    nCut = nNext ^ nLast;
361
0
                    sal_uInt16 nOldAct = nAct;
362
0
                    if( nAct )
363
0
                        CheckCut( rLast, rNext );
364
0
                    if( nCut & 4 )
365
0
                    {
366
0
                        NoteUpLow( Cut( nLower, rLast, rNext ), 2 );
367
0
                        if( nAct && nAct != nOldAct )
368
0
                        {
369
0
                            nOldAct = nAct;
370
0
                            CheckCut( rLast, rNext );
371
0
                        }
372
0
                    }
373
0
                    if( nCut & 8 )
374
0
                    {
375
0
                        NoteUpLow( Cut( nUpper, rLast, rNext ), 1 );
376
0
                        if( nAct && nAct != nOldAct )
377
0
                            CheckCut( rLast, rNext );
378
0
                    }
379
0
                    if( !nIdx )
380
0
                    {
381
0
                        if( !( nNext & 12 ) )
382
0
                            NoteLast();
383
0
                        break;
384
0
                    }
385
0
                    if( !( nNext & 12 ) )
386
0
                    {
387
0
                        if( !nNext )
388
0
                            NotePoint( A(rNext) );
389
0
                        else if( nNext & 1 )
390
0
                            NoteFarPoint( A(rNext), nLower-B(rNext), nLowDiff );
391
0
                        else
392
0
                            NoteFarPoint( A(rNext), B(rNext)-nUpper, nUpDiff );
393
0
                    }
394
0
                    nLast = nNext;
395
0
                    if( ++nIdx == nCount && !bClosed )
396
0
                    {
397
0
                        if( !( nNext & 12 ) )
398
0
                            NoteLast();
399
0
                        break;
400
0
                    }
401
0
                }
402
0
            }
403
0
            if( bMultiple && IsConcat() )
404
0
            {
405
0
                Add();
406
0
                nAct = 0;
407
0
            }
408
0
        }
409
0
    }
410
0
    if( !bMultiple )
411
0
    {
412
0
        DBG_ASSERT( pLongArr->empty(), "I said: Simple!" );
413
0
        if( nAct )
414
0
        {
415
0
            if( bInner )
416
0
            {
417
0
                tools::Long nTmpMin = nMin + 2 * nStart;
418
0
                tools::Long nTmpMax = nMax - 2 * nEnd;
419
0
                if( nTmpMin <= nTmpMax )
420
0
                {
421
0
                    pLongArr->push_front(nTmpMax);
422
0
                    pLongArr->push_front(nTmpMin);
423
0
                }
424
0
            }
425
0
            else
426
0
            {
427
0
                pLongArr->push_front(nMax);
428
0
                pLongArr->push_front(nMin);
429
0
            }
430
0
        }
431
0
    }
432
0
    else if( !IsConcat() )
433
0
        Add();
434
0
}
435
436
void SvxBoundArgs::Add()
437
0
{
438
0
    size_t nCount = aBoolArr.size();
439
0
    if( nCount && ( !bInner || !pTextRanger->IsSimple() ) )
440
0
    {
441
0
        bool bDelete = aBoolArr.front();
442
0
        if( bInner )
443
0
            bDelete = !bDelete;
444
0
        sal_uInt16 nLongIdx = 1;
445
0
        for( size_t nBoolIdx = 1; nBoolIdx < nCount; ++nBoolIdx )
446
0
        {
447
0
            if( bDelete )
448
0
            {
449
0
                sal_uInt16 next = 2;
450
0
                while( nBoolIdx < nCount && !aBoolArr[ nBoolIdx++ ] &&
451
0
                       (!bInner || nBoolIdx < nCount ) )
452
0
                    next += 2;
453
0
                pLongArr->erase( pLongArr->begin() + nLongIdx, pLongArr->begin() + nLongIdx + next );
454
0
                next /= 2;
455
0
                nBoolIdx = nBoolIdx - next;
456
0
                nCount = nCount - next;
457
0
                aBoolArr.erase( aBoolArr.begin() + nBoolIdx, aBoolArr.begin() + (nBoolIdx + next) );
458
0
                if (nBoolIdx > 0)
459
0
                    aBoolArr[ nBoolIdx - 1 ] = false;
460
#if OSL_DEBUG_LEVEL > 1
461
                else
462
                    ++next;
463
#endif
464
0
            }
465
0
            bDelete = nBoolIdx < nCount && aBoolArr[ nBoolIdx ];
466
0
            nLongIdx += 2;
467
0
            DBG_ASSERT( nLongIdx == 2*nBoolIdx+1, "BoundArgs: Array-Idx Confusion" );
468
0
            DBG_ASSERT( aBoolArr.size()*2 == pLongArr->size(),
469
0
                        "BoundArgs: Array-Count: Confusion" );
470
0
        }
471
0
    }
472
0
    if( pLongArr->empty() )
473
0
        return;
474
475
0
    if( !bInner )
476
0
        return;
477
478
0
    pLongArr->pop_front();
479
0
    pLongArr->pop_back();
480
481
    // Here the line is held inside a large rectangle for "simple"
482
    // contour wrap. Currently (April 1999) the EditEngine evaluates
483
    // only the first rectangle. If it one day is able to output a line
484
    // in several parts, it may be advisable to delete the following lines.
485
0
    if( pTextRanger->IsSimple() && pLongArr->size() > 2 )
486
0
        pLongArr->erase( pLongArr->begin() + 1, pLongArr->end() - 1 );
487
0
}
488
489
void SvxBoundArgs::Concat( const tools::PolyPolygon* pPoly )
490
0
{
491
0
    SetConcat( true );
492
0
    DBG_ASSERT( pPoly, "Nothing to do?" );
493
0
    std::deque<tools::Long>* pOld = pLongArr;
494
0
    pLongArr = new std::deque<tools::Long>;
495
0
    aBoolArr.clear();
496
0
    bInner = false;
497
0
    Calc( *pPoly ); // Note that this updates pLongArr, which is why we swapped it out earlier.
498
0
    std::deque<tools::Long>::size_type nCount = pLongArr->size();
499
0
    std::deque<tools::Long>::size_type nIdx = 0;
500
0
    std::deque<tools::Long>::size_type i = 0;
501
0
    bool bSubtract = pTextRanger->IsInner();
502
0
    while( i < nCount )
503
0
    {
504
0
        std::deque<tools::Long>::size_type nOldCount = pOld->size();
505
0
        if( nIdx == nOldCount )
506
0
        {   // Reached the end of the old Array...
507
0
            if( !bSubtract )
508
0
                pOld->insert( pOld->begin() + nIdx, pLongArr->begin() + i, pLongArr->end() );
509
0
            break;
510
0
        }
511
0
        tools::Long nLeft = (*pLongArr)[ i++ ];
512
0
        tools::Long nRight = (*pLongArr)[ i++ ];
513
0
        std::deque<tools::Long>::size_type nLeftPos = nIdx + 1;
514
0
        while( nLeftPos < nOldCount && nLeft > (*pOld)[ nLeftPos ] )
515
0
            nLeftPos += 2;
516
0
        if( nLeftPos >= nOldCount )
517
0
        {   // The current interval belongs to the end of the old array ...
518
0
            if( !bSubtract )
519
0
                pOld->insert( pOld->begin() + nOldCount, pLongArr->begin() + i - 2, pLongArr->end() );
520
0
            break;
521
0
        }
522
0
        std::deque<tools::Long>::size_type nRightPos = nLeftPos - 1;
523
0
        while( nRightPos < nOldCount && nRight >= (*pOld)[ nRightPos ] )
524
0
            nRightPos += 2;
525
0
        if( nRightPos < nLeftPos )
526
0
        {   // The current interval belongs between two old intervals
527
0
            if( !bSubtract )
528
0
                pOld->insert( pOld->begin() + nRightPos, pLongArr->begin() + i - 2, pLongArr->begin() + i );
529
0
        }
530
0
        else if( bSubtract ) // Subtract, if necessary separate
531
0
        {
532
0
            const tools::Long nOld = (*pOld)[nLeftPos - 1];
533
0
            if (nLeft > nOld)
534
0
            {   // Now we split the left part...
535
0
                if( nLeft - 1 > nOld )
536
0
                {
537
0
                    pOld->insert( pOld->begin() + nLeftPos - 1, nOld );
538
0
                    pOld->insert( pOld->begin() + nLeftPos, nLeft - 1 );
539
0
                    nLeftPos += 2;
540
0
                    nRightPos += 2;
541
0
                }
542
0
            }
543
0
            if( nRightPos - nLeftPos > 1 )
544
0
                pOld->erase( pOld->begin() + nLeftPos, pOld->begin() + nRightPos - 1 );
545
0
            if (++nRight >= (*pOld)[nLeftPos])
546
0
                pOld->erase( pOld->begin() + nLeftPos - 1, pOld->begin() + nLeftPos + 1 );
547
0
            else
548
0
                (*pOld)[ nLeftPos - 1 ] = nRight;
549
0
        }
550
0
        else // Merge
551
0
        {
552
0
            if( nLeft < (*pOld)[ nLeftPos - 1 ] )
553
0
                (*pOld)[ nLeftPos - 1 ] = nLeft;
554
0
            if( nRight > (*pOld)[ nRightPos - 1 ] )
555
0
                (*pOld)[ nRightPos - 1 ] = nRight;
556
0
            if( nRightPos - nLeftPos > 1 )
557
0
                pOld->erase( pOld->begin() + nLeftPos, pOld->begin() + nRightPos - 1 );
558
559
0
        }
560
0
        nIdx = nLeftPos - 1;
561
0
    }
562
0
    delete pLongArr;
563
0
}
564
565
/*************************************************************************
566
 * SvxBoundArgs::Area returns the area in which the point is located.
567
 * 0 = within the line
568
 * 1 = below, but within the upper edge
569
 * 2 = above, but within the lower edge
570
 * 5 = below the upper edge
571
 *10 = above the lower edge
572
 *************************************************************************/
573
574
sal_uInt16 SvxBoundArgs::Area( const Point& rPt )
575
0
{
576
0
    tools::Long nB = B( rPt );
577
0
    if( nB >= nBottom )
578
0
    {
579
0
        if( nB >= nLower )
580
0
            return 5;
581
0
        return 1;
582
0
    }
583
0
    if( nB <= nTop )
584
0
    {
585
0
        if( nB <= nUpper )
586
0
            return 10;
587
0
        return 2;
588
0
    }
589
0
    return 0;
590
0
}
591
592
/*************************************************************************
593
 * lcl_Cut calculates the X-Coordinate of the distance (Pt1-Pt2) at the
594
 * Y-Coordinate nY.
595
 * It is assumed that the one of the points are located above and the other
596
 * one below the Y-Coordinate.
597
 *************************************************************************/
598
599
tools::Long SvxBoundArgs::Cut( tools::Long nB, const Point& rPt1, const Point& rPt2 )
600
0
{
601
0
    if( pTextRanger->IsVertical() )
602
0
    {
603
0
        double nQuot = nB - rPt1.X();
604
0
        nQuot /= ( rPt2.X() - rPt1.X() );
605
0
        nQuot *= ( rPt2.Y() - rPt1.Y() );
606
0
        return tools::Long( rPt1.Y() + nQuot );
607
0
    }
608
0
    double nQuot = nB - rPt1.Y();
609
0
    nQuot /= ( rPt2.Y() - rPt1.Y() );
610
0
    nQuot *= ( rPt2.X() - rPt1.X() );
611
0
    return tools::Long( rPt1.X() + nQuot );
612
0
}
613
614
void SvxBoundArgs::NoteUpLow( tools::Long nA, const sal_uInt8 nArea )
615
0
{
616
0
    if( nAct )
617
0
    {
618
0
        NoteMargin( nA, nA );
619
0
        if( bMultiple )
620
0
        {
621
0
            NoteRange( nArea != nAct );
622
0
            nAct = 0;
623
0
        }
624
0
        if( !nFirst )
625
0
            nFirst = nArea;
626
0
    }
627
0
    else
628
0
    {
629
0
        nAct = nArea;
630
0
        nMin = nA;
631
0
        nMax = nA;
632
0
    }
633
0
}
634
635
std::deque<tools::Long>* TextRanger::GetTextRanges( const Range& rRange )
636
0
{
637
0
    DBG_ASSERT( rRange.Min() || rRange.Max(), "Zero-Range not allowed, Bye Bye" );
638
    //Can we find the result we need in the cache?
639
0
    for (auto & elem : mRangeCache)
640
0
    {
641
0
        if (elem.range == rRange)
642
0
            return &(elem.results);
643
0
    }
644
    //Calculate a new result
645
0
    RangeCacheItem rngCache(rRange);
646
0
    SvxBoundArgs aArg( this, &(rngCache.results), rRange );
647
0
    aArg.Calc( maPolyPolygon );
648
0
    if( mpLinePolyPolygon )
649
0
        aArg.Concat( &*mpLinePolyPolygon );
650
    //Add new result to the cache
651
0
    mRangeCache.push_back(std::move(rngCache));
652
0
    if (mRangeCache.size() > nCacheSize)
653
0
        mRangeCache.pop_front();
654
0
    return &(mRangeCache.back().results);
655
0
}
656
657
const tools::Rectangle& TextRanger::GetBoundRect_() const
658
0
{
659
0
    DBG_ASSERT( !mxBound, "Don't call twice." );
660
0
    mxBound = maPolyPolygon.GetBoundRect();
661
0
    return *mxBound;
662
0
}
663
664
665
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */