You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by jm...@apache.org on 2014/08/28 02:58:12 UTC

[07/21] remove Adobe from directory names (package name still contains Adobe)

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/asdocgen.bat
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/asdocgen.bat b/Squiggly/main/SpellingFramework/asdocgen.bat
new file mode 100644
index 0000000..b458486
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/asdocgen.bat
@@ -0,0 +1,18 @@
+@echo off
+rem Licensed to the Apache Software Foundation (ASF) under one or more
+rem contributor license agreements.  See the NOTICE file distributed with
+rem this work for additional information regarding copyright ownership.
+rem The ASF licenses this file to You under the Apache License, Version 2.0
+rem (the "License"); you may not use this file except in compliance with
+rem the License.  You may obtain a copy of the License at
+rem
+rem     http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing, software
+rem distributed under the License is distributed on an "AS IS" BASIS,
+rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem See the License for the specific language governing permissions and
+rem limitations under the License.
+
+REM This generates the ASDoc for Engine and SInC. Modify the path as you need. TODO: move to build folder.
+"C:\Program Files\Adobe\Adobe Flash Builder 4\sdks\4.0.0\bin\asdoc" -source-path src -doc-classes com.adobe.linguistics.spelling.framework.ResourceConfig com.adobe.linguistics.spelling.framework.SpellingConfiguration com.adobe.linguistics.spelling.framework.SpellingService com.adobe.linguistics.spelling.framework.UserDictionary -library-path "C:\Program Files\Adobe\Adobe Flash Builder 4\sdks\4.0.0\frameworks\libs" -exclude-dependencies=true -output docs -main-title "AdobeSpellingFramework API Documentation 0.4" -package com.adobe.linguistics.spelling.framework "This package provides spell checking framework for easy integration with the Squiggly spelling engine."

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ResourceTable.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ResourceTable.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ResourceTable.as
new file mode 100644
index 0000000..a72a95d
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ResourceTable.as
@@ -0,0 +1,134 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+  
+package com.adobe.linguistics.spelling.framework
+{
+	import flash.utils.IDataInput;
+	import flash.utils.IDataOutput;
+	import flash.utils.IExternalizable;
+	
+	[RemoteClass(alias='com.adobe.linguistics.spelling.framework.ResourceConfig')]
+		
+	/**
+	 * The ResourceTable class contains a table mapping language to the spelling resources. Resources here imply the URL of rule file and dict file to be used for the language.
+	 * 
+	 * @includeExample ../Examples/Flex/ConfigExample/src/ConfigExample.mxml -noswf
+	 * @playerversion Flash 10
+	 * @langversion 3.0
+	 */
+	public class ResourceTable implements IExternalizable
+	{
+		private var _resources:Object;
+		
+		/**
+		 * Constructs a new ResourceTable object that performs language to resource mapping. 
+		 */
+		public function ResourceTable()
+		{
+			_resources = new Object();
+		}
+
+		/**
+		 * A list of languages supported in this ResourceTable
+		 */
+		public function get availableLanguages():Vector.<String>
+		{
+			var result:Vector.<String> = new Vector.<String>();
+			for (var i:String in _resources)
+			{
+				result.push(i);
+			}
+			return result;
+		}
+		
+		/**
+		 * Set the resource for the specified language.
+		 * 
+		 * @param language The language that you want to assign spelling resources to.
+		 * @param resource A <code>Object</code> that behave as an associated array, it 
+		 * contains the path(s) to the resource file(s). For the time being, the only 
+		 * supported resource is hunspell dictionary, which contains a rule file (.aff) and a 
+		 * dictionary file (.dic). 
+		 * 
+		 * @example The following code sets the resource for American English language.
+		 * <listing version="3.0">
+		 * var resourceTable:ResourceTable = new ResourceTable();
+		 * resourceTable.setResource("en_US", {rule:"en_US.aff", dict:"en_US.dic"});
+		 * </listing>
+		 */
+		public function setResource(language:String, resource:Object):void
+		{
+			_resources[language] = resource;
+		}
+		
+		/**
+		 * Get the resource for the specified language.
+		 * 
+		 * @param language The language associated with the resource you are looking for.
+		 * @return An <code>Object</code> that stores the resource file URL(s).
+		 * @example The following code gets and uses the resource for American English language.
+		 * <listing version="3.0">
+		 * var resource_en_US:Object = SpellingConfiguration.resourceTable.getResource("en_US");
+		 * trace("rule file:" + resource_en_US["rule"] + ", dictionary file:" + resource_en_US.dict);
+		 * </listing>
+		 */
+		public function getResource(language:String):Object
+		{
+			return _resources[language];
+		}
+		
+		/**
+		 * Overwrite toString() for debug purpose.
+		 * @private
+		 */
+		public function toString():String
+		{
+			var result:String = new String();
+			for (var i:String in _resources)
+			{
+				result += i;
+				result += ": ";
+				result += "[";
+				for (var j:String in getResource(i))
+				{
+					result += j + ":" + getResource(i)[j] + " "
+				}
+				result += "]";
+				result += "; ";
+			}
+			return result;
+		}
+		
+		/**
+		 * Implement this IExternalizable API so that it can be serialized to an ByteArray.
+		 * @private
+		 */
+		public function readExternal(input:IDataInput):void {
+			_resources = input.readObject();
+		}
+		
+		/**
+		 * Implement this IExternalizable API so that it can be serialized to an ByteArray.
+		 * @private
+		 */
+		public function writeExternal(output:IDataOutput):void {
+			output.writeObject(_resources);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingConfiguration.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingConfiguration.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingConfiguration.as
new file mode 100644
index 0000000..38f316a
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingConfiguration.as
@@ -0,0 +1,102 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+  
+  
+package com.adobe.linguistics.spelling.framework
+{
+	
+	
+	import flash.errors.IllegalOperationError;
+	import com.adobe.linguistics.spelling.core.env.InternalConstants;
+	import com.adobe.linguistics.spelling.framework.ResourceTable;
+	
+	/**
+	 * The SpellingConfiguration is for setting and getting the configuration for the spell checker.
+	 * 
+	 * @includeExample ../Examples/Flex/ConfigExample/src/ConfigExample.mxml -noswf
+	 * @playerversion Flash 10
+	 * @langversion 3.0
+	 */
+	
+	public class SpellingConfiguration
+	{
+		
+
+		private static var _resourceTable:ResourceTable = null;
+		private static var _enableDictionarySplit:Boolean=false;//static value so can be initialised here
+		private static var _wordsPerDictionarySplit:int=InternalConstants.WORDS_PER_SPLIT;
+		
+		/**
+		 * The resourceTable is used for mapping the language to resources.
+		 */
+		public static function get resourceTable():ResourceTable
+		{
+			// Lazy initialization for the default value
+			if (_resourceTable == null) {
+				_resourceTable = new ResourceTable();
+				//_resourceTable.setResource("en_US", {rule:"data/en_US.aff", dict:"data/en_US.dic"});
+			}
+			return _resourceTable;	
+		}
+		
+		public static function set resourceTable(resourceTable:ResourceTable):void
+		{
+			_resourceTable = resourceTable;
+		}
+		
+		/**
+		 * This is a flag that enables/disables loading of dictionary in splits.
+		 * By default this flag is set to <code>false</code>. In case the initial loading time of dictionaries is found slow, this flag should be set to <code>true</code>. By enabling this, squiggly will load dictionary in splits with each split having <code>wordsPerDictionarySplit</code> number of words.
+		 * <p>NOTE: This property, if used, should be set before calling <code>SpellUI.enableSpeliing</code>. Once <code>SpellUI.enableSpeliing</code> is called dictionaries will be loaded according to default values, and this property will not be used. </p>
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public static function get enableDictionarySplit():Boolean
+		{
+			return _enableDictionarySplit;	
+		}
+		
+		public static function set enableDictionarySplit(enableDictionarySplit:Boolean):void
+		{
+			_enableDictionarySplit = enableDictionarySplit;
+		}
+		
+		/**
+		 * This property defines the number of words in one dictionary split.
+		 * By default the value of this property is set to 20000 words. This property is used only if <code>enableDictionarySplit</code> is set to <code>true</code>. If <code>enableDictionarySplit</code> is set to <code>flase</code> this property turns void.
+		 * <p>NOTE: This property, if used, should be defined before calling <code>SpellUI.enableSpeliing</code>. Once <code>SpellUI.enableSpeliing</code> is called dictionaries will be loaded according to default values, and this property will not be used.</p>
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public static function get wordsPerDictionarySplit():int
+		{
+			
+			return _wordsPerDictionarySplit;	
+		}
+		
+		public static function set wordsPerDictionarySplit(wordsPerDictionarySplit:int):void
+		{
+			if(wordsPerDictionarySplit<=0){
+				//Do error Handling
+				throw new IllegalOperationError("wordsPerDictionarySplit should be a positive non-zero value.");
+			}
+			_wordsPerDictionarySplit = wordsPerDictionarySplit;
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingService.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingService.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingService.as
new file mode 100644
index 0000000..9e687ee
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/SpellingService.as
@@ -0,0 +1,241 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+  
+  
+package com.adobe.linguistics.spelling.framework
+{
+	import com.adobe.linguistics.spelling.HunspellDictionary;
+	import com.adobe.linguistics.spelling.SpellChecker;
+	import com.adobe.linguistics.spelling.UserDictionary;
+	import com.adobe.linguistics.spelling.core.UserDictionaryEngine;
+	import com.adobe.linguistics.spelling.core.env.InternalConstants;
+	
+	import flash.events.Event;
+	import flash.events.EventDispatcher;
+//	import flash.utils.Timer;
+//	import flash.events.TimerEvent;
+	
+	/**
+	 * The SpellingService provides spell checking features for the specified language. 
+	 * This class makes use of SpellingConfiguration class to dynamically get the language dictionary location. The dictionaries are then loaded and SpellChecker object
+	 * created based on these dictionaries. SpellingService also caches SpellChecker and dictionary objects for individual languages for efficient reuse.
+	 * @includeExample ../Examples/Flex/SpellingServiceEsg/src/SpellingServiceEsg.mxml -noswf
+	 * @playerversion Flash 10
+	 * @langversion 3.0.
+	 * 
+	 */
+	public class SpellingService extends EventDispatcher
+	{
+		private var _language:String = null;
+		private var _engine:SpellChecker = null;
+		private var _udEngine:UserDictionaryEngine = null;
+		private var _userDictionaries:Array = new Array();
+		
+				
+		// Static table for caching engines and fixed dictionaries
+		private static var _engines:Array = new Array();
+		private static var _dicts:Array = new Array();
+		
+		/**
+		 * Constructs a spelling service object.
+		 *
+		 * @param language The language used to create a <code>SpellingService</code>.
+		 */
+		public function SpellingService(language:String)
+		{
+			_language = language;		
+		}
+
+		/**
+		 * Initialize the <code>SpellingService</code>. Once the initialization is done, an <code>Event.COMPLETE</code> event will be dispatched
+		 * and the <code>SpellingService</code> is ready to be used.
+		 */		
+		public function init():void
+		{
+			_udEngine = new UserDictionaryEngine();
+			
+			// Since the engine and dictionary are shared, the loading has three status
+			// Loaded
+			if (_engines[_language] != null)
+			{
+				loadDictComplete(null);
+			}
+			// Loading
+			else if (_dicts[_language] != null)
+			{
+				_dicts[_language].addEventListener(Event.COMPLETE, loadDictComplete);
+			}
+			// Loading not started
+			else
+			{			
+				var urls:Object = SpellingConfiguration.resourceTable.getResource(_language);
+				var hunspellDict:HunspellDictionary = new HunspellDictionary();
+				_dicts[_language] = hunspellDict;
+				hunspellDict.addEventListener(Event.COMPLETE, loadDictComplete);
+				/*added for check on 10-12-2010
+				var mytimer:Timer =new Timer(50,0);
+				mytimer.start();
+				var initTime:int =mytimer.currentCount;
+				trace(initTime);*/
+				
+				//adding code for enabling loading in parts. Since spelling service class needs SpellingConfiguration so it this property uses it.
+				hunspellDict.enableDictionarySplit=SpellingConfiguration.enableDictionarySplit;//user has to be freed from this. So we have to put a default value in SpellingConfiguration class.
+				hunspellDict.wordsPerDictionarySplit=SpellingConfiguration.wordsPerDictionarySplit;//user has to be freed from this. So we have to put a default value in SpellingConfiguration class.
+				
+				hunspellDict.load(urls["rule"], urls["dict"]);
+				/*var timePassed:int =mytimer.currentCount;
+				trace(timePassed);*/
+			}
+		}
+		
+		private function loadDictComplete(e:Event):void
+		{
+			if (_engines[_language] == null) {
+				_engines[_language] = new SpellChecker(_dicts[_language]);
+			}
+			_engine = _engines[_language];
+			dispatchEvent(new Event(Event.COMPLETE));
+		}
+	
+		/**
+		 * Check the spelling of a word.
+		 *
+		 * @param word The word to be checked.
+		 * @return True if the word is correctly spelled, false if it is misspelled.
+		 */		
+		public function checkWord(word:String):Boolean
+		{
+			return ((_udEngine.spell(word)) || (_engine.checkWord(word)));
+		}
+
+		/**
+		 * Get the suggestion of a misspelled word. 
+		 *
+		 * @param word The word to be checked.
+		 * @return A vector containing all suggestions for the misspelled word, ordered by similarity to the original word. 
+		 * Note that if a word is already correctly spelled, an empty Vector is returned.
+		 * @internal TODO: get the suggestions from user dicitonaries
+		 */			
+		public function getSuggestions(word:String):Vector.<String>
+		{
+			var resultArray:Array = _engine.getSuggestions(word);
+			
+			var resultVector:Vector.<String> = new Vector.<String>();
+			for each (var i:String in resultArray) {
+				resultVector.push(i);		
+			}
+			
+			return resultVector;
+		}
+		
+		/** 
+		 * Add a <code>UserDictionary</code> to the <code>SpellingService</code>.
+		 * 
+		 * @param userDictionary The UserDictionary to be added.
+		 * @return True if the UserDictionary is added successfully, false if any error occurs. An example error scenario: Trying to add a previously added user dictionary. 
+		 * @see UserDictionary
+		 */
+		public function addUserDictionary(userDictionary:UserDictionary):Boolean
+		{
+			if  (_udEngine.addDictionary(userDictionary.internalUserDictionary) == true)
+			{
+				_userDictionaries.push(userDictionary);
+				return true;
+			} 
+			
+			return false;
+		}
+
+		/** 
+		 * Remove a <code>UserDictionary</code> from the <code>SpellingService</code>.
+		 * 
+		 * @param userDictionary The UserDictionary to be removed.
+		 * @return True if the UserDictionary is removed successfully, false if any error occurs. An example error scenario: Trying to remove a user dictionary that has not been added previously. 
+		 * @see UserDictionary
+		 */		
+		public function removeUserDictionary(userDictionary:UserDictionary):Boolean
+		{
+			if (_udEngine.removeDictionary(userDictionary.internalUserDictionary) == true)
+			{
+				for ( var i:int =0; i < _userDictionaries.length; ++i ) {
+					if ( userDictionary == _userDictionaries[i] ) {
+						_userDictionaries.splice(i,1);
+						return true;
+					}
+				}
+			}
+			
+			return false;
+		}
+		
+		/**
+		 * A <code>Vector</code> of user dictionaries added to this <code>SpellingService</code>.
+		 * 
+		 * @return A <code>Vector</code> of <code>UserDictionary</code> objects.
+		 * @see UserDictionary
+		 */
+		public function get userDictionaries():Vector.<UserDictionary>
+		{	
+			var resultVector:Vector.<UserDictionary> = new Vector.<UserDictionary>;
+			for each (var i:UserDictionary in _userDictionaries) {
+				resultVector.push(i);		
+			}
+			
+			return resultVector;
+		}
+		
+		/**
+		 * This property controls if words in all upper-case should be considered as properly spelled or not.
+		 * 
+		 * <table class="innertable">
+		 *		<tr>
+		 *			<td align="center"><strong><code>ignoreWordWithAllUpperCase</code></strong></td>
+		 *			<td align="center"><strong>&#160;</strong></td>
+		 *			<td align="center"><strong>Description</strong></td>
+		 *		</tr>
+		 *		<tr>
+		 *			<td><code>false</code></td>
+		 *			<td>Default</td>
+		 *			<td><p>Words with all characters in upper case are checked against the dictionary for proper spelling.</p>
+		 *				<p>Example: if <code>ignoreWordWithAllUpperCase = false</code>, "MISPEL" will be checked for proper spelling.</p></td>
+		 *		</tr>
+		 *		<tr>
+		 *			<td><code>true</code></td>
+		 *			<td>&#160;</td>
+		 *			<td><p>Any words with all characters in upper case are always considered as properly spelled,
+		 *					no matter whether the word is in the dictionary or not.</p>
+		 *				<p>Example: if <code>ignoreWordWithAllUpperCase = true</code>, "MISPEL" will be considered as properly spelled.</p></td>
+		 *		</tr>
+		 *	</table>
+		 * */
+		/* Getter Function for ignoring all word with all upper case*/
+		public function get ignoreWordWithAllUpperCase():Boolean
+		{
+			return _engine.ignoreWordWithAllUpperCase;
+		}
+		/* Setter Function for ignoring all word with all upper case*/
+		public function set ignoreWordWithAllUpperCase(value:Boolean):void
+		{
+			_engine.ignoreWordWithAllUpperCase=value;
+		}
+		
+	}
+}
+
+

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloHighlighter.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloHighlighter.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloHighlighter.as
new file mode 100644
index 0000000..6945e20
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloHighlighter.as
@@ -0,0 +1,124 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import __AS3__.vec.Vector;
+	
+	import com.adobe.linguistics.utils.Token;
+	
+	import flash.geom.Point;
+	import flash.text.TextField;
+	
+	import mx.core.IUITextField;
+
+	/**
+	 * <p>This class facilitates drawing of squiggly lines below words for TextField class. TextField class is used to create display objects for text display 
+	 * and input for Halo TextArea and TextInput components. HaloHighlighter could therefore be used for drawing squiggly lines in these Halo components.</p>
+	 * 	
+	 * @playerversion Flash 9.x
+	 * @langversion 3.0
+	 */
+
+	public class HaloHighlighter implements IHighlighter
+	{
+		private var mTextField:TextField;
+		private var mHighlighter:SpellingHighlighter;
+		/*
+		* offset point:
+		*/
+		private var _offsetPoint:Point;
+
+		/**
+		 * The constructor for HaloHighlighter.
+		 * @param textField <code>TextField</code> in which to enable highlighting.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function HaloHighlighter( textField:TextField )
+		{
+			if (textField == null ) throw new Error("illegal argument."); 
+			mTextField = textField;
+			mHighlighter = null;
+			this._offsetPoint = new Point(0,0);
+		}
+		/**
+		 * Draw squiggly lines below a given token.
+		 * @param token <code>Token</code> information of the word to be highlighted.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function drawSquiggleAt(token:Token):void
+		{
+			squiggleWord(token);
+		}
+		
+		/**
+		 * Clear all squiggly lines in the TextField.		
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function clearSquiggles():void
+		{
+			if (mHighlighter) {
+				mTextField.parent.removeChild(mHighlighter);
+				mHighlighter=null;
+			}
+			
+		}
+		
+		/**
+		 * Set offset point information for scrollable controls. This is used by the highlighter to move 
+		 * the squiggly lines as the text scrolls inside the control.	
+		 * @param op offset information as a <code>Point</code> instance.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */		
+		public function set offsetPoint(op:Point):void{
+			_offsetPoint = op;
+		}
+		
+		/**
+		 * Get offset point information for scrollable controls. This is used by the highlighter to move 
+		 * the squiggly lines as the text scrolls inside the control.	
+		 * @param op offset information as a <code>Point</code> instance.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */		
+		public function get offsetPoint():Point{
+			return _offsetPoint;
+		}
+		
+
+		private function squiggleWord(token:Token):void {
+						
+			if (!mHighlighter) {
+				mHighlighter= new SpellingHighlighter( mTextField as IUITextField);
+				mTextField.parent.addChild(mHighlighter);				
+			}
+						
+			mHighlighter.drawSquigglyLine(token.first, token.last);
+		
+		
+			//mTextField.parent.addChild(mHighlighter);	
+			mHighlighter.move(_offsetPoint.x, _offsetPoint.y);
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloWordProcessor.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloWordProcessor.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloWordProcessor.as
new file mode 100644
index 0000000..cf77943
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/HaloWordProcessor.as
@@ -0,0 +1,111 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.ITokenizer;
+	import com.adobe.linguistics.utils.TextTokenizer;
+	import com.adobe.linguistics.utils.Token;
+	
+	import flash.text.TextField;
+	import flash.text.TextFormat;
+	
+	import mx.controls.TextArea;
+	import mx.controls.TextInput;
+
+
+	public class HaloWordProcessor implements IWordProcessor
+	{
+		private var mTextField:TextField;
+
+		public function HaloWordProcessor(textField:TextField)
+		{
+			if (textField == null ) throw new Error("illegal argument."); 
+			mTextField = textField;
+		}
+				
+		
+		public function replaceText(token:Token, replacement:String):void {
+			var startIndex:int = token.first;
+			var endIndex:int = token.last;
+			
+			if ( replacement == null ) return;
+			
+			if (mTextField.text.length<endIndex || startIndex<0) {
+				return;
+			}
+			
+			var _misspellStart:int = startIndex;
+			var _misspellEnd:int = endIndex;
+			// Try to preserve the format, this works if the whole misspelled word is the same format
+			var tf:TextFormat = mTextField.getTextFormat(_misspellStart, _misspellEnd);
+			mTextField.replaceText(_misspellStart, _misspellEnd, replacement);	
+			mTextField.setTextFormat(tf, _misspellStart, _misspellStart+replacement.length);
+			
+			var ta:TextArea = mTextField.parent as TextArea;
+			var ti:TextInput = mTextField.parent as TextInput;
+			
+			if (ta != null) {
+				ta.selectionBeginIndex = _misspellStart + replacement.length;
+				ta.selectionEndIndex = _misspellStart + replacement.length;
+			}
+			else if (ti != null) {
+				ti.selectionBeginIndex = _misspellStart + replacement.length;
+				ti.selectionEndIndex = _misspellStart + replacement.length;				
+			}
+			else {
+				// Do nothing if it's not a valid text component
+			}
+		}
+
+		
+		public function getWordAtPoint(x:uint, y:uint, externalTokenizer:ITokenizer=null):Token
+		{
+			var _token:Token = tryGetWordAtPoint(x,y, externalTokenizer);
+			return _token;
+		}
+		
+		private function tryGetWordAtPoint(x:uint, y:uint, externalTokenizer:ITokenizer=null):Token {
+			// TODO: use a better alternative than _misspellStart, end
+			var index:uint = mTextField.getCharIndexAtPoint(x + mTextField.scrollH, y);
+			if (index >= mTextField.text.length) return null;
+
+			var tmpToken:Token = new Token(index,index);
+			var tokenizer:ITokenizer;
+			if ( externalTokenizer == null ) {
+				tokenizer = new TextTokenizer(mTextField.text);	
+			}else {
+				tokenizer = externalTokenizer;
+			}
+			
+			var result:Token = new Token(0,0);
+			
+			var preToken:Token = tokenizer.getPreviousToken(tmpToken);
+			var nextToken:Token = tokenizer.getNextToken(tmpToken);
+			if ( preToken.last == nextToken.first ) {
+				result.first = preToken.first;
+				result.last = nextToken.last;
+				return result;		
+			}else {
+				return null;
+			}
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IHighlighter.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IHighlighter.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IHighlighter.as
new file mode 100644
index 0000000..a8b826f
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IHighlighter.as
@@ -0,0 +1,34 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.Token;
+	import __AS3__.vec.Vector;
+	import flash.geom.Point;
+	
+	public interface IHighlighter
+	{
+		function drawSquiggleAt(token:Token):void;
+		function clearSquiggles():void;
+		function set offsetPoint(op:Point):void;
+		function get offsetPoint():Point;
+		
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IWordProcessor.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IWordProcessor.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IWordProcessor.as
new file mode 100644
index 0000000..76c3c8e
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/IWordProcessor.as
@@ -0,0 +1,30 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.ITokenizer;
+	import com.adobe.linguistics.utils.Token;
+	
+	public interface IWordProcessor
+	{
+		function getWordAtPoint(x:uint, y:uint, externalTokenizer:ITokenizer=null):Token;
+		function replaceText(token:Token, replacement:String):void;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkHighlighter.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkHighlighter.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkHighlighter.as
new file mode 100644
index 0000000..fc5308d
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkHighlighter.as
@@ -0,0 +1,225 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.Token;
+	import com.adobe.linguistics.utils.TextTokenizer;
+	import flash.geom.Point;
+	
+	import flash.display.Shape;
+	import flash.geom.Rectangle;
+	import flash.text.engine.TextLine;
+	
+	import flashx.textLayout.compose.TextFlowLine;
+	import flashx.textLayout.edit.SelectionManager;
+	import flashx.textLayout.elements.TextFlow;
+	import flashx.textLayout.tlf_internal;
+	
+	import spark.components.RichEditableText;
+	use namespace tlf_internal;	
+	
+	/**
+	 * <p>This class facilitates drawing of squiggly lines below words for RichEditableText class. RichEditableText is a low-level UIComponent for displaying, 
+	 * scrolling, selecting, and editing richly-formatted text. This class is used in the skins of the Spark versions of TextInput and TextArea. 
+	 * SparkHighlighter could therefore be used for drawing squiggly lines in these Spark components.</p>
+	 * 	
+	 * @playerversion Flash 10
+	 * @langversion 3.0
+	 */
+	public class SparkHighlighter implements IHighlighter
+	{
+		
+		private var mTextField:RichEditableText;
+		private var mHighlighter:Shape;
+		/*
+		* offset point:
+		*/
+		private var _offsetPoint:Point;
+
+		/**
+		 * The constructor for SparkHighlighter.
+		 * @param richEditableText <code>RichEditableText</code> in which to enable highlighting.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function SparkHighlighter( richEditableText:RichEditableText )
+		{
+			if (richEditableText == null ) throw new Error("illegal argument."); 
+			mTextField = richEditableText;
+			mHighlighter = null;
+			this._offsetPoint = new Point(0,0);
+		}
+
+		/**
+		 * Draw squiggly lines below a given token.
+		 * @param token <code>Token</code> information of the word to be highlighted.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function drawSquiggleAt(token:Token):void
+		{
+			squiggleWord(token);
+		}
+		
+		/**
+		 * Clear all squiggly lines in the component.		
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function clearSquiggles():void
+		{
+			if (mHighlighter) {
+				mTextField.removeChild(mHighlighter);
+				mHighlighter=null;
+			}		
+		}
+		
+		/**
+		 * Set offset point information for scrollable controls. This is used by the highlighter to move 
+		 * the squiggly lines as the text scrolls inside the control.	
+		 * @param op offset information as a <code>Point</code> instance.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */		
+		public function set offsetPoint(op:Point):void{
+			_offsetPoint = op;
+		}
+		
+		/**
+		 * Get offset point information for scrollable controls. This is used by the highlighter to move 
+		 * the squiggly lines as the text scrolls inside the control.	
+		 * @param op offset information as a <code>Point</code> instance.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */		
+		public function get offsetPoint():Point{
+			return _offsetPoint;
+		}
+
+		
+
+		// TODO: refactor this code to share with halo components, and support words that cross lines
+		private function squiggleWord(token:Token):void {
+					
+			var ta:RichEditableText = mTextField;
+			if (!ta) return;		
+			
+			if (!mHighlighter) {
+				mHighlighter= new Shape();
+				mHighlighter.graphics.clear();
+				mTextField.addChild(mHighlighter);	
+			}
+					
+		        drawSquigglyLineForRange(token.first, token.last);
+			
+			// Just adjust the left padding, top padding is not an issue 
+			//var pleft:uint = mTextField.getStyle("paddingLeft");
+			//mHighlighter.x += pleft;		
+		}
+		
+		// Draw squiggly line
+		private function drawSquigglyLineForRange(start:Number, end:Number):void
+		{
+			// draw squiggly line
+			var tf:TextFlow = mTextField.textFlow;
+			var tflFirst:TextFlowLine = tf.flowComposer.findLineAtPosition(start);
+			var tflLast:TextFlowLine = tf.flowComposer.findLineAtPosition(end);
+			var tflIndexFirst:int = tf.flowComposer.findLineIndexAtPosition(start);
+			var tflIndexLast:int = tf.flowComposer.findLineIndexAtPosition(end);
+			
+			// Pointer
+			var tflIndex:int = tflIndexFirst;
+			var tfl:TextFlowLine = tflFirst;
+			
+			if (tflIndexFirst == tflIndexLast) {
+				// Draw one line
+				drawSquigglyLineAtIndex(tflIndexFirst, start - tflFirst.absoluteStart, end - tflFirst.absoluteStart);
+			} else {
+				// Multiple lines (very long word)
+				drawSquigglyLineAtIndex(tflIndexFirst, start - tflFirst.absoluteStart);
+				
+				tflIndex++;
+				while (tflIndex != tflIndexLast) {
+					drawSquigglyLineAtIndex(tflIndex);
+					tflIndex++;
+				}
+				
+				drawSquigglyLineAtIndex(tflIndexLast, 0, end - tflLast.absoluteStart);
+			}
+		}
+		
+		// Draw a squiggly line at specific line for specific index range
+		private function drawSquigglyLineAtIndex(lineIndex:Number, startIndex:Number=0, endIndex:Number=0x7FFFFFFF):void
+		{
+			var tf:TextFlow = mTextField.textFlow;
+			var tfl:TextFlowLine = tf.flowComposer.getLineAt(lineIndex);
+			var rectLine:Rectangle = tfl.getBounds();
+			if (endIndex == 0x7FFFFFFF) {
+				drawSquigglyLineAtPoint(rectLine.left, rectLine.bottom, rectLine.right - rectLine.left);
+			}
+			else {
+				// Force to have a valid TextLine
+				var tl:TextLine = tfl.getTextLine(true);
+				
+				// TODO: atom index and char index is not matching for some chars, use try/catch to avoid crash
+				try {
+					var rectFirst:Rectangle = tl.getAtomBounds(startIndex);
+					var rectLast:Rectangle = tl.getAtomBounds(endIndex);
+					drawSquigglyLineAtPoint(rectFirst.left + tfl.x, rectLine.bottom, rectLast.right - rectFirst.left);
+				} catch (err:Error)
+				{
+					//TODO: report error
+				}
+			}
+				
+		}
+		// Draw a squiggly from point x,y with given width, the line is drew in mHighlighter 
+		private function drawSquigglyLineAtPoint(x:Number, y:Number, width:Number):void
+		{
+			mHighlighter.graphics.lineStyle(1, 0xfa0707, .65);
+			mHighlighter.graphics.moveTo(x, y);
+			var upDirection:Boolean = false;
+			var offset:uint = 0;
+			var stepLength:uint = 2;
+			for ( var i:uint = 1; offset <= width; i++) {
+				offset = offset + stepLength;
+				if ( upDirection )
+					mHighlighter.graphics.lineTo(x+offset,y);
+				else
+					mHighlighter.graphics.lineTo(x+offset,y+stepLength);
+				upDirection = !upDirection;
+			}	
+		}
+		
+		private function getValidFirstWordIndex():int{
+			var index:int = SelectionManager.computeSelectionIndex(mTextField.textFlow, mTextField, mTextField, 0 + mTextField.horizontalScrollPosition, 0 + mTextField.verticalScrollPosition);
+			return index;
+
+			
+		}
+		
+		private function getValidLastWordIndex():int{
+			var index:int = SelectionManager.computeSelectionIndex(mTextField.textFlow, mTextField, mTextField, mTextField.width+mTextField.horizontalScrollPosition, mTextField.height+mTextField.verticalScrollPosition);
+			return index;
+
+		}
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkWordProcessor.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkWordProcessor.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkWordProcessor.as
new file mode 100644
index 0000000..c174eee
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SparkWordProcessor.as
@@ -0,0 +1,132 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.ITokenizer;
+	import com.adobe.linguistics.utils.TextTokenizer;
+	import com.adobe.linguistics.utils.Token;
+	
+	import flashx.textLayout.edit.SelectionManager;
+	import flashx.textLayout.tlf_internal;
+	
+	import spark.components.RichEditableText;
+	
+	use namespace tlf_internal;	
+	
+	public class SparkWordProcessor implements IWordProcessor
+	{
+		private var mTextField:RichEditableText;
+
+		public function SparkWordProcessor(textField:RichEditableText)
+		{
+			if (textField == null ) throw new Error("illegal argument."); 
+			mTextField = textField;
+		}
+				
+		
+		public function replaceText(token:Token, replacement:String):void {
+			var startIndex:int = token.first;
+			var endIndex:int = token.last;
+			
+			var ta:RichEditableText = mTextField;
+			var end:int = getValidLastWordIndex();
+			
+			if ( replacement == null ) return;
+			
+			if (mTextField.text.length<endIndex || startIndex<0) {
+				return;
+			}
+			
+			var _misspellStart:int = startIndex;
+			var _misspellEnd:int = endIndex;
+			
+			// Workaround for Spark: changes in inactive components will trigger strange behavior			
+			//var selectedElementRange:ElementRange = ElementRange.createElementRange(ta.textFlow, _misspellStart, _misspellEnd);
+			//var selectedCharacterFormat:ITextLayoutFormat = ta.textFlow.interactionManager.activePosition == ta.textFlow.interactionManager.anchorPosition ? ta.textFlow.interactionManager.getCommonCharacterFormat() : selectedElementRange.characterFormat;
+			//var selectedParagraphFormat:ITextLayoutFormat = selectedElementRange.paragraphFormat;
+			//var selectedContainerFormat:ITextLayoutFormat = selectedElementRange.containerFormat;
+			
+			
+			
+			//var selectedCharacterFormat:ITextLayoutFormat = ta.textFlow.interactionManager.getCommonCharacterFormat();
+			//var selectedContainerFormat:ITextLayoutFormat = ta.textFlow.interactionManager.getCommonContainerFormat();
+			//var selectedParagraphFormat:ITextLayoutFormat = ta.textFlow.interactionManager.getCommonParagraphFormat();
+			
+			/*var tem:EditManager = new EditManager();
+			ta.textFlow.interactionManager = tem;	*/
+			
+			
+			ta.setFocus();
+			//ta.text = ta.text.substr(0, _misspellStart) + replacement + ta.text.substr(_misspellEnd);
+			
+			//tem.applyFormat(selectedCharacterFormat,selectedParagraphFormat,selectedContainerFormat);
+			//ta.textFlow.flowComposer.updateAllControllers();
+			
+			ta.textFlow;
+			//ta.selectRange(_misspellStart + replacement.length, _misspellStart + replacement.length);
+			ta.selectRange(_misspellStart+1, _misspellEnd);
+			ta.insertText(replacement);
+			ta.selectRange(_misspellStart, _misspellStart+1);
+			ta.insertText("");
+			
+			//ta.textFlow.interactionManager.applyFormat(selectedCharacterFormat,null,null);
+			
+			// Workaround for unexpected jump
+			ta.scrollToRange(end, end);
+		}
+		
+		public function getWordAtPoint(x:uint, y:uint, externalTokenizer:ITokenizer=null):Token
+		{
+			// TODO: use a better alternative than _misspellStart, end
+			var ta:RichEditableText = mTextField;	
+			var index:int = SelectionManager.computeSelectionIndex(ta.textFlow, ta, ta, x, y);
+
+			if (index >= ta.text.length) return null;
+
+			var tmpToken:Token = new Token(index,index);
+			var tokenizer:ITokenizer;
+			if ( externalTokenizer == null ) {
+				tokenizer = new TextTokenizer(mTextField.text);	
+			}else {
+				tokenizer = externalTokenizer;
+			}
+			
+			var result:Token = new Token(0,0);
+			var preToken:Token = tokenizer.getPreviousToken(tmpToken);
+			var nextToken:Token = tokenizer.getNextToken(tmpToken);
+			if ( preToken.last == nextToken.first ) {
+				result.first = preToken.first;
+				result.last = nextToken.last;
+				return result;		
+			}else {
+				return null;
+			}
+				
+		}
+
+		// TODO: workaround for unexpected jump when word replaced, to be refactored for code sharing
+		private function getValidLastWordIndex():int{
+			var index:int = SelectionManager.computeSelectionIndex(mTextField.textFlow, mTextField, mTextField, mTextField.width+mTextField.horizontalScrollPosition, mTextField.height+mTextField.verticalScrollPosition);
+			return index;
+		}
+
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SpellingHighlighter.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SpellingHighlighter.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SpellingHighlighter.as
new file mode 100644
index 0000000..5095331
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/SpellingHighlighter.as
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import flash.display.Shape;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	import flash.text.TextLineMetrics;
+	
+	import mx.core.IUITextField;
+	import mx.flash.UIMovieClip;
+
+
+	public class SpellingHighlighter extends UIMovieClip
+	{
+		/*
+		* offset point:
+		*/
+		private var _offsetPoint:Point;
+		
+		/*
+		* Target TextField.
+		*/
+		private var _textField:IUITextField;
+		private static var InvalidIndexValue:int = -2;
+		public function SpellingHighlighter(textField:IUITextField) {
+			super();
+			this._textField = textField;
+			this._offsetPoint = new Point(0,0);
+		}
+		
+		public function drawSquigglyLine(firstCharIndex:int, lastCharIndex:int ):void {
+			var validFirstCharIndex:int = getValidFirstCharIndex(firstCharIndex);
+			var validLastCharIndex:int = getValidLastCharIndex(lastCharIndex);
+			if ( validFirstCharIndex == InvalidIndexValue || validLastCharIndex == InvalidIndexValue ){
+				return;
+			}
+			/* draw squiggly line here. */
+			if ( validFirstCharIndex <= validLastCharIndex ) {
+				var firstLine:int = _textField.getLineIndexOfChar(validFirstCharIndex);
+				var lastLine:int = _textField.getLineIndexOfChar(validLastCharIndex);
+				//only one line case.
+				if(lastLine==firstLine)
+				{
+					drawSingleSquigglyLine(validFirstCharIndex, validLastCharIndex);
+					return;
+				}
+				//more than one line.
+				//first line
+				drawSingleSquigglyLine(validFirstCharIndex, _textField.getLineOffset(firstLine)+_textField.getLineLength(firstLine)-1);
+				//middle....
+				for(var i:int=firstLine+1;i<lastLine;i++)
+				{
+					drawSingleSquigglyLine(_textField.getLineOffset(i), _textField.getLineOffset(i)+_textField.getLineLength(i)-1);
+				}
+				//last lines.
+				drawSingleSquigglyLine(_textField.getLineOffset(lastLine), validLastCharIndex);
+			}
+		}
+		
+		public function drawSingleSquigglyLine(firstCharIndex:int, lastCharIndex:int ):void {
+			var firstLine:int = _textField.getLineIndexOfChar(firstCharIndex);
+			var lastLine:int = _textField.getLineIndexOfChar(lastCharIndex);
+			if ( firstLine != lastLine ) {
+				return;
+			}else {
+				var rect1:Rectangle = _textField.getCharBoundaries(firstCharIndex);
+				var rect2:Rectangle = _textField.getCharBoundaries(lastCharIndex);
+				var x:Number = rect1.x+_offsetPoint.x - _textField.scrollH;
+				var y:Number = rect1.y + rect1.height + 2;
+				var width:Number = rect2.x+rect2.width-rect1.x;
+				
+				// Avoid drawing outside the textField
+				if (x<0) 
+				{
+					if (x+width > 0) {
+						width += x;
+						x = 0;
+					} 
+					else
+						return;
+				}
+				if (x+width > _textField.width) 
+				{
+					if (x < _textField.width) {
+						width = textField.width - x;
+					} 	
+					else
+						return;
+				}
+				
+				// The rectangle that bound the string you want
+				// actual work here.
+				var myShape:Shape = new Shape();
+				myShape.graphics.clear();
+				//myShape.graphics.beginFill(0x0099CC, .35); 
+				myShape.graphics.lineStyle(1, 0xfa0707, .65);
+				myShape.graphics.moveTo(x, y);
+				var upDirection:Boolean = false;
+				var offset:uint = 0;
+				var stepLength:uint = 2;
+				for ( var i:uint = 1; offset <= width; i++) {
+					offset = offset + stepLength;
+					if ( upDirection )
+						myShape.graphics.lineTo(x+offset,y);
+					else
+						myShape.graphics.lineTo(x+offset,y+stepLength);
+					upDirection = !upDirection;
+				}
+				//myShape.graphics.endFill();
+				this.addChild(myShape);	
+			}
+		}
+		
+		private function getValidFirstCharIndex(firstCharIndex:int):int{
+			if(firstCharIndex<0 || firstCharIndex>_textField.text.length-1) 
+			{
+				return InvalidIndexValue;
+			}
+			var firstLine:Number = _textField.getLineIndexOfChar(firstCharIndex);
+			
+			if(firstLine<_textField.scrollV-1)
+			{
+				firstLine = _textField.scrollV-1;
+				return _textField.getLineOffset(firstLine);
+			}
+			return firstCharIndex;
+		}
+		
+		private function getValidLastCharIndex(lastCharIndex:int):int{
+			if(lastCharIndex<0 || lastCharIndex>_textField.text.length-1) 
+			{
+				return InvalidIndexValue;
+			}
+			var lastLine:Number = _textField.getLineIndexOfChar(lastCharIndex);
+			if(lastLine>_textField.bottomScrollV-1)
+			{
+				lastLine = _textField.bottomScrollV-1;
+				return _textField.getLineOffset(lastLine)+_textField.getLineLength(lastLine)-1;
+			}
+			return lastCharIndex;
+		}
+					
+		public function set textField(tf:IUITextField):void{
+			_textField = tf;
+		}
+		
+		public function get textField():IUITextField{
+			return _textField;
+		}
+		
+		public function set offsetPoint(op:Point):void{
+			_offsetPoint = op;
+		}
+		
+		public function get offsetPoint():Point{
+			return _offsetPoint;
+		}
+
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFHighlighter.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFHighlighter.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFHighlighter.as
new file mode 100644
index 0000000..75f6576
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFHighlighter.as
@@ -0,0 +1,248 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.TextTokenizer;
+	import com.adobe.linguistics.utils.Token;
+	
+	import flash.display.Graphics;
+	import flash.display.Shape;
+	import flash.display.Sprite;
+	import flash.geom.Point;
+	import flash.geom.Rectangle;
+	import flash.text.engine.TextLine;
+	import flash.utils.Dictionary;
+	
+	import flashx.textLayout.compose.TextFlowLine;
+	import flashx.textLayout.container.ContainerController;
+	import flashx.textLayout.edit.SelectionManager;
+	import flashx.textLayout.elements.TextFlow;
+	import flashx.textLayout.tlf_internal;
+
+
+	use namespace tlf_internal;	
+
+	/**
+	 * <p>This class facilitates drawing of squiggly lines below words for TLF TextFlow class.</p>
+	 * <p>The TextFlow class is responsible for managing all 
+	 * the text content of a story. In TextLayout, text is stored in a hierarchical tree of elements. TextFlow is the root object of the element tree. 
+	 * All elements on the tree derive from the base class, FlowElement. </p> 
+	 * TLFHighlighter could be used for drawing squiggly lines in any of the custom visual components(probably based on <code>Sprite</code>) which make use 
+	 * of TextFlow to display text.
+	 * 	
+	 * @playerversion Flash 10
+	 * @langversion 3.0
+	 */
+	public class TLFHighlighter implements IHighlighter
+	{
+		
+		private var mTextFlow:TextFlow;
+		private var mHighlighter:Dictionary;
+	
+		//private var mHighlighter:Shape;
+		private var ccindex:int;
+		private var cc:ContainerController;
+		/*
+		* offset point:
+		*/
+		private var _offsetPoint:Point;
+
+		/**
+		 * The constructor for TLFHighlighter.
+		 * @param textFlow <code>TextFlow</code> in which to enable highlighting.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function TLFHighlighter( textFlow:TextFlow )
+		{
+			if (textFlow == null ) throw new Error("illegal argument."); 
+			mTextFlow = textFlow;
+			//mHighlighter = null;
+			mHighlighter = new Dictionary(true);
+			this._offsetPoint = new Point(0,0);
+		}
+		/**
+		 * Draw squiggly lines below a given token.
+		 * @param token <code>Token</code> information of the word to be highlighted.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function drawSquiggleAt(token:Token):void
+		{
+			squiggleWord(token);
+		}
+		/**
+		 * Clear all squiggly lines in the component.		
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */
+		public function clearSquiggles():void
+		{
+			
+			for (var idx:int = 0; idx < mTextFlow.flowComposer.numControllers; idx++)
+			{	
+				var cctmp:ContainerController = mTextFlow.flowComposer.getControllerAt(idx);
+				if (mHighlighter[cctmp.container] != null) {
+					
+					//ToDO: This assumes single container for whole of mTextFlow. Need to implement for multiple container case.
+					cctmp.container.removeChild((mHighlighter[cctmp.container] as Shape));
+					
+					mHighlighter[cctmp.container] = null;
+				}	
+			}
+		}
+	
+		/**
+		 * Set offset point information for scrollable controls. This is used by the highlighter to move 
+		 * the squiggly lines as the text scrolls inside the control.	
+		 * @param op offset information as a <code>Point</code> instance.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */		
+		public function set offsetPoint(op:Point):void{
+			_offsetPoint = op;
+		}
+		/**
+		 * Get offset point information for scrollable controls. This is used by the highlighter to move 
+		 * the squiggly lines as the text scrolls inside the control.	
+		 * @param op offset information as a <code>Point</code> instance.		 
+		 * @playerversion Flash 10
+		 * @langversion 3.0
+		 */	
+		public function get offsetPoint():Point{
+			return _offsetPoint;
+		}
+
+		
+
+		// TODO: refactor this code to share with halo components, and support words that cross lines
+		private function squiggleWord(token:Token):void {					
+			var ta:TextFlow = mTextFlow;
+			
+			if (!ta) return;		
+			ccindex = ta.flowComposer.findControllerIndexAtPosition(token.first);
+			
+			cc = ta.flowComposer.getControllerAt(ccindex);
+			
+			if (mHighlighter[cc.container] == null ) {
+				mHighlighter[cc.container]= new Shape();
+				(mHighlighter[cc.container] as Shape).graphics.clear();
+				//ccindex = ta.flowComposer.findControllerIndexAtPosition(token.first);
+				
+				//var cc:ContainerController = ta.flowComposer.getControllerAt(ccindex);
+				//ToDO: This assumes single container for whole of mTextFlow. Need to implement for multiple container case.
+				cc.container.addChild((mHighlighter[cc.container] as Shape));				
+			}
+					
+		    drawSquigglyLineForRange(token.first, token.last);
+			
+			// Just adjust the left padding, top padding is not an issue 
+			//var pleft:uint = mTextFlow.getStyle("paddingLeft");
+			//mHighlighter.x += pleft;		
+		}
+		
+		// Draw squiggly line
+		private function drawSquigglyLineForRange(start:Number, end:Number):void
+		{
+			// draw squiggly line
+			var tf:TextFlow = mTextFlow;
+			var tflFirst:TextFlowLine = tf.flowComposer.findLineAtPosition(start);
+			var tflLast:TextFlowLine = tf.flowComposer.findLineAtPosition(end);
+			var tflIndexFirst:int = tf.flowComposer.findLineIndexAtPosition(start);
+			var tflIndexLast:int = tf.flowComposer.findLineIndexAtPosition(end);
+			
+			// Pointer
+			var tflIndex:int = tflIndexFirst;
+			var tfl:TextFlowLine = tflFirst;
+			
+			if (tflIndexFirst == tflIndexLast) {
+				// Draw one line
+				drawSquigglyLineAtIndex(tflIndexFirst, start - tflFirst.absoluteStart, end - tflFirst.absoluteStart);
+			} else {
+				// Multiple lines (very long word)
+				drawSquigglyLineAtIndex(tflIndexFirst, start - tflFirst.absoluteStart);
+				
+				tflIndex++;
+				while (tflIndex != tflIndexLast) {
+					drawSquigglyLineAtIndex(tflIndex);
+					tflIndex++;
+				}
+				
+				drawSquigglyLineAtIndex(tflIndexLast, 0, end - tflLast.absoluteStart);
+			}
+		}
+		
+		// Draw a squiggly line at specific line for specific index range
+		private function drawSquigglyLineAtIndex(lineIndex:Number, startIndex:Number=0, endIndex:Number=0x7FFFFFFF):void
+		{
+			var tf:TextFlow = mTextFlow;
+			var tfl:TextFlowLine = tf.flowComposer.getLineAt(lineIndex);
+			var rectLine:Rectangle = tfl.getBounds(); 
+			if (endIndex == 0x7FFFFFFF) {
+				drawSquigglyLineAtPoint(rectLine.left, rectLine.bottom, rectLine.right - rectLine.left, lineIndex);
+			}
+			else {
+				// Force to have a valid TextLine
+				var tl:TextLine = tfl.getTextLine(true);
+				
+				// TODO: atom index and char index is not matching for some chars, use try/catch to avoid crash
+				try {
+					var rectFirst:Rectangle = tl.getAtomBounds(startIndex);
+					var rectLast:Rectangle = tl.getAtomBounds(endIndex);
+					drawSquigglyLineAtPoint(rectFirst.left + tfl.x, rectLine.bottom, rectLast.right - rectFirst.left, lineIndex);
+				} catch (err:Error)
+				{
+					//TODO: report error
+				}
+			}
+				
+		}
+		// Draw a squiggly from point x,y with given width, the line is drawn in mHighlighter 
+		private function drawSquigglyLineAtPoint(x:Number, y:Number, width:Number, lineIndex:Number):void
+		{
+			var tf:TextFlow = mTextFlow;
+			var tfl:TextFlowLine = tf.flowComposer.getLineAt(lineIndex);
+			var tl:TextLine = tfl.getTextLine(true);
+						
+			(mHighlighter[cc.container] as Shape).graphics.lineStyle(1, 0xfa0707, .65);
+			(mHighlighter[cc.container] as Shape).graphics.moveTo(x, y);
+			var upDirection:Boolean = false;
+			var offset:uint = 0;
+			var stepLength:uint = 2;
+			for ( var i:uint = 1; offset <= width; i++) {
+				offset = offset + stepLength;
+				if ( upDirection )
+					(mHighlighter[cc.container] as Shape).graphics.lineTo(x+offset,y);
+				else
+					(mHighlighter[cc.container] as Shape).graphics.lineTo(x+offset,y+stepLength);
+				upDirection = !upDirection;
+			}
+			
+			//tl.addChild(mHighlighter);
+						
+			//tf.flowComposer.updateToController(ccindex);
+
+		}
+		
+
+	}
+	
+}
+

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFWordProcessor.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFWordProcessor.as b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFWordProcessor.as
new file mode 100644
index 0000000..f506227
--- /dev/null
+++ b/Squiggly/main/SpellingFramework/src/com/adobe/linguistics/spelling/framework/ui/TLFWordProcessor.as
@@ -0,0 +1,156 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package com.adobe.linguistics.spelling.framework.ui
+{
+	import com.adobe.linguistics.utils.ITokenizer;
+	import com.adobe.linguistics.utils.TextTokenizer;
+	import com.adobe.linguistics.utils.Token;
+	
+	import flashx.textLayout.edit.SelectionManager;
+	import flashx.textLayout.edit.EditManager;
+	import flashx.textLayout.tlf_internal;
+	import flashx.textLayout.elements.TextFlow;
+	
+	import flashx.textLayout.container.ContainerController;
+	import flashx.textLayout.elements.FlowLeafElement;
+	import flashx.textLayout.elements.ParagraphElement;
+	
+	use namespace tlf_internal;	
+	
+	public class TLFWordProcessor implements IWordProcessor
+	{
+		private var mTextFlow:TextFlow;
+		private var _containerController:ContainerController;
+
+		public function TLFWordProcessor(textFlow:TextFlow)
+		{
+			if (textFlow == null ) throw new Error("illegal argument."); 
+			mTextFlow = textFlow;
+		}
+				
+		
+		public function replaceText(token:Token, replacement:String):void {
+			var startIndex:int = token.first;
+			var endIndex:int = token.last;
+			
+			var ta:TextFlow = mTextFlow;
+			//var end:int = getValidLastWordIndex();
+			
+			if ( replacement == null ) return;
+			
+			/*if (mTextFlow.text.length<endIndex || startIndex<0) {
+				return;
+			}*/
+			
+			var _misspellStart:int = startIndex;
+			var _misspellEnd:int = endIndex;
+			
+			// Workaround for Spark: changes in inactive components will trigger strange behavior			
+			//var selectedElementRange:ElementRange = ElementRange.createElementRange(ta.textFlow, _misspellStart, _misspellEnd);
+			//var selectedCharacterFormat:ITextLayoutFormat = ta.textFlow.interactionManager.activePosition == ta.textFlow.interactionManager.anchorPosition ? ta.textFlow.interactionManager.getCommonCharacterFormat() : selectedElementRange.characterFormat;
+			//var selectedParagraphFormat:ITextLayoutFormat = selectedElementRange.paragraphFormat;
+			//var selectedContainerFormat:ITextLayoutFormat = selectedElementRange.containerFormat;
+			
+			
+			
+			//var selectedCharacterFormat:ITextLayoutFormat = ta.textFlow.interactionManager.getCommonCharacterFormat();
+			//var selectedContainerFormat:ITextLayoutFormat = ta.textFlow.interactionManager.getCommonContainerFormat();
+			//var selectedParagraphFormat:ITextLayoutFormat = ta.textFlow.interactionManager.getCommonParagraphFormat();
+			
+			var tem:EditManager = ta.interactionManager as EditManager;
+			
+			
+			
+			//ta.setFocus();
+			//ta.text = ta.text.substr(0, _misspellStart) + replacement + ta.text.substr(_misspellEnd);
+			
+			//tem.applyFormat(selectedCharacterFormat,selectedParagraphFormat,selectedContainerFormat);
+			//ta.textFlow.flowComposer.updateAllControllers();
+			
+			//ta.textFlow;
+			//ta.selectRange(_misspellStart + replacement.length, _misspellStart + replacement.length);
+			
+			
+			tem.selectRange(_misspellStart+1, _misspellEnd);
+			tem.insertText(replacement);
+			tem.selectRange(_misspellStart, _misspellStart+1);
+			tem.insertText("");
+			
+			//ta.textFlow.interactionManager.applyFormat(selectedCharacterFormat,null,null);
+			
+			// Workaround for unexpected jump
+			//ta.scrollToRange(end, end);
+		}
+		
+		/**
+		 @private
+		 (This property is for Squiggly Developer use only.)
+		 */
+		public function set textFlowContainerController(value:ContainerController):void {
+			_containerController = value;
+		}
+		
+		public function getWordAtPoint(x:uint, y:uint, externalTokenizer:ITokenizer=null):Token
+		{
+			// TODO: use a better alternative than _misspellStart, end
+			var ta:TextFlow = mTextFlow;	
+									
+			var index:int = SelectionManager.computeSelectionIndex(ta, _containerController.container, _containerController.container, x, y);
+
+			if (index >= ta.textLength) return null;
+
+			var currentLeaf:FlowLeafElement = ta.findLeaf(index);
+			var currentParagraph:ParagraphElement = currentLeaf ? currentLeaf.getParagraph() : null;
+			
+			var paraStart:uint = currentParagraph.getAbsoluteStart();
+				
+			//tokenizer = new TextTokenizer(currentParagraph.getText().substring());
+			
+			var tmpToken:Token = new Token(index - paraStart,index - paraStart);
+			var tokenizer:ITokenizer;
+			if ( externalTokenizer == null ) {
+				tokenizer = new TextTokenizer(currentParagraph.getText().substring());	
+			}else {
+				tokenizer = externalTokenizer;
+			}
+			
+			var result:Token = new Token(0,0);
+			var preToken:Token = tokenizer.getPreviousToken(tmpToken);
+			var nextToken:Token = tokenizer.getNextToken(tmpToken);
+			if ( preToken.last == nextToken.first ) {
+				result.first = preToken.first + paraStart;
+				result.last = nextToken.last + paraStart;
+				return result;		
+			}else {
+				return null;
+			}
+							
+		}
+
+		// TODO: workaround for unexpected jump when word replaced, to be refactored for code sharing
+		private function getValidLastWordIndex():int{
+			var index:int = 0;
+			//var index:int = SelectionManager.computeSelectionIndex(mTextFlow.textFlow, mTextFlow, mTextFlow, mTextFlow.width+mTextFlow.horizontalScrollPosition, mTextFlow.height+mTextFlow.verticalScrollPosition);
+			return index;
+		}
+
+
+	}
+}
\ No newline at end of file