LibreOffice Module sw (master)  1
accportions.cxx
Go to the documentation of this file.
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 
22 #include <string_view>
23 
24 #include "accportions.hxx"
25 #include <osl/diagnose.h>
26 #include <rtl/ustring.hxx>
27 #include <com/sun/star/i18n/Boundary.hpp>
28 #include <com/sun/star/i18n/XBreakIterator.hpp>
29 #include <txttypes.hxx>
30 
31 // for portion replacement in Special()
32 #include <viewopt.hxx>
33 
34 // for GetWordBoundary(...), GetSentenceBoundary(...):
35 #include <breakit.hxx>
36 #include <txtfrm.hxx>
37 
38 // for FillSpecialPos(...)
39 #include <crstate.hxx>
40 
41 using namespace ::com::sun::star;
42 
43 using i18n::Boundary;
44 
45 // 'portion type' for terminating portions
46 #define POR_TERMINATE PortionType::NONE
47 
48 // portion attributes
49 #define PORATTR_SPECIAL 1
50 #define PORATTR_READONLY 2
51 #define PORATTR_GRAY 4
52 #define PORATTR_TERM 128
53 
56 template<typename T>
57 static size_t FindBreak(const std::vector<T>& rPositions, T nValue);
58 
60 template<typename T>
61 static size_t FindLastBreak(const std::vector<T>& rPositions, T nValue);
62 
63 
65  const SwTextFrame *const pTextFrame,
66  const SwViewOption* pViewOpt ) :
68  m_pTextFrame(pTextFrame),
69  m_aBuffer(),
70  m_nViewPosition( 0 ),
71  m_pViewOptions( pViewOpt ),
72  m_sAccessibleString(),
73  m_aLineBreaks(),
74  m_aAccessiblePositions(),
75  m_aFieldPosition(),
76  m_aPortionAttrs(),
77  m_nBeforePortions( 0 ),
78  m_bFinished( false )
79 {
80  OSL_ENSURE( m_pTextFrame != nullptr, "Need SwTextFrame!" );
81 
82  // reserve some space to reduce memory allocations
83  m_aLineBreaks.reserve( 5 );
84  m_ViewPositions.reserve( 10 );
85  m_aAccessiblePositions.reserve( 10 );
86 
87  // always include 'first' line-break position
88  m_aLineBreaks.push_back( 0 );
89 }
90 
92 {
93 }
94 
96  PortionType nType, sal_Int32 /*nHeight*/, sal_Int32 /*nWidth*/)
97 {
98  OSL_ENSURE((m_nViewPosition + nLength) <= TextFrameIndex(m_pTextFrame->GetText().getLength()),
99  "portion exceeds model string!" );
100 
101  OSL_ENSURE( !m_bFinished, "We are already done!" );
102 
103  // ignore zero-length portions
104  if (nLength == TextFrameIndex(0))
105  return;
106 
107  // store 'old' positions
108  m_ViewPositions.push_back( m_nViewPosition );
109  m_aAccessiblePositions.push_back( m_aBuffer.getLength() );
110 
111  // store portion attributes
112  sal_uInt8 nAttr = IsGrayPortionType(nType) ? PORATTR_GRAY : 0;
113  m_aPortionAttrs.push_back( nAttr );
114 
115  // update buffer + nViewPosition
116  m_aBuffer.append(m_pTextFrame->GetText().subView(sal_Int32(m_nViewPosition), sal_Int32(nLength)));
117  m_nViewPosition += nLength;
118 }
119 
121  TextFrameIndex const nLength, const OUString& rText, PortionType nType,
122  sal_Int32 /*nHeight*/, sal_Int32 /*nWidth*/, const SwFont* /*pFont*/)
123 {
124  OSL_ENSURE(m_nViewPosition >= TextFrameIndex(0), "illegal position");
125  OSL_ENSURE((m_nViewPosition + nLength) <= TextFrameIndex(m_pTextFrame->GetText().getLength()),
126  "portion exceeds model string!" );
127 
128  OSL_ENSURE( !m_bFinished, "We are already done!" );
129 
130  // construct string with representation; either directly from
131  // rText, or use resources for special case portions
132  OUString sDisplay;
133  switch( nType )
134  {
136  case PortionType::FlyCnt:
137  sDisplay = OUString(u'\xfffc');
138  break;
139  case PortionType::Field:
140  case PortionType::Hidden:
142  case PortionType::IsoRef:
143  // When the field content is empty, input a special character.
144  if (rText.isEmpty())
145  sDisplay = OUString(u'\xfffc');
146  else
147  sDisplay = rText;
148  m_aFieldPosition.push_back(m_aBuffer.getLength());
149  m_aFieldPosition.push_back(m_aBuffer.getLength() + rText.getLength());
150  break;
152  break;
154  {
155  sDisplay = rText;
156  sal_Int32 nStart=m_aBuffer.getLength();
157  sal_Int32 nEnd=nStart + rText.getLength();
158  m_vecPairPos.emplace_back(nStart,nEnd);
159  break;
160  }
161  break;
162  case PortionType::Number:
163  case PortionType::Bullet:
164  sDisplay = rText + " ";
165  break;
166  // There should probably be some special treatment to graphical bullets
167  case PortionType::GrfNum:
168  break;
169  // #i111768# - apply patch from kstribley:
170  // Include the control characters.
172  sDisplay = rText + OUStringChar(m_pTextFrame->GetText()[sal_Int32(m_nViewPosition)]);
173  break;
175  // TODO
176  break;
177  default:
178  sDisplay = rText;
179  break;
180  }
181 
182  // ignore zero/zero portions (except for terminators)
183  if ((nLength == TextFrameIndex(0)) && (sDisplay.getLength() == 0) && (nType != POR_TERMINATE))
184  return;
185 
186  // special treatment for zero length portion at the beginning:
187  // count as 'before' portion
188  if ((nLength == TextFrameIndex(0)) && (m_nViewPosition == TextFrameIndex(0)))
190 
191  // store the 'old' positions
192  m_ViewPositions.push_back( m_nViewPosition );
193  m_aAccessiblePositions.push_back( m_aBuffer.getLength() );
194 
195  // store portion attributes
196  sal_uInt8 nAttr = PORATTR_SPECIAL;
197  if( IsGrayPortionType(nType) ) nAttr |= PORATTR_GRAY;
198  if (nLength == TextFrameIndex(0)) nAttr |= PORATTR_READONLY;
199  if( nType == POR_TERMINATE ) nAttr |= PORATTR_TERM;
200  m_aPortionAttrs.push_back( nAttr );
201 
202  // update buffer + nViewPosition
203  m_aBuffer.append( sDisplay );
204  m_nViewPosition += nLength;
205 }
206 
207 void SwAccessiblePortionData::LineBreak(sal_Int32 /*nWidth*/)
208 {
209  OSL_ENSURE( !m_bFinished, "We are already done!" );
210 
211  m_aLineBreaks.push_back( m_aBuffer.getLength() );
212 }
213 
215 {
216  OSL_ENSURE( !m_bFinished, "We are already done!" );
217  OSL_ENSURE( m_ViewPositions.empty(), "Never Skip() after portions" );
218  OSL_ENSURE(nLength <= TextFrameIndex(m_pTextFrame->GetText().getLength()),
219  "skip exceeds model string!" );
220 
221  m_nViewPosition += nLength;
222 }
223 
225 {
226  OSL_ENSURE( !m_bFinished, "We are already done!" );
227 
228  // include terminator values: always include two 'last character'
229  // markers in the position arrays to make sure we always find one
230  // position before the end
231  Special( TextFrameIndex(0), OUString(), POR_TERMINATE );
232  Special( TextFrameIndex(0), OUString(), POR_TERMINATE );
233  LineBreak(0);
234  LineBreak(0);
235 
236  m_sAccessibleString = m_aBuffer.makeStringAndClear();
237  m_bFinished = true;
238 }
239 
241  size_t nPortionNo, sal_uInt8 nAttr ) const
242 {
243  OSL_ENSURE( nPortionNo < m_aPortionAttrs.size(),
244  "Illegal portion number" );
245  return (m_aPortionAttrs[nPortionNo] & nAttr) != 0;
246 }
247 
248 bool SwAccessiblePortionData::IsSpecialPortion( size_t nPortionNo ) const
249 {
250  return IsPortionAttrSet(nPortionNo, PORATTR_SPECIAL);
251 }
252 
254 {
255  // gray portions?
256  // Compare with: inftxt.cxx, SwTextPaintInfo::DrawViewOpt(...)
257  bool bGray = false;
258  switch( nType )
259  {
261  case PortionType::IsoRef:
262  case PortionType::Ref:
264  case PortionType::Number:
265  case PortionType::Field:
267  case PortionType::IsoTox:
268  case PortionType::Tox:
269  case PortionType::Hidden:
270  bGray = !m_pViewOptions->IsPagePreview() &&
272  break;
273  case PortionType::Table: bGray = m_pViewOptions->IsTab(); break;
274  case PortionType::SoftHyphen: bGray = m_pViewOptions->IsSoftHyph(); break;
275  case PortionType::Blank: bGray = m_pViewOptions->IsHardBlank(); break;
276  default:
277  break; // bGray is false
278  }
279  return bGray;
280 }
281 
283 {
284  OSL_ENSURE( m_bFinished, "Shouldn't call this before we are done!" );
285 
286  return m_sAccessibleString;
287 }
288 
290  Boundary& rBound,
291  sal_Int32 nPos ) const
292 {
293  FillBoundary( rBound, m_aLineBreaks,
294  FindBreak( m_aLineBreaks, nPos ) );
295 }
296 
297 // #i89175#
299 {
300  size_t nBreaks = m_aLineBreaks.size();
301  // A non-empty paragraph has at least 4 breaks: one for each line3 and
302  // 3 additional ones.
303  // An empty paragraph has 3 breaks.
304  // Less than 3 breaks is an error case.
305  sal_Int32 nLineCount = ( nBreaks > 3 )
306  ? nBreaks - 3
307  : ( ( nBreaks == 3 ) ? 1 : 0 );
308  return nLineCount;
309 }
310 
311 sal_Int32 SwAccessiblePortionData::GetLineNo( const sal_Int32 nPos ) const
312 {
313  sal_Int32 nLineNo = FindBreak( m_aLineBreaks, nPos );
314 
315  // handling of position after last character
316  const sal_Int32 nLineCount( GetLineCount() );
317  if ( nLineNo >= nLineCount )
318  {
319  nLineNo = nLineCount - 1;
320  }
321 
322  return nLineNo;
323 }
324 
325 void SwAccessiblePortionData::GetBoundaryOfLine( const sal_Int32 nLineNo,
326  i18n::Boundary& rLineBound )
327 {
328  FillBoundary( rLineBound, m_aLineBreaks, nLineNo );
329 }
330 
332  Boundary& rBound ) const
333 {
334  OSL_ENSURE( m_aLineBreaks.size() >= 2, "need min + max value" );
335 
336  // The last two positions except the two delimiters are the ones
337  // we are looking for, except for empty paragraphs (nBreaks==3)
338  size_t nBreaks = m_aLineBreaks.size();
339  FillBoundary( rBound, m_aLineBreaks, nBreaks <= 3 ? 0 : nBreaks-4 );
340 }
341 
343 {
344  OSL_ENSURE( nPos >= 0, "illegal position" );
345  OSL_ENSURE( nPos <= m_sAccessibleString.getLength(), "illegal position" );
346 
347  // find the portion number
348  size_t nPortionNo = FindBreak( m_aAccessiblePositions, nPos );
349 
350  // get core view portion size
351  TextFrameIndex nStartPos = m_ViewPositions[nPortionNo];
352 
353  // if it's a non-special portion, move into the portion, else
354  // return the portion start
355  if( ! IsSpecialPortion( nPortionNo ) )
356  {
357  // text portions have to be of the same width
358  OSL_ENSURE( sal_Int32(m_ViewPositions[nPortionNo+1] - nStartPos) ==
359  ( m_aAccessiblePositions[nPortionNo+1] -
360  m_aAccessiblePositions[nPortionNo] ),
361  "accessibility portion disagrees with text model" );
362 
363  nStartPos += TextFrameIndex(nPos - m_aAccessiblePositions[nPortionNo]);
364  }
365  // else: return nStartPos unmodified
366 
367  OSL_ENSURE(nStartPos >= TextFrameIndex(0), "There's something weird in number of characters of SwTextFrame");
368  return nStartPos;
369 }
370 
372  Boundary& rBound,
373  const AccessiblePositions& rPositions,
374  size_t nPos )
375 {
376  rBound.startPos = rPositions[nPos];
377  rBound.endPos = rPositions[nPos+1];
378 }
379 
380 template<typename T>
381 static size_t FindBreak(const std::vector<T>& rPositions, T const nValue)
382 {
383  OSL_ENSURE( rPositions.size() >= 2, "need min + max value" );
384  OSL_ENSURE( rPositions[0] <= nValue, "need min value" );
385  OSL_ENSURE( rPositions[rPositions.size()-1] >= nValue,
386  "need first terminator value" );
387  OSL_ENSURE( rPositions[rPositions.size()-2] >= nValue,
388  "need second terminator value" );
389 
390  size_t nMin = 0;
391  size_t nMax = rPositions.size()-2;
392 
393  // loop until no more than two candidates are left
394  while( nMin+1 < nMax )
395  {
396  // check loop invariants
397  OSL_ENSURE( ( (nMin == 0) && (rPositions[nMin] <= nValue) ) ||
398  ( (nMin != 0) && (rPositions[nMin] < nValue) ),
399  "minvalue not minimal" );
400  OSL_ENSURE( nValue <= rPositions[nMax], "max value not maximal" );
401 
402  // get middle (and ensure progress)
403  size_t nMiddle = (nMin + nMax)/2;
404  OSL_ENSURE( nMin < nMiddle, "progress?" );
405  OSL_ENSURE( nMiddle < nMax, "progress?" );
406 
407  // check array
408  OSL_ENSURE( rPositions[nMin] <= rPositions[nMiddle],
409  "garbled positions array" );
410  OSL_ENSURE( rPositions[nMiddle] <= rPositions[nMax],
411  "garbled positions array" );
412 
413  if( nValue > rPositions[nMiddle] )
414  nMin = nMiddle;
415  else
416  nMax = nMiddle;
417  }
418 
419  // only two are left; we only need to check which one is the winner
420  OSL_ENSURE( (nMax == nMin) || (nMax == nMin+1), "only two left" );
421  if( (rPositions[nMin] < nValue) && (rPositions[nMin+1] <= nValue) )
422  nMin = nMin+1;
423 
424  // finally, check to see whether the returned value is the 'right' position
425  OSL_ENSURE( rPositions[nMin] <= nValue, "not smaller or equal" );
426  OSL_ENSURE( nValue <= rPositions[nMin+1], "not equal or larger" );
427  OSL_ENSURE( (nMin == 0) || (rPositions[nMin-1] <= nValue),
428  "earlier value should have been returned" );
429 
430  OSL_ENSURE( nMin < rPositions.size()-1,
431  "shouldn't return last position (due to terminator values)" );
432 
433  return nMin;
434 }
435 
436 template<typename T>
437 static size_t FindLastBreak(const std::vector<T>& rPositions, T const nValue)
438 {
439  size_t nResult = FindBreak( rPositions, nValue );
440 
441  // skip 'zero-length' portions
442  // #i70538# consider size of <rPosition> and ignore last entry
443  while ( nResult < rPositions.size() - 2 &&
444  rPositions[nResult+1] <= nValue )
445  {
446  nResult++;
447  }
448 
449  return nResult;
450 }
451 
453  Boundary& rBound,
454  sal_Int32 nPos )
455 {
456  OSL_ENSURE( nPos >= 0, "illegal position; check before" );
457  OSL_ENSURE( nPos < m_sAccessibleString.getLength(), "illegal position" );
458 
459  if( m_pSentences == nullptr )
460  {
462 
464  m_pSentences->reserve(10);
465 
466  // use xBreak->endOfSentence to iterate over all words; store
467  // positions in pSentences
468  sal_Int32 nCurrent = 0;
469  sal_Int32 nLength = m_sAccessibleString.getLength();
470  do
471  {
472  m_pSentences->push_back( nCurrent );
473 
474  const TextFrameIndex nFramePos = GetCoreViewPosition(nCurrent);
475 
476  sal_Int32 nNew = g_pBreakIt->GetBreakIter()->endOfSentence(
477  m_sAccessibleString, nCurrent,
478  g_pBreakIt->GetLocale(m_pTextFrame->GetLangOfChar(nFramePos, 0, true))) + 1;
479 
480  if( (nNew < 0) && (nNew > nLength) )
481  nNew = nLength;
482  else if (nNew <= nCurrent)
483  nNew = nCurrent + 1; // ensure forward progress
484 
485  nCurrent = nNew;
486  }
487  while (nCurrent < nLength);
488 
489  // finish with two terminators
490  m_pSentences->push_back( nLength );
491  m_pSentences->push_back( nLength );
492  }
493 
494  FillBoundary( rBound, *m_pSentences, FindBreak( *m_pSentences, nPos ) );
495 }
496 
498  Boundary& rBound,
499  sal_Int32 nPos) const
500 {
501  OSL_ENSURE( m_pTextFrame != nullptr, "Need SwTextNode!" );
502 
503  // attribute boundaries can only occur on portion boundaries
506 }
507 
509 {
510  OSL_ENSURE(nPos <= TextFrameIndex(m_pTextFrame->GetText().getLength()), "illegal position");
511 
512  // find the portion number
513  // #i70538# - consider "empty" model portions - e.g. number portion
514  size_t nPortionNo = FindLastBreak( m_ViewPositions, nPos );
515 
516  sal_Int32 nRet = m_aAccessiblePositions[nPortionNo];
517 
518  // if the view portion has more than one position, go into it;
519  // else return that position
520  TextFrameIndex nStartPos = m_ViewPositions[nPortionNo];
521  TextFrameIndex nEndPos = m_ViewPositions[nPortionNo+1];
522  if (!IsSpecialPortion(nPortionNo))
523  {
524  // text portions have to be of the same width
525  OSL_ENSURE( sal_Int32(nEndPos - nStartPos) ==
526  ( m_aAccessiblePositions[nPortionNo+1] -
527  m_aAccessiblePositions[nPortionNo] ),
528  "accessibility portion disagrees with text model" );
529 
530  TextFrameIndex nWithinPortion = nPos - m_ViewPositions[nPortionNo];
531  nRet += sal_Int32(nWithinPortion);
532  }
533  // else: return nRet unmodified
534 
535  OSL_ENSURE( (nRet >= 0) && (nRet <= m_sAccessibleString.getLength()),
536  "too long!" );
537  return nRet;
538 }
539 
541  sal_Int32 nPos,
542  SwSpecialPos& rPos,
543  SwSpecialPos*& rpPos ) const
544 {
545  size_t nPortionNo = FindLastBreak( m_aAccessiblePositions, nPos );
546 
548  sal_Int32 nRefPos(0);
549  TextFrameIndex nCorePos(0);
550 
551  if( nPortionNo < m_nBeforePortions )
552  {
553  nExtend = SwSPExtendRange::BEFORE;
554  rpPos = &rPos;
555  }
556  else
557  {
558  TextFrameIndex nCoreEndPos = m_ViewPositions[nPortionNo+1];
559  nCorePos = m_ViewPositions[nPortionNo];
560 
561  // skip backwards over zero-length portions, since GetCharRect()
562  // counts all model-zero-length portions as belonging to the
563  // previous portion
564  size_t nCorePortionNo = nPortionNo;
565  while (nCorePos == nCoreEndPos)
566  {
567  nCorePortionNo--;
568  nCoreEndPos = nCorePos;
569  nCorePos = m_ViewPositions[nCorePortionNo];
570 
571  OSL_ENSURE( nCorePos >= TextFrameIndex(0), "Can't happen." );
572  OSL_ENSURE( nCorePortionNo >= m_nBeforePortions, "Can't happen." );
573  }
574  OSL_ENSURE( nCorePos != nCoreEndPos,
575  "portion with core-representation expected" );
576 
577  // if we have anything except plain text, compute nExtend + nRefPos
578  if (IsSpecialPortion(nCorePortionNo))
579  {
580  // case 1: a non-text portion
581  // reference position is the first accessibility for our
582  // core portion
583  nRefPos = m_aAccessiblePositions[ nCorePortionNo ];
584  nExtend = SwSPExtendRange::NONE;
585  rpPos = &rPos;
586  }
587  else if(nPortionNo != nCorePortionNo)
588  {
589  // case 2: a multi-character (text!) portion, followed by
590  // zero-length portions
591  // reference position is the first character of the next
592  // portion, and we are 'behind'
593  nRefPos = m_aAccessiblePositions[ nCorePortionNo+1 ];
594  nExtend = SwSPExtendRange::BEHIND;
595  rpPos = &rPos;
596  }
597  else
598  {
599  // case 3: regular text portion
600  OSL_ENSURE( sal_Int32(nCoreEndPos - nCorePos) ==
601  ( m_aAccessiblePositions[nPortionNo+1] -
602  m_aAccessiblePositions[nPortionNo] ),
603  "text portion expected" );
604 
605  nCorePos += TextFrameIndex(nPos - m_aAccessiblePositions[nPortionNo]);
606  rpPos = nullptr;
607  }
608  }
609  if( rpPos != nullptr )
610  {
611  OSL_ENSURE( rpPos == &rPos, "Yes!" );
612  OSL_ENSURE( nRefPos <= nPos, "wrong reference" );
613 
614  // get the line number, and adjust nRefPos for the line
615  // (if necessary)
616  size_t nRefLine = FindBreak( m_aLineBreaks, nRefPos );
617  size_t nMyLine = FindBreak( m_aLineBreaks, nPos );
618  sal_uInt16 nLineOffset = o3tl::narrowing<sal_uInt16>( nMyLine - nRefLine );
619  if( nLineOffset != 0 )
620  nRefPos = m_aLineBreaks[ nMyLine ];
621 
622  // fill char offset and 'special position'
623  rPos.nCharOfst = nPos - nRefPos;
624  rPos.nExtendRange = nExtend;
625  rPos.nLineOfst = nLineOffset;
626  }
627 
628  return nCorePos;
629 }
630 
631 bool SwAccessiblePortionData::FillBoundaryIFDateField( css::i18n::Boundary& rBound, const sal_Int32 nPos )
632 {
633  if( m_aFieldPosition.size() < 2 )
634  return false;
635  for( size_t i = 0; i < m_aFieldPosition.size() - 1; i += 2 )
636  {
637  if( nPos < m_aFieldPosition[ i + 1 ] && nPos >= m_aFieldPosition[ i ] )
638  {
639  rBound.startPos = m_aFieldPosition[i];
640  rBound.endPos = m_aFieldPosition[i + 1];
641  return true;
642  }
643  }
644  return false;
645 }
646 
648  sal_Int32 nPos,
649  size_t& nPortionNo,
650  TextFrameIndex& rCorePos,
651  bool& bEdit) const
652 {
653  // find portion and get mode position
654  nPortionNo = FindBreak( m_aAccessiblePositions, nPos );
655  rCorePos = m_ViewPositions[ nPortionNo ];
656 
657  // for special portions, make sure we're on a portion boundary
658  // for text portions, add the in-portion offset
659  if( IsSpecialPortion( nPortionNo ) )
660  bEdit &= nPos == m_aAccessiblePositions[nPortionNo];
661  else
662  rCorePos += TextFrameIndex(nPos - m_aAccessiblePositions[nPortionNo]);
663 }
664 
666  sal_Int32 nStart, sal_Int32 nEnd,
667  TextFrameIndex& rCoreStart, TextFrameIndex& rCoreEnd) const
668 {
669  bool bIsEditable = true;
670 
671  // get start and end portions
672  size_t nStartPortion, nEndPortion;
673  AdjustAndCheck( nStart, nStartPortion, rCoreStart, bIsEditable );
674  AdjustAndCheck( nEnd, nEndPortion, rCoreEnd, bIsEditable );
675 
676  // iterate over portions, and make sure there is no read-only portion
677  // in-between
678  size_t nLastPortion = nEndPortion;
679 
680  // don't count last portion if we're in front of a special portion
681  if( IsSpecialPortion(nLastPortion) )
682  {
683  if (nLastPortion > 0)
684  nLastPortion--;
685  else
686  // special case: because size_t is usually unsigned, we can't just
687  // decrease nLastPortion to -1 (which would normally do the job, so
688  // this whole if wouldn't be needed). Instead, we'll do this
689  // special case and just increase the start portion beyond the last
690  // portion to make sure the loop below will have zero iteration.
691  nStartPortion = nLastPortion + 1;
692  }
693 
694  for( size_t nPor = nStartPortion; nPor <= nLastPortion; nPor++ )
695  {
696  bIsEditable &= ! IsPortionAttrSet(nPor, PORATTR_READONLY);
697  }
698 
699  return bIsEditable;
700 }
701 
703 {
704  // a position is valid if it's within the core view positions that we know
705  return (m_ViewPositions[0] <= nPos) && (nPos <= m_ViewPositions.back());
706 }
707 
709 {
710  if (m_ViewPositions.empty()) return true;
711  return m_ViewPositions[0] == TextFrameIndex(0)
712  && m_ViewPositions.back() == TextFrameIndex(0);
713 }
714 
716 {
717  for (const auto & pairPos : m_vecPairPos)
718  {
719  if(nIndex >= pairPos.first && nIndex < pairPos.second )
720  {
721  return true;
722  }
723  }
724  return false;
725 }
726 
728 {
729 // return IsGrayPortion( FindBreak( aAccessiblePositions, nPos ) );
731  PORATTR_GRAY );
732 }
733 
734 sal_Int32 SwAccessiblePortionData::GetFieldIndex(sal_Int32 nPos) const
735 {
736  sal_Int32 nIndex = -1;
737  if( m_aFieldPosition.size() >= 2 )
738  {
739  for( size_t i = 0; i < m_aFieldPosition.size() - 1; i += 2 )
740  {
741  if( nPos <= m_aFieldPosition[ i + 1 ] && nPos >= m_aFieldPosition[ i ] )
742  {
743  nIndex = i/2;
744  break;
745  }
746  }
747  }
748  return nIndex;
749 }
750 
752 {
753  return m_ViewPositions[0];
754 }
755 
757 {
758  return m_ViewPositions.back();
759 }
760 
761 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const OUString & GetAccessibleString() const
get the text string, as presented by the layout
const SwViewOption * m_pViewOptions
Definition: accportions.hxx:47
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:158
#define PORATTR_SPECIAL
Definition: accportions.cxx:49
SwAccessiblePortionData(const SwTextFrame *pTextFrame, const SwViewOption *pViewOpt)
Definition: accportions.cxx:64
AccessiblePositions m_aLineBreaks
Definition: accportions.hxx:62
sal_Int32 nIndex
bool IsPagePreview() const
Definition: viewopt.hxx:635
sal_Int32 nCharOfst
Definition: crstate.hxx:110
LanguageType GetLangOfChar(TextFrameIndex nIndex, sal_uInt16 nScript, bool bNoChar=false) const
Definition: txtfrm.cxx:1345
#define PORATTR_GRAY
Definition: accportions.cxx:51
virtual ~SwAccessiblePortionData() override
Definition: accportions.cxx:91
virtual void LineBreak(sal_Int32 nWidth) override
line break.
TextFrameIndex FillSpecialPos(sal_Int32 nPos, SwSpecialPos &rPos, SwSpecialPos *&rpPos) const
fill a SwSpecialPos structure, suitable for calling SwTextFrame->GetCharRect Returns the core positio...
The SwPortionHandler interface implements a visitor for the layout engine's text portions.
TextFrameIndex GetFirstValidCorePosition() const
bool IsGrayPortionType(PortionType nType) const
OUString m_sAccessibleString
the accessible string note that the content is different both from the string in the text node(s) as ...
Definition: accportions.hxx:53
FramePositions m_ViewPositions
position of line breaks
Definition: accportions.hxx:63
bool IsHardBlank() const
Definition: viewopt.hxx:231
void AdjustAndCheck(sal_Int32 nPos, size_t &nPortionNo, TextFrameIndex &rCorePos, bool &bEdit) const
#define PORATTR_READONLY
Definition: accportions.cxx:50
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1295
#define POR_TERMINATE
Definition: accportions.cxx:46
std::vector< sal_uInt8 > m_aPortionAttrs
Definition: accportions.hxx:67
bool IsReadonly() const
Definition: viewopt.hxx:463
OUStringBuffer m_aBuffer
Definition: accportions.hxx:45
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
SwBreakIt * g_pBreakIt
Definition: breakit.cxx:33
size_t m_nBeforePortions
positions of sentence breaks
Definition: accportions.hxx:71
std::vector< std::pair< sal_Int32, sal_Int32 > > m_vecPairPos
sal_Int32 GetLineCount() const
virtual void Text(TextFrameIndex nLength, PortionType nType, sal_Int32 nHeight=0, sal_Int32 nWidth=0) override
(empty) destructor
Definition: accportions.cxx:95
virtual void Skip(TextFrameIndex nLength) override
skip characters.
static sal_uInt8 nFramePos
Definition: basesh.cxx:112
void GetAttributeBoundary(css::i18n::Boundary &rBound, sal_Int32 nPos) const
void GetLineBoundary(css::i18n::Boundary &rBound, sal_Int32 nPos) const
get the start & end positions of the sentence
std::unique_ptr< AccessiblePositions > m_pSentences
additional portion attributes
Definition: accportions.hxx:69
bool IsInGrayPortion(sal_Int32 nPos)
#define PORATTR_TERM
Definition: accportions.cxx:52
TextFrameIndex GetLastValidCorePosition() const
int i
bool GetEditableRange(sal_Int32 nStart, sal_Int32 nEnd, TextFrameIndex &rCoreStart, TextFrameIndex &rCoreEnd) const
Convert start and end positions into core positions.
void GetBoundaryOfLine(const sal_Int32 nLineNo, css::i18n::Boundary &rLineBound)
static void FillBoundary(css::i18n::Boundary &rBound, const AccessiblePositions &rPositions, size_t nPos)
fill the boundary with the values from rPositions[nPos]
bool FillBoundaryIFDateField(css::i18n::Boundary &rBound, const sal_Int32 nPos)
float u
void GetSentenceBoundary(css::i18n::Boundary &rBound, sal_Int32 nPos)
TextFrameIndex GetCoreViewPosition(sal_Int32 nPos) const
get the position in the core view string for a given (accessibility) position
bool IsTab(bool bHard=false) const
Definition: viewopt.hxx:219
PortionType
Definition: txttypes.hxx:23
TextFrameIndex m_nViewPosition
Definition: accportions.hxx:46
static bool IsFieldShadings()
Definition: viewopt.hxx:671
sal_uInt16 nLineOfst
Definition: crstate.hxx:111
css::uno::Reference< css::i18n::XBreakIterator > const & GetBreakIter() const
Definition: breakit.hxx:62
const css::lang::Locale & GetLocale(const LanguageType aLang)
Definition: breakit.hxx:67
virtual void Finish() override
end of paragraph.
bool IsValidCorePosition(TextFrameIndex nPos) const
Determine whether this core position is valid for these portions.
std::vector< sal_Int32 > AccessiblePositions
Definition: accportions.hxx:59
unsigned char sal_uInt8
sal_Int32 GetLineNo(const sal_Int32 nPos) const
bool IsPortionAttrSet(size_t nPortionNo, sal_uInt8 nAttr) const
Access to portion attributes.
bool m_bFinished
of portions before first core character
Definition: accportions.hxx:72
const char sDisplay[]
AccessiblePositions m_aAccessiblePositions
position of portion breaks in the core view
Definition: accportions.hxx:64
SwSPExtendRange
SwSpecialPos.
Definition: crstate.hxx:103
void GetLastLineBoundary(css::i18n::Boundary &rBound) const
bool IsSoftHyph() const
Definition: viewopt.hxx:264
SwSPExtendRange nExtendRange
Definition: crstate.hxx:112
AccessiblePositions m_aFieldPosition
portion breaks in m_sAccessibleString
Definition: accportions.hxx:65
sal_Int32 nLength
static size_t FindBreak(const std::vector< T > &rPositions, T nValue)
returns the index of the first position whose value is smaller or equal, and whose following value is...
SwTextFrame const * m_pTextFrame
Definition: accportions.hxx:42
sal_Int32 GetAccessiblePosition(TextFrameIndex nPos) const
get the position in the accessibility string for a given view position
bool IsSpecialPortion(size_t nPortionNo) const
sal_Int32 GetFieldIndex(sal_Int32 nPos) const
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
bool IsIndexInFootnode(sal_Int32 nIndex)
static size_t FindLastBreak(const std::vector< T > &rPositions, T nValue)
like FindBreak, but finds the last equal or larger position
virtual void Special(TextFrameIndex nLength, const OUString &rText, PortionType nType, sal_Int32 nHeight=0, sal_Int32 nWidth=0, const SwFont *pFont=nullptr) override
special portion.