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