1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accportions.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include "accportions.hxx"
34 #include <tools/debug.hxx>
35 #include <rtl/ustring.hxx>
36 #include <com/sun/star/i18n/Boundary.hpp>
37 #include <txttypes.hxx>
39 // for portion replacement in Special()
43 #include <tools/resid.hxx>
44 #include "viewopt.hxx"
46 // for GetWordBoundary(...), GetSentenceBoundary(...):
47 #include <breakit.hxx>
48 #include <com/sun/star/i18n/WordType.hpp>
49 #include <com/sun/star/i18n/XBreakIterator.hpp>
52 // for FillSpecialPos(...)
53 #include "crstate.hxx"
55 // for SwAccessibleContext::GetResource()
56 #include "acccontext.hxx"
58 // for Post-It replacement text:
59 #include "txatbase.hxx"
62 #include "docufld.hxx"
64 // for in-line graphics replacement:
65 #include "ndindex.hxx"
66 #include "ndnotxt.hxx"
67 #include "fmtflcnt.hxx"
69 #include "fmtcntnt.hxx"
72 using namespace ::com::sun::star
;
75 using rtl::OUStringBuffer
;
79 // 'portion type' for terminating portions
80 #define POR_TERMINATE 0
84 #define PORATTR_SPECIAL 1
85 #define PORATTR_READONLY 2
86 #define PORATTR_GRAY 4
87 #define PORATTR_TERM 128
89 SwAccessiblePortionData::SwAccessiblePortionData(
90 const SwTxtNode
* pTxtNd
,
91 const SwViewOption
* pViewOpt
) :
96 bFinished( sal_False
),
97 pViewOptions( pViewOpt
),
101 aAccessiblePositions(),
103 nBeforePortions( 0 ),
104 bLastIsSpecial( sal_False
)
106 DBG_ASSERT( pTxtNode
!= NULL
, "Text node is needed!" );
108 // reserve some space to reduce memory allocations
109 aLineBreaks
.reserve( 5 );
110 aModelPositions
.reserve( 10 );
111 aAccessiblePositions
.reserve( 10 );
113 // always include 'first' line-break position
114 aLineBreaks
.push_back( 0 );
117 SwAccessiblePortionData::~SwAccessiblePortionData()
122 void SwAccessiblePortionData::Text(USHORT nLength
, USHORT nType
)
124 DBG_ASSERT( (nModelPosition
+ nLength
) <= pTxtNode
->GetTxt().Len(),
125 "portion exceeds model string!" );
127 DBG_ASSERT( !bFinished
, "We are already done!" );
129 // ignore zero-length portions
133 // store 'old' positions
134 aModelPositions
.push_back( nModelPosition
);
135 aAccessiblePositions
.push_back( aBuffer
.getLength() );
137 // store portion attributes
138 sal_uInt8 nAttr
= IsGrayPortionType(nType
) ? PORATTR_GRAY
: 0;
139 aPortionAttrs
.push_back( nAttr
);
141 // update buffer + nModelPosition
142 aBuffer
.append( OUString(
143 pTxtNode
->GetTxt().Copy(
144 static_cast<USHORT
>( nModelPosition
),
146 nModelPosition
+= nLength
;
148 bLastIsSpecial
= sal_False
;
151 void SwAccessiblePortionData::Special(
152 USHORT nLength
, const String
& rText
, USHORT nType
)
154 DBG_ASSERT( nModelPosition
>= 0, "illegal position" );
155 DBG_ASSERT( (nModelPosition
+ nLength
) <= pTxtNode
->GetTxt().Len(),
156 "portion exceeds model string!" );
158 DBG_ASSERT( !bFinished
, "We are already done!" );
160 // construct string with representation; either directly from
161 // rText, or use resources for special case portions
168 sDisplay
= String(sal_Unicode(0xfffc));
173 OUStringBuffer
aTmpBuffer( rText
.Len() + 1 );
174 aTmpBuffer
.append( rText
);
175 aTmpBuffer
.append( sal_Unicode(' ') );
176 sDisplay
= aTmpBuffer
.makeStringAndClear();
184 // ignore zero/zero portions (except for terminators)
185 if( (nLength
== 0) && (sDisplay
.Len() == 0) && (nType
!= POR_TERMINATE
) )
188 // special treatment for zero length portion at the beginning:
189 // count as 'before' portion
190 if( ( nLength
== 0 ) && ( nModelPosition
== 0 ) )
193 // store the 'old' positions
194 aModelPositions
.push_back( nModelPosition
);
195 aAccessiblePositions
.push_back( aBuffer
.getLength() );
197 // store portion attributes
198 sal_uInt8 nAttr
= PORATTR_SPECIAL
;
199 if( IsGrayPortionType(nType
) ) nAttr
|= PORATTR_GRAY
;
200 if( nLength
== 0 ) nAttr
|= PORATTR_READONLY
;
201 if( nType
== POR_TERMINATE
) nAttr
|= PORATTR_TERM
;
202 aPortionAttrs
.push_back( nAttr
);
204 // update buffer + nModelPosition
205 aBuffer
.append( OUString(sDisplay
) );
206 nModelPosition
+= nLength
;
208 // remember 'last' special portion (unless it's our own 'closing'
209 // portions from 'Finish()'
210 if( nType
!= POR_TERMINATE
)
211 bLastIsSpecial
= sal_True
;
214 void SwAccessiblePortionData::LineBreak()
216 DBG_ASSERT( !bFinished
, "We are already done!" );
218 aLineBreaks
.push_back( aBuffer
.getLength() );
221 void SwAccessiblePortionData::Skip(USHORT nLength
)
223 DBG_ASSERT( !bFinished
, "We are already done!" );
224 DBG_ASSERT( aModelPositions
.size() == 0, "Never Skip() after portions" );
225 DBG_ASSERT( nLength
<= pTxtNode
->GetTxt().Len(), "skip exceeds model string!" );
227 nModelPosition
+= nLength
;
230 void SwAccessiblePortionData::Finish()
232 DBG_ASSERT( !bFinished
, "We are already done!" );
234 // include terminator values: always include two 'last character'
235 // markers in the position arrays to make sure we always find one
236 // position before the end
237 Special( 0, String(), POR_TERMINATE
);
238 Special( 0, String(), POR_TERMINATE
);
242 sAccessibleString
= aBuffer
.makeStringAndClear();
243 bFinished
= sal_True
;
247 sal_Bool
SwAccessiblePortionData::IsPortionAttrSet(
248 size_t nPortionNo
, sal_uInt8 nAttr
) const
250 DBG_ASSERT( nPortionNo
< aPortionAttrs
.size(),
251 "Illegal portion number" );
252 return (aPortionAttrs
[nPortionNo
] & nAttr
) != 0;
255 sal_Bool
SwAccessiblePortionData::IsSpecialPortion( size_t nPortionNo
) const
257 return IsPortionAttrSet(nPortionNo
, PORATTR_SPECIAL
);
260 sal_Bool
SwAccessiblePortionData::IsReadOnlyPortion( size_t nPortionNo
) const
262 return IsPortionAttrSet(nPortionNo
, PORATTR_READONLY
);
265 sal_Bool
SwAccessiblePortionData::IsGrayPortion( size_t nPortionNo
) const
267 return IsPortionAttrSet(nPortionNo
, PORATTR_GRAY
);
271 sal_Bool
SwAccessiblePortionData::IsGrayPortionType( USHORT nType
) const
274 // Compare with: inftxt.cxx, SwTxtPaintInfo::DrawViewOpt(...)
275 sal_Bool bGray
= sal_False
;
288 bGray
= !pViewOptions
->IsPagePreview() &&
289 !pViewOptions
->IsReadonly() && SwViewOption::IsFieldShadings();
291 case POR_TAB
: bGray
= pViewOptions
->IsTab(); break;
292 case POR_SOFTHYPH
: bGray
= pViewOptions
->IsSoftHyph(); break;
293 case POR_BLANK
: bGray
= pViewOptions
->IsHardBlank(); break;
295 break; // bGray is false
301 const OUString
& SwAccessiblePortionData::GetAccessibleString() const
303 DBG_ASSERT( bFinished
, "Shouldn't call this before we are done!" );
305 return sAccessibleString
;
309 void SwAccessiblePortionData::GetLineBoundary(
311 sal_Int32 nPos
) const
313 FillBoundary( rBound
, aLineBreaks
,
314 FindBreak( aLineBreaks
, nPos
) );
317 // --> OD 2008-05-30 #i89175#
318 sal_Int32
SwAccessiblePortionData::GetLineCount() const
320 size_t nBreaks
= aLineBreaks
.size();
321 // A non-empty paragraph has at least 4 breaks: one for each line3 and
322 // 3 additional ones.
323 // An empty paragraph has 3 breaks.
324 // Less than 3 breaks is an error case.
325 sal_Int32 nLineCount
= ( nBreaks
> 3 )
327 : ( ( nBreaks
== 3 ) ? 1 : 0 );
331 sal_Int32
SwAccessiblePortionData::GetLineNo( const sal_Int32 nPos
) const
333 sal_Int32 nLineNo
= FindBreak( aLineBreaks
, nPos
);
335 // handling of position after last character
336 const sal_Int32
nLineCount( GetLineCount() );
337 if ( nLineNo
>= nLineCount
)
339 nLineNo
= nLineCount
- 1;
345 void SwAccessiblePortionData::GetBoundaryOfLine( const sal_Int32 nLineNo
,
346 i18n::Boundary
& rLineBound
)
348 FillBoundary( rLineBound
, aLineBreaks
, nLineNo
);
352 void SwAccessiblePortionData::GetLastLineBoundary(
353 Boundary
& rBound
) const
355 DBG_ASSERT( aLineBreaks
.size() >= 2, "need min + max value" );
357 // The last two positions except the two deleimiters are the ones
358 // we are looking for, except for empty paragraphs (nBreaks==3)
359 size_t nBreaks
= aLineBreaks
.size();
360 FillBoundary( rBound
, aLineBreaks
, nBreaks
<= 3 ? 0 : nBreaks
-4 );
363 USHORT
SwAccessiblePortionData::GetModelPosition( sal_Int32 nPos
) const
365 DBG_ASSERT( nPos
>= 0, "illegal position" );
366 DBG_ASSERT( nPos
<= sAccessibleString
.getLength(), "illegal position" );
368 // find the portion number
369 size_t nPortionNo
= FindBreak( aAccessiblePositions
, nPos
);
371 // get model portion size
372 sal_Int32 nStartPos
= aModelPositions
[nPortionNo
];
374 // if it's a non-special portion, move into the portion, else
375 // return the portion start
376 if( ! IsSpecialPortion( nPortionNo
) )
378 // 'wide' portions have to be of the same width
379 DBG_ASSERT( ( aModelPositions
[nPortionNo
+1] - nStartPos
) ==
380 ( aAccessiblePositions
[nPortionNo
+1] -
381 aAccessiblePositions
[nPortionNo
] ),
382 "accesability portion disagrees with text model" );
384 sal_Int32 nWithinPortion
= nPos
- aAccessiblePositions
[nPortionNo
];
385 nStartPos
+= nWithinPortion
;
387 // else: return nStartPos unmodified
389 DBG_ASSERT( (nStartPos
>= 0) && (nStartPos
< USHRT_MAX
),
390 "How can the SwTxtNode have so many characters?" );
391 return static_cast<USHORT
>(nStartPos
);
394 void SwAccessiblePortionData::FillBoundary(
396 const Positions_t
& rPositions
,
399 rBound
.startPos
= rPositions
[nPos
];
400 rBound
.endPos
= rPositions
[nPos
+1];
404 size_t SwAccessiblePortionData::FindBreak(
405 const Positions_t
& rPositions
,
406 sal_Int32 nValue
) const
408 DBG_ASSERT( rPositions
.size() >= 2, "need min + max value" );
409 DBG_ASSERT( rPositions
[0] <= nValue
, "need min value" );
410 DBG_ASSERT( rPositions
[rPositions
.size()-1] >= nValue
,
411 "need first terminator value" );
412 DBG_ASSERT( rPositions
[rPositions
.size()-2] >= nValue
,
413 "need second terminator value" );
416 size_t nMax
= rPositions
.size()-2;
418 // loop until no more than two candidates are left
419 while( nMin
+1 < nMax
)
421 // check loop invariants
422 DBG_ASSERT( ( (nMin
== 0) && (rPositions
[nMin
] <= nValue
) ) ||
423 ( (nMin
!= 0) && (rPositions
[nMin
] < nValue
) ),
424 "minvalue not minimal" );
425 DBG_ASSERT( nValue
<= rPositions
[nMax
], "max value not maximal" );
427 // get middle (and ensure progress)
428 size_t nMiddle
= (nMin
+ nMax
)/2;
429 DBG_ASSERT( nMin
< nMiddle
, "progress?" );
430 DBG_ASSERT( nMiddle
< nMax
, "progress?" );
433 DBG_ASSERT( rPositions
[nMin
] <= rPositions
[nMiddle
],
434 "garbled positions array" );
435 DBG_ASSERT( rPositions
[nMiddle
] <= rPositions
[nMax
],
436 "garbled positions array" );
438 if( nValue
> rPositions
[nMiddle
] )
444 // only two are left; we only need to check which one is the winner
445 DBG_ASSERT( (nMax
== nMin
) || (nMax
== nMin
+1), "only two left" );
446 if( (rPositions
[nMin
] < nValue
) && (rPositions
[nMin
+1] <= nValue
) )
449 // finally, check to see whether the returned value is the 'right' position
450 DBG_ASSERT( rPositions
[nMin
] <= nValue
, "not smaller or equal" );
451 DBG_ASSERT( nValue
<= rPositions
[nMin
+1], "not equal or larger" );
452 DBG_ASSERT( (nMin
== 0) || (rPositions
[nMin
-1] <= nValue
),
453 "earlier value should have been returned" );
455 DBG_ASSERT( nMin
< rPositions
.size()-1,
456 "shouldn't return last position (due to termintator values)" );
461 size_t SwAccessiblePortionData::FindLastBreak(
462 const Positions_t
& rPositions
,
463 sal_Int32 nValue
) const
465 size_t nResult
= FindBreak( rPositions
, nValue
);
467 // skip 'zero-length' portions
468 // --> OD 2006-10-19 #i70538#
469 // consider size of <rPosition> and ignore last entry
470 // while( rPositions[nResult+1] <= nValue )
471 while ( nResult
< rPositions
.size() - 2 &&
472 rPositions
[nResult
+1] <= nValue
)
482 void SwAccessiblePortionData::GetSentenceBoundary(
486 DBG_ASSERT( nPos
>= 0, "illegal position; check before" );
487 DBG_ASSERT( nPos
< sAccessibleString
.getLength(), "illegal position" );
489 if( pSentences
== NULL
)
491 DBG_ASSERT( pBreakIt
!= NULL
, "We always need a break." );
492 DBG_ASSERT( pBreakIt
->GetBreakIter().is(), "No break-iterator." );
493 if( pBreakIt
->GetBreakIter().is() )
495 pSentences
= new Positions_t();
496 pSentences
->reserve(10);
498 // use xBreak->endOfSentence to iterate over all words; store
499 // positions in pSentences
500 sal_Int32 nCurrent
= 0;
501 sal_Int32 nLength
= sAccessibleString
.getLength();
504 pSentences
->push_back( nCurrent
);
506 USHORT nModelPos
= GetModelPosition( nCurrent
);
508 sal_Int32 nNew
= pBreakIt
->GetBreakIter()->endOfSentence(
509 sAccessibleString
, nCurrent
,
510 pBreakIt
->GetLocale(pTxtNode
->GetLang(nModelPos
)) ) + 1;
512 if( (nNew
< 0) && (nNew
> nLength
) )
514 else if (nNew
<= nCurrent
)
515 nNew
= nCurrent
+ 1; // ensure forward progress
519 while (nCurrent
< nLength
);
521 // finish with two terminators
522 pSentences
->push_back( nLength
);
523 pSentences
->push_back( nLength
);
527 // no break iterator -> empty word
534 FillBoundary( rBound
, *pSentences
, FindBreak( *pSentences
, nPos
) );
537 void SwAccessiblePortionData::GetAttributeBoundary(
539 sal_Int32 nPos
) const
541 DBG_ASSERT( pTxtNode
!= NULL
, "Need SwTxtNode!" );
543 // attribute boundaries can only occur on portion boundaries
544 FillBoundary( rBound
, aAccessiblePositions
,
545 FindBreak( aAccessiblePositions
, nPos
) );
549 sal_Int32
SwAccessiblePortionData::GetAccessiblePosition( USHORT nPos
) const
551 DBG_ASSERT( nPos
<= pTxtNode
->GetTxt().Len(), "illegal position" );
553 // find the portion number
554 // --> OD 2006-10-19 #i70538#
555 // consider "empty" model portions - e.g. number portion
556 size_t nPortionNo
= FindLastBreak( aModelPositions
,
557 static_cast<sal_Int32
>(nPos
) );
560 sal_Int32 nRet
= aAccessiblePositions
[nPortionNo
];
562 // if the model portion has more than one position, go into it;
563 // else return that position
564 sal_Int32 nStartPos
= aModelPositions
[nPortionNo
];
565 sal_Int32 nEndPos
= aModelPositions
[nPortionNo
+1];
566 if( (nEndPos
- nStartPos
) > 1 )
568 // 'wide' portions have to be of the same width
569 DBG_ASSERT( ( nEndPos
- nStartPos
) ==
570 ( aAccessiblePositions
[nPortionNo
+1] -
571 aAccessiblePositions
[nPortionNo
] ),
572 "accesability portion disagrees with text model" );
574 sal_Int32 nWithinPortion
= nPos
- aModelPositions
[nPortionNo
];
575 nRet
+= nWithinPortion
;
577 // else: return nRet unmodified
579 DBG_ASSERT( (nRet
>= 0) && (nRet
<= sAccessibleString
.getLength()),
584 USHORT
SwAccessiblePortionData::FillSpecialPos(
587 SwSpecialPos
*& rpPos
) const
589 size_t nPortionNo
= FindLastBreak( aAccessiblePositions
, nPos
);
591 BYTE
nExtend(SP_EXTEND_RANGE_NONE
);
592 sal_Int32
nRefPos(0);
593 sal_Int32
nModelPos(0);
595 if( nPortionNo
< nBeforePortions
)
597 nExtend
= SP_EXTEND_RANGE_BEFORE
;
602 sal_Int32 nModelEndPos
= aModelPositions
[nPortionNo
+1];
603 nModelPos
= aModelPositions
[nPortionNo
];
605 // skip backwards over zero-length portions, since GetCharRect()
606 // counts all model-zero-length portions as belonging to the
608 size_t nCorePortionNo
= nPortionNo
;
609 while( nModelPos
== nModelEndPos
)
612 nModelEndPos
= nModelPos
;
613 nModelPos
= aModelPositions
[nCorePortionNo
];
615 DBG_ASSERT( nModelPos
>= 0, "Can't happen." );
616 DBG_ASSERT( nCorePortionNo
>= nBeforePortions
, "Can't happen." );
618 DBG_ASSERT( nModelPos
!= nModelEndPos
,
619 "portion with core-representation expected" );
621 // if we have anything except plain text, compute nExtend + nRefPos
622 if( (nModelEndPos
- nModelPos
== 1) &&
623 (pTxtNode
->GetTxt().GetChar(static_cast<USHORT
>(nModelPos
)) !=
624 sAccessibleString
.getStr()[nPos
]) )
626 // case 1: a one-character, non-text portion
627 // reference position is the first accessibilty for our
629 nRefPos
= aAccessiblePositions
[ nCorePortionNo
];
630 nExtend
= SP_EXTEND_RANGE_NONE
;
633 else if(nPortionNo
!= nCorePortionNo
)
635 // case 2: a multi-character (text!) portion, followed by
636 // zero-length portions
637 // reference position is the first character of the next
638 // portion, and we are 'behind'
639 nRefPos
= aAccessiblePositions
[ nCorePortionNo
+1 ];
640 nExtend
= SP_EXTEND_RANGE_BEHIND
;
645 // case 3: regular text portion
646 DBG_ASSERT( ( nModelEndPos
- nModelPos
) ==
647 ( aAccessiblePositions
[nPortionNo
+1] -
648 aAccessiblePositions
[nPortionNo
] ),
649 "text portion expected" );
651 nModelPos
+= nPos
- aAccessiblePositions
[ nPortionNo
];
657 DBG_ASSERT( rpPos
== &rPos
, "Yes!" );
658 DBG_ASSERT( nRefPos
<= nPos
, "wrong reference" );
659 DBG_ASSERT( (nExtend
== SP_EXTEND_RANGE_NONE
) ||
660 (nExtend
== SP_EXTEND_RANGE_BEFORE
) ||
661 (nExtend
== SP_EXTEND_RANGE_BEHIND
), "need extend" );
663 // get the line number, and adjust nRefPos for the line
665 size_t nRefLine
= FindBreak( aLineBreaks
, nRefPos
);
666 size_t nMyLine
= FindBreak( aLineBreaks
, nPos
);
667 USHORT nLineOffset
= static_cast<USHORT
>( nMyLine
- nRefLine
);
668 if( nLineOffset
!= 0 )
669 nRefPos
= aLineBreaks
[ nMyLine
];
671 // fill char offset and 'special position'
672 rPos
.nCharOfst
= static_cast<USHORT
>( nPos
- nRefPos
);
673 rPos
.nExtendRange
= nExtend
;
674 rPos
.nLineOfst
= nLineOffset
;
677 return static_cast<USHORT
>( nModelPos
);
680 void SwAccessiblePortionData::AdjustAndCheck(
684 sal_Bool
& bEdit
) const
686 // find portion and get mode position
687 nPortionNo
= FindBreak( aAccessiblePositions
, nPos
);
688 nCorePos
= static_cast<USHORT
>( aModelPositions
[ nPortionNo
] );
690 // for special portions, make sure we're on a portion boundary
691 // for text portions, add the in-portion offset
692 if( IsSpecialPortion( nPortionNo
) )
693 bEdit
&= nPos
== aAccessiblePositions
[nPortionNo
];
695 nCorePos
= static_cast<USHORT
>( nCorePos
+
696 nPos
- aAccessiblePositions
[nPortionNo
] );
699 sal_Bool
SwAccessiblePortionData::GetEditableRange(
700 sal_Int32 nStart
, sal_Int32 nEnd
,
701 USHORT
& nCoreStart
, USHORT
& nCoreEnd
) const
703 sal_Bool bIsEditable
= sal_True
;
705 // get start and end portions
706 size_t nStartPortion
, nEndPortion
;
707 AdjustAndCheck( nStart
, nStartPortion
, nCoreStart
, bIsEditable
);
708 AdjustAndCheck( nEnd
, nEndPortion
, nCoreEnd
, bIsEditable
);
710 // iterate over portions, and make sure there is no read-only portion
712 size_t nLastPortion
= nEndPortion
;
714 // don't count last portion if we're in front of a special portion
715 if( IsSpecialPortion(nLastPortion
) )
717 if (nLastPortion
> 0)
720 // special case: because size_t is usually unsigned, we can't just
721 // decrease nLastPortion to -1 (which would normally do the job, so
722 // this whole if wouldn't be needed). Instead, we'll do this
723 // special case and just increae the start portion beyond the last
724 // portion to make sure the loop below will have zero iteration.
725 nStartPortion
= nLastPortion
+ 1;
728 for( size_t nPor
= nStartPortion
; nPor
<= nLastPortion
; nPor
++ )
730 bIsEditable
&= ! IsReadOnlyPortion( nPor
);
736 sal_Bool
SwAccessiblePortionData::IsValidCorePosition( USHORT nPos
) const
738 // a position is valid its within the model positions that we know
739 return ( aModelPositions
[0] <= nPos
) &&
740 ( nPos
<= aModelPositions
[ aModelPositions
.size()-1 ] );
743 USHORT
SwAccessiblePortionData::GetFirstValidCorePosition() const
745 return static_cast<USHORT
>( aModelPositions
[0] );
748 USHORT
SwAccessiblePortionData::GetLastValidCorePosition() const
750 return static_cast<USHORT
>( aModelPositions
[ aModelPositions
.size()-1 ] );