os/textandloc/textrendering/texthandling/stext/Txtparse.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: 
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
#include "TXTRICH.H"
sl@0
    20
#include "TXTSTD.H"
sl@0
    21
#include "ParseLst.h"
sl@0
    22
#include "OstTraceDefinitions.h"
sl@0
    23
#ifdef OST_TRACE_COMPILER_IN_USE
sl@0
    24
#include "TxtparseTraces.h"
sl@0
    25
#endif
sl@0
    26
sl@0
    27
sl@0
    28
sl@0
    29
// Install and activate a particular parser, app provides instance
sl@0
    30
EXPORT_C void CRichText::ActivateParserL(MParser* aParser)
sl@0
    31
	{
sl@0
    32
	CParserList* activeParserList = (CParserList*)Dll::Tls();
sl@0
    33
	if (!activeParserList)
sl@0
    34
		{
sl@0
    35
		CreateParserETextTLSL();
sl@0
    36
		activeParserList = (CParserList*)Dll::Tls();
sl@0
    37
		}
sl@0
    38
	activeParserList->ActivateParserL(aParser);
sl@0
    39
	}
sl@0
    40
sl@0
    41
sl@0
    42
// Deactivate and deinstall a particular parser, identified by ptr to instance
sl@0
    43
EXPORT_C void CRichText::DeactivateParser(MParser* aParser)
sl@0
    44
	{
sl@0
    45
	CParserList* activeParserList = (CParserList*)Dll::Tls();
sl@0
    46
	if (!activeParserList)
sl@0
    47
	    {
sl@0
    48
	    OstTrace0( TRACE_DUMP, CRICHTEXT_DEACTIVATEPARSER, "EParserListNotInitialized" );
sl@0
    49
	    }
sl@0
    50
	__ASSERT_DEBUG(activeParserList, Panic(EParserListNotInitialized));
sl@0
    51
	activeParserList->DeactivateParser(aParser);
sl@0
    52
	if ((activeParserList->iRefCount == 0) && (activeParserList->iNumberInList == 0))
sl@0
    53
		{
sl@0
    54
		Dll::FreeTls();
sl@0
    55
		delete activeParserList;
sl@0
    56
		}
sl@0
    57
	}
sl@0
    58
sl@0
    59
sl@0
    60
// Install and activate a parser in the default set
sl@0
    61
EXPORT_C void CRichText::ActivateDefaultParserL(MParser* aParser)
sl@0
    62
	{
sl@0
    63
	CParserList* activeParserList = (CParserList*)Dll::Tls();
sl@0
    64
	if (!activeParserList)
sl@0
    65
		{
sl@0
    66
		CreateParserETextTLSL();
sl@0
    67
		activeParserList = (CParserList*)Dll::Tls();
sl@0
    68
		}
sl@0
    69
	activeParserList->ActivateDefaultParserL(aParser);
sl@0
    70
	}
sl@0
    71
sl@0
    72
sl@0
    73
// Deactivate and deinstall the standard set of default parsers
sl@0
    74
EXPORT_C void CRichText::DeactivateParserDefaults()
sl@0
    75
	{
sl@0
    76
	CParserList* activeParserList = (CParserList*)Dll::Tls();
sl@0
    77
	if (activeParserList)
sl@0
    78
		{
sl@0
    79
		activeParserList->DeactivateParserDefaults();
sl@0
    80
		if ((activeParserList->iRefCount == 0) && (activeParserList->iNumberInList == 0))
sl@0
    81
			{
sl@0
    82
			Dll::FreeTls();
sl@0
    83
			delete activeParserList;
sl@0
    84
			}
sl@0
    85
		}
sl@0
    86
	}
sl@0
    87
sl@0
    88
sl@0
    89
// Create ParserLst instance and retain ownership of it but pass address to EText TLS
sl@0
    90
