diff -r 000000000000 -r 1fb32624e06b textrendering/texthandling/stext/TXTSCAN.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/textrendering/texthandling/stext/TXTSCAN.CPP Tue Feb 02 02:02:46 2010 +0200 @@ -0,0 +1,441 @@ +/* +* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include "TXTETEXT.H" +#include "TXTSTD.H" + + +EXPORT_C TInt CPlainText::CharPosOfParagraph(TInt& aLength,TInt aParaOffset)const +/** Finds the length and the start position of a paragraph identified by its +paragraph number the first paragraph is numbered zero. + +Notes: + +if aParaOffset is invalid, (equal to or greater than the total number of +paragraphs), the function's return value is EScanEndOfData + +@param aLength On return contains the length of the specified paragraph. +@param aParaOffset The paragraph number. The first paragraph is numbered zero. +@return The document position of the first character in the paragraph. */ + { + __TEST_INVARIANT; + + TInt startPos=aLength=0; + TUint scanMask=(EScanToUnitStart); + aLength=ScanParas(startPos,scanMask); + for (TInt offset=1;offset<=aParaOffset;offset++) + { + if (startPos<=EScanEndOfData) + return EScanEndOfData; + aLength=ScanParas(startPos,scanMask); + } + if (startPos==EScanEndOfData) + startPos=iByteStore->Size()/sizeof(TText); + return startPos-aLength; + } + +EXPORT_C TInt CPlainText::ParagraphNumberForPos(TInt& aPos)const +/** Gets the number of the paragraph which contains a document position. +Paragraph numbering begins at zero. + +@param aPos A document position. Must be valid or a panic occurs. On return, +contains the document position of the first character in the paragraph in +which it is located. +@return The number of the paragraph containing the specified document position. +The first paragraph is numbered zero. */ + { + __TEST_INVARIANT; + + __ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument)); + TUint scanMask=(EScanBackwards|EScanStayIfBoundary|EScanToUnitStart); + ScanParas(aPos,scanMask); + // aPos now holds the 1st char of the paragraph. + TInt paraOffset=0,currentPos=0; + scanMask=EScanToUnitStart; + while (currentPos=0 && aCurrentPos<=DocumentLength(),Panic(ECharPosBeyondDocument)); + aStartPos=aLength=aCurrentPos; + // First find the start of the word. + TUint scanMask=(EScanBackwards| + EScanStayIfBoundary| + EScanToUnitStart); + if (aPictureIsDelimiter) + scanMask|=EScanPictureIsDelimiter; + if (aPunctuationIsDelimiter) + scanMask|=EScanPunctuationIsDelimiter; + ScanWords(aStartPos,scanMask); + // Next find the end of the word. + scanMask=(EScanStayIfBoundary|EScanToUnitEnd); + if (aPictureIsDelimiter) + scanMask|=EScanPictureIsDelimiter; + if (aPunctuationIsDelimiter) + scanMask|=EScanPunctuationIsDelimiter; + ScanWords(aLength,scanMask); + aLength-=aStartPos; + __ASSERT_DEBUG(aLength+aStartPos<=(DocumentLength()+1),Panic(ECharPosBeyondDocument)); + + __TEST_INVARIANT; + } + +EXPORT_C TInt CPlainText::ToParagraphStart(TInt& aPos) const +/** Gets the document position of the start of the paragraph containing the +specified document position. + +@param aPos A document position. Must be valid or a panic occurs. On return, +contains the document position of the first character in the paragraph in +which it is located. +@return The number of characters skipped in scanning to the start of the +paragraph. */ + { + __TEST_INVARIANT; + __ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument)); + + int skipped = 0; + while (aPos > 0) + { + TPtrC8 p = iByteStore->BackPtr(aPos * sizeof(TText)); + const TText* start = (TText*)p.Ptr(); + const TText* end = start + p.Length() / sizeof(TText); + while (end > start) + { + end--; + if (*end == EParagraphDelimiter) + return skipped; + aPos--; + skipped++; + } + } + return skipped; + } + +EXPORT_C TInt CPlainText::WordCount()const +/** Gets a count of the number of words in the text object. + +@return The number of words in the text object. */ + {return CountUnits(EUnitIsWord);} + +EXPORT_C TInt CPlainText::ParagraphCount()const +/** Gets a count of the number of paragraphs in the text object. + +Note: the paragraph delimiter which terminates every text object means this +function always returns a count of at least one. + +@return The number of paragraphs contained in the text object. */ + {//return CountUnits(EUnitIsParagraph);} + TInt pos=0,unitCount=0; + TUint scanMask=(EScanToUnitStart); + while (pos!=EScanEndOfData) + { + unitCount++; + ScanParas(pos,scanMask); + } + return unitCount; + } + +TInt CPlainText::CountUnits(TUnitOfText aContext)const +// Returns the number of units in the document, where +// units are defined by the parameter aContext. +// + { + SScanData scanData; + TInt pos=0,unitCount=0; + TUint scanMask=(EScanToUnitStart|EScanJoinDelimiters|EScanStayIfBoundary); + InitScanControl(pos,scanMask,aContext,scanData); + ScanUnit(pos,aContext,scanData); + // The above code skips over leading white space + scanData.scanMask &=~ EScanStayIfBoundary; + while(pos!=EScanEndOfData) + { + unitCount++; + ScanUnit(pos,aContext,scanData); + }// Count complete, so return pos to the beginning of the data + pos=0; + return unitCount; + } + + + + +EXPORT_C TInt CPlainText::ScanWords(TInt& aPos,TUint& aScanMask)const +/** Scans from a document position to the beginning or end of a word. The +destination is determined by a scan mask. The scan can either be forwards +(the default) or backwards, and the destination may be the first or last +character in the word containing the position, or the first character in +the next word. + +Note: If an attempt is made to scan beyond the end of text delimiter, on return, +aPos is set to EScanEndOfData and the function's return value indicates +the number of characters skipped in passing the end of text delimiter. + +@param aPos The document position from which to scan. Must be valid, or a +panic occurs. On return, contains the new document position. +@param aScanMask The scan mask. See the enumeration whose values begin with +CPlainText::EScanBackwards. +@return The number of characters skipped to reach the new document position. */ + { + __ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument)); + SScanData scanData; + InitScanControl(aPos,aScanMask,EUnitIsWord,scanData); + return ScanUnit(aPos,EUnitIsWord,scanData); + } + +EXPORT_C TInt CPlainText::ScanParas(TInt& aPos,TUint& aScanMask)const +/** Scans from a document position to the beginning or end of a paragraph. The +destination is determined by a scan mask. The scan can either be forwards +(the default) or backwards, and the destination may be the first or last +character in the paragraph containing the position, or the first character in +the next paragraph. + +Note: if an attempt is made to scan beyond the end of text delimiter, on return, +aPos is set to EScanEndOfData ) and the function's return value indicates +the number of characters skipped in passing the end of text delimiter. + +@param aPos The document position to scan from. Must be valid or a panic occurs. +On return, contains the new document position. +@param aScanMask The scan mask. See the enumeration whose values begin with +CPlainText::EScanBackwards. +@return The number of characters skipped to reach the new document position. */ + { + __ASSERT_ALWAYS(aPos>=0 && aPos<=DocumentLength(),Panic(ECharPosBeyondDocument)); + SScanData scanData; + InitScanControl(aPos,aScanMask,EUnitIsParagraph,scanData); + return ScanUnit(aPos,EUnitIsParagraph,scanData); + } + + +void CPlainText::InitScanControl(TInt& aPos,TUint& aScanMask,TUnitOfText aContext,SScanData& aScanData)const +// Initialises the control segment of the bitmask +// used to determine when scan has completed. +// Calls the initialisation of aScanData. +// + { + aScanData.pos=aPos; + aScanData.scanMask=0; + aScanData.scanMask|=aScanMask; + if (aScanData.scanMask & EScanStayIfBoundary) + {//Scan one unit the other way first. + aScanData.scanMask ^= EScanBackwards; // Alter scan direction. + InitScanData(aScanData.pos,aScanData); + TestForDelimiter(aContext,aScanData); + aScanData.scanMask ^= EScanBackwards; // Restore original scan direction. + } + InitScanData(aScanData.pos,aScanData); + if(!aPos && (aScanData.scanMask&(EScanStayIfBoundary|EScanBackwards))==EScanStayIfBoundary) + {//At the start of the buffer and scanning forwards and ScanStayIfBoundary set. + aScanData.scanMask &=~aScanData.EInsideUnit; + } + else + { + TestForDelimiter(aContext,aScanData); + if (aScanData.scanMask & aScanData.EIsDelimiter) + aScanData.scanMask &=~ aScanData.EInsideUnit; + else + aScanData.scanMask |= aScanData.EInsideUnit; + } + if (aScanData.scanMask & EScanBackwards) + {//Set stop flags relative to scan direction + if (aScanData.scanMask & EScanToUnitStart) + aScanData.scanMask |= aScanData.EStopEnd; + if (aScanData.scanMask & EScanToUnitEnd) + aScanData.scanMask |= aScanData.EStopBegin; + } + else + {//Set stop flags relative to scan direction + if (aScanData.scanMask & EScanToUnitStart) + aScanData.scanMask |= aScanData.EStopBegin; + if (aScanData.scanMask & EScanToUnitEnd) + aScanData.scanMask |= aScanData.EStopEnd; + } + } + + +void CPlainText::InitScanData(TInt aPos,SScanData& aScanData)const +// Initialises the necessary elements of the scan structure, for ScanXxx +// methods. These are used to track scan progress. +// + { + aScanData.pos=aPos; + aScanData.oldPos=aPos; + aScanData.currentSegLen=0; + if (aScanData.scanMask & EScanBackwards) + {//Scanning backwards. + aScanData.delta=-1; + aScanData.totalBufLen=aPos; + } + else + {//Scanning forwards. + aScanData.delta=+1; + aScanData.totalBufLen=((iByteStore->Size()/sizeof(TText))-aScanData.pos); + } + } + + +TInt CPlainText::ScanUnit(TInt& aPos,TUnitOfText aContext,SScanData& aScanData)const +// Scan from position aPos, by one unit. +// Update aPos to the current position, and return the number +// of characters skipped or EScanEndOfData if at the end of the buffer. +// + { + while (TestForDelimiter(aContext,aScanData)) + {//More data has been read + if (aScanData.scanMask & aScanData.EInsideUnit) + { + if (aScanData.scanMask & aScanData.EIsDelimiter) + { + aScanData.scanMask &=~aScanData.EInsideUnit; + if (aScanData.scanMask & aScanData.EStopEnd) + break; + } + } + else + { + if (aScanData.scanMask & aScanData.EIsDelimiter) + { + if (!(aScanData.scanMask & EScanJoinDelimiters)) + break; + } + else + { + aScanData.scanMask |= aScanData.EInsideUnit; + if (aScanData.scanMask & aScanData.EStopBegin) + break; + } + } + } + TInt charsSkipped=(aScanData.scanMask & EScanBackwards)? aPos-aScanData.oldPos : + aScanData.oldPos-aPos; + aPos=(aScanData.oldPos<(TInt)(iByteStore->Size()/sizeof(TText)))? aScanData.oldPos : EScanEndOfData; + return charsSkipped; + } + + +TBool CPlainText::TestForDelimiter(TUnitOfText aContext,SScanData& aScanData) const +/** Return ETrue if a character was read successfully. +Set EIsDelimiter flag if the character read +is a delimiter of the appropriate type.*/ + { + aScanData.scanMask |= aScanData.EIsDelimiter; + aScanData.oldPos = aScanData.pos; + TChar c; + if (!GetChar(aScanData,c)) + return FALSE; + + TBool found = FALSE; + if (aContext == EUnitIsParagraph) + found = c == EParagraphDelimiter; + else if (aContext == EUnitIsWord) + { + if (c == EParagraphDelimiter || + c == ELineBreak || + c == EPageBreak || + c == ESpace || + c == ETabCharacter) + found = TRUE; + if (!found && (aScanData.scanMask & EScanPictureIsDelimiter)) + { + if (c == EPictureCharacter) + found = TRUE; + } + if (!found) + { + TChar::TCategory cat = c.GetCategory(); + if (cat == TChar::EZsCategory) // it's a space + found = TRUE; + if (!found && + (aScanData.scanMask & EScanPunctuationIsDelimiter) && + (cat & TChar::EPunctuationGroup)) + { + if (c != EHyphenMinus && + c != EApostrophe && + c != EPotentialHyphen && + c != EHyphen && + c != ERightSingleQuote) + found = TRUE; + } + } + } + + if (found) + aScanData.scanMask |= aScanData.EIsDelimiter; + else + aScanData.scanMask &= ~aScanData.EIsDelimiter; + return TRUE; + } + + +TBool CPlainText::GetChar(SScanData& aScanData,TChar& aChar)const +// If there is one, write the next character to aChar, and return ETrue, +// otherwise return EFalse. +// + { + TPtrC view(_S("a")); // Dummy value cos no default constructor. + if (!aScanData.currentSegLen) + {//First time in, or new segment. + if (!aScanData.totalBufLen) + {//No data left to read. + return EFalse; + } + if (aScanData.delta < 0) + {//Scanning backwards + TPtrC8 tempView=iByteStore->BackPtr(aScanData.pos*sizeof(TText)); + view.Set((TText*)tempView.Ptr(),tempView.Length()/sizeof(TText)); + } + else + {//Scanning forwards + TPtrC8 tempView=iByteStore->Ptr(aScanData.pos*sizeof(TText)); + view.Set((TText*)tempView.Ptr(),tempView.Length()/sizeof(TText)); + }//Ptr now returns a TDes. + aScanData.currentSegLen=(TInt)Min(aScanData.totalBufLen,(TInt)view.Length()); + aScanData.totalBufLen-=aScanData.currentSegLen; + aScanData.buf=(TText*)view.Ptr(); + if (aScanData.delta < 0) + aScanData.buf+=aScanData.currentSegLen-1; + } + aChar=*(aScanData.buf); // aChar takes the character just read. + aScanData.buf+=aScanData.delta; // pText increments correctly for both ASCII and Unicode + aScanData.pos+=aScanData.delta; + aScanData.currentSegLen-=1; // len holds the number of chars left, for ASCII and Unicode + return ETrue; + } + +