Merge "Fix for text handle positioning." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/adaptor-framework/key.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/text/bidirectional-support.h>
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/color-segmentation.h>
29 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
30 #include <dali-toolkit/internal/text/multi-language-support.h>
31 #include <dali-toolkit/internal/text/segmentation.h>
32 #include <dali-toolkit/internal/text/shaper.h>
33 #include <dali-toolkit/internal/text/text-run-container.h>
34
35 namespace
36 {
37
38 #if defined(DEBUG_ENABLED)
39   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
40 #endif
41
42 } // namespace
43
44 namespace Dali
45 {
46
47 namespace Toolkit
48 {
49
50 namespace Text
51 {
52
53 EventData::EventData( DecoratorPtr decorator )
54 : mDecorator( decorator ),
55   mImfManager(),
56   mPlaceholderTextActive(),
57   mPlaceholderTextInactive(),
58   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
59   mEventQueue(),
60   mState( INACTIVE ),
61   mPrimaryCursorPosition( 0u ),
62   mLeftSelectionPosition( 0u ),
63   mRightSelectionPosition( 0u ),
64   mPreEditStartPosition( 0u ),
65   mPreEditLength( 0u ),
66   mIsShowingPlaceholderText( false ),
67   mPreEditFlag( false ),
68   mDecoratorUpdated( false ),
69   mCursorBlinkEnabled( true ),
70   mGrabHandleEnabled( true ),
71   mGrabHandlePopupEnabled( true ),
72   mSelectionEnabled( true ),
73   mHorizontalScrollingEnabled( true ),
74   mVerticalScrollingEnabled( false ),
75   mUpdateCursorPosition( false ),
76   mUpdateLeftSelectionPosition( false ),
77   mUpdateRightSelectionPosition( false ),
78   mScrollAfterUpdatePosition( false ),
79   mScrollAfterDelete( false ),
80   mAllTextSelected( false ),
81   mUpdateInputStyle( false )
82 {
83   mImfManager = ImfManager::Get();
84 }
85
86 EventData::~EventData()
87 {}
88
89 bool Controller::Impl::ProcessInputEvents()
90 {
91   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
92   if( NULL == mEventData )
93   {
94     // Nothing to do if there is no text input.
95     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
96     return false;
97   }
98
99   if( mEventData->mDecorator )
100   {
101     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
102          iter != mEventData->mEventQueue.end();
103          ++iter )
104     {
105       switch( iter->type )
106       {
107         case Event::CURSOR_KEY_EVENT:
108         {
109           OnCursorKeyEvent( *iter );
110           break;
111         }
112         case Event::TAP_EVENT:
113         {
114           OnTapEvent( *iter );
115           break;
116         }
117         case Event::LONG_PRESS_EVENT:
118         {
119           OnLongPressEvent( *iter );
120           break;
121         }
122         case Event::PAN_EVENT:
123         {
124           OnPanEvent( *iter );
125           break;
126         }
127         case Event::GRAB_HANDLE_EVENT:
128         case Event::LEFT_SELECTION_HANDLE_EVENT:
129         case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
130         {
131           OnHandleEvent( *iter );
132           break;
133         }
134         case Event::SELECT:
135         {
136           OnSelectEvent( *iter );
137           break;
138         }
139         case Event::SELECT_ALL:
140         {
141           OnSelectAllEvent();
142           break;
143         }
144       }
145     }
146   }
147
148   // The cursor must also be repositioned after inserts into the model
149   if( mEventData->mUpdateCursorPosition )
150   {
151     // Updates the cursor position and scrolls the text to make it visible.
152     CursorInfo cursorInfo;
153     GetCursorPosition( mEventData->mPrimaryCursorPosition,
154                        cursorInfo );
155
156     // Scroll first the text after delete ...
157     if( mEventData->mScrollAfterDelete )
158     {
159       ScrollTextToMatchCursor( cursorInfo );
160     }
161
162     // ... then, text can be scrolled to make the cursor visible.
163     if( mEventData->mScrollAfterUpdatePosition )
164     {
165       ScrollToMakePositionVisible( cursorInfo.primaryPosition );
166     }
167     mEventData->mScrollAfterUpdatePosition = false;
168     mEventData->mScrollAfterDelete = false;
169
170     UpdateCursorPosition( cursorInfo );
171
172     mEventData->mDecoratorUpdated = true;
173     mEventData->mUpdateCursorPosition = false;
174   }
175   else
176   {
177     bool leftScroll = false;
178     bool rightScroll = false;
179
180     CursorInfo leftHandleInfo;
181     CursorInfo rightHandleInfo;
182
183     if( mEventData->mUpdateLeftSelectionPosition )
184     {
185       GetCursorPosition( mEventData->mLeftSelectionPosition,
186                          leftHandleInfo );
187
188       if( mEventData->mScrollAfterUpdatePosition )
189       {
190         ScrollToMakePositionVisible( leftHandleInfo.primaryPosition );
191         leftScroll = true;
192       }
193     }
194
195     if( mEventData->mUpdateRightSelectionPosition )
196     {
197       GetCursorPosition( mEventData->mRightSelectionPosition,
198                          rightHandleInfo );
199
200       if( mEventData->mScrollAfterUpdatePosition )
201       {
202         ScrollToMakePositionVisible( rightHandleInfo.primaryPosition );
203         rightScroll = true;
204       }
205     }
206
207     if( mEventData->mUpdateLeftSelectionPosition )
208     {
209       UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
210                              leftHandleInfo );
211
212       SetPopupButtons();
213       mEventData->mDecoratorUpdated = true;
214     }
215
216     if( mEventData->mUpdateRightSelectionPosition )
217     {
218       UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
219                              rightHandleInfo );
220
221       SetPopupButtons();
222       mEventData->mDecoratorUpdated = true;
223     }
224
225     if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
226     {
227       RepositionSelectionHandles();
228
229       mEventData->mUpdateLeftSelectionPosition = false;
230       mEventData->mUpdateRightSelectionPosition = false;
231     }
232
233     if( leftScroll || rightScroll )
234     {
235       mEventData->mScrollAfterUpdatePosition = false;
236     }
237   }
238
239   if( mEventData->mUpdateInputStyle )
240   {
241     // Set the default style first.
242     RetrieveDefaultInputStyle( mEventData->mInputStyle );
243
244     // Get the character index from the cursor index.
245     const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
246
247     // Retrieve the style from the style runs stored in the logical model.
248     mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
249
250     mEventData->mUpdateInputStyle = false;
251   }
252
253   mEventData->mEventQueue.clear();
254
255   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
256
257   const bool decoratorUpdated = mEventData->mDecoratorUpdated;
258   mEventData->mDecoratorUpdated = false;
259
260   return decoratorUpdated;
261 }
262
263 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
264 {
265   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
266   mTextUpdateInfo.mStartGlyphIndex = 0u;
267   mTextUpdateInfo.mStartLineIndex = 0u;
268   numberOfCharacters = 0u;
269
270   const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
271   if( 0u == numberOfParagraphs )
272   {
273     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
274     numberOfCharacters = 0u;
275
276     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
277
278     // Nothing else to do if there are no paragraphs.
279     return;
280   }
281
282   // Find the paragraphs to be updated.
283   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
284   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
285   {
286     // Text is being added at the end of the current text.
287     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
288     {
289       // Text is being added in a new paragraph after the last character of the text.
290       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
291       numberOfCharacters = 0u;
292       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
293
294       mTextUpdateInfo.mStartGlyphIndex = mVisualModel->mGlyphs.Count();
295       mTextUpdateInfo.mStartLineIndex = mVisualModel->mLines.Count() - 1u;
296
297       // Nothing else to do;
298       return;
299     }
300
301     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
302   }
303   else
304   {
305     Length numberOfCharactersToUpdate = 0u;
306     if( mTextUpdateInfo.mFullRelayoutNeeded )
307     {
308       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
309     }
310     else
311     {
312       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
313     }
314     mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
315                                    numberOfCharactersToUpdate,
316                                    paragraphsToBeUpdated );
317   }
318
319   if( 0u != paragraphsToBeUpdated.Count() )
320   {
321     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
322     const ParagraphRun& firstParagraph = *( mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
323     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
324
325     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
326     const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
327
328     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
329         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
330         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
331           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
332     {
333       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
334       const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
335
336       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
337     }
338     else
339     {
340       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
341     }
342   }
343
344   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
345   mTextUpdateInfo.mStartGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
346 }
347
348 void Controller::Impl::ClearFullModelData( OperationsMask operations )
349 {
350   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
351   {
352     mLogicalModel->mLineBreakInfo.Clear();
353     mLogicalModel->mParagraphInfo.Clear();
354   }
355
356   if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
357   {
358     mLogicalModel->mLineBreakInfo.Clear();
359   }
360
361   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
362   {
363     mLogicalModel->mScriptRuns.Clear();
364   }
365
366   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
367   {
368     mLogicalModel->mFontRuns.Clear();
369   }
370
371   if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
372   {
373     if( NO_OPERATION != ( BIDI_INFO & operations ) )
374     {
375       mLogicalModel->mBidirectionalParagraphInfo.Clear();
376       mLogicalModel->mCharacterDirections.Clear();
377     }
378
379     if( NO_OPERATION != ( REORDER & operations ) )
380     {
381       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
382       for( Vector<BidirectionalLineInfoRun>::Iterator it = mLogicalModel->mBidirectionalLineInfo.Begin(),
383              endIt = mLogicalModel->mBidirectionalLineInfo.End();
384            it != endIt;
385            ++it )
386       {
387         BidirectionalLineInfoRun& bidiLineInfo = *it;
388
389         free( bidiLineInfo.visualToLogicalMap );
390         bidiLineInfo.visualToLogicalMap = NULL;
391       }
392       mLogicalModel->mBidirectionalLineInfo.Clear();
393     }
394   }
395
396   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
397   {
398     mVisualModel->mGlyphs.Clear();
399     mVisualModel->mGlyphsToCharacters.Clear();
400     mVisualModel->mCharactersToGlyph.Clear();
401     mVisualModel->mCharactersPerGlyph.Clear();
402     mVisualModel->mGlyphsPerCharacter.Clear();
403     mVisualModel->mGlyphPositions.Clear();
404   }
405
406   if( NO_OPERATION != ( LAYOUT & operations ) )
407   {
408     mVisualModel->mLines.Clear();
409   }
410
411   if( NO_OPERATION != ( COLOR & operations ) )
412   {
413     mVisualModel->mColorIndices.Clear();
414   }
415 }
416
417 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
418 {
419   const CharacterIndex endIndexPlusOne = endIndex + 1u;
420
421   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
422   {
423     // Clear the line break info.
424     LineBreakInfo* lineBreakInfoBuffer = mLogicalModel->mLineBreakInfo.Begin();
425
426     mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
427                                          lineBreakInfoBuffer + endIndexPlusOne );
428
429     // Clear the paragraphs.
430     ClearCharacterRuns( startIndex,
431                         endIndex,
432                         mLogicalModel->mParagraphInfo );
433   }
434
435   if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
436   {
437     // Clear the word break info.
438     WordBreakInfo* wordBreakInfoBuffer = mLogicalModel->mWordBreakInfo.Begin();
439
440     mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
441                                          wordBreakInfoBuffer + endIndexPlusOne );
442   }
443
444   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
445   {
446     // Clear the scripts.
447     ClearCharacterRuns( startIndex,
448                         endIndex,
449                         mLogicalModel->mScriptRuns );
450   }
451
452   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
453   {
454     // Clear the fonts.
455     ClearCharacterRuns( startIndex,
456                         endIndex,
457                         mLogicalModel->mFontRuns );
458   }
459
460   if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
461   {
462     if( NO_OPERATION != ( BIDI_INFO & operations ) )
463     {
464       // Clear the bidirectional paragraph info.
465       ClearCharacterRuns( startIndex,
466                           endIndex,
467                           mLogicalModel->mBidirectionalParagraphInfo );
468
469       // Clear the character's directions.
470       CharacterDirection* characterDirectionsBuffer = mLogicalModel->mCharacterDirections.Begin();
471
472       mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
473                                                  characterDirectionsBuffer + endIndexPlusOne );
474     }
475
476     if( NO_OPERATION != ( REORDER & operations ) )
477     {
478       uint32_t startRemoveIndex = mLogicalModel->mBidirectionalLineInfo.Count();
479       uint32_t endRemoveIndex = startRemoveIndex;
480       ClearCharacterRuns( startIndex,
481                           endIndex,
482                           mLogicalModel->mBidirectionalLineInfo,
483                           startRemoveIndex,
484                           endRemoveIndex );
485
486       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mLogicalModel->mBidirectionalLineInfo.Begin();
487
488       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
489       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
490              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
491            it != endIt;
492            ++it )
493       {
494         BidirectionalLineInfoRun& bidiLineInfo = *it;
495
496         free( bidiLineInfo.visualToLogicalMap );
497         bidiLineInfo.visualToLogicalMap = NULL;
498       }
499
500       mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
501                                                    bidirectionalLineInfoBuffer + endRemoveIndex );
502     }
503   }
504 }
505
506 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
507 {
508   const CharacterIndex endIndexPlusOne = endIndex + 1u;
509   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
510
511   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
512   GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
513   Length* glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
514
515   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
516   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
517
518   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
519   {
520     // Update the character to glyph indices.
521     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
522            endIt =  charactersToGlyphBuffer + mVisualModel->mCharactersToGlyph.Count();
523          it != endIt;
524          ++it )
525     {
526       CharacterIndex& index = *it;
527       index -= numberOfGlyphsRemoved;
528     }
529
530     // Clear the character to glyph conversion table.
531     mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
532                                             charactersToGlyphBuffer + endIndexPlusOne );
533
534     // Clear the glyphs per character table.
535     mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
536                                              glyphsPerCharacterBuffer + endIndexPlusOne );
537
538     // Clear the glyphs buffer.
539     GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
540     mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
541                                  glyphsBuffer + endGlyphIndexPlusOne );
542
543     CharacterIndex* glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
544
545     // Update the glyph to character indices.
546     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
547            endIt = glyphsToCharactersBuffer + mVisualModel->mGlyphsToCharacters.Count();
548          it != endIt;
549          ++it )
550     {
551       CharacterIndex& index = *it;
552       index -= numberOfCharactersRemoved;
553     }
554
555     // Clear the glyphs to characters buffer.
556     mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
557                                              glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
558
559     // Clear the characters per glyph buffer.
560     Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
561     mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
562                                              charactersPerGlyphBuffer + endGlyphIndexPlusOne );
563
564     // Clear the positions buffer.
565     Vector2* positionsBuffer = mVisualModel->mGlyphPositions.Begin();
566     mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
567                                          positionsBuffer + endGlyphIndexPlusOne );
568   }
569
570   if( NO_OPERATION != ( LAYOUT & operations ) )
571   {
572     // Clear the lines.
573     uint32_t startRemoveIndex = mVisualModel->mLines.Count();
574     uint32_t endRemoveIndex = startRemoveIndex;
575     ClearCharacterRuns( startIndex,
576                         endIndex,
577                         mVisualModel->mLines,
578                         startRemoveIndex,
579                         endRemoveIndex );
580
581     // Will update the glyph runs.
582     startRemoveIndex = mVisualModel->mLines.Count();
583     endRemoveIndex = startRemoveIndex;
584     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
585                     endGlyphIndexPlusOne - 1u,
586                     mVisualModel->mLines,
587                     startRemoveIndex,
588                     endRemoveIndex );
589
590     // Set the line index from where to insert the new laid-out lines.
591     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
592
593     LineRun* linesBuffer = mVisualModel->mLines.Begin();
594     mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
595                                 linesBuffer + endRemoveIndex );
596   }
597
598   if( NO_OPERATION != ( COLOR & operations ) )
599   {
600     if( 0u != mVisualModel->mColorIndices.Count() )
601     {
602       ColorIndex* colorIndexBuffer = mVisualModel->mColorIndices.Begin();
603       mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
604                                          colorIndexBuffer + endGlyphIndexPlusOne );
605     }
606   }
607 }
608
609 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
610 {
611   if( mTextUpdateInfo.mClearAll ||
612       ( ( 0u == startIndex ) &&
613         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
614   {
615     ClearFullModelData( operations );
616   }
617   else
618   {
619     // Clear the model data related with characters.
620     ClearCharacterModelData( startIndex, endIndex, operations );
621
622     // Clear the model data related with glyphs.
623     ClearGlyphModelData( startIndex, endIndex, operations );
624   }
625
626   // The estimated number of lines. Used to avoid reallocations when layouting.
627   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
628
629   mVisualModel->ClearCaches();
630 }
631
632 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
633 {
634   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
635
636   // Calculate the operations to be done.
637   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
638
639   if( NO_OPERATION == operations )
640   {
641     // Nothing to do if no operations are pending and required.
642     return false;
643   }
644
645   Vector<Character>& utf32Characters = mLogicalModel->mText;
646
647   const Length numberOfCharacters = utf32Characters.Count();
648
649   // Index to the first character of the first paragraph to be updated.
650   CharacterIndex startIndex = 0u;
651   // Number of characters of the paragraphs to be removed.
652   Length paragraphCharacters = 0u;
653
654   CalculateTextUpdateIndices( paragraphCharacters );
655   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
656
657   if( mTextUpdateInfo.mClearAll ||
658       ( 0u != paragraphCharacters ) )
659   {
660     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
661   }
662
663   mTextUpdateInfo.mClearAll = false;
664
665   // Whether the model is updated.
666   bool updated = false;
667
668   Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
669   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
670
671   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
672   {
673     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
674     // calculate the bidirectional info for each 'paragraph'.
675     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
676     // is not shaped together).
677     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
678
679     SetLineBreakInfo( utf32Characters,
680                       startIndex,
681                       requestedNumberOfCharacters,
682                       lineBreakInfo );
683
684     // Create the paragraph info.
685     mLogicalModel->CreateParagraphInfo( startIndex,
686                                         requestedNumberOfCharacters );
687     updated = true;
688   }
689
690   Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
691   if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
692   {
693     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
694     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
695
696     SetWordBreakInfo( utf32Characters,
697                       startIndex,
698                       requestedNumberOfCharacters,
699                       wordBreakInfo );
700     updated = true;
701   }
702
703   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
704   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
705
706   Vector<ScriptRun>& scripts = mLogicalModel->mScriptRuns;
707   Vector<FontRun>& validFonts = mLogicalModel->mFontRuns;
708
709   if( getScripts || validateFonts )
710   {
711     // Validates the fonts assigned by the application or assigns default ones.
712     // It makes sure all the characters are going to be rendered by the correct font.
713     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
714
715     if( getScripts )
716     {
717       // Retrieves the scripts used in the text.
718       multilanguageSupport.SetScripts( utf32Characters,
719                                        startIndex,
720                                        requestedNumberOfCharacters,
721                                        scripts );
722     }
723
724     if( validateFonts )
725     {
726       // Validate the fonts set through the mark-up string.
727       Vector<FontDescriptionRun>& fontDescriptionRuns = mLogicalModel->mFontDescriptionRuns;
728
729       // Get the default font id.
730       const FontId defaultFontId = ( NULL == mFontDefaults ) ? 0u : mFontDefaults->GetFontId( mFontClient );
731
732       // Validates the fonts. If there is a character with no assigned font it sets a default one.
733       // After this call, fonts are validated.
734       multilanguageSupport.ValidateFonts( utf32Characters,
735                                           scripts,
736                                           fontDescriptionRuns,
737                                           defaultFontId,
738                                           startIndex,
739                                           requestedNumberOfCharacters,
740                                           validFonts );
741     }
742     updated = true;
743   }
744
745   Vector<Character> mirroredUtf32Characters;
746   bool textMirrored = false;
747   const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
748   if( NO_OPERATION != ( BIDI_INFO & operations ) )
749   {
750     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
751     bidirectionalInfo.Reserve( numberOfParagraphs );
752
753     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
754     SetBidirectionalInfo( utf32Characters,
755                           scripts,
756                           lineBreakInfo,
757                           startIndex,
758                           requestedNumberOfCharacters,
759                           bidirectionalInfo );
760
761     if( 0u != bidirectionalInfo.Count() )
762     {
763       // Only set the character directions if there is right to left characters.
764       Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
765       GetCharactersDirection( bidirectionalInfo,
766                               numberOfCharacters,
767                               startIndex,
768                               requestedNumberOfCharacters,
769                               directions );
770
771       // This paragraph has right to left text. Some characters may need to be mirrored.
772       // TODO: consider if the mirrored string can be stored as well.
773
774       textMirrored = GetMirroredText( utf32Characters,
775                                       directions,
776                                       bidirectionalInfo,
777                                       startIndex,
778                                       requestedNumberOfCharacters,
779                                       mirroredUtf32Characters );
780     }
781     else
782     {
783       // There is no right to left characters. Clear the directions vector.
784       mLogicalModel->mCharacterDirections.Clear();
785     }
786     updated = true;
787   }
788
789   Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
790   Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
791   Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
792   Vector<GlyphIndex> newParagraphGlyphs;
793   newParagraphGlyphs.Reserve( numberOfParagraphs );
794
795   const Length currentNumberOfGlyphs = glyphs.Count();
796   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
797   {
798     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
799     // Shapes the text.
800     ShapeText( textToShape,
801                lineBreakInfo,
802                scripts,
803                validFonts,
804                startIndex,
805                mTextUpdateInfo.mStartGlyphIndex,
806                requestedNumberOfCharacters,
807                glyphs,
808                glyphsToCharactersMap,
809                charactersPerGlyph,
810                newParagraphGlyphs );
811
812     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
813     mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
814     mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
815     updated = true;
816   }
817
818   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
819
820   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
821   {
822     GlyphInfo* glyphsBuffer = glyphs.Begin();
823     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
824
825     // Update the width and advance of all new paragraph characters.
826     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
827     {
828       const GlyphIndex index = *it;
829       GlyphInfo& glyph = *( glyphsBuffer + index );
830
831       glyph.xBearing = 0.f;
832       glyph.width = 0.f;
833       glyph.advance = 0.f;
834     }
835     updated = true;
836   }
837
838   if( NO_OPERATION != ( COLOR & operations ) )
839   {
840     // Set the color runs in glyphs.
841     SetColorSegmentationInfo( mLogicalModel->mColorRuns,
842                               mVisualModel->mCharactersToGlyph,
843                               mVisualModel->mGlyphsPerCharacter,
844                               startIndex,
845                               mTextUpdateInfo.mStartGlyphIndex,
846                               requestedNumberOfCharacters,
847                               mVisualModel->mColors,
848                               mVisualModel->mColorIndices );
849
850     updated = true;
851   }
852
853   if( ( NULL != mEventData ) &&
854       mEventData->mPreEditFlag &&
855       ( 0u != mVisualModel->mCharactersToGlyph.Count() ) )
856   {
857     // Add the underline for the pre-edit text.
858     const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
859     const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
860
861     const GlyphIndex glyphStart = *( charactersToGlyphBuffer + mEventData->mPreEditStartPosition );
862     const CharacterIndex lastPreEditCharacter = mEventData->mPreEditStartPosition + ( ( mEventData->mPreEditLength > 0u ) ? mEventData->mPreEditLength - 1u : 0u );
863     const Length numberOfGlyphsLastCharacter = *( glyphsPerCharacterBuffer + lastPreEditCharacter );
864     const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + lastPreEditCharacter ) + ( numberOfGlyphsLastCharacter > 1u ? numberOfGlyphsLastCharacter - 1u : 0u );
865
866     GlyphRun underlineRun;
867     underlineRun.glyphIndex = glyphStart;
868     underlineRun.numberOfGlyphs = 1u + glyphEnd - glyphStart;
869
870     // TODO: At the moment the underline runs are only for pre-edit.
871     mVisualModel->mUnderlineRuns.PushBack( underlineRun );
872   }
873
874   // The estimated number of lines. Used to avoid reallocations when layouting.
875   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
876
877   // Set the previous number of characters for the next time the text is updated.
878   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
879
880   return updated;
881 }
882
883 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
884 {
885   // Sets the default text's color.
886   inputStyle.textColor = mTextColor;
887   inputStyle.isDefaultColor = true;
888
889   inputStyle.familyName.clear();
890   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
891   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
892   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
893   inputStyle.size = 0.f;
894
895   inputStyle.familyDefined = false;
896   inputStyle.weightDefined = false;
897   inputStyle.widthDefined = false;
898   inputStyle.slantDefined = false;
899   inputStyle.sizeDefined = false;
900
901   // Sets the default font's family name, weight, width, slant and size.
902   if( mFontDefaults )
903   {
904     if( mFontDefaults->familyDefined )
905     {
906       inputStyle.familyName = mFontDefaults->mFontDescription.family;
907       inputStyle.familyDefined = true;
908     }
909
910     if( mFontDefaults->weightDefined )
911     {
912       inputStyle.weight = mFontDefaults->mFontDescription.weight;
913       inputStyle.weightDefined = true;
914     }
915
916     if( mFontDefaults->widthDefined )
917     {
918       inputStyle.width = mFontDefaults->mFontDescription.width;
919       inputStyle.widthDefined = true;
920     }
921
922     if( mFontDefaults->slantDefined )
923     {
924       inputStyle.slant = mFontDefaults->mFontDescription.slant;
925       inputStyle.slantDefined = true;
926     }
927
928     if( mFontDefaults->sizeDefined )
929     {
930       inputStyle.size = mFontDefaults->mDefaultPointSize;
931       inputStyle.sizeDefined = true;
932     }
933   }
934 }
935
936 float Controller::Impl::GetDefaultFontLineHeight()
937 {
938   FontId defaultFontId = 0u;
939   if( NULL == mFontDefaults )
940   {
941     TextAbstraction::FontDescription fontDescription;
942     defaultFontId = mFontClient.GetFontId( fontDescription );
943   }
944   else
945   {
946     defaultFontId = mFontDefaults->GetFontId( mFontClient );
947   }
948
949   Text::FontMetrics fontMetrics;
950   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
951
952   return( fontMetrics.ascender - fontMetrics.descender );
953 }
954
955 void Controller::Impl::OnCursorKeyEvent( const Event& event )
956 {
957   if( NULL == mEventData )
958   {
959     // Nothing to do if there is no text input.
960     return;
961   }
962
963   int keyCode = event.p1.mInt;
964
965   if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
966   {
967     if( mEventData->mPrimaryCursorPosition > 0u )
968     {
969       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
970     }
971   }
972   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
973   {
974     if( mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
975     {
976       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
977     }
978   }
979   else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
980   {
981     // TODO
982   }
983   else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
984   {
985     // TODO
986   }
987
988   mEventData->mUpdateCursorPosition = true;
989   mEventData->mUpdateInputStyle = true;
990   mEventData->mScrollAfterUpdatePosition = true;
991 }
992
993 void Controller::Impl::OnTapEvent( const Event& event )
994 {
995   if( NULL != mEventData )
996   {
997     const unsigned int tapCount = event.p1.mUint;
998
999     if( 1u == tapCount )
1000     {
1001       if( IsShowingRealText() )
1002       {
1003         // Convert from control's coords to text's coords.
1004         const float xPosition = event.p2.mFloat - mScrollPosition.x;
1005         const float yPosition = event.p3.mFloat - mScrollPosition.y;
1006
1007         mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
1008                                                                           mLogicalModel,
1009                                                                           mMetrics,
1010                                                                           xPosition,
1011                                                                           yPosition );
1012
1013         // When the cursor position is changing, delay cursor blinking
1014         mEventData->mDecorator->DelayCursorBlink();
1015       }
1016       else
1017       {
1018         mEventData->mPrimaryCursorPosition = 0u;
1019       }
1020
1021       mEventData->mUpdateCursorPosition = true;
1022       mEventData->mScrollAfterUpdatePosition = true;
1023       mEventData->mUpdateInputStyle = true;
1024
1025       // Notify the cursor position to the imf manager.
1026       if( mEventData->mImfManager )
1027       {
1028         mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
1029         mEventData->mImfManager.NotifyCursorPosition();
1030       }
1031     }
1032   }
1033 }
1034
1035 void Controller::Impl::OnPanEvent( const Event& event )
1036 {
1037   if( NULL == mEventData )
1038   {
1039     // Nothing to do if there is no text input.
1040     return;
1041   }
1042
1043   int state = event.p1.mInt;
1044
1045   if( ( Gesture::Started == state ) ||
1046       ( Gesture::Continuing == state ) )
1047   {
1048     const Vector2& actualSize = mVisualModel->GetLayoutSize();
1049     const Vector2 currentScroll = mScrollPosition;
1050
1051     if( mEventData->mHorizontalScrollingEnabled )
1052     {
1053       const float displacementX = event.p2.mFloat;
1054       mScrollPosition.x += displacementX;
1055
1056       ClampHorizontalScroll( actualSize );
1057     }
1058
1059     if( mEventData->mVerticalScrollingEnabled )
1060     {
1061       const float displacementY = event.p3.mFloat;
1062       mScrollPosition.y += displacementY;
1063
1064       ClampVerticalScroll( actualSize );
1065     }
1066
1067     if( mEventData->mDecorator )
1068     {
1069       mEventData->mDecorator->UpdatePositions( mScrollPosition - currentScroll );
1070     }
1071   }
1072 }
1073
1074 void Controller::Impl::OnLongPressEvent( const Event& event )
1075 {
1076   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
1077
1078   if( EventData::EDITING == mEventData->mState )
1079   {
1080     ChangeState ( EventData::EDITING_WITH_POPUP );
1081     mEventData->mDecoratorUpdated = true;
1082   }
1083 }
1084
1085 void Controller::Impl::OnHandleEvent( const Event& event )
1086 {
1087   if( NULL == mEventData )
1088   {
1089     // Nothing to do if there is no text input.
1090     return;
1091   }
1092
1093   const unsigned int state = event.p1.mUint;
1094   const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
1095
1096   if( HANDLE_PRESSED == state )
1097   {
1098     // Convert from decorator's coords to text's coords.
1099     const float xPosition = event.p2.mFloat - mScrollPosition.x;
1100     const float yPosition = event.p3.mFloat - mScrollPosition.y;
1101
1102     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mVisualModel,
1103                                                                           mLogicalModel,
1104                                                                           mMetrics,
1105                                                                           xPosition,
1106                                                                           yPosition );
1107
1108     if( Event::GRAB_HANDLE_EVENT == event.type )
1109     {
1110       ChangeState ( EventData::GRAB_HANDLE_PANNING );
1111
1112       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
1113       {
1114         mEventData->mPrimaryCursorPosition = handleNewPosition;
1115         mEventData->mUpdateCursorPosition = true;
1116       }
1117     }
1118     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1119     {
1120       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1121
1122       if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
1123           ( handleNewPosition != mEventData->mRightSelectionPosition ) )
1124       {
1125         mEventData->mLeftSelectionPosition = handleNewPosition;
1126
1127         mEventData->mUpdateLeftSelectionPosition = true;
1128       }
1129     }
1130     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1131     {
1132       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1133
1134       if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
1135           ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
1136       {
1137         mEventData->mRightSelectionPosition = handleNewPosition;
1138
1139         mEventData->mUpdateRightSelectionPosition = true;
1140       }
1141     }
1142   } // end ( HANDLE_PRESSED == state )
1143   else if( ( HANDLE_RELEASED == state ) ||
1144            handleStopScrolling )
1145   {
1146     CharacterIndex handlePosition = 0u;
1147     if( handleStopScrolling )
1148     {
1149       // Convert from decorator's coords to text's coords.
1150       const float xPosition = event.p2.mFloat - mScrollPosition.x;
1151       const float yPosition = event.p3.mFloat - mScrollPosition.y;
1152
1153       handlePosition = Text::GetClosestCursorIndex( mVisualModel,
1154                                                     mLogicalModel,
1155                                                     mMetrics,
1156                                                     xPosition,
1157                                                     yPosition );
1158     }
1159
1160     if( Event::GRAB_HANDLE_EVENT == event.type )
1161     {
1162       mEventData->mUpdateCursorPosition = true;
1163       mEventData->mUpdateInputStyle = true;
1164
1165       if( !IsClipboardEmpty() )
1166       {
1167         ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
1168       }
1169
1170       if( handleStopScrolling )
1171       {
1172         mEventData->mScrollAfterUpdatePosition = mEventData->mPrimaryCursorPosition != handlePosition;
1173         mEventData->mPrimaryCursorPosition = handlePosition;
1174       }
1175     }
1176     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1177     {
1178       ChangeState( EventData::SELECTING );
1179
1180       if( handleStopScrolling )
1181       {
1182         mEventData->mUpdateLeftSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition );
1183         mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
1184
1185         if( mEventData->mUpdateLeftSelectionPosition )
1186         {
1187           mEventData->mLeftSelectionPosition = handlePosition;
1188         }
1189       }
1190     }
1191     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1192     {
1193       ChangeState( EventData::SELECTING );
1194
1195       if( handleStopScrolling )
1196       {
1197         mEventData->mUpdateRightSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition );
1198         mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
1199         if( mEventData->mUpdateRightSelectionPosition )
1200         {
1201           mEventData->mRightSelectionPosition = handlePosition;
1202         }
1203       }
1204     }
1205
1206     mEventData->mDecoratorUpdated = true;
1207   } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
1208   else if( HANDLE_SCROLLING == state )
1209   {
1210     const float xSpeed = event.p2.mFloat;
1211     const Vector2& actualSize = mVisualModel->GetLayoutSize();
1212     const Vector2 currentScrollPosition = mScrollPosition;
1213
1214     mScrollPosition.x += xSpeed;
1215
1216     ClampHorizontalScroll( actualSize );
1217
1218     bool endOfScroll = false;
1219     if( Vector2::ZERO == ( currentScrollPosition - mScrollPosition ) )
1220     {
1221       // Notify the decorator there is no more text to scroll.
1222       // The decorator won't send more scroll events.
1223       mEventData->mDecorator->NotifyEndOfScroll();
1224       // Still need to set the position of the handle.
1225       endOfScroll = true;
1226     }
1227
1228     // Set the position of the handle.
1229     const bool scrollRightDirection = xSpeed > 0.f;
1230     const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
1231     const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
1232
1233     if( Event::GRAB_HANDLE_EVENT == event.type )
1234     {
1235       ChangeState( EventData::GRAB_HANDLE_PANNING );
1236
1237       Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
1238
1239       // Position the grag handle close to either the left or right edge.
1240       position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
1241
1242       // Get the new handle position.
1243       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
1244       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel,
1245                                                                          mLogicalModel,
1246                                                                          mMetrics,
1247                                                                          position.x - mScrollPosition.x,
1248                                                                          position.y - mScrollPosition.y );
1249
1250       mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
1251       mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
1252       mEventData->mPrimaryCursorPosition = handlePosition;
1253       mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
1254     }
1255     else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
1256     {
1257       // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
1258       //       Think if something can be done to save power.
1259
1260       ChangeState( EventData::SELECTION_HANDLE_PANNING );
1261
1262       Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
1263
1264       // Position the selection handle close to either the left or right edge.
1265       position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
1266
1267       // Get the new handle position.
1268       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
1269       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel,
1270                                                                          mLogicalModel,
1271                                                                          mMetrics,
1272                                                                          position.x - mScrollPosition.x,
1273                                                                          position.y - mScrollPosition.y );
1274
1275       if( leftSelectionHandleEvent )
1276       {
1277         const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
1278         mEventData->mUpdateLeftSelectionPosition = endOfScroll || differentHandles;
1279         if( differentHandles )
1280         {
1281           mEventData->mLeftSelectionPosition = handlePosition;
1282         }
1283       }
1284       else
1285       {
1286         const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
1287         mEventData->mUpdateRightSelectionPosition = endOfScroll || differentHandles;
1288         if( differentHandles )
1289         {
1290           mEventData->mRightSelectionPosition = handlePosition;
1291         }
1292       }
1293
1294       if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
1295       {
1296         RepositionSelectionHandles();
1297
1298         mEventData->mScrollAfterUpdatePosition = true;
1299       }
1300     }
1301     mEventData->mDecoratorUpdated = true;
1302   } // end ( HANDLE_SCROLLING == state )
1303 }
1304
1305 void Controller::Impl::OnSelectEvent( const Event& event )
1306 {
1307   if( NULL == mEventData )
1308   {
1309     // Nothing to do if there is no text.
1310     return;
1311   }
1312
1313   if( mEventData->mSelectionEnabled )
1314   {
1315     // Convert from control's coords to text's coords.
1316     const float xPosition = event.p2.mFloat - mScrollPosition.x;
1317     const float yPosition = event.p3.mFloat - mScrollPosition.y;
1318
1319     // Calculates the logical position from the x,y coords.
1320     RepositionSelectionHandles( xPosition,
1321                                 yPosition );
1322
1323     mEventData->mUpdateLeftSelectionPosition = true;
1324     mEventData->mUpdateRightSelectionPosition = true;
1325     mEventData->mUpdateCursorPosition = false;
1326
1327     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
1328   }
1329 }
1330
1331 void Controller::Impl::OnSelectAllEvent()
1332 {
1333   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
1334
1335   if( NULL == mEventData )
1336   {
1337     // Nothing to do if there is no text.
1338     return;
1339   }
1340
1341   if( mEventData->mSelectionEnabled )
1342   {
1343     mEventData->mLeftSelectionPosition = 0u;
1344     mEventData->mRightSelectionPosition = mLogicalModel->mText.Count();
1345
1346     mEventData->mScrollAfterUpdatePosition = true;
1347     mEventData->mUpdateLeftSelectionPosition = true;
1348     mEventData->mUpdateRightSelectionPosition = true;
1349   }
1350 }
1351
1352 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1353 {
1354   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1355   {
1356     // Nothing to select if handles are in the same place.
1357     selectedText.clear();
1358     return;
1359   }
1360
1361   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1362
1363   //Get start and end position of selection
1364   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1365   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1366
1367   Vector<Character>& utf32Characters = mLogicalModel->mText;
1368   const Length numberOfCharacters = utf32Characters.Count();
1369
1370   // Validate the start and end selection points
1371   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1372   {
1373     //Get text as a UTF8 string
1374     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1375
1376     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1377     {
1378       // Set as input style the style of the first deleted character.
1379       mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1380
1381       mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1382
1383       // Mark the paragraphs to be updated.
1384       mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1385       mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1386
1387       // Delete text between handles
1388       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1389       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1390       utf32Characters.Erase( first, last );
1391
1392       // Scroll after delete.
1393       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1394     }
1395     mEventData->mDecoratorUpdated = true;
1396   }
1397 }
1398
1399 void Controller::Impl::ShowClipboard()
1400 {
1401   if( mClipboard )
1402   {
1403     mClipboard.ShowClipboard();
1404   }
1405 }
1406
1407 void Controller::Impl::HideClipboard()
1408 {
1409   if( mClipboard && mClipboardHideEnabled )
1410   {
1411     mClipboard.HideClipboard();
1412   }
1413 }
1414
1415 void Controller::Impl::SetClipboardHideEnable(bool enable)
1416 {
1417   mClipboardHideEnabled = enable;
1418 }
1419
1420 bool Controller::Impl::CopyStringToClipboard( std::string& source )
1421 {
1422   //Send string to clipboard
1423   return ( mClipboard && mClipboard.SetItem( source ) );
1424 }
1425
1426 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
1427 {
1428   std::string selectedText;
1429   RetrieveSelection( selectedText, deleteAfterSending );
1430   CopyStringToClipboard( selectedText );
1431   ChangeState( EventData::EDITING );
1432 }
1433
1434 void Controller::Impl::GetTextFromClipboard( unsigned int itemIndex, std::string& retrievedString )
1435 {
1436   if ( mClipboard )
1437   {
1438     retrievedString =  mClipboard.GetItem( itemIndex );
1439   }
1440 }
1441
1442 void Controller::Impl::RepositionSelectionHandles()
1443 {
1444   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
1445   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
1446
1447   if( selectionStart == selectionEnd )
1448   {
1449     // Nothing to select if handles are in the same place.
1450     return;
1451   }
1452
1453   mEventData->mDecorator->ClearHighlights();
1454
1455   const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
1456   const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
1457   const GlyphInfo* const glyphsBuffer = mVisualModel->mGlyphs.Begin();
1458   const Vector2* const positionsBuffer = mVisualModel->mGlyphPositions.Begin();
1459   const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
1460   const CharacterIndex* const glyphToCharacterBuffer = mVisualModel->mGlyphsToCharacters.Begin();
1461   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
1462
1463   // TODO: Better algorithm to create the highlight box.
1464   // TODO: Multi-line.
1465
1466   // Get the height of the line.
1467   const Vector<LineRun>& lines = mVisualModel->mLines;
1468   const LineRun& firstLine = *lines.Begin();
1469   const float height = firstLine.ascender + -firstLine.descender;
1470
1471   const bool isLastCharacter = selectionEnd >= mLogicalModel->mText.Count();
1472   const bool startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
1473   const bool endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
1474
1475   // Swap the indices if the start is greater than the end.
1476   const bool indicesSwapped = selectionStart > selectionEnd;
1477
1478   // Tell the decorator to flip the selection handles if needed.
1479   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
1480
1481   if( indicesSwapped )
1482   {
1483     std::swap( selectionStart, selectionEnd );
1484   }
1485
1486   // Get the indices to the first and last selected glyphs.
1487   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
1488   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
1489   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
1490   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
1491
1492   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
1493   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
1494   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionStart ) );
1495
1496   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
1497   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
1498   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionEndMinusOne ) );
1499
1500   // Traverse the glyphs.
1501   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
1502   {
1503     const GlyphInfo& glyph = *( glyphsBuffer + index );
1504     const Vector2& position = *( positionsBuffer + index );
1505
1506     if( splitStartGlyph )
1507     {
1508       // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
1509
1510       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
1511       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
1512       // Get the direction of the character.
1513       CharacterDirection isCurrentRightToLeft = false;
1514       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1515       {
1516         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
1517       }
1518
1519       // The end point could be in the middle of the ligature.
1520       // Calculate the number of characters selected.
1521       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
1522
1523       const float xPosition = firstLine.alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
1524
1525       mEventData->mDecorator->AddHighlight( xPosition,
1526                                             mScrollPosition.y,
1527                                             xPosition + static_cast<float>( numberOfCharacters ) * glyphAdvance,
1528                                             mScrollPosition.y + height );
1529
1530       splitStartGlyph = false;
1531       continue;
1532     }
1533
1534     if( splitEndGlyph && ( index == glyphEnd ) )
1535     {
1536       // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
1537
1538       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
1539       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
1540       // Get the direction of the character.
1541       CharacterDirection isCurrentRightToLeft = false;
1542       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
1543       {
1544         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
1545       }
1546
1547       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
1548
1549       const float xPosition = firstLine.alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
1550       mEventData->mDecorator->AddHighlight( xPosition,
1551                                             mScrollPosition.y,
1552                                             xPosition + static_cast<float>( interGlyphIndex ) * glyphAdvance,
1553                                             mScrollPosition.y + height );
1554
1555       splitEndGlyph = false;
1556       continue;
1557     }
1558
1559     const float xPosition = firstLine.alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x;
1560     mEventData->mDecorator->AddHighlight( xPosition,
1561                                           mScrollPosition.y,
1562                                           xPosition + glyph.advance,
1563                                           mScrollPosition.y + height );
1564   }
1565
1566   CursorInfo primaryCursorInfo;
1567   GetCursorPosition( mEventData->mLeftSelectionPosition,
1568                      primaryCursorInfo );
1569
1570   CursorInfo secondaryCursorInfo;
1571   GetCursorPosition( mEventData->mRightSelectionPosition,
1572                      secondaryCursorInfo );
1573
1574   const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mScrollPosition;
1575   const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mScrollPosition;
1576
1577   mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
1578                                        primaryPosition.x,
1579                                        primaryCursorInfo.lineOffset + mScrollPosition.y,
1580                                        primaryCursorInfo.lineHeight );
1581
1582   mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
1583                                        secondaryPosition.x,
1584                                        secondaryCursorInfo.lineOffset + mScrollPosition.y,
1585                                        secondaryCursorInfo.lineHeight );
1586
1587   // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
1588   mEventData->mPrimaryCursorPosition = ( indicesSwapped ) ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1589
1590   // Set the flag to update the decorator.
1591   mEventData->mDecoratorUpdated = true;
1592 }
1593
1594 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
1595 {
1596   if( NULL == mEventData )
1597   {
1598     // Nothing to do if there is no text input.
1599     return;
1600   }
1601
1602   if( IsShowingPlaceholderText() )
1603   {
1604     // Nothing to do if there is the place-holder text.
1605     return;
1606   }
1607
1608   const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
1609   const Length numberOfLines  = mVisualModel->mLines.Count();
1610   if( ( 0 == numberOfGlyphs ) ||
1611       ( 0 == numberOfLines ) )
1612   {
1613     // Nothing to do if there is no text.
1614     return;
1615   }
1616
1617   // Find which word was selected
1618   CharacterIndex selectionStart( 0 );
1619   CharacterIndex selectionEnd( 0 );
1620   FindSelectionIndices( mVisualModel,
1621                         mLogicalModel,
1622                         mMetrics,
1623                         visualX,
1624                         visualY,
1625                         selectionStart,
1626                         selectionEnd );
1627   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
1628
1629   if( selectionStart == selectionEnd )
1630   {
1631     ChangeState( EventData::EDITING );
1632     // Nothing to select. i.e. a white space, out of bounds
1633     return;
1634   }
1635
1636   mEventData->mLeftSelectionPosition = selectionStart;
1637   mEventData->mRightSelectionPosition = selectionEnd;
1638 }
1639
1640 void Controller::Impl::SetPopupButtons()
1641 {
1642   /**
1643    *  Sets the Popup buttons to be shown depending on State.
1644    *
1645    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
1646    *
1647    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
1648    */
1649
1650   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
1651
1652   if( EventData::SELECTING == mEventData->mState )
1653   {
1654     buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
1655
1656     if( !IsClipboardEmpty() )
1657     {
1658       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1659       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1660     }
1661
1662     if( !mEventData->mAllTextSelected )
1663     {
1664       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
1665     }
1666   }
1667   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
1668   {
1669     if( mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
1670     {
1671       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
1672     }
1673
1674     if( !IsClipboardEmpty() )
1675     {
1676       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1677       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1678     }
1679   }
1680   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
1681   {
1682     if ( !IsClipboardEmpty() )
1683     {
1684       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1685       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1686     }
1687   }
1688
1689   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
1690 }
1691
1692 void Controller::Impl::ChangeState( EventData::State newState )
1693 {
1694   if( NULL == mEventData )
1695   {
1696     // Nothing to do if there is no text input.
1697     return;
1698   }
1699
1700   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
1701
1702   if( mEventData->mState != newState )
1703   {
1704     mEventData->mState = newState;
1705
1706     if( EventData::INACTIVE == mEventData->mState )
1707     {
1708       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1709       mEventData->mDecorator->StopCursorBlink();
1710       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1711       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1712       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1713       mEventData->mDecorator->SetPopupActive( false );
1714       mEventData->mDecoratorUpdated = true;
1715       HideClipboard();
1716     }
1717     else if( EventData::INTERRUPTED  == mEventData->mState)
1718     {
1719       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1720       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1721       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1722       mEventData->mDecorator->SetPopupActive( false );
1723       mEventData->mDecoratorUpdated = true;
1724       HideClipboard();
1725     }
1726     else if( EventData::SELECTING == mEventData->mState )
1727     {
1728       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1729       mEventData->mDecorator->StopCursorBlink();
1730       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1731       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
1732       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
1733       if( mEventData->mGrabHandlePopupEnabled )
1734       {
1735         SetPopupButtons();
1736         mEventData->mDecorator->SetPopupActive( true );
1737       }
1738       mEventData->mDecoratorUpdated = true;
1739     }
1740     else if( EventData::EDITING == mEventData->mState )
1741     {
1742       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1743       if( mEventData->mCursorBlinkEnabled )
1744       {
1745         mEventData->mDecorator->StartCursorBlink();
1746       }
1747       // Grab handle is not shown until a tap is received whilst EDITING
1748       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1749       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1750       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1751       if( mEventData->mGrabHandlePopupEnabled )
1752       {
1753         mEventData->mDecorator->SetPopupActive( false );
1754       }
1755       mEventData->mDecoratorUpdated = true;
1756       HideClipboard();
1757     }
1758     else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
1759     {
1760       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
1761
1762       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1763       if( mEventData->mCursorBlinkEnabled )
1764       {
1765         mEventData->mDecorator->StartCursorBlink();
1766       }
1767       if( mEventData->mSelectionEnabled )
1768       {
1769         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1770         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1771       }
1772       else
1773       {
1774         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1775       }
1776       if( mEventData->mGrabHandlePopupEnabled )
1777       {
1778         SetPopupButtons();
1779         mEventData->mDecorator->SetPopupActive( true );
1780       }
1781       HideClipboard();
1782       mEventData->mDecoratorUpdated = true;
1783     }
1784     else if( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState )
1785     {
1786       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
1787
1788       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1789       if( mEventData->mCursorBlinkEnabled )
1790       {
1791         mEventData->mDecorator->StartCursorBlink();
1792       }
1793       // Grab handle is not shown until a tap is received whilst EDITING
1794       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1795       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1796       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1797       if( mEventData->mGrabHandlePopupEnabled )
1798       {
1799         mEventData->mDecorator->SetPopupActive( false );
1800       }
1801       mEventData->mDecoratorUpdated = true;
1802       HideClipboard();
1803     }
1804     else if( EventData::SELECTION_HANDLE_PANNING == mEventData->mState )
1805     {
1806       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1807       mEventData->mDecorator->StopCursorBlink();
1808       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1809       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
1810       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
1811       if( mEventData->mGrabHandlePopupEnabled )
1812       {
1813         mEventData->mDecorator->SetPopupActive( false );
1814       }
1815       mEventData->mDecoratorUpdated = true;
1816     }
1817     else if( EventData::GRAB_HANDLE_PANNING == mEventData->mState )
1818     {
1819       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
1820
1821       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1822       if( mEventData->mCursorBlinkEnabled )
1823       {
1824         mEventData->mDecorator->StartCursorBlink();
1825       }
1826       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1827       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1828       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1829       if( mEventData->mGrabHandlePopupEnabled )
1830       {
1831         mEventData->mDecorator->SetPopupActive( false );
1832       }
1833       mEventData->mDecoratorUpdated = true;
1834     }
1835     else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
1836     {
1837       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
1838
1839       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1840       if( mEventData->mCursorBlinkEnabled )
1841       {
1842         mEventData->mDecorator->StartCursorBlink();
1843       }
1844
1845       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1846       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1847       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1848
1849       if( mEventData->mGrabHandlePopupEnabled )
1850       {
1851         SetPopupButtons();
1852         mEventData->mDecorator->SetPopupActive( true );
1853       }
1854       HideClipboard();
1855       mEventData->mDecoratorUpdated = true;
1856     }
1857   }
1858 }
1859
1860 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
1861                                           CursorInfo& cursorInfo )
1862 {
1863   if( !IsShowingRealText() )
1864   {
1865     // Do not want to use the place-holder text to set the cursor position.
1866
1867     // Use the line's height of the font's family set to set the cursor's size.
1868     // If there is no font's family set, use the default font.
1869     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1870
1871     cursorInfo.lineOffset = 0.f;
1872     cursorInfo.lineHeight = GetDefaultFontLineHeight();
1873     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1874
1875     switch( mLayoutEngine.GetHorizontalAlignment() )
1876     {
1877       case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1878       {
1879         cursorInfo.primaryPosition.x = 0.f;
1880         break;
1881       }
1882       case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1883       {
1884         cursorInfo.primaryPosition.x = floorf( 0.5f * mVisualModel->mControlSize.width );
1885         break;
1886       }
1887       case LayoutEngine::HORIZONTAL_ALIGN_END:
1888       {
1889         cursorInfo.primaryPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1890         break;
1891       }
1892     }
1893
1894     // Nothing else to do.
1895     return;
1896   }
1897
1898   Text::GetCursorPosition( mVisualModel,
1899                            mLogicalModel,
1900                            mMetrics,
1901                            logical,
1902                            cursorInfo );
1903
1904   if( LayoutEngine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
1905   {
1906     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1907
1908     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1909     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1910
1911     if( 0.f > cursorInfo.primaryPosition.x )
1912     {
1913       cursorInfo.primaryPosition.x = 0.f;
1914     }
1915
1916     const float edgeWidth = mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
1917     if( cursorInfo.primaryPosition.x > edgeWidth )
1918     {
1919       cursorInfo.primaryPosition.x = edgeWidth;
1920     }
1921   }
1922 }
1923
1924 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
1925 {
1926   if( NULL == mEventData )
1927   {
1928     // Nothing to do if there is no text input.
1929     return 0u;
1930   }
1931
1932   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1933
1934   const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
1935   const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
1936
1937   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
1938   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
1939
1940   if( numberOfCharacters > 1u )
1941   {
1942     const Script script = mLogicalModel->GetScript( index );
1943     if( HasLigatureMustBreak( script ) )
1944     {
1945       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ,  ...
1946       numberOfCharacters = 1u;
1947     }
1948   }
1949   else
1950   {
1951     while( 0u == numberOfCharacters )
1952     {
1953       ++glyphIndex;
1954       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
1955     }
1956   }
1957
1958   if( index < mEventData->mPrimaryCursorPosition )
1959   {
1960     cursorIndex -= numberOfCharacters;
1961   }
1962   else
1963   {
1964     cursorIndex += numberOfCharacters;
1965   }
1966
1967   return cursorIndex;
1968 }
1969
1970 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
1971 {
1972   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
1973   if( NULL == mEventData )
1974   {
1975     // Nothing to do if there is no text input.
1976     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
1977     return;
1978   }
1979
1980   const Vector2 cursorPosition = cursorInfo.primaryPosition + mScrollPosition;
1981
1982   // Sets the cursor position.
1983   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
1984                                        cursorPosition.x,
1985                                        cursorPosition.y,
1986                                        cursorInfo.primaryCursorHeight,
1987                                        cursorInfo.lineHeight );
1988   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
1989
1990   // Sets the grab handle position.
1991   mEventData->mDecorator->SetPosition( GRAB_HANDLE,
1992                                        cursorPosition.x,
1993                                        cursorInfo.lineOffset + mScrollPosition.y,
1994                                        cursorInfo.lineHeight );
1995
1996   if( cursorInfo.isSecondaryCursor )
1997   {
1998     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
1999                                          cursorInfo.secondaryPosition.x + mScrollPosition.x,
2000                                          cursorInfo.secondaryPosition.y + mScrollPosition.y,
2001                                          cursorInfo.secondaryCursorHeight,
2002                                          cursorInfo.lineHeight );
2003     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mScrollPosition.x, cursorInfo.secondaryPosition.y + mScrollPosition.y );
2004   }
2005
2006   // Set which cursors are active according the state.
2007   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
2008   {
2009     if( cursorInfo.isSecondaryCursor )
2010     {
2011       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
2012     }
2013     else
2014     {
2015       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2016     }
2017   }
2018   else
2019   {
2020     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2021   }
2022
2023   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
2024 }
2025
2026 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
2027                                               const CursorInfo& cursorInfo )
2028 {
2029   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
2030       ( RIGHT_SELECTION_HANDLE != handleType ) )
2031   {
2032     return;
2033   }
2034
2035   const Vector2 cursorPosition = cursorInfo.primaryPosition + mScrollPosition;
2036
2037   // Sets the handle's position.
2038   mEventData->mDecorator->SetPosition( handleType,
2039                                        cursorPosition.x,
2040                                        cursorInfo.lineOffset + mScrollPosition.y,
2041                                        cursorInfo.lineHeight );
2042
2043   // If selection handle at start of the text and other at end of the text then all text is selected.
2044   const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2045   const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2046   mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mLogicalModel->mText.Count() );
2047 }
2048
2049 void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
2050 {
2051   // Clamp between -space & 0.
2052
2053   if( actualSize.width > mVisualModel->mControlSize.width )
2054   {
2055     const float space = ( actualSize.width - mVisualModel->mControlSize.width );
2056     mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
2057     mScrollPosition.x = ( mScrollPosition.x > 0.f ) ? 0.f : mScrollPosition.x;
2058
2059     mEventData->mDecoratorUpdated = true;
2060   }
2061   else
2062   {
2063     mScrollPosition.x = 0.f;
2064   }
2065 }
2066
2067 void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
2068 {
2069   // Clamp between -space & 0.
2070   if( actualSize.height > mVisualModel->mControlSize.height )
2071   {
2072     const float space = ( actualSize.height - mVisualModel->mControlSize.height );
2073     mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
2074     mScrollPosition.y = ( mScrollPosition.y > 0.f ) ? 0.f : mScrollPosition.y;
2075
2076     mEventData->mDecoratorUpdated = true;
2077   }
2078   else
2079   {
2080     mScrollPosition.y = 0.f;
2081   }
2082 }
2083
2084 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
2085 {
2086   const float cursorWidth = mEventData->mDecorator ? mEventData->mDecorator->GetCursorWidth() : 0.f;
2087
2088   // position is in actor's coords.
2089   const float positionEnd = position.x + cursorWidth;
2090
2091   // Transform the position to decorator coords.
2092   const float decoratorPositionBegin = position.x + mScrollPosition.x;
2093   const float decoratorPositionEnd = positionEnd + mScrollPosition.x;
2094
2095   if( decoratorPositionBegin < 0.f )
2096   {
2097     mScrollPosition.x = -position.x;
2098   }
2099   else if( decoratorPositionEnd > mVisualModel->mControlSize.width )
2100   {
2101     mScrollPosition.x = mVisualModel->mControlSize.width - positionEnd;
2102   }
2103 }
2104
2105 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
2106 {
2107   // Get the current cursor position in decorator coords.
2108   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2109
2110   // Calculate the offset to match the cursor position before the character was deleted.
2111   mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
2112
2113   ClampHorizontalScroll( mVisualModel->GetLayoutSize() );
2114
2115   // Makes the new cursor position visible if needed.
2116   ScrollToMakePositionVisible( cursorInfo.primaryPosition );
2117 }
2118
2119 void Controller::Impl::RequestRelayout()
2120 {
2121   mControlInterface.RequestTextRelayout();
2122 }
2123
2124 } // namespace Text
2125
2126 } // namespace Toolkit
2127
2128 } // namespace Dali