void CRichText::CreateParserETextTLSL()
sl@0
    91
	{
sl@0
    92
	if (Dll::Tls() != NULL)
sl@0
    93
	    {
sl@0
    94
	    OstTrace0( TRACE_DUMP, CRICHTEXT_CREATEPARSERETEXTTLSL, "EParserListAlreadyExists" );
sl@0
    95
	    }
sl@0
    96
	__ASSERT_DEBUG(Dll::Tls() == NULL, Panic(EParserListAlreadyExists));
sl@0
    97
	CParserList* activeParserList = new (ELeave) CParserList;
sl@0
    98
	CleanupStack::PushL(activeParserList);
sl@0
    99
	TInt err = Dll::SetTls(activeParserList);
sl@0
   100
	User::LeaveIfError(err);
sl@0
   101
	CleanupStack::Pop(activeParserList);
sl@0
   102
	}
sl@0
   103
sl@0
   104
sl@0
   105
// Set observer callback to tell whenever the object has been edited.
sl@0
   106
// If set set then the parser system is active for this instance, otherwise not.
sl@0
   107
sl@0
   108
 
sl@0
   109
sl@0
   110
EXPORT_C void CRichText::SetEditObserver(MEditObserver* aEditObserver)
sl@0
   111
/** Sets the rich text object's edit observer. The observer's EditObserver() function 
sl@0
   112
is called by the rich text object each time the object's text content is edited 
sl@0
   113
(e.g. after a paste, insert, delete, reset etc.).
sl@0
   114
sl@0
   115
@param aEditObserver Pointer to the edit observer. */
sl@0
   116
	{
sl@0
   117
	iParserData->iEditObserver = aEditObserver;
sl@0
   118
	}
sl@0
   119
sl@0
   120
	
sl@0
   121
EXPORT_C TBool CRichText::ParseText(TInt& aStartOfTags, TInt& aLength, TBool aForceScanAllText)
sl@0
   122
	{
sl@0
   123
	if (!iIndex.IsPtr())
sl@0
   124
	    {
sl@0
   125
	    OstTrace0( TRACE_DUMP, CRICHTEXT_PARSETEXT, "EParserListTextIndexNotInitialized" );
sl@0
   126
	    }
sl@0
   127
	__ASSERT_ALWAYS(iIndex.IsPtr(),Panic(EParserListTextIndexNotInitialized));
sl@0
   128
	TBool foundSomething = EFalse;
sl@0
   129
	if (iParserData->iActiveParserList && iParserData->iEditObserver)
sl@0
   130
		{
sl@0
   131
		if (aForceScanAllText)
sl@0
   132
			foundSomething = iParserData->iActiveParserList->ParseThisText(*this,0,DocumentLength(),
sl@0
   133
																		   aStartOfTags,aLength);
sl@0
   134
		else if (iParserData->HaveRange())
sl@0
   135
			foundSomething = iParserData->iActiveParserList->ParseThisText(*this,iParserData->StartParse(),
sl@0
   136
									iParserData->EndParse() - iParserData->StartParse(),
sl@0
   137
									aStartOfTags,aLength);
sl@0
   138
		// All parsers have scanned the area
sl@0
   139
		iParserData->KillRange();
sl@0
   140
		}
sl@0
   141
	return foundSomething;
sl@0
   142
	}
sl@0
   143
sl@0
   144
sl@0
   145
// Given a cursor position, is there a tag under it and, if so, give me details	
sl@0
   146
