diff -r 000000000000 -r 1fb32624e06b textrendering/texthandling/stext/ParseLst.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/textrendering/texthandling/stext/ParseLst.cpp Tue Feb 02 02:02:46 2010 +0200 @@ -0,0 +1,476 @@ +/* +* Copyright (c) 1999-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 "TXTSTD.H" +#include "ParseLst.h" +//++ sort out definitive hash includes + + +CParserList::CParserItem::CParserItem(MParser* aParser, const TUint aTagIndex) +: iParser(aParser), + iTagIndex(aTagIndex) + { + } + + +// Panic the process with UikParse as the category. +void CParserList::Panic(TParserListPanic aPanic) const + { + _LIT(panicStr, "ParseLst"); + User::Panic(panicStr, aPanic); + } + + +CParserList::CParserList() +: iParserList(4) + { + iHighestIndex = 0; + iNumberInList = 0; + } + + +CParserList::~CParserList() + { + iParserList.ResetAndDestroy(); // Reset the list and destroy the CParserItems + iParserList.Close(); // but leave the parsers and free the resources + } + + +// Add parser to appropriate list +void CParserList::ActivateAParserL(MParser* aParser, const TBool aDefaultParser) + { + // Check the index isn't rolling over + // N.B. This is somewhat unlikely. Since index is effectively a 29-bit + // uint (I'm using the top 3 bits as flags) this allows 268435456 parsers + // to be installed. (Assuming we deinstall almost as many, as we went + // along, to avoid OOM.) At 50 per sec that's 20 years continuous action! + __ASSERT_DEBUG((iHighestIndex < EMaxParserIndex), Panic(EParserIndexRollover)); + __ASSERT_DEBUG(aParser, Panic(EParserNullPtr)); + TUint parserIndex = iHighestIndex + 1; + // Adjust flags to describe parser + if (aParser->ReformatOnRecognise()) + parserIndex |= static_cast( EReformatOnRecogniseFlag ); + if (aParser->ReformatOnRollover()) + parserIndex |= EReformatOnRolloverFlag; + if (aDefaultParser) + parserIndex |= EDefaultParserFlag; + // Create a parser item + TInt result; + CParserItem* parserItem = new (ELeave) CParserItem(aParser, parserIndex); + ++iHighestIndex; + if (aDefaultParser) + { + CleanupStack::PushL(parserItem); + result = iParserList.Append(parserItem); + if (result) // We couldn't get it in the main list + User::Leave(result); + CleanupStack::Pop(); + } + else + { + // Look for the end of the specific parsers and the start of the default set + TInt count; + for (count = 0; count < iNumberInList; count++) + { + if (DefaultParser(iParserList[count]->TagIndex())) + break; + } + CleanupStack::PushL(parserItem); + result = iParserList.Insert(parserItem, count); + if (result) // We couldn't get it in the main list + User::Leave(result); + CleanupStack::Pop(); + } + iNumberInList++; + } + + +// Activate an individual parser +void CParserList::ActivateParserL(MParser* aParser) + { + ActivateAParserL(aParser, EFalse); + } + + +// N.B. We can't just delete CParserList and zero TLS when we get back +// to a list with no specific or default parsers because there could be +// an EText left with a local ptr to it. +void CParserList::DeactivateParser(MParser* aParser) + { + __ASSERT_DEBUG(iNumberInList, Panic(EParserNoneActive)); + __ASSERT_DEBUG(aParser, Panic(EParserNullPtr)); + // Run thru list till find entry we need + TInt count; + for (count = 0; count < iNumberInList; count++) + { + if (iParserList[count]->Parser() == aParser) + { + delete iParserList[count]; + iParserList.Remove(count); + break; + } + } + __ASSERT_DEBUG((count < iNumberInList), Panic(EParserInstanceNotActive)); + iNumberInList--; + } + + +// Activate a parser as one of the default set +void CParserList::ActivateDefaultParserL(MParser* aParser) + { + ActivateAParserL(aParser, ETrue); + } + + +//++ Put comment here +void CParserList::DeactivateParserDefaults() + { + if (iNumberInList) + { + // Take them out of the list + while (iNumberInList && DefaultParser(iParserList[iNumberInList - 1]->TagIndex())) + { + // Tell the parser to free itself + iParserList[iNumberInList - 1]->Parser()->Release(); + // Delete the item that refers to it + delete iParserList[iNumberInList - 1]; + // Remove the entry from the list + iParserList.Remove(iNumberInList - 1); + iNumberInList--; + } + } + } + + +// Called by EText to scan an area of text +TBool CParserList::ParseThisText(CRichText& aTextObj,TInt aStartScan,TInt aScanLength,TInt& aStartOfTags,TInt& aLength) + { + TBool foundSomething = EFalse; + TCharFormatX format; + TCharFormatXMask varies; + TPtrC ptr; + TInt endRange; + + // Scan either side of the range in case part of some tagged text was deleted. + if (aStartScan > 0) + { + aStartScan--; + aScanLength++; + } + if (aStartScan + aScanLength < aTextObj.DocumentLength()) + aScanLength++; + + if (iNumberInList && aScanLength) + { + aStartOfTags = aStartScan + aScanLength; + aLength = 0; + for (TInt count = 0; count < iNumberInList; count++) + { + // For each parser in the list + TUint tagIndex = iParserList[count]->TagIndex(); + TInt pos; + MParser* parser = iParserList[count]->Parser(); + TInt localStartScan = aStartScan; + TInt localScanLength = aScanLength; + // Start by removing existing tags for this parser. This ensures + // that old tags that have been invalidated by subsequent editing + // are removed. Any that are still valid will be replaced. + aTextObj.GetExtendedCharFormat(format, varies, localStartScan, aScanLength); + + if (format.iParserTag || varies.AttribIsSet(EAttParserTag)) + { + // At least some of the object contains a non-zero tag - go through it + // Are we starting part way through a tag? + aTextObj.GetExtendedCharFormat(format, varies, localStartScan, 1); + if (format.iParserTag == tagIndex) + { + // The first char of this range has the current parsers tag + // so we need to check backwards for the start of that tag + for (pos = localStartScan; pos > 0; pos--) + { + aTextObj.GetExtendedCharFormat(format, varies, pos - 1, 1); + if (format.iParserTag != tagIndex) + break; + } + // Since we are going to remove a tag starting from here + // we need to allow this area to be rescanned + localScanLength += localStartScan - pos; + localStartScan = pos; + } + // What about off the end? + aTextObj.GetExtendedCharFormat(format, varies, localStartScan + localScanLength - 1, 1); + if (format.iParserTag == tagIndex) + { + // The last char of this range has the current parsers tag + // so we need to check forwards for the end of that tag + pos = localStartScan + localScanLength; + TInt end = aTextObj.DocumentLength(); + while (pos < end) + { + aTextObj.GetTextAndExtendedFormat(ptr, format, pos); + if (format.iParserTag != tagIndex) + break; + pos += ptr.Length(); + } + // Adjust scan length + localScanLength = pos - localStartScan; + } + pos = localStartScan; + while (pos < localStartScan + localScanLength) + { + // Run along the scan range + aTextObj.GetTextAndExtendedFormat(ptr, format, pos); + if (format.iParserTag == tagIndex) + { + // Remove this tag + format.iParserTag = 0; + varies.ClearAll(); + varies.SetAttrib(EAttParserTag); + TRAPD(leaveCode, aTextObj.ApplyExtendedCharFormatL(format, varies, pos, ptr.Length())); + if (leaveCode==KErrNone) + foundSomething = ETrue; // We are removing a tag + if (aLength) + { + if (pos < aStartOfTags) + { + aLength += aStartOfTags - pos; + aStartOfTags = pos; + } + if (pos + ptr.Length() > aStartOfTags + aLength) + aLength = pos + ptr.Length() - aStartOfTags; + } + else + { + aStartOfTags = pos; + aLength = ptr.Length(); + } + } + pos += ptr.Length(); + } + } + endRange = localStartScan + localScanLength; + + // For this parser, run through text looking for changes + TBool allowBack = ETrue; + for (;;) // Run forever + { + TInt localStartTag = aTextObj.DocumentLength(); + TInt localTagLength = 0; + TInt result = parser->ParseThisText(aTextObj, allowBack, localStartScan, localScanLength, localStartTag, localTagLength); + if (!result) + break; + __ASSERT_DEBUG(allowBack || (localStartTag >= localStartScan), Panic(EParserIgnoringAllowFlag)); + TInt startNewTag = localStartTag; + TInt lengthNewTag = localTagLength; + aTextObj.GetExtendedCharFormat(format, varies, localStartTag, localTagLength); + if (format.iParserTag || varies.AttribIsSet(EAttParserTag)) + { + // At least some of this area contains a non-zero tag - go through it + pos = localStartTag; + TBool higher = EFalse; + while (pos < localStartTag + localTagLength) + { + aTextObj.GetTextAndExtendedFormat(ptr, format, pos); + if (format.iParserTag && (MaskedTag(format.iParserTag) < MaskedTag(tagIndex))) + { + // A higher precedence tag is already here so we can't + // insert our tag - let's see how far it goes + TUint tag = format.iParserTag; // Stash tag before overwriting it + TInt len = aTextObj.DocumentLength(); + while (pos < len) + { + aTextObj.GetTextAndExtendedFormat(ptr, format, pos); + if (format.iParserTag != tag) + break; + pos += ptr.Length(); + } + result = EFalse; + startNewTag = pos; + lengthNewTag = 0; + break; + } + // If there aren't any higher precedence tags in here then this + // will save us having to go through again if there aren't any + // lower precedence tags either + if (MaskedTag(format.iParserTag) >= MaskedTag(tagIndex)) + higher = ETrue; + pos += ptr.Length(); + } + if (higher) + { + // There are lower or equal precedence tags in this range + // Do they extend back off the start? + aTextObj.GetExtendedCharFormat(format, varies, localStartTag, 1); + if (format.iParserTag) + { + // need to check backwards + TUint tag = format.iParserTag; // Stash tag before overwriting it + for (pos = localStartTag; pos > 0; pos--) + { + aTextObj.GetExtendedCharFormat(format, varies, pos - 1, 1); + if (format.iParserTag != tag) + break; + } + localTagLength += localStartTag - pos; + localStartTag = pos; + } + // What about off the end? + pos = localStartTag + localTagLength; + aTextObj.GetExtendedCharFormat(format, varies, pos - 1, 1); + if (format.iParserTag) + { + // need to check forwards + TUint tag = format.iParserTag; // Stash tag before overwriting it + TInt len = aTextObj.DocumentLength(); + while (pos < len) + { + aTextObj.GetTextAndExtendedFormat(ptr, format, pos); + if (format.iParserTag != tag) + break; + pos += ptr.Length(); + } + localTagLength = pos - localStartTag; + } + + // Remove all tags in this area - they all have lower precedence + format.iParserTag = 0; + varies.ClearAll(); + varies.SetAttrib(EAttCharLanguage); + TRAPD(leaveCode, aTextObj.ApplyExtendedCharFormatL(format, varies, localStartTag, localTagLength)); + if (leaveCode==KErrNone) + foundSomething = ETrue; // We are removing a tag + } + } + + if (result) + { + // Format tag this area with tagIndex + format.iParserTag = tagIndex; + varies.ClearAll(); + varies.SetAttrib(EAttParserTag); + // Use the original length, not the possibly expanded version + TRAPD(leaveCode, aTextObj.ApplyExtendedCharFormatL(format, varies, startNewTag, lengthNewTag)); + if (leaveCode==KErrNone) + foundSomething = ETrue; // We are applying a tag + if (aLength) + { + if (localStartTag < aStartOfTags) + { + aLength += aStartOfTags - localStartTag; + aStartOfTags = localStartTag; + } + if (localStartTag + localTagLength > aStartOfTags + aLength) + aLength = localStartTag + localTagLength - aStartOfTags; + } + else + { + aStartOfTags = localStartTag; + aLength = localTagLength; + } + } + // Jump over + localScanLength -= startNewTag + lengthNewTag - localStartScan; + localStartScan = startNewTag + lengthNewTag; // Adjust start of next scan run + if (localStartScan >= endRange) // Have we reached the end of the range yet? + break; + allowBack = EFalse; + } + } + } + + return foundSomething; + } + + +// given a tag, fetch a ptr to the parser - or null +MParser* CParserList::ParserWithThisTag(const TUint aTagIndex) const + { + MParser* parser = NULL; + for (TInt count = 0; count < iNumberInList; count++) + { + if (aTagIndex == iParserList[count]->TagIndex()) + { + parser = iParserList[count]->Parser(); + break; + } + } + return parser; + } + +// given a ptr to a parser, fetch a tag - or zero +TUint CParserList::TagForThisParser(const MParser *const aParser) const + { + TUint tagIndex = 0; + for (TInt count = 0; count < iNumberInList; count++) + { + if (aParser == iParserList[count]->Parser()) + { + tagIndex = iParserList[count]->TagIndex(); + break; + } + } + __ASSERT_DEBUG(tagIndex, Panic(EParserNoSuchTag)); + return tagIndex; + } + + +CParserData::CParserData(TInt aEndParse): + iStartParse(0), + iEndParse(aEndParse) + { + // Get parser data + iActiveParserList = (CParserList*)Dll::Tls(); + iLastKnownCursor = -1; + if (iActiveParserList) + iActiveParserList->iRefCount++; + } + + +CParserData::~CParserData() + { + if (iActiveParserList) + { + iActiveParserList->iRefCount--; + if ((iActiveParserList->iRefCount == 0) && (iActiveParserList->iNumberInList == 0)) + { + Dll::FreeTls(); + delete iActiveParserList; + } + } + } + + +// Merge the specified range, which may have changed length, into the current range. +// aOldLength is the # of chars deleted and to be removed from the range +// aNewLength is the # of chars inserted and to be added to the range +void CParserData::MergeRange(TInt aStart,TInt aOldLength,TInt aNewLength) + { + if (iStartParse == -1) // no current range + { + iStartParse = aStart; + iEndParse = aStart + aNewLength; + } + else + { + if (aStart < iStartParse) + iStartParse = aStart; + if (aStart + aOldLength > iEndParse) + iEndParse = aStart + aOldLength; + iEndParse += aNewLength - aOldLength; + } + }