textrendering/texthandling/stext/ParseLst.cpp
changeset 0 1fb32624e06b
child 40 91ef7621b7fc
--- /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<TUint>( 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;
+		}
+	}