TBool CRichText::DoCursorOverTag(TInt aPos, MParser*& aParser, TInt& aTagStart, TInt& aLength) const
sl@0
   147
	{
sl@0
   148
	TCharFormatX format;
sl@0
   149
	TCharFormatXMask varies;
sl@0
   150
	TBool success = EFalse;
sl@0
   151
	TBuf<1> buf;
sl@0
   152
sl@0
   153
	if (!iParserData->iActiveParserList)
sl@0
   154
	    {
sl@0
   155
	    OstTrace0( TRACE_DUMP, CRICHTEXT_DOCURSOROVERTAG, "EParserListNotInitialized" );
sl@0
   156
	    }
sl@0
   157
	__ASSERT_DEBUG(iParserData->iActiveParserList, Panic(EParserListNotInitialized));
sl@0
   158
	if (!iParserData->iEditObserver)
sl@0
   159
	    {
sl@0
   160
	    OstTrace0( TRACE_DUMP, DUP1_CRICHTEXT_DOCURSOROVERTAG, "EParserListNotActive" );
sl@0
   161
	    }
sl@0
   162
	__ASSERT_DEBUG(iParserData->iEditObserver, Panic(EParserListNotActive));
sl@0
   163
	GetExtendedCharFormat(format, varies, aPos, 1);
sl@0
   164
	Extract(buf, aPos, 1);
sl@0
   165
	if ((format.iParserTag) && (buf[0] != 0x2029))
sl@0
   166
		{
sl@0
   167
		aParser = iParserData->iActiveParserList->ParserWithThisTag(format.iParserTag);
sl@0
   168
		if (aParser == NULL)
sl@0
   169
			{ // Parser has been deactivated
sl@0
   170
			return EFalse;
sl@0
   171
			}
sl@0
   172
		// Get extent of tag (or set of contiguous tags for same parser)
sl@0
   173
		TInt pos = aPos;
sl@0
   174
		TInt startScan;
sl@0
   175
		TInt scanLength;
sl@0
   176
		// need to check backwards
sl@0
   177
		TUint tag = format.iParserTag;	// Stash tag before overwriting it
sl@0
   178
		for (; pos > 0; pos--)
sl@0
   179
			{
sl@0
   180
			GetExtendedCharFormat(format, varies, pos - 1, 1);
sl@0
   181
			Extract(buf, aPos, 1);
sl@0
   182
			if ((format.iParserTag != tag) || (buf[0] == 0x2029))
sl@0
   183
				break;
sl@0
   184
			}
sl@0
   185
		startScan = pos;
sl@0
   186
		// Now forwards
sl@0
   187
		TInt len = DocumentLength();
sl@0
   188
		while (pos < len)
sl@0
   189
			{
sl@0
   190
			TPtrC ptr;
sl@0
   191
			GetTextAndExtendedFormat(ptr, format, pos);
sl@0
   192
			if (format.iParserTag != tag)
sl@0
   193
				break;
sl@0
   194
			pos += ptr.Length();
sl@0
   195
			}
sl@0
   196
		if (pos > len)
sl@0
   197
			pos = len;
sl@0
   198
		scanLength = pos - startScan;
sl@0
   199
		// Now use the parser that found it originally to isolate the exact range
sl@0
   200
		// of the tag from the range that could contain several
sl@0
   201
		for (;;)
sl@0
   202
			{
sl@0
   203
			TInt result = aParser->ParseThisText(*this, EFalse, startScan, scanLength, aTagStart, aLength);
sl@0
   204
			// Check we haven't gone past it (failed to find it this time)
sl@0
   205
			if (!result || (aTagStart > aPos))
sl@0
   206
				break;
sl@0
   207
			if ((aPos >= aTagStart) && (aPos < aTagStart + aLength))
sl@0
   208
				{
sl@0
   209
				// We've found it
sl@0
   210
				success = ETrue;
sl@0
   211
				break;
sl@0
   212
				}
sl@0
   213
			// Not yet, skip over that one
sl@0
   214
			startScan += aLength;
sl@0
   215
			scanLength -= aLength;
sl@0
   216
			if (scanLength < 0)
sl@0
   217
				break;
sl@0
   218
			}
sl@0
   219
	
sl@0
   220
		}
sl@0
   221
	return success;
sl@0
   222
	}
sl@0
   223
sl@0
   224
sl@0
   225
