textrendering/texthandling/stext/Txtparse.cpp
changeset 0 1fb32624e06b
child 40 91ef7621b7fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/textrendering/texthandling/stext/Txtparse.cpp	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,357 @@
+/*
+* 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 "TXTRICH.H"
+#include "TXTSTD.H"
+#include "ParseLst.h"
+
+
+// Install and activate a particular parser, app provides instance
+EXPORT_C void CRichText::ActivateParserL(MParser* aParser)
+	{
+	CParserList* activeParserList = (CParserList*)Dll::Tls();
+	if (!activeParserList)
+		{
+		CreateParserETextTLSL();
+		activeParserList = (CParserList*)Dll::Tls();
+		}
+	activeParserList->ActivateParserL(aParser);
+	}
+
+
+// Deactivate and deinstall a particular parser, identified by ptr to instance
+EXPORT_C void CRichText::DeactivateParser(MParser* aParser)
+	{
+	CParserList* activeParserList = (CParserList*)Dll::Tls();
+	__ASSERT_DEBUG(activeParserList, Panic(EParserListNotInitialized));
+	activeParserList->DeactivateParser(aParser);
+	if ((activeParserList->iRefCount == 0) && (activeParserList->iNumberInList == 0))
+		{
+		Dll::FreeTls();
+		delete activeParserList;
+		}
+	}
+
+
+// Install and activate a parser in the default set
+EXPORT_C void CRichText::ActivateDefaultParserL(MParser* aParser)
+	{
+	CParserList* activeParserList = (CParserList*)Dll::Tls();
+	if (!activeParserList)
+		{
+		CreateParserETextTLSL();
+		activeParserList = (CParserList*)Dll::Tls();
+		}
+	activeParserList->ActivateDefaultParserL(aParser);
+	}
+
+
+// Deactivate and deinstall the standard set of default parsers
+EXPORT_C void CRichText::DeactivateParserDefaults()
+	{
+	CParserList* activeParserList = (CParserList*)Dll::Tls();
+	if (activeParserList)
+		{
+		activeParserList->DeactivateParserDefaults();
+		if ((activeParserList->iRefCount == 0) && (activeParserList->iNumberInList == 0))
+			{
+			Dll::FreeTls();
+			delete activeParserList;
+			}
+		}
+	}
+
+
+// Create ParserLst instance and retain ownership of it but pass address to EText TLS
+void CRichText::CreateParserETextTLSL()
+	{
+	__ASSERT_DEBUG(Dll::Tls() == NULL, Panic(EParserListAlreadyExists));
+	CParserList* activeParserList = new (ELeave) CParserList;
+	CleanupStack::PushL(activeParserList);
+	TInt err = Dll::SetTls(activeParserList);
+	User::LeaveIfError(err);
+	CleanupStack::Pop(activeParserList);
+	}
+
+
+// Set observer callback to tell whenever the object has been edited.
+// If set set then the parser system is active for this instance, otherwise not.
+
+ 
+
+EXPORT_C void CRichText::SetEditObserver(MEditObserver* aEditObserver)
+/** Sets the rich text object's edit observer. The observer's EditObserver() function 
+is called by the rich text object each time the object's text content is edited 
+(e.g. after a paste, insert, delete, reset etc.).
+
+@param aEditObserver Pointer to the edit observer. */
+	{
+	iParserData->iEditObserver = aEditObserver;
+	}
+
+	
+EXPORT_C TBool CRichText::ParseText(TInt& aStartOfTags, TInt& aLength, TBool aForceScanAllText)
+	{
+	__ASSERT_ALWAYS(iIndex.IsPtr(),Panic(EParserListTextIndexNotInitialized));
+	TBool foundSomething = EFalse;
+	if (iParserData->iActiveParserList && iParserData->iEditObserver)
+		{
+		if (aForceScanAllText)
+			foundSomething = iParserData->iActiveParserList->ParseThisText(*this,0,DocumentLength(),
+																		   aStartOfTags,aLength);
+		else if (iParserData->HaveRange())
+			foundSomething = iParserData->iActiveParserList->ParseThisText(*this,iParserData->StartParse(),
+									iParserData->EndParse() - iParserData->StartParse(),
+									aStartOfTags,aLength);
+		// All parsers have scanned the area
+		iParserData->KillRange();
+		}
+	return foundSomething;
+	}
+
+
+// Given a cursor position, is there a tag under it and, if so, give me details	
+TBool CRichText::DoCursorOverTag(TInt aPos, MParser*& aParser, TInt& aTagStart, TInt& aLength) const
+	{
+	TCharFormatX format;
+	TCharFormatXMask varies;
+	TBool success = EFalse;
+	TBuf<1> buf;
+
+	__ASSERT_DEBUG(iParserData->iActiveParserList, Panic(EParserListNotInitialized));
+	__ASSERT_DEBUG(iParserData->iEditObserver, Panic(EParserListNotActive));
+	GetExtendedCharFormat(format, varies, aPos, 1);
+	Extract(buf, aPos, 1);
+	if ((format.iParserTag) && (buf[0] != 0x2029))
+		{
+		aParser = iParserData->iActiveParserList->ParserWithThisTag(format.iParserTag);
+		if (aParser == NULL)
+			{ // Parser has been deactivated
+			return EFalse;
+			}
+		// Get extent of tag (or set of contiguous tags for same parser)
+		TInt pos = aPos;
+		TInt startScan;
+		TInt scanLength;
+		// need to check backwards
+		TUint tag = format.iParserTag;	// Stash tag before overwriting it
+		for (; pos > 0; pos--)
+			{
+			GetExtendedCharFormat(format, varies, pos - 1, 1);
+			Extract(buf, aPos, 1);
+			if ((format.iParserTag != tag) || (buf[0] == 0x2029))
+				break;
+			}
+		startScan = pos;
+		// Now forwards
+		TInt len = DocumentLength();
+		while (pos < len)
+			{
+			TPtrC ptr;
+			GetTextAndExtendedFormat(ptr, format, pos);
+			if (format.iParserTag != tag)
+				break;
+			pos += ptr.Length();
+			}
+		if (pos > len)
+			pos = len;
+		scanLength = pos - startScan;
+		// Now use the parser that found it originally to isolate the exact range
+		// of the tag from the range that could contain several
+		for (;;)
+			{
+			TInt result = aParser->ParseThisText(*this, EFalse, startScan, scanLength, aTagStart, aLength);
+			// Check we haven't gone past it (failed to find it this time)
+			if (!result || (aTagStart > aPos))
+				break;
+			if ((aPos >= aTagStart) && (aPos < aTagStart + aLength))
+				{
+				// We've found it
+				success = ETrue;
+				break;
+				}
+			// Not yet, skip over that one
+			startScan += aLength;
+			scanLength -= aLength;
+			if (scanLength < 0)
+				break;
+			}
+	
+		}
+	return success;
+	}
+
+
+EXPORT_C TBool CRichText::CursorOverTag(TInt aPos, MParser*& aParser, TInt& aTagStart, TInt& aLength) const
+	{
+	TBool over = EFalse;
+
+	if (iParserData->iActiveParserList && iParserData->iEditObserver)
+		{
+		iParserData->iLastKnownCursor = aPos;
+		if (DoCursorOverTag(aPos, aParser, aTagStart, aLength))
+			{
+			over = ETrue;
+			}
+		if (aPos && DoCursorOverTag(aPos - 1, aParser, aTagStart, aLength))
+			{
+			over = ETrue;
+			}
+		}
+	return over && 
+		aParser->ConfirmCursorOverTag(*this, aTagStart, aLength, aPos);
+	}
+
+
+EXPORT_C TInt CRichText::PositionOfNextTag(TInt aPos, const MParser * aParser) const
+	{
+	if (iParserData->iActiveParserList && iParserData->iEditObserver)
+		{
+		MParser* parser;
+		TInt tagStart;
+		TInt length;
+		TInt newPos = aPos;
+		TUint tag = 0;
+		if (aParser)
+			tag = iParserData->iActiveParserList->TagForThisParser(aParser);
+		if (DoCursorOverTag(newPos, parser, tagStart, length))
+			newPos = tagStart + length;	// To get past the current tag
+		TPtrC ptr;
+		TCharFormatX format;
+		while (newPos < DocumentLength())
+			{
+			GetTextAndExtendedFormat(ptr, format, newPos);
+			if (format.iParserTag &&(!aParser || format.iParserTag == tag))
+				return newPos;
+			newPos += ptr.Length();
+			}
+		}
+
+	return KErrNotFound;
+	}
+
+
+EXPORT_C TInt CRichText::PositionOfNextTag(TInt aPos) const
+	{
+	return PositionOfNextTag(aPos, NULL);
+	}
+
+
+EXPORT_C TInt CRichText::PositionOfPrevTag(TInt aPos, const MParser * aParser) const
+	{
+	if (iParserData->iActiveParserList && iParserData->iEditObserver)
+		{
+		MParser* parser;
+		TInt tagStart;
+		TInt length;
+		TInt newPos = aPos;
+		TUint tag = 0;
+		if (aParser)
+			tag = iParserData->iActiveParserList->TagForThisParser(aParser);
+		if (DoCursorOverTag(newPos, parser, tagStart, length))
+			newPos = tagStart;	// To get past the current tag
+		TCharFormatX format;
+		TCharFormatXMask varies;
+		
+		for (; newPos > 0; newPos--)
+			{
+			GetExtendedCharFormat(format, varies, newPos - 1, 1);
+			if (format.iParserTag &&(!aParser || format.iParserTag == tag))
+				{
+				if (DoCursorOverTag(newPos - 1, parser, tagStart, length))
+					return tagStart;
+				}
+			}
+		}
+
+	return KErrNotFound;
+	}
+
+
+EXPORT_C TInt CRichText::PositionOfPrevTag(TInt aPos) const
+	{
+	return PositionOfPrevTag(aPos, NULL);
+	}
+
+
+void CRichText::OverrideFormatForParsersIfApplicable(TPtrC& aText, TCharFormatX& aFormat, TInt aStartPos) const
+	{
+	if (aFormat.iParserTag && iParserData->iActiveParserList && iParserData->iEditObserver)
+		{
+		// Replace format
+		TInt start = -1;
+		TInt length = 0;
+		TInt curPos = iParserData->iLastKnownCursor;
+		if (curPos > DocumentLength())
+			curPos = DocumentLength();  // This shouldn't be neccesary but it makes it more
+										// bulletproof if the calls from outside are made in
+										// the wrong order
+		if (curPos != -1)
+			{
+			TCharFormatX format;
+			TCharFormatXMask varies;
+			MParser* parser;
+
+			GetExtendedCharFormat(format, varies, curPos, 1);
+			// If char at curpos has a tag then cursor is over that tag, get extents of tag
+			if (CParserList::ReformatOnRollover(format.iParserTag))
+				DoCursorOverTag(curPos, parser, start, length);
+			else if (curPos)
+				{
+				GetExtendedCharFormat(format, varies, curPos - 1, 1);
+				// Try the char "before" curpos
+				if (CParserList::ReformatOnRollover(format.iParserTag))
+					DoCursorOverTag(curPos - 1, parser, start, length);
+				}
+			}
+
+		MParser* parser = iParserData->iActiveParserList->ParserWithThisTag(aFormat.iParserTag);
+		
+		if (length && (aStartPos >= start) && (aStartPos < start + length))
+			{
+			if (start + length < aStartPos + aText.Length())
+				aText.Set(aText.Left(start + length - aStartPos));
+			if (parser != NULL)
+				{
+				// Only accept the rollover format if the parser agrees 
+				// with the framework match of a tag
+				if (parser->ConfirmCursorOverTag(*this, start, length, curPos))
+					parser->GetRolloverFormat(aFormat.iCharFormat);
+				else 
+					// Reset format to recognised format if parser disagrees
+					// with the framework match as the tag is still in view
+					// and must be formatted as in the else clause below.
+					parser->GetRecogniseFormat(aFormat.iCharFormat);
+				}
+			}
+		else
+			{
+			if (length && (start > aStartPos))
+				aText.Set(aText.Left(start - aStartPos));
+			if (parser != NULL)
+				parser->GetRecogniseFormat(aFormat.iCharFormat);
+			}
+		}
+	}
+
+
+void CRichText::CallEditObserver(TInt aStart, TInt aExtent) const
+	{
+	if (iParserData->iEditObserver)
+		iParserData->iEditObserver->EditObserver(aStart, aExtent);
+	}