/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: */ |