EXPORT_C TBool CRichText::CursorOverTag(TInt aPos, MParser*& aParser, TInt& aTagStart, TInt& aLength) const
sl@0
   226
	{
sl@0
   227
	TBool over = EFalse;
sl@0
   228
sl@0
   229
	if (iParserData->iActiveParserList && iParserData->iEditObserver)
sl@0
   230
		{
sl@0
   231
		iParserData->iLastKnownCursor = aPos;
sl@0
   232
		if (DoCursorOverTag(aPos, aParser, aTagStart, aLength))
sl@0
   233
			{
sl@0
   234
			over = ETrue;
sl@0
   235
			}
sl@0
   236
		if (aPos && DoCursorOverTag(aPos - 1, aParser, aTagStart, aLength))
sl@0
   237
			{
sl@0
   238
			over = ETrue;
sl@0
   239
			}
sl@0
   240
		}
sl@0
   241
	return over && 
sl@0
   242
		aParser->ConfirmCursorOverTag(*this, aTagStart, aLength, aPos);
sl@0
   243
	}
sl@0
   244
sl@0
   245
sl@0
   246
EXPORT_C TInt CRichText::PositionOfNextTag(TInt aPos, const MParser * aParser) const
sl@0
   247
	{
sl@0
   248
	if (iParserData->iActiveParserList && iParserData->iEditObserver)
sl@0
   249
		{
sl@0
   250
		MParser* parser;
sl@0
   251
		TInt tagStart;
sl@0
   252
		TInt length;
sl@0
   253
		TInt newPos = aPos;
sl@0
   254
		TUint tag = 0;
sl@0
   255
		if (aParser)
sl@0
   256
			tag = iParserData->iActiveParserList->TagForThisParser(aParser);
sl@0
   257
		if (DoCursorOverTag(newPos, parser, tagStart, length))
sl@0
   258
			newPos = tagStart + length;	// To get past the current tag
sl@0
   259
		TPtrC ptr;
sl@0
   260
		TCharFormatX format;
sl@0
   261
		while (newPos < DocumentLength())
sl@0
   262
			{
sl@0
   263
			GetTextAndExtendedFormat(ptr, format, newPos);
sl@0
   264
			if (format.iParserTag &&(!aParser || format.iParserTag == tag))
sl@0
   265
				return newPos;
sl@0
   266
			newPos += ptr.Length();
sl@0
   267
			}
sl@0
   268
		}
sl@0
   269
sl@0
   270
	return KErrNotFound;
sl@0
   271
	}
sl@0
   272
sl@0
   273
sl@0
   274
EXPORT_C TInt CRichText::PositionOfNextTag(TInt aPos) const
sl@0
   275
	{
sl@0
   276
	return PositionOfNextTag(aPos, NULL);
sl@0
   277
	}
sl@0
   278
sl@0
   279
sl@0
   280
EXPORT_C TInt CRichText::PositionOfPrevTag(TInt aPos, const MParser * aParser) const
sl@0
   281
	{
sl@0
   282
	if (iParserData->iActiveParserList && iParserData->iEditObserver)
sl@0
   283
		{
sl@0
   284
		MParser* parser;
sl@0
   285
		TInt tagStart;
sl@0
   286
		TInt length;
sl@0
   287
		TInt newPos = aPos;
sl@0
   288
		TUint tag = 0;
sl@0
   289
		if (aParser)
sl@0
   290
			tag = iParserData->iActiveParserList->TagForThisParser(aParser);
sl@0
   291
		if (DoCursorOverTag(newPos, parser, tagStart, length))
sl@0
   292
			newPos = tagStart;	// To get past the current tag
sl@0
   293
		TCharFormatX format;
sl@0
   294
		TCharFormatXMask varies;
sl@0
   295
		
sl@0
   296
		for (; newPos > 0; newPos--)
sl@0
   297
			{
sl@0
   298
			GetExtendedCharFormat(format, varies, newPos - 1, 1);
sl@0
   299
			if (format.iParserTag &&(!aParser || format.iParserTag == tag))
sl@0
   300
				{
sl@0
   301
				if (DoCursorOverTag(newPos - 1, parser, tagStart, length))
sl@0
   302
					return tagStart;
sl@0
   303
				}
sl@0
   304
			}
sl@0
   305
		}
sl@0
   306
sl@0
   307
	return KErrNotFound;
sl@0
   308
	}
sl@0
   309
sl@0
   310
sl@0
   311
