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