EXPORT_C TInt CRichText::PositionOfPrevTag(TInt aPos) const
sl@0
   312
	{
sl@0
   313
	return PositionOfPrevTag(aPos, NULL);
sl@0
   314
	}
sl@0
   315
sl@0
   316
sl@0
   317
void CRichText::OverrideFormatForParsersIfApplicable(TPtrC& aText, TCharFormatX& aFormat, TInt aStartPos) const
sl@0
   318
	{
sl@0
   319
	if (aFormat.iParserTag && iParserData->iActiveParserList && iParserData->iEditObserver)
sl@0
   320
		{
sl@0
   321
		// Replace format
sl@0
   322
		TInt start = -1;
sl@0
   323
		TInt length = 0;
sl@0
   324
		TInt curPos = iParserData->iLastKnownCursor;
sl@0
   325
		if (curPos > DocumentLength())
sl@0
   326
			curPos = DocumentLength();  // This shouldn't be neccesary but it makes it more
sl@0
   327
										// bulletproof if the calls from outside are made in
sl@0
   328
										// the wrong order
sl@0
   329
		if (curPos != -1)
sl@0
   330
			{
sl@0
   331
			TCharFormatX format;
sl@0
   332
			TCharFormatXMask varies;
sl@0
   333
			MParser* parser;
sl@0
   334
sl@0
   335
			GetExtendedCharFormat(format, varies, curPos, 1);
sl@0
   336
			// If char at curpos has a tag then cursor is over that tag, get extents of tag
sl@0
   337
			if (CParserList::ReformatOnRollover(format.iParserTag))
sl@0
   338
				DoCursorOverTag(curPos, parser, start, length);
sl@0
   339
			else if (curPos)
sl@0
   340
				{
sl@0
   341
				GetExtendedCharFormat(format, varies, curPos - 1, 1);
sl@0
   342
				// Try the char "before" curpos
sl@0
   343
				if (CParserList::ReformatOnRollover(format.iParserTag))
sl@0
   344
					DoCursorOverTag(curPos - 1, parser, start, length);
sl@0
   345
				}
sl@0
   346
			}
sl@0
   347
sl@0
   348
		MParser* parser = iParserData->iActiveParserList->ParserWithThisTag(aFormat.iParserTag);
sl@0
   349
		
sl@0
   350
		if (length && (aStartPos >= start) && (aStartPos < start + length))
sl@0
   351
			{
sl@0
   352
			if (start + length < aStartPos + aText.Length())
sl@0
   353
				aText.Set(aText.Left(start + length - aStartPos));
sl@0
   354
			if (parser != NULL)
sl@0
   355
				{
sl@0
   356
				// Only accept the rollover format if the parser agrees 
sl@0
   357
				// with the framework match of a tag
sl@0
   358
				if (parser->ConfirmCursorOverTag(*this, start, length, curPos))
sl@0
   359
					parser->GetRolloverFormat(aFormat.iCharFormat);
sl@0
   360
				else 
sl@0
   361
					// Reset format to recognised format if parser disagrees
sl@0
   362
					// with the framework match as the tag is still in view
sl@0
   363
					// and must be formatted as in the else clause below.
sl@0
   364
					parser->GetRecogniseFormat(aFormat.iCharFormat);
sl@0
   365
				}
sl@0
   366
			}
sl@0
   367
		else
sl@0
   368
			{
sl@0
   369
			if (length && (start > aStartPos))
sl@0
   370
				aText.Set(aText.Left(start - aStartPos));
sl@0
   371
			if (parser != NULL)
sl@0
   372
				parser->GetRecogniseFormat(aFormat.iCharFormat);
sl@0
   373
			}
sl@0
   374
		}
sl@0
   375
	}
sl@0
   376
sl@0
   377
sl@0
   378
void CRichText::CallEditObserver(TInt aStart, TInt aExtent) const
sl@0
   379
	{
sl@0
   380
	if (iParserData->iEditObserver)
sl@0
   381
		iParserData->iEditObserver->EditObserver(aStart, aExtent);
sl@0
   382
	}