Text Editing (enable) property in text controls
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2017 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/public-api/rendering/renderer.h>
24 #include <dali/integration-api/debug.h>
25 #include <limits>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
29 #include <dali-toolkit/internal/text/bidirectional-support.h>
30 #include <dali-toolkit/internal/text/character-set-conversion.h>
31 #include <dali-toolkit/internal/text/color-segmentation.h>
32 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/segmentation.h>
35 #include <dali-toolkit/internal/text/shaper.h>
36 #include <dali-toolkit/internal/text/text-control-interface.h>
37 #include <dali-toolkit/internal/text/text-run-container.h>
38
39 using namespace Dali;
40
41 namespace
42 {
43
44 /**
45  * @brief Struct used to calculate the selection box.
46  */
47 struct SelectionBoxInfo
48 {
49   float lineOffset;
50   float lineHeight;
51   float minX;
52   float maxX;
53 };
54
55 #if defined(DEBUG_ENABLED)
56   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
57 #endif
58
59 const float MAX_FLOAT = std::numeric_limits<float>::max();
60 const float MIN_FLOAT = std::numeric_limits<float>::min();
61 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
62
63 #define MAKE_SHADER(A)#A
64
65 const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
66 attribute mediump vec2    aPosition;
67 attribute mediump vec4    aColor;
68 varying   mediump vec4    vColor;
69 uniform   highp mat4      uMvpMatrix;
70
71 void main()
72 {
73   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
74   gl_Position = uMvpMatrix * position;
75   vColor = aColor;
76 }
77 );
78
79 const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
80 varying mediump vec4      vColor;
81 uniform lowp    vec4      uColor;
82
83 void main()
84 {
85   gl_FragColor = vColor * uColor;
86 }
87 );
88
89 struct BackgroundVertex
90 {
91   Vector2 mPosition;        ///< Vertex posiiton
92   Vector4 mColor;           ///< Vertex color
93 };
94
95 struct BackgroundMesh
96 {
97   Vector< BackgroundVertex > mVertices;    ///< container of vertices
98   Vector< unsigned short > mIndices;       ///< container of indices
99 };
100
101 const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f );
102 const Dali::Vector4 BACKGROUND_SUB4( 0.58f, 0.87f, 0.96f, 1.f );
103 const Dali::Vector4 BACKGROUND_SUB5( 0.83f, 0.94f, 0.98f, 1.f );
104 const Dali::Vector4 BACKGROUND_SUB6( 1.f, 0.5f, 0.5f, 1.f );
105 const Dali::Vector4 BACKGROUND_SUB7( 1.f, 0.8f, 0.8f, 1.f );
106
107 } // namespace
108
109 namespace Dali
110 {
111
112 namespace Toolkit
113 {
114
115 namespace Text
116 {
117
118 EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
119 : mDecorator( decorator ),
120   mInputMethodContext( inputMethodContext ),
121   mPlaceholderFont( NULL ),
122   mPlaceholderTextActive(),
123   mPlaceholderTextInactive(),
124   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
125   mEventQueue(),
126   mInputStyleChangedQueue(),
127   mPreviousState( INACTIVE ),
128   mState( INACTIVE ),
129   mPrimaryCursorPosition( 0u ),
130   mLeftSelectionPosition( 0u ),
131   mRightSelectionPosition( 0u ),
132   mPreEditStartPosition( 0u ),
133   mPreEditLength( 0u ),
134   mCursorHookPositionX( 0.f ),
135   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
136   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
137   mIsShowingPlaceholderText( false ),
138   mPreEditFlag( false ),
139   mDecoratorUpdated( false ),
140   mCursorBlinkEnabled( true ),
141   mGrabHandleEnabled( true ),
142   mGrabHandlePopupEnabled( true ),
143   mSelectionEnabled( true ),
144   mUpdateCursorHookPosition( false ),
145   mUpdateCursorPosition( false ),
146   mUpdateGrabHandlePosition( false ),
147   mUpdateLeftSelectionPosition( false ),
148   mUpdateRightSelectionPosition( false ),
149   mIsLeftHandleSelected( false ),
150   mIsRightHandleSelected( false ),
151   mUpdateHighlightBox( false ),
152   mScrollAfterUpdatePosition( false ),
153   mScrollAfterDelete( false ),
154   mAllTextSelected( false ),
155   mUpdateInputStyle( false ),
156   mPasswordInput( false ),
157   mCheckScrollAmount( false ),
158   mIsPlaceholderPixelSize( false ),
159   mIsPlaceholderElideEnabled( false ),
160   mPlaceholderEllipsisFlag( false ),
161   mShiftSelectionFlag( true ),
162   mUpdateAlignment( false ),
163   mEditingEnabled( true )
164 {
165 }
166
167 EventData::~EventData()
168 {}
169
170 bool Controller::Impl::ProcessInputEvents()
171 {
172   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
173   if( NULL == mEventData )
174   {
175     // Nothing to do if there is no text input.
176     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
177     return false;
178   }
179
180   if( mEventData->mDecorator )
181   {
182     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
183          iter != mEventData->mEventQueue.end();
184          ++iter )
185     {
186       switch( iter->type )
187       {
188         case Event::CURSOR_KEY_EVENT:
189         {
190           OnCursorKeyEvent( *iter );
191           break;
192         }
193         case Event::TAP_EVENT:
194         {
195           OnTapEvent( *iter );
196           break;
197         }
198         case Event::LONG_PRESS_EVENT:
199         {
200           OnLongPressEvent( *iter );
201           break;
202         }
203         case Event::PAN_EVENT:
204         {
205           OnPanEvent( *iter );
206           break;
207         }
208         case Event::GRAB_HANDLE_EVENT:
209         case Event::LEFT_SELECTION_HANDLE_EVENT:
210         case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
211         {
212           OnHandleEvent( *iter );
213           break;
214         }
215         case Event::SELECT:
216         {
217           OnSelectEvent( *iter );
218           break;
219         }
220         case Event::SELECT_ALL:
221         {
222           OnSelectAllEvent();
223           break;
224         }
225         case Event::SELECT_NONE:
226         {
227           OnSelectNoneEvent();
228           break;
229         }
230       }
231     }
232   }
233
234   if( mEventData->mUpdateCursorPosition ||
235       mEventData->mUpdateHighlightBox )
236   {
237     NotifyInputMethodContext();
238   }
239
240   // The cursor must also be repositioned after inserts into the model
241   if( mEventData->mUpdateCursorPosition )
242   {
243     // Updates the cursor position and scrolls the text to make it visible.
244     CursorInfo cursorInfo;
245     // Calculate the cursor position from the new cursor index.
246     GetCursorPosition( mEventData->mPrimaryCursorPosition,
247                        cursorInfo );
248
249     if( mEventData->mUpdateCursorHookPosition )
250     {
251       // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
252       mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
253       mEventData->mUpdateCursorHookPosition = false;
254     }
255
256     // Scroll first the text after delete ...
257     if( mEventData->mScrollAfterDelete )
258     {
259       ScrollTextToMatchCursor( cursorInfo );
260     }
261
262     // ... then, text can be scrolled to make the cursor visible.
263     if( mEventData->mScrollAfterUpdatePosition )
264     {
265       const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
266       ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
267     }
268     mEventData->mScrollAfterUpdatePosition = false;
269     mEventData->mScrollAfterDelete = false;
270
271     UpdateCursorPosition( cursorInfo );
272
273     mEventData->mDecoratorUpdated = true;
274     mEventData->mUpdateCursorPosition = false;
275     mEventData->mUpdateGrabHandlePosition = false;
276   }
277   else
278   {
279     CursorInfo leftHandleInfo;
280     CursorInfo rightHandleInfo;
281
282     if( mEventData->mUpdateHighlightBox )
283     {
284       GetCursorPosition( mEventData->mLeftSelectionPosition,
285                          leftHandleInfo );
286
287       GetCursorPosition( mEventData->mRightSelectionPosition,
288                          rightHandleInfo );
289
290       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
291       {
292         if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
293         {
294           CursorInfo& infoLeft = leftHandleInfo;
295
296           const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
297           ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
298
299           CursorInfo& infoRight = rightHandleInfo;
300
301           const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
302           ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
303         }
304         else
305         {
306           CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
307
308           const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
309           ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
310         }
311       }
312     }
313
314     if( mEventData->mUpdateLeftSelectionPosition )
315     {
316       UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
317                              leftHandleInfo );
318
319       SetPopupButtons();
320       mEventData->mDecoratorUpdated = true;
321       mEventData->mUpdateLeftSelectionPosition = false;
322     }
323
324     if( mEventData->mUpdateRightSelectionPosition )
325     {
326       UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
327                              rightHandleInfo );
328
329       SetPopupButtons();
330       mEventData->mDecoratorUpdated = true;
331       mEventData->mUpdateRightSelectionPosition = false;
332     }
333
334     if( mEventData->mUpdateHighlightBox )
335     {
336       RepositionSelectionHandles();
337
338       mEventData->mUpdateLeftSelectionPosition = false;
339       mEventData->mUpdateRightSelectionPosition = false;
340       mEventData->mUpdateHighlightBox = false;
341       mEventData->mIsLeftHandleSelected = false;
342       mEventData->mIsRightHandleSelected = false;
343     }
344
345     mEventData->mScrollAfterUpdatePosition = false;
346   }
347
348   if( mEventData->mUpdateInputStyle )
349   {
350     // Keep a copy of the current input style.
351     InputStyle currentInputStyle;
352     currentInputStyle.Copy( mEventData->mInputStyle );
353
354     // Set the default style first.
355     RetrieveDefaultInputStyle( mEventData->mInputStyle );
356
357     // Get the character index from the cursor index.
358     const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
359
360     // Retrieve the style from the style runs stored in the logical model.
361     mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
362
363     // Compare if the input style has changed.
364     const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
365
366     if( hasInputStyleChanged )
367     {
368       const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
369       // Queue the input style changed signal.
370       mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
371     }
372
373     mEventData->mUpdateInputStyle = false;
374   }
375
376   mEventData->mEventQueue.clear();
377
378   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
379
380   const bool decoratorUpdated = mEventData->mDecoratorUpdated;
381   mEventData->mDecoratorUpdated = false;
382
383   return decoratorUpdated;
384 }
385
386 void Controller::Impl::NotifyInputMethodContext()
387 {
388   if( mEventData && mEventData->mInputMethodContext )
389   {
390     CharacterIndex cursorPosition = GetLogicalCursorPosition();
391
392     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
393
394     // Update the cursor position by removing the initial white spaces.
395     if( cursorPosition < numberOfWhiteSpaces )
396     {
397       cursorPosition = 0u;
398     }
399     else
400     {
401       cursorPosition -= numberOfWhiteSpaces;
402     }
403
404     mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
405     mEventData->mInputMethodContext.NotifyCursorPosition();
406   }
407 }
408
409 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
410 {
411   if ( mEventData && mEventData->mInputMethodContext )
412   {
413     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
414     mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
415   }
416 }
417
418 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
419 {
420   CharacterIndex cursorPosition = 0u;
421
422   if( mEventData )
423   {
424     if( ( EventData::SELECTING == mEventData->mState ) ||
425         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
426     {
427       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
428     }
429     else
430     {
431       cursorPosition = mEventData->mPrimaryCursorPosition;
432     }
433   }
434
435   return cursorPosition;
436 }
437
438 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
439 {
440   Length numberOfWhiteSpaces = 0u;
441
442   // Get the buffer to the text.
443   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
444
445   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
446   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
447   {
448     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
449     {
450       break;
451     }
452   }
453
454   return numberOfWhiteSpaces;
455 }
456
457 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
458 {
459   // Get the total number of characters.
460   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
461
462   // Retrieve the text.
463   if( 0u != numberOfCharacters )
464   {
465     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
466   }
467 }
468
469 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
470 {
471   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
472   mTextUpdateInfo.mStartGlyphIndex = 0u;
473   mTextUpdateInfo.mStartLineIndex = 0u;
474   numberOfCharacters = 0u;
475
476   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
477   if( 0u == numberOfParagraphs )
478   {
479     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
480     numberOfCharacters = 0u;
481
482     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
483
484     // Nothing else to do if there are no paragraphs.
485     return;
486   }
487
488   // Find the paragraphs to be updated.
489   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
490   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
491   {
492     // Text is being added at the end of the current text.
493     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
494     {
495       // Text is being added in a new paragraph after the last character of the text.
496       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
497       numberOfCharacters = 0u;
498       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
499
500       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
501       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
502
503       // Nothing else to do;
504       return;
505     }
506
507     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
508   }
509   else
510   {
511     Length numberOfCharactersToUpdate = 0u;
512     if( mTextUpdateInfo.mFullRelayoutNeeded )
513     {
514       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
515     }
516     else
517     {
518       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
519     }
520     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
521                                            numberOfCharactersToUpdate,
522                                            paragraphsToBeUpdated );
523   }
524
525   if( 0u != paragraphsToBeUpdated.Count() )
526   {
527     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
528     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
529     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
530
531     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
532     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
533
534     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
535         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
536         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
537           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
538     {
539       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
540       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
541
542       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
543     }
544     else
545     {
546       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
547     }
548   }
549
550   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
551   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
552 }
553
554 void Controller::Impl::ClearFullModelData( OperationsMask operations )
555 {
556   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
557   {
558     mModel->mLogicalModel->mLineBreakInfo.Clear();
559     mModel->mLogicalModel->mParagraphInfo.Clear();
560   }
561
562   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
563   {
564     mModel->mLogicalModel->mScriptRuns.Clear();
565   }
566
567   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
568   {
569     mModel->mLogicalModel->mFontRuns.Clear();
570   }
571
572   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
573   {
574     if( NO_OPERATION != ( BIDI_INFO & operations ) )
575     {
576       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
577       mModel->mLogicalModel->mCharacterDirections.Clear();
578     }
579
580     if( NO_OPERATION != ( REORDER & operations ) )
581     {
582       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
583       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
584              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
585            it != endIt;
586            ++it )
587       {
588         BidirectionalLineInfoRun& bidiLineInfo = *it;
589
590         free( bidiLineInfo.visualToLogicalMap );
591         bidiLineInfo.visualToLogicalMap = NULL;
592       }
593       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
594     }
595   }
596
597   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
598   {
599     mModel->mVisualModel->mGlyphs.Clear();
600     mModel->mVisualModel->mGlyphsToCharacters.Clear();
601     mModel->mVisualModel->mCharactersToGlyph.Clear();
602     mModel->mVisualModel->mCharactersPerGlyph.Clear();
603     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
604     mModel->mVisualModel->mGlyphPositions.Clear();
605   }
606
607   if( NO_OPERATION != ( LAYOUT & operations ) )
608   {
609     mModel->mVisualModel->mLines.Clear();
610   }
611
612   if( NO_OPERATION != ( COLOR & operations ) )
613   {
614     mModel->mVisualModel->mColorIndices.Clear();
615     mModel->mVisualModel->mBackgroundColorIndices.Clear();
616   }
617 }
618
619 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
620 {
621   const CharacterIndex endIndexPlusOne = endIndex + 1u;
622
623   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
624   {
625     // Clear the line break info.
626     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
627
628     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
629                                                  lineBreakInfoBuffer + endIndexPlusOne );
630
631     // Clear the paragraphs.
632     ClearCharacterRuns( startIndex,
633                         endIndex,
634                         mModel->mLogicalModel->mParagraphInfo );
635   }
636
637   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
638   {
639     // Clear the scripts.
640     ClearCharacterRuns( startIndex,
641                         endIndex,
642                         mModel->mLogicalModel->mScriptRuns );
643   }
644
645   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
646   {
647     // Clear the fonts.
648     ClearCharacterRuns( startIndex,
649                         endIndex,
650                         mModel->mLogicalModel->mFontRuns );
651   }
652
653   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
654   {
655     if( NO_OPERATION != ( BIDI_INFO & operations ) )
656     {
657       // Clear the bidirectional paragraph info.
658       ClearCharacterRuns( startIndex,
659                           endIndex,
660                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
661
662       // Clear the character's directions.
663       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
664
665       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
666                                                          characterDirectionsBuffer + endIndexPlusOne );
667     }
668
669     if( NO_OPERATION != ( REORDER & operations ) )
670     {
671       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
672       uint32_t endRemoveIndex = startRemoveIndex;
673       ClearCharacterRuns( startIndex,
674                           endIndex,
675                           mModel->mLogicalModel->mBidirectionalLineInfo,
676                           startRemoveIndex,
677                           endRemoveIndex );
678
679       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
680
681       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
682       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
683              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
684            it != endIt;
685            ++it )
686       {
687         BidirectionalLineInfoRun& bidiLineInfo = *it;
688
689         free( bidiLineInfo.visualToLogicalMap );
690         bidiLineInfo.visualToLogicalMap = NULL;
691       }
692
693       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
694                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
695     }
696   }
697 }
698
699 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
700 {
701   const CharacterIndex endIndexPlusOne = endIndex + 1u;
702   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
703
704   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
705   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
706   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
707
708   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
709   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
710
711   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
712   {
713     // Update the character to glyph indices.
714     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
715            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
716          it != endIt;
717          ++it )
718     {
719       CharacterIndex& index = *it;
720       index -= numberOfGlyphsRemoved;
721     }
722
723     // Clear the character to glyph conversion table.
724     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
725                                                     charactersToGlyphBuffer + endIndexPlusOne );
726
727     // Clear the glyphs per character table.
728     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
729                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
730
731     // Clear the glyphs buffer.
732     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
733     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
734                                          glyphsBuffer + endGlyphIndexPlusOne );
735
736     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
737
738     // Update the glyph to character indices.
739     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
740            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
741          it != endIt;
742          ++it )
743     {
744       CharacterIndex& index = *it;
745       index -= numberOfCharactersRemoved;
746     }
747
748     // Clear the glyphs to characters buffer.
749     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
750                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
751
752     // Clear the characters per glyph buffer.
753     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
754     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
755                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
756
757     // Clear the positions buffer.
758     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
759     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
760                                                  positionsBuffer + endGlyphIndexPlusOne );
761   }
762
763   if( NO_OPERATION != ( LAYOUT & operations ) )
764   {
765     // Clear the lines.
766     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
767     uint32_t endRemoveIndex = startRemoveIndex;
768     ClearCharacterRuns( startIndex,
769                         endIndex,
770                         mModel->mVisualModel->mLines,
771                         startRemoveIndex,
772                         endRemoveIndex );
773
774     // Will update the glyph runs.
775     startRemoveIndex = mModel->mVisualModel->mLines.Count();
776     endRemoveIndex = startRemoveIndex;
777     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
778                     endGlyphIndexPlusOne - 1u,
779                     mModel->mVisualModel->mLines,
780                     startRemoveIndex,
781                     endRemoveIndex );
782
783     // Set the line index from where to insert the new laid-out lines.
784     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
785
786     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
787     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
788                                         linesBuffer + endRemoveIndex );
789   }
790
791   if( NO_OPERATION != ( COLOR & operations ) )
792   {
793     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
794     {
795       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
796       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
797                                                  colorIndexBuffer + endGlyphIndexPlusOne );
798     }
799
800     if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
801     {
802       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
803       mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
804                                                            backgroundColorIndexBuffer + endGlyphIndexPlusOne );
805     }
806   }
807 }
808
809 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
810 {
811   if( mTextUpdateInfo.mClearAll ||
812       ( ( 0u == startIndex ) &&
813         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
814   {
815     ClearFullModelData( operations );
816   }
817   else
818   {
819     // Clear the model data related with characters.
820     ClearCharacterModelData( startIndex, endIndex, operations );
821
822     // Clear the model data related with glyphs.
823     ClearGlyphModelData( startIndex, endIndex, operations );
824   }
825
826   // The estimated number of lines. Used to avoid reallocations when layouting.
827   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
828
829   mModel->mVisualModel->ClearCaches();
830 }
831
832 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
833 {
834   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
835
836   // Calculate the operations to be done.
837   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
838
839   if( NO_OPERATION == operations )
840   {
841     // Nothing to do if no operations are pending and required.
842     return false;
843   }
844
845   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
846   Vector<Character> displayCharacters;
847   bool useHiddenText = false;
848   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
849   {
850     mHiddenInput->Substitute( srcCharacters,displayCharacters );
851     useHiddenText = true;
852   }
853
854   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
855   const Length numberOfCharacters = utf32Characters.Count();
856
857   // Index to the first character of the first paragraph to be updated.
858   CharacterIndex startIndex = 0u;
859   // Number of characters of the paragraphs to be removed.
860   Length paragraphCharacters = 0u;
861
862   CalculateTextUpdateIndices( paragraphCharacters );
863
864   // Check whether the indices for updating the text is valid
865   if ( numberOfCharacters > 0u &&
866        ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
867          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
868   {
869     std::string currentText;
870     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
871
872     DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
873     DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
874
875     // Dump mTextUpdateInfo
876     DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
877     DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
878     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
879     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
880     DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
881     DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
882     DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
883     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
884     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
885     DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
886     DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
887     DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
888     DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
889
890     return false;
891   }
892
893   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
894
895   if( mTextUpdateInfo.mClearAll ||
896       ( 0u != paragraphCharacters ) )
897   {
898     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
899   }
900
901   mTextUpdateInfo.mClearAll = false;
902
903   // Whether the model is updated.
904   bool updated = false;
905
906   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
907   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
908
909   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
910   {
911     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
912     // calculate the bidirectional info for each 'paragraph'.
913     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
914     // is not shaped together).
915     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
916
917     SetLineBreakInfo( utf32Characters,
918                       startIndex,
919                       requestedNumberOfCharacters,
920                       lineBreakInfo );
921
922     // Create the paragraph info.
923     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
924                                                 requestedNumberOfCharacters );
925     updated = true;
926   }
927
928   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
929   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
930
931   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
932   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
933
934   if( getScripts || validateFonts )
935   {
936     // Validates the fonts assigned by the application or assigns default ones.
937     // It makes sure all the characters are going to be rendered by the correct font.
938     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
939
940     if( getScripts )
941     {
942       // Retrieves the scripts used in the text.
943       multilanguageSupport.SetScripts( utf32Characters,
944                                        startIndex,
945                                        requestedNumberOfCharacters,
946                                        scripts );
947     }
948
949     if( validateFonts )
950     {
951       // Validate the fonts set through the mark-up string.
952       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
953
954       // Get the default font's description.
955       TextAbstraction::FontDescription defaultFontDescription;
956       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
957
958       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
959       {
960         // If the placeholder font is set specifically, only placeholder font is changed.
961         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
962         if( mEventData->mPlaceholderFont->sizeDefined )
963         {
964           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
965         }
966       }
967       else if( NULL != mFontDefaults )
968       {
969         // Set the normal font and the placeholder font.
970         defaultFontDescription = mFontDefaults->mFontDescription;
971
972         if( mTextFitEnabled )
973         {
974           defaultPointSize = mFontDefaults->mFitPointSize * 64u;
975         }
976         else
977         {
978           defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
979         }
980       }
981
982       // Validates the fonts. If there is a character with no assigned font it sets a default one.
983       // After this call, fonts are validated.
984       multilanguageSupport.ValidateFonts( utf32Characters,
985                                           scripts,
986                                           fontDescriptionRuns,
987                                           defaultFontDescription,
988                                           defaultPointSize,
989                                           startIndex,
990                                           requestedNumberOfCharacters,
991                                           validFonts );
992     }
993     updated = true;
994   }
995
996   Vector<Character> mirroredUtf32Characters;
997   bool textMirrored = false;
998   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
999   if( NO_OPERATION != ( BIDI_INFO & operations ) )
1000   {
1001     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
1002     bidirectionalInfo.Reserve( numberOfParagraphs );
1003
1004     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
1005     SetBidirectionalInfo( utf32Characters,
1006                           scripts,
1007                           lineBreakInfo,
1008                           startIndex,
1009                           requestedNumberOfCharacters,
1010                           bidirectionalInfo,
1011                           mModel->mMatchSystemLanguageDirection,
1012                           mLayoutDirection );
1013
1014     if( 0u != bidirectionalInfo.Count() )
1015     {
1016       // Only set the character directions if there is right to left characters.
1017       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
1018       GetCharactersDirection( bidirectionalInfo,
1019                               numberOfCharacters,
1020                               startIndex,
1021                               requestedNumberOfCharacters,
1022                               directions );
1023
1024       // This paragraph has right to left text. Some characters may need to be mirrored.
1025       // TODO: consider if the mirrored string can be stored as well.
1026
1027       textMirrored = GetMirroredText( utf32Characters,
1028                                       directions,
1029                                       bidirectionalInfo,
1030                                       startIndex,
1031                                       requestedNumberOfCharacters,
1032                                       mirroredUtf32Characters );
1033     }
1034     else
1035     {
1036       // There is no right to left characters. Clear the directions vector.
1037       mModel->mLogicalModel->mCharacterDirections.Clear();
1038     }
1039     updated = true;
1040   }
1041
1042   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
1043   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
1044   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
1045   Vector<GlyphIndex> newParagraphGlyphs;
1046   newParagraphGlyphs.Reserve( numberOfParagraphs );
1047
1048   const Length currentNumberOfGlyphs = glyphs.Count();
1049   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
1050   {
1051     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1052     // Shapes the text.
1053     ShapeText( textToShape,
1054                lineBreakInfo,
1055                scripts,
1056                validFonts,
1057                startIndex,
1058                mTextUpdateInfo.mStartGlyphIndex,
1059                requestedNumberOfCharacters,
1060                glyphs,
1061                glyphsToCharactersMap,
1062                charactersPerGlyph,
1063                newParagraphGlyphs );
1064
1065     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1066     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1067     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1068     updated = true;
1069   }
1070
1071   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
1072
1073   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
1074   {
1075     GlyphInfo* glyphsBuffer = glyphs.Begin();
1076     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
1077
1078     // Update the width and advance of all new paragraph characters.
1079     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
1080     {
1081       const GlyphIndex index = *it;
1082       GlyphInfo& glyph = *( glyphsBuffer + index );
1083
1084       glyph.xBearing = 0.f;
1085       glyph.width = 0.f;
1086       glyph.advance = 0.f;
1087     }
1088     updated = true;
1089   }
1090
1091   if( ( NULL != mEventData ) &&
1092       mEventData->mPreEditFlag &&
1093       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
1094   {
1095     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
1096     mEventData->mInputMethodContext.GetPreeditStyle( attrs );
1097     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
1098
1099     // Check the type of preedit and run it.
1100     for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
1101     {
1102       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
1103       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
1104       type = attrData.preeditType;
1105
1106       // Check the number of commit characters for the start position.
1107       unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
1108       Length numberOfIndices = attrData.endIndex - attrData.startIndex;
1109
1110       switch( type )
1111       {
1112         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
1113         {
1114           // Add the underline for the pre-edit text.
1115           GlyphRun underlineRun;
1116           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1117           underlineRun.numberOfGlyphs = numberOfIndices;
1118           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1119           break;
1120         }
1121         case Dali::InputMethodContext::PreeditStyle::REVERSE:
1122         {
1123           Vector4 textColor = mModel->mVisualModel->GetTextColor();
1124           ColorRun backgroundColorRun;
1125           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1126           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1127           backgroundColorRun.color = textColor;
1128           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1129
1130           Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
1131           Vector<ColorRun>  colorRuns;
1132           colorRuns.Resize( 1u );
1133           ColorRun& colorRun = *( colorRuns.Begin() );
1134           colorRun.color = backgroundColor;
1135           colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1136           colorRun.characterRun.numberOfCharacters = numberOfIndices;
1137
1138           mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
1139           break;
1140         }
1141         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
1142         {
1143           ColorRun backgroundColorRun;
1144           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1145           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1146           backgroundColorRun.color = LIGHT_BLUE;
1147           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1148           break;
1149         }
1150         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
1151         {
1152           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
1153           ColorRun backgroundColorRun;
1154           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1155           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1156           backgroundColorRun.color = BACKGROUND_SUB4;
1157           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1158
1159           GlyphRun underlineRun;
1160           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1161           underlineRun.numberOfGlyphs = numberOfIndices;
1162           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1163           break;
1164         }
1165         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
1166         {
1167           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
1168           ColorRun backgroundColorRun;
1169           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1170           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1171           backgroundColorRun.color = BACKGROUND_SUB5;
1172           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1173
1174           GlyphRun underlineRun;
1175           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1176           underlineRun.numberOfGlyphs = numberOfIndices;
1177           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1178           break;
1179         }
1180         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
1181         {
1182           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
1183           ColorRun backgroundColorRun;
1184           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1185           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1186           backgroundColorRun.color = BACKGROUND_SUB6;
1187           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1188
1189           GlyphRun underlineRun;
1190           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1191           underlineRun.numberOfGlyphs = numberOfIndices;
1192           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1193           break;
1194         }
1195         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
1196         {
1197           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
1198           ColorRun backgroundColorRun;
1199           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
1200           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1201           backgroundColorRun.color = BACKGROUND_SUB7;
1202           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
1203
1204           GlyphRun underlineRun;
1205           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
1206           underlineRun.numberOfGlyphs = numberOfIndices;
1207           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1208           break;
1209         }
1210         case Dali::InputMethodContext::PreeditStyle::NONE:
1211         default:
1212         {
1213           break;
1214         }
1215       }
1216     }
1217     attrs.Clear();
1218     updated = true;
1219   }
1220
1221   if( NO_OPERATION != ( COLOR & operations ) )
1222   {
1223     // Set the color runs in glyphs.
1224     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
1225                               mModel->mVisualModel->mCharactersToGlyph,
1226                               mModel->mVisualModel->mGlyphsPerCharacter,
1227                               startIndex,
1228                               mTextUpdateInfo.mStartGlyphIndex,
1229                               requestedNumberOfCharacters,
1230                               mModel->mVisualModel->mColors,
1231                               mModel->mVisualModel->mColorIndices );
1232
1233     // Set the background color runs in glyphs.
1234     SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
1235                               mModel->mVisualModel->mCharactersToGlyph,
1236                               mModel->mVisualModel->mGlyphsPerCharacter,
1237                               startIndex,
1238                               mTextUpdateInfo.mStartGlyphIndex,
1239                               requestedNumberOfCharacters,
1240                               mModel->mVisualModel->mBackgroundColors,
1241                               mModel->mVisualModel->mBackgroundColorIndices );
1242
1243     updated = true;
1244   }
1245
1246
1247   // The estimated number of lines. Used to avoid reallocations when layouting.
1248   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
1249
1250   // Set the previous number of characters for the next time the text is updated.
1251   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1252
1253   return updated;
1254 }
1255
1256 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1257 {
1258   // Sets the default text's color.
1259   inputStyle.textColor = mTextColor;
1260   inputStyle.isDefaultColor = true;
1261
1262   inputStyle.familyName.clear();
1263   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1264   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1265   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1266   inputStyle.size = 0.f;
1267
1268   inputStyle.lineSpacing = 0.f;
1269
1270   inputStyle.underlineProperties.clear();
1271   inputStyle.shadowProperties.clear();
1272   inputStyle.embossProperties.clear();
1273   inputStyle.outlineProperties.clear();
1274
1275   inputStyle.isFamilyDefined = false;
1276   inputStyle.isWeightDefined = false;
1277   inputStyle.isWidthDefined = false;
1278   inputStyle.isSlantDefined = false;
1279   inputStyle.isSizeDefined = false;
1280
1281   inputStyle.isLineSpacingDefined = false;
1282
1283   inputStyle.isUnderlineDefined = false;
1284   inputStyle.isShadowDefined = false;
1285   inputStyle.isEmbossDefined = false;
1286   inputStyle.isOutlineDefined = false;
1287
1288   // Sets the default font's family name, weight, width, slant and size.
1289   if( mFontDefaults )
1290   {
1291     if( mFontDefaults->familyDefined )
1292     {
1293       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1294       inputStyle.isFamilyDefined = true;
1295     }
1296
1297     if( mFontDefaults->weightDefined )
1298     {
1299       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1300       inputStyle.isWeightDefined = true;
1301     }
1302
1303     if( mFontDefaults->widthDefined )
1304     {
1305       inputStyle.width = mFontDefaults->mFontDescription.width;
1306       inputStyle.isWidthDefined = true;
1307     }
1308
1309     if( mFontDefaults->slantDefined )
1310     {
1311       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1312       inputStyle.isSlantDefined = true;
1313     }
1314
1315     if( mFontDefaults->sizeDefined )
1316     {
1317       inputStyle.size = mFontDefaults->mDefaultPointSize;
1318       inputStyle.isSizeDefined = true;
1319     }
1320   }
1321 }
1322
1323 float Controller::Impl::GetDefaultFontLineHeight()
1324 {
1325   FontId defaultFontId = 0u;
1326   if( NULL == mFontDefaults )
1327   {
1328     TextAbstraction::FontDescription fontDescription;
1329     defaultFontId = mFontClient.GetFontId( fontDescription );
1330   }
1331   else
1332   {
1333     defaultFontId = mFontDefaults->GetFontId( mFontClient );
1334   }
1335
1336   Text::FontMetrics fontMetrics;
1337   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1338
1339   return( fontMetrics.ascender - fontMetrics.descender );
1340 }
1341
1342 void Controller::Impl::OnCursorKeyEvent( const Event& event )
1343 {
1344   if( NULL == mEventData || !IsShowingRealText() )
1345   {
1346     // Nothing to do if there is no text input.
1347     return;
1348   }
1349
1350   int keyCode = event.p1.mInt;
1351   bool isShiftModifier = event.p2.mBool;
1352
1353   CharacterIndex previousPrimaryCursorPosition = mEventData->mPrimaryCursorPosition;
1354
1355   if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
1356   {
1357     if( mEventData->mPrimaryCursorPosition > 0u )
1358     {
1359       if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
1360       {
1361         mEventData->mPrimaryCursorPosition = std::min(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
1362       }
1363       else
1364       {
1365         mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
1366       }
1367     }
1368   }
1369   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
1370   {
1371     if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
1372     {
1373       if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
1374       {
1375         mEventData->mPrimaryCursorPosition = std::max(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
1376       }
1377       else
1378       {
1379         mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
1380       }
1381     }
1382   }
1383   else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
1384   {
1385     // Ignore Shift-Up for text selection for now.
1386
1387     // Get first the line index of the current cursor position index.
1388     CharacterIndex characterIndex = 0u;
1389
1390     if( mEventData->mPrimaryCursorPosition > 0u )
1391     {
1392       characterIndex = mEventData->mPrimaryCursorPosition - 1u;
1393     }
1394
1395     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
1396     const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
1397
1398     // Retrieve the cursor position info.
1399     CursorInfo cursorInfo;
1400     GetCursorPosition( mEventData->mPrimaryCursorPosition,
1401                        cursorInfo );
1402
1403     // Get the line above.
1404     const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex );
1405
1406     // Get the next hit 'y' point.
1407     const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
1408
1409     // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
1410     bool matchedCharacter = false;
1411     mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1412                                                                       mModel->mLogicalModel,
1413                                                                       mMetrics,
1414                                                                       mEventData->mCursorHookPositionX,
1415                                                                       hitPointY,
1416                                                                       CharacterHitTest::TAP,
1417                                                                       matchedCharacter );
1418   }
1419   else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier )
1420   {
1421     // Ignore Shift-Down for text selection for now.
1422
1423     // Get first the line index of the current cursor position index.
1424     CharacterIndex characterIndex = 0u;
1425
1426     if( mEventData->mPrimaryCursorPosition > 0u )
1427     {
1428       characterIndex = mEventData->mPrimaryCursorPosition - 1u;
1429     }
1430
1431     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
1432
1433     if( lineIndex + 1u < mModel->mVisualModel->mLines.Count() )
1434     {
1435       // Retrieve the cursor position info.
1436       CursorInfo cursorInfo;
1437       GetCursorPosition( mEventData->mPrimaryCursorPosition,
1438                          cursorInfo );
1439
1440       // Get the line below.
1441       const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + lineIndex + 1u );
1442
1443       // Get the next hit 'y' point.
1444       const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
1445
1446       // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
1447       bool matchedCharacter = false;
1448       mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1449                                                                         mModel->mLogicalModel,
1450                                                                         mMetrics,
1451                                                                         mEventData->mCursorHookPositionX,
1452                                                                         hitPointY,
1453                                                                         CharacterHitTest::TAP,
1454                                                                         matchedCharacter );
1455     }
1456   }
1457
1458   if ( !isShiftModifier && mEventData->mState != EventData::SELECTING )
1459   {
1460     // Update selection position after moving the cursor
1461     mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
1462     mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1463   }
1464
1465   if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
1466   {
1467     // Handle text selection
1468     bool selecting = false;
1469
1470     if ( Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
1471     {
1472       // Shift-Left/Right to select the text
1473       int cursorPositionDelta = mEventData->mPrimaryCursorPosition - previousPrimaryCursorPosition;
1474       if ( cursorPositionDelta > 0 || mEventData->mRightSelectionPosition > 0u ) // Check the boundary
1475       {
1476         mEventData->mRightSelectionPosition += cursorPositionDelta;
1477       }
1478       selecting = true;
1479     }
1480     else if ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition )
1481     {
1482       // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
1483       selecting = true;
1484     }
1485
1486     if ( selecting )
1487     {
1488       // Notify the cursor position to the InputMethodContext.
1489       if( mEventData->mInputMethodContext )
1490       {
1491         mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
1492         mEventData->mInputMethodContext.NotifyCursorPosition();
1493       }
1494
1495       ChangeState( EventData::SELECTING );
1496
1497       mEventData->mUpdateLeftSelectionPosition = true;
1498       mEventData->mUpdateRightSelectionPosition = true;
1499       mEventData->mUpdateGrabHandlePosition = true;
1500       mEventData->mUpdateHighlightBox = true;
1501
1502       // Hide the text selection popup if select the text using keyboard instead of moving grab handles
1503       if( mEventData->mGrabHandlePopupEnabled )
1504       {
1505         mEventData->mDecorator->SetPopupActive( false );
1506       }
1507     }
1508   }
1509   else
1510   {
1511     // Handle normal cursor move
1512     ChangeState( EventData::EDITING );
1513     mEventData->mUpdateCursorPosition = true;
1514   }
1515
1516   mEventData->mUpdateInputStyle = true;
1517   mEventData->mScrollAfterUpdatePosition = true;
1518 }
1519
1520 void Controller::Impl::OnTapEvent( const Event& event )
1521 {
1522   if( NULL != mEventData )
1523   {
1524     const unsigned int tapCount = event.p1.mUint;
1525
1526     if( 1u == tapCount )
1527     {
1528       if( IsShowingRealText() )
1529       {
1530         // Convert from control's coords to text's coords.
1531         const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1532         const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1533
1534         // Keep the tap 'x' position. Used to move the cursor.
1535         mEventData->mCursorHookPositionX = xPosition;
1536
1537         // Whether to touch point hits on a glyph.
1538         bool matchedCharacter = false;
1539         mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1540                                                                           mModel->mLogicalModel,
1541                                                                           mMetrics,
1542                                                                           xPosition,
1543                                                                           yPosition,
1544                                                                           CharacterHitTest::TAP,
1545                                                                           matchedCharacter );
1546
1547         // When the cursor position is changing, delay cursor blinking
1548         mEventData->mDecorator->DelayCursorBlink();
1549       }
1550       else
1551       {
1552         mEventData->mPrimaryCursorPosition = 0u;
1553       }
1554
1555       // Update selection position after tapping
1556       mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
1557       mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1558
1559       mEventData->mUpdateCursorPosition = true;
1560       mEventData->mUpdateGrabHandlePosition = true;
1561       mEventData->mScrollAfterUpdatePosition = true;
1562       mEventData->mUpdateInputStyle = true;
1563
1564       // Notify the cursor position to the InputMethodContext.
1565       if( mEventData->mInputMethodContext )
1566       {
1567         mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
1568         mEventData->mInputMethodContext.NotifyCursorPosition();
1569       }
1570     }
1571     else if( 2u == tapCount )
1572     {
1573       if( mEventData->mSelectionEnabled )
1574       {
1575         // Convert from control's coords to text's coords.
1576         const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1577         const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1578
1579         // Calculates the logical position from the x,y coords.
1580         RepositionSelectionHandles( xPosition,
1581                                     yPosition,
1582                                     mEventData->mDoubleTapAction );
1583       }
1584     }
1585   }
1586 }
1587
1588 void Controller::Impl::OnPanEvent( const Event& event )
1589 {
1590   if( NULL == mEventData )
1591   {
1592     // Nothing to do if there is no text input.
1593     return;
1594   }
1595
1596   const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
1597   const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
1598
1599   if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
1600   {
1601     // Nothing to do if scrolling is not enabled.
1602     return;
1603   }
1604
1605   const GestureState state = static_cast<GestureState>( event.p1.mInt );
1606   switch( state )
1607   {
1608     case GestureState::STARTED:
1609     {
1610       // Will remove the cursor, handles or text's popup, ...
1611       ChangeState( EventData::TEXT_PANNING );
1612       break;
1613     }
1614     case GestureState::CONTINUING:
1615     {
1616       const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1617       const Vector2 currentScroll = mModel->mScrollPosition;
1618
1619       if( isHorizontalScrollEnabled )
1620       {
1621         const float displacementX = event.p2.mFloat;
1622         mModel->mScrollPosition.x += displacementX;
1623
1624         ClampHorizontalScroll( layoutSize );
1625       }
1626
1627       if( isVerticalScrollEnabled )
1628       {
1629         const float displacementY = event.p3.mFloat;
1630         mModel->mScrollPosition.y += displacementY;
1631
1632         ClampVerticalScroll( layoutSize );
1633       }
1634
1635       mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
1636       break;
1637     }
1638     case GestureState::FINISHED:
1639     case GestureState::CANCELLED: // FALLTHROUGH
1640     {
1641       // Will go back to the previous state to show the cursor, handles, the text's popup, ...
1642       ChangeState( mEventData->mPreviousState );
1643       break;
1644     }
1645     default:
1646       break;
1647   }
1648 }
1649
1650 void Controller::Impl::OnLongPressEvent( const Event& event )
1651 {
1652   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
1653
1654   if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
1655   {
1656     ChangeState( EventData::EDITING_WITH_POPUP );
1657     mEventData->mDecoratorUpdated = true;
1658     mEventData->mUpdateInputStyle = true;
1659   }
1660   else
1661   {
1662     if( mEventData->mSelectionEnabled )
1663     {
1664       // Convert from control's coords to text's coords.
1665       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1666       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1667
1668       // Calculates the logical position from the x,y coords.
1669       RepositionSelectionHandles( xPosition,
1670                                   yPosition,
1671                                   mEventData->mLongPressAction );
1672     }
1673   }
1674 }
1675
1676 void Controller::Impl::OnHandleEvent( const Event& event )
1677 {
1678   if( NULL == mEventData )
1679   {
1680     // Nothing to do if there is no text input.
1681     return;
1682   }
1683
1684   const unsigned int state = event.p1.mUint;
1685   const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
1686   const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
1687
1688   if( HANDLE_PRESSED == state )
1689   {
1690     // Convert from decorator's coords to text's coords.
1691     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1692     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1693
1694     // Need to calculate the handle's new position.
1695     bool matchedCharacter = false;
1696     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1697                                                                           mModel->mLogicalModel,
1698                                                                           mMetrics,
1699                                                                           xPosition,
1700                                                                           yPosition,
1701                                                                           CharacterHitTest::SCROLL,
1702                                                                           matchedCharacter );
1703
1704     if( Event::GRAB_HANDLE_EVENT == event.type )
1705     {
1706       ChangeState ( EventData::GRAB_HANDLE_PANNING );
1707
1708       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
1709       {
1710         // Updates the cursor position if the handle's new position is different than the current one.
1711         mEventData->mUpdateCursorPosition = true;
1712         // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
1713         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1714         mEventData->mPrimaryCursorPosition = handleNewPosition;
1715       }
1716
1717       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1718       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1719     }
1720     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1721     {
1722       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1723
1724       if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
1725           ( handleNewPosition != mEventData->mRightSelectionPosition ) )
1726       {
1727         // Updates the highlight box if the handle's new position is different than the current one.
1728         mEventData->mUpdateHighlightBox = true;
1729         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1730         mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1731         mEventData->mLeftSelectionPosition = handleNewPosition;
1732       }
1733
1734       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1735       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1736
1737       // Will define the order to scroll the text to match the handle position.
1738       mEventData->mIsLeftHandleSelected = true;
1739       mEventData->mIsRightHandleSelected = false;
1740     }
1741     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1742     {
1743       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1744
1745       if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
1746           ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
1747       {
1748         // Updates the highlight box if the handle's new position is different than the current one.
1749         mEventData->mUpdateHighlightBox = true;
1750         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1751         mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1752         mEventData->mRightSelectionPosition = handleNewPosition;
1753       }
1754
1755       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1756       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1757
1758       // Will define the order to scroll the text to match the handle position.
1759       mEventData->mIsLeftHandleSelected = false;
1760       mEventData->mIsRightHandleSelected = true;
1761     }
1762   } // end ( HANDLE_PRESSED == state )
1763   else if( ( HANDLE_RELEASED == state ) ||
1764            handleStopScrolling )
1765   {
1766     CharacterIndex handlePosition = 0u;
1767     if( handleStopScrolling || isSmoothHandlePanEnabled )
1768     {
1769       // Convert from decorator's coords to text's coords.
1770       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1771       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1772
1773       bool matchedCharacter = false;
1774       handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1775                                                     mModel->mLogicalModel,
1776                                                     mMetrics,
1777                                                     xPosition,
1778                                                     yPosition,
1779                                                     CharacterHitTest::SCROLL,
1780                                                     matchedCharacter );
1781     }
1782
1783     if( Event::GRAB_HANDLE_EVENT == event.type )
1784     {
1785       mEventData->mUpdateCursorPosition = true;
1786       mEventData->mUpdateGrabHandlePosition = true;
1787       mEventData->mUpdateInputStyle = true;
1788
1789       if( !IsClipboardEmpty() )
1790       {
1791         ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
1792       }
1793
1794       if( handleStopScrolling || isSmoothHandlePanEnabled )
1795       {
1796         mEventData->mScrollAfterUpdatePosition = true;
1797         mEventData->mPrimaryCursorPosition = handlePosition;
1798       }
1799     }
1800     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1801     {
1802       ChangeState( EventData::SELECTING );
1803
1804       mEventData->mUpdateHighlightBox = true;
1805       mEventData->mUpdateLeftSelectionPosition = true;
1806       mEventData->mUpdateRightSelectionPosition = true;
1807
1808       if( handleStopScrolling || isSmoothHandlePanEnabled )
1809       {
1810         mEventData->mScrollAfterUpdatePosition = true;
1811
1812         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1813             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1814         {
1815           mEventData->mLeftSelectionPosition = handlePosition;
1816         }
1817       }
1818     }
1819     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1820     {
1821       ChangeState( EventData::SELECTING );
1822
1823       mEventData->mUpdateHighlightBox = true;
1824       mEventData->mUpdateRightSelectionPosition = true;
1825       mEventData->mUpdateLeftSelectionPosition = true;
1826
1827       if( handleStopScrolling || isSmoothHandlePanEnabled )
1828       {
1829         mEventData->mScrollAfterUpdatePosition = true;
1830         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1831             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1832         {
1833           mEventData->mRightSelectionPosition = handlePosition;
1834         }
1835       }
1836     }
1837
1838     mEventData->mDecoratorUpdated = true;
1839   } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
1840   else if( HANDLE_SCROLLING == state )
1841   {
1842     const float xSpeed = event.p2.mFloat;
1843     const float ySpeed = event.p3.mFloat;
1844     const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1845     const Vector2 currentScrollPosition = mModel->mScrollPosition;
1846
1847     mModel->mScrollPosition.x += xSpeed;
1848     mModel->mScrollPosition.y += ySpeed;
1849
1850     ClampHorizontalScroll( layoutSize );
1851     ClampVerticalScroll( layoutSize );
1852
1853     bool endOfScroll = false;
1854     if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
1855     {
1856       // Notify the decorator there is no more text to scroll.
1857       // The decorator won't send more scroll events.
1858       mEventData->mDecorator->NotifyEndOfScroll();
1859       // Still need to set the position of the handle.
1860       endOfScroll = true;
1861     }
1862
1863     // Set the position of the handle.
1864     const bool scrollRightDirection = xSpeed > 0.f;
1865     const bool scrollBottomDirection = ySpeed > 0.f;
1866     const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
1867     const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
1868
1869     if( Event::GRAB_HANDLE_EVENT == event.type )
1870     {
1871       ChangeState( EventData::GRAB_HANDLE_PANNING );
1872
1873       // Get the grab handle position in decorator coords.
1874       Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
1875
1876       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1877       {
1878         // Position the grag handle close to either the left or right edge.
1879         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1880       }
1881
1882       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1883       {
1884         position.x = mEventData->mCursorHookPositionX;
1885
1886         // Position the grag handle close to either the top or bottom edge.
1887         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1888       }
1889
1890       // Get the new handle position.
1891       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
1892       bool matchedCharacter = false;
1893       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1894                                                                          mModel->mLogicalModel,
1895                                                                          mMetrics,
1896                                                                          position.x - mModel->mScrollPosition.x,
1897                                                                          position.y - mModel->mScrollPosition.y,
1898                                                                          CharacterHitTest::SCROLL,
1899                                                                          matchedCharacter );
1900
1901       if( mEventData->mPrimaryCursorPosition != handlePosition )
1902       {
1903         mEventData->mUpdateCursorPosition = true;
1904         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1905         mEventData->mScrollAfterUpdatePosition = true;
1906         mEventData->mPrimaryCursorPosition = handlePosition;
1907       }
1908       mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
1909
1910       // Updates the decorator if the soft handle panning is enabled.
1911       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1912     }
1913     else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
1914     {
1915       ChangeState( EventData::SELECTION_HANDLE_PANNING );
1916
1917       // Get the selection handle position in decorator coords.
1918       Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
1919
1920       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1921       {
1922         // Position the selection handle close to either the left or right edge.
1923         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1924       }
1925
1926       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1927       {
1928         position.x = mEventData->mCursorHookPositionX;
1929
1930         // Position the grag handle close to either the top or bottom edge.
1931         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1932       }
1933
1934       // Get the new handle position.
1935       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
1936       bool matchedCharacter = false;
1937       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1938                                                                          mModel->mLogicalModel,
1939                                                                          mMetrics,
1940                                                                          position.x - mModel->mScrollPosition.x,
1941                                                                          position.y - mModel->mScrollPosition.y,
1942                                                                          CharacterHitTest::SCROLL,
1943                                                                          matchedCharacter );
1944
1945       if( leftSelectionHandleEvent )
1946       {
1947         const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
1948
1949         if( differentHandles || endOfScroll )
1950         {
1951           mEventData->mUpdateHighlightBox = true;
1952           mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1953           mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
1954           mEventData->mLeftSelectionPosition = handlePosition;
1955         }
1956       }
1957       else
1958       {
1959         const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
1960         if( differentHandles || endOfScroll )
1961         {
1962           mEventData->mUpdateHighlightBox = true;
1963           mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1964           mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
1965           mEventData->mRightSelectionPosition = handlePosition;
1966         }
1967       }
1968
1969       if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
1970       {
1971         RepositionSelectionHandles();
1972
1973         mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
1974       }
1975     }
1976     mEventData->mDecoratorUpdated = true;
1977   } // end ( HANDLE_SCROLLING == state )
1978 }
1979
1980 void Controller::Impl::OnSelectEvent( const Event& event )
1981 {
1982   if( NULL == mEventData )
1983   {
1984     // Nothing to do if there is no text.
1985     return;
1986   }
1987
1988   if( mEventData->mSelectionEnabled )
1989   {
1990     // Convert from control's coords to text's coords.
1991     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1992     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1993
1994     // Calculates the logical position from the x,y coords.
1995     RepositionSelectionHandles( xPosition,
1996                                 yPosition,
1997                                 Controller::NoTextTap::HIGHLIGHT );
1998   }
1999 }
2000
2001 void Controller::Impl::OnSelectAllEvent()
2002 {
2003   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
2004
2005   if( NULL == mEventData )
2006   {
2007     // Nothing to do if there is no text.
2008     return;
2009   }
2010
2011   if( mEventData->mSelectionEnabled )
2012   {
2013     // Calculates the logical position from the start.
2014     RepositionSelectionHandles( 0.f - mModel->mScrollPosition.x,
2015                                 0.f - mModel->mScrollPosition.y,
2016                                 Controller::NoTextTap::HIGHLIGHT );
2017
2018     mEventData->mLeftSelectionPosition = 0u;
2019     mEventData->mRightSelectionPosition = mModel->mLogicalModel->mText.Count();
2020   }
2021 }
2022
2023 void Controller::Impl::OnSelectNoneEvent()
2024 {
2025   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectNoneEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
2026
2027   if( NULL == mEventData )
2028   {
2029     // Nothing to do if there is no text.
2030     return;
2031   }
2032
2033   if( mEventData->mSelectionEnabled && mEventData->mState == EventData::SELECTING)
2034   {
2035     mEventData->mPrimaryCursorPosition = 0u;
2036     mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
2037     ChangeState( EventData::INACTIVE );
2038     mEventData->mUpdateCursorPosition = true;
2039     mEventData->mUpdateInputStyle = true;
2040     mEventData->mScrollAfterUpdatePosition = true;
2041   }
2042 }
2043
2044 void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
2045 {
2046   if( nullptr == mEventData )
2047   {
2048     // Nothing to do if there is no text.
2049     return;
2050   }
2051
2052   if( mEventData->mSelectionEnabled && (pStart || pEnd))
2053   {
2054     uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
2055
2056     if (pStart)
2057     {
2058       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
2059     }
2060     if (pEnd)
2061     {
2062       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
2063     }
2064
2065     if (mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
2066     {
2067       ChangeState( EventData::EDITING );
2068       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
2069       mEventData->mUpdateCursorPosition = true;
2070     }
2071     else
2072     {
2073       ChangeState( EventData::SELECTING );
2074       mEventData->mUpdateHighlightBox = true;
2075     }
2076   }
2077 }
2078
2079 Uint32Pair Controller::Impl::GetTextSelectionRange() const
2080 {
2081   Uint32Pair range;
2082
2083   if( mEventData )
2084   {
2085     range.first = mEventData->mLeftSelectionPosition;
2086     range.second = mEventData->mRightSelectionPosition;
2087   }
2088
2089   return range;
2090 }
2091
2092 bool Controller::Impl::IsEditable() const
2093 {
2094   return mEventData && mEventData->mEditingEnabled;
2095 }
2096
2097 void Controller::Impl::SetEditable( bool editable )
2098 {
2099   if( mEventData)
2100   {
2101     mEventData->mEditingEnabled = editable;
2102   }
2103 }
2104
2105 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
2106 {
2107   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
2108   {
2109     // Nothing to select if handles are in the same place.
2110     selectedText.clear();
2111     return;
2112   }
2113
2114   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
2115
2116   //Get start and end position of selection
2117   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
2118   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
2119
2120   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
2121   const Length numberOfCharacters = utf32Characters.Count();
2122
2123   // Validate the start and end selection points
2124   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
2125   {
2126     //Get text as a UTF8 string
2127     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
2128
2129     if( deleteAfterRetrieval ) // Only delete text if copied successfully
2130     {
2131       // Keep a copy of the current input style.
2132       InputStyle currentInputStyle;
2133       currentInputStyle.Copy( mEventData->mInputStyle );
2134
2135       // Set as input style the style of the first deleted character.
2136       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
2137
2138       // Compare if the input style has changed.
2139       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
2140
2141       if( hasInputStyleChanged )
2142       {
2143         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
2144         // Queue the input style changed signal.
2145         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
2146       }
2147
2148       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
2149
2150       // Mark the paragraphs to be updated.
2151       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
2152       {
2153         mTextUpdateInfo.mCharacterIndex = 0;
2154         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
2155         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
2156         mTextUpdateInfo.mClearAll = true;
2157       }
2158       else
2159       {
2160         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
2161         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
2162       }
2163
2164       // Delete text between handles
2165       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
2166       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
2167       utf32Characters.Erase( first, last );
2168
2169       // Will show the cursor at the first character of the selection.
2170       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
2171     }
2172     else
2173     {
2174       // Will show the cursor at the last character of the selection.
2175       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
2176     }
2177
2178     mEventData->mDecoratorUpdated = true;
2179   }
2180 }
2181
2182 void Controller::Impl::ShowClipboard()
2183 {
2184   if( mClipboard )
2185   {
2186     mClipboard.ShowClipboard();
2187   }
2188 }
2189
2190 void Controller::Impl::HideClipboard()
2191 {
2192   if( mClipboard && mClipboardHideEnabled )
2193   {
2194     mClipboard.HideClipboard();
2195   }
2196 }
2197
2198 void Controller::Impl::SetClipboardHideEnable(bool enable)
2199 {
2200   mClipboardHideEnabled = enable;
2201 }
2202
2203 bool Controller::Impl::CopyStringToClipboard( std::string& source )
2204 {
2205   //Send string to clipboard
2206   return ( mClipboard && mClipboard.SetItem( source ) );
2207 }
2208
2209 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
2210 {
2211   std::string selectedText;
2212   RetrieveSelection( selectedText, deleteAfterSending );
2213   CopyStringToClipboard( selectedText );
2214   ChangeState( EventData::EDITING );
2215 }
2216
2217 void Controller::Impl::RequestGetTextFromClipboard()
2218 {
2219   if ( mClipboard )
2220   {
2221     mClipboard.RequestItem();
2222   }
2223 }
2224
2225 void Controller::Impl::RepositionSelectionHandles()
2226 {
2227   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
2228   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
2229
2230   if( selectionStart == selectionEnd )
2231   {
2232     // Nothing to select if handles are in the same place.
2233     // So, deactive Highlight box.
2234     mEventData->mDecorator->SetHighlightActive( false );
2235     return;
2236   }
2237
2238   mEventData->mDecorator->ClearHighlights();
2239
2240   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2241   const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
2242   const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
2243   const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
2244   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2245   const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
2246   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
2247
2248   const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
2249   const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
2250   const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
2251
2252   // Swap the indices if the start is greater than the end.
2253   const bool indicesSwapped = selectionStart > selectionEnd;
2254
2255   // Tell the decorator to flip the selection handles if needed.
2256   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
2257
2258   if( indicesSwapped )
2259   {
2260     std::swap( selectionStart, selectionEnd );
2261   }
2262
2263   // Get the indices to the first and last selected glyphs.
2264   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
2265   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
2266   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
2267   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
2268
2269   // Get the lines where the glyphs are laid-out.
2270   const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
2271
2272   LineIndex lineIndex = 0u;
2273   Length numberOfLines = 0u;
2274   mModel->mVisualModel->GetNumberOfLines( glyphStart,
2275                                           1u + glyphEnd - glyphStart,
2276                                           lineIndex,
2277                                           numberOfLines );
2278   const LineIndex firstLineIndex = lineIndex;
2279
2280   // Create the structure to store some selection box info.
2281   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
2282   selectionBoxLinesInfo.Resize( numberOfLines );
2283
2284   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
2285   selectionBoxInfo->minX = MAX_FLOAT;
2286   selectionBoxInfo->maxX = MIN_FLOAT;
2287
2288   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
2289   float minHighlightX = std::numeric_limits<float>::max();
2290   float maxHighlightX = std::numeric_limits<float>::min();
2291   Size highLightSize;
2292   Vector2 highLightPosition; // The highlight position in decorator's coords.
2293
2294   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
2295
2296   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
2297   selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
2298                                                       firstLineIndex );
2299
2300   // Transform to decorator's (control) coords.
2301   selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
2302
2303   lineRun += firstLineIndex;
2304
2305   // The line height is the addition of the line ascender and the line descender.
2306   // However, the line descender has a negative value, hence the subtraction.
2307   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2308
2309   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2310
2311   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
2312   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
2313   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
2314
2315   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
2316   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
2317   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
2318
2319   // The number of quads of the selection box.
2320   const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
2321   mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
2322
2323   // Count the actual number of quads.
2324   unsigned int actualNumberOfQuads = 0u;
2325   Vector4 quad;
2326
2327   // Traverse the glyphs.
2328   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
2329   {
2330     const GlyphInfo& glyph = *( glyphsBuffer + index );
2331     const Vector2& position = *( positionsBuffer + index );
2332
2333     if( splitStartGlyph )
2334     {
2335       // 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.
2336
2337       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
2338       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
2339       // Get the direction of the character.
2340       CharacterDirection isCurrentRightToLeft = false;
2341       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2342       {
2343         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
2344       }
2345
2346       // The end point could be in the middle of the ligature.
2347       // Calculate the number of characters selected.
2348       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
2349
2350       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
2351       quad.y = selectionBoxInfo->lineOffset;
2352       quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
2353       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
2354
2355       // Store the min and max 'x' for each line.
2356       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2357       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2358
2359       mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
2360       ++actualNumberOfQuads;
2361
2362       splitStartGlyph = false;
2363       continue;
2364     }
2365
2366     if( splitEndGlyph && ( index == glyphEnd ) )
2367     {
2368       // 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.
2369
2370       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
2371       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
2372       // Get the direction of the character.
2373       CharacterDirection isCurrentRightToLeft = false;
2374       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2375       {
2376         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
2377       }
2378
2379       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
2380
2381       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
2382       quad.y = selectionBoxInfo->lineOffset;
2383       quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
2384       quad.w = quad.y + selectionBoxInfo->lineHeight;
2385
2386       // Store the min and max 'x' for each line.
2387       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2388       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2389
2390       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2391                                             quad );
2392       ++actualNumberOfQuads;
2393
2394       splitEndGlyph = false;
2395       continue;
2396     }
2397
2398     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
2399     quad.y = selectionBoxInfo->lineOffset;
2400     quad.z = quad.x + glyph.advance;
2401     quad.w = quad.y + selectionBoxInfo->lineHeight;
2402
2403     // Store the min and max 'x' for each line.
2404     selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2405     selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2406
2407     mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2408                                           quad );
2409     ++actualNumberOfQuads;
2410
2411     // Whether to retrieve the next line.
2412     if( index == lastGlyphOfLine )
2413     {
2414       ++lineIndex;
2415       if( lineIndex < firstLineIndex + numberOfLines )
2416       {
2417         // Retrieve the next line.
2418         ++lineRun;
2419
2420         // Get the last glyph of the new line.
2421         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2422
2423         // Keep the offset and height of the current selection box.
2424         const float currentLineOffset = selectionBoxInfo->lineOffset;
2425         const float currentLineHeight = selectionBoxInfo->lineHeight;
2426
2427         // Get the selection box info for the next line.
2428         ++selectionBoxInfo;
2429
2430         selectionBoxInfo->minX = MAX_FLOAT;
2431         selectionBoxInfo->maxX = MIN_FLOAT;
2432
2433         // Update the line's vertical offset.
2434         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
2435
2436         // The line height is the addition of the line ascender and the line descender.
2437         // However, the line descender has a negative value, hence the subtraction.
2438         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2439       }
2440     }
2441   }
2442
2443   // Traverses all the lines and updates the min and max 'x' positions and the total height.
2444   // The final width is calculated after 'boxifying' the selection.
2445   for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
2446          endIt = selectionBoxLinesInfo.End();
2447        it != endIt;
2448        ++it )
2449   {
2450     const SelectionBoxInfo& info = *it;
2451
2452     // Update the size of the highlighted text.
2453     highLightSize.height += info.lineHeight;
2454     minHighlightX = std::min( minHighlightX, info.minX );
2455     maxHighlightX = std::max( maxHighlightX, info.maxX );
2456   }
2457
2458   // Add extra geometry to 'boxify' the selection.
2459
2460   if( 1u < numberOfLines )
2461   {
2462     // Boxify the first line.
2463     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
2464     const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2465
2466     bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
2467     bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
2468
2469     if( boxifyBegin )
2470     {
2471       quad.x = 0.f;
2472       quad.y = firstSelectionBoxLineInfo.lineOffset;
2473       quad.z = firstSelectionBoxLineInfo.minX;
2474       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2475
2476       // Boxify at the beginning of the line.
2477       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2478                                             quad );
2479       ++actualNumberOfQuads;
2480
2481       // Update the size of the highlighted text.
2482       minHighlightX = 0.f;
2483     }
2484
2485     if( boxifyEnd )
2486     {
2487       quad.x = firstSelectionBoxLineInfo.maxX;
2488       quad.y = firstSelectionBoxLineInfo.lineOffset;
2489       quad.z = mModel->mVisualModel->mControlSize.width;
2490       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2491
2492       // Boxify at the end of the line.
2493       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2494                                             quad );
2495       ++actualNumberOfQuads;
2496
2497       // Update the size of the highlighted text.
2498       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2499     }
2500
2501     // Boxify the central lines.
2502     if( 2u < numberOfLines )
2503     {
2504       for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
2505              endIt = selectionBoxLinesInfo.End() - 1u;
2506            it != endIt;
2507            ++it )
2508       {
2509         const SelectionBoxInfo& info = *it;
2510
2511         quad.x = 0.f;
2512         quad.y = info.lineOffset;
2513         quad.z = info.minX;
2514         quad.w = info.lineOffset + info.lineHeight;
2515
2516         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2517                                               quad );
2518         ++actualNumberOfQuads;
2519
2520         quad.x = info.maxX;
2521         quad.y = info.lineOffset;
2522         quad.z = mModel->mVisualModel->mControlSize.width;
2523         quad.w = info.lineOffset + info.lineHeight;
2524
2525         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2526                                               quad );
2527         ++actualNumberOfQuads;
2528       }
2529
2530       // Update the size of the highlighted text.
2531       minHighlightX = 0.f;
2532       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2533     }
2534
2535     // Boxify the last line.
2536     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
2537     const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
2538
2539     boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
2540     boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
2541
2542     if( boxifyBegin )
2543     {
2544       quad.x = 0.f;
2545       quad.y = lastSelectionBoxLineInfo.lineOffset;
2546       quad.z = lastSelectionBoxLineInfo.minX;
2547       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2548
2549       // Boxify at the beginning of the line.
2550       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2551                                             quad );
2552       ++actualNumberOfQuads;
2553
2554       // Update the size of the highlighted text.
2555       minHighlightX = 0.f;
2556     }
2557
2558     if( boxifyEnd )
2559     {
2560       quad.x = lastSelectionBoxLineInfo.maxX;
2561       quad.y = lastSelectionBoxLineInfo.lineOffset;
2562       quad.z = mModel->mVisualModel->mControlSize.width;
2563       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2564
2565       // Boxify at the end of the line.
2566       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2567                                             quad );
2568       ++actualNumberOfQuads;
2569
2570       // Update the size of the highlighted text.
2571       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2572     }
2573   }
2574
2575   // Set the actual number of quads.
2576   mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
2577
2578   // Sets the highlight's size and position. In decorator's coords.
2579   // The highlight's height has been calculated above (before 'boxifying' the highlight).
2580   highLightSize.width = maxHighlightX - minHighlightX;
2581
2582   highLightPosition.x = minHighlightX;
2583   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2584   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
2585
2586   mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
2587
2588   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
2589   {
2590     CursorInfo primaryCursorInfo;
2591     GetCursorPosition( mEventData->mLeftSelectionPosition,
2592                        primaryCursorInfo );
2593
2594     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2595
2596     mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
2597                                          primaryPosition.x,
2598                                          primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2599                                          primaryCursorInfo.lineHeight );
2600
2601     CursorInfo secondaryCursorInfo;
2602     GetCursorPosition( mEventData->mRightSelectionPosition,
2603                        secondaryCursorInfo );
2604
2605     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2606
2607     mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
2608                                          secondaryPosition.x,
2609                                          secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2610                                          secondaryCursorInfo.lineHeight );
2611   }
2612
2613   // Set the flag to update the decorator.
2614   mEventData->mDecoratorUpdated = true;
2615 }
2616
2617 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
2618 {
2619   if( NULL == mEventData )
2620   {
2621     // Nothing to do if there is no text input.
2622     return;
2623   }
2624
2625   if( IsShowingPlaceholderText() )
2626   {
2627     // Nothing to do if there is the place-holder text.
2628     return;
2629   }
2630
2631   const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
2632   const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
2633   if( ( 0 == numberOfGlyphs ) ||
2634       ( 0 == numberOfLines ) )
2635   {
2636     // Nothing to do if there is no text.
2637     return;
2638   }
2639
2640   // Find which word was selected
2641   CharacterIndex selectionStart( 0 );
2642   CharacterIndex selectionEnd( 0 );
2643   CharacterIndex noTextHitIndex( 0 );
2644   const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
2645                                                   mModel->mLogicalModel,
2646                                                   mMetrics,
2647                                                   visualX,
2648                                                   visualY,
2649                                                   selectionStart,
2650                                                   selectionEnd,
2651                                                   noTextHitIndex );
2652   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
2653
2654   if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
2655   {
2656     ChangeState( EventData::SELECTING );
2657
2658     mEventData->mLeftSelectionPosition = selectionStart;
2659     mEventData->mRightSelectionPosition = selectionEnd;
2660
2661     mEventData->mUpdateLeftSelectionPosition = true;
2662     mEventData->mUpdateRightSelectionPosition = true;
2663     mEventData->mUpdateHighlightBox = true;
2664
2665     // It may happen an InputMethodContext commit event arrives before the selection event
2666     // if the InputMethodContext is in pre-edit state. The commit event will set the
2667     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
2668     // to false, the highlight box won't be updated.
2669     mEventData->mUpdateCursorPosition = false;
2670
2671     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
2672
2673     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
2674     mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2675   }
2676   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
2677   {
2678     // Nothing to select. i.e. a white space, out of bounds
2679     ChangeState( EventData::EDITING_WITH_POPUP );
2680
2681     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2682
2683     mEventData->mUpdateCursorPosition = true;
2684     mEventData->mUpdateGrabHandlePosition = true;
2685     mEventData->mScrollAfterUpdatePosition = true;
2686     mEventData->mUpdateInputStyle = true;
2687   }
2688   else if( Controller::NoTextTap::NO_ACTION == action )
2689   {
2690     // Nothing to select. i.e. a white space, out of bounds
2691     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2692
2693     mEventData->mUpdateCursorPosition = true;
2694     mEventData->mUpdateGrabHandlePosition = true;
2695     mEventData->mScrollAfterUpdatePosition = true;
2696     mEventData->mUpdateInputStyle = true;
2697   }
2698 }
2699
2700 void Controller::Impl::SetPopupButtons()
2701 {
2702   /**
2703    *  Sets the Popup buttons to be shown depending on State.
2704    *
2705    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
2706    *
2707    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
2708    */
2709
2710   bool isEditable = IsEditable();
2711   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
2712
2713   if( EventData::SELECTING == mEventData->mState )
2714   {
2715     buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
2716     if(isEditable)
2717     {
2718       buttonsToShow = TextSelectionPopup::Buttons( buttonsToShow | TextSelectionPopup::CUT );
2719     }
2720
2721     if( !IsClipboardEmpty() )
2722     {
2723       if(isEditable)
2724       {
2725         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2726       }
2727       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2728     }
2729
2730     if( !mEventData->mAllTextSelected )
2731     {
2732       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
2733     }
2734   }
2735   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
2736   {
2737     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
2738     {
2739       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
2740     }
2741
2742     if( !IsClipboardEmpty() )
2743     {
2744       if(isEditable)
2745       {
2746         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2747       }
2748       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2749     }
2750   }
2751   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
2752   {
2753     if ( !IsClipboardEmpty() )
2754     {
2755       if(isEditable)
2756       {
2757         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2758       }
2759       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2760     }
2761   }
2762
2763   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
2764 }
2765
2766 void Controller::Impl::ChangeState( EventData::State newState )
2767 {
2768   if( NULL == mEventData )
2769   {
2770     // Nothing to do if there is no text input.
2771     return;
2772   }
2773
2774   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
2775
2776   if( mEventData->mState != newState )
2777   {
2778     mEventData->mPreviousState = mEventData->mState;
2779     mEventData->mState = newState;
2780
2781     switch( mEventData->mState )
2782     {
2783       case EventData::INACTIVE:
2784       {
2785         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2786         mEventData->mDecorator->StopCursorBlink();
2787         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2788         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2789         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2790         mEventData->mDecorator->SetHighlightActive( false );
2791         mEventData->mDecorator->SetPopupActive( false );
2792         mEventData->mDecoratorUpdated = true;
2793         break;
2794       }
2795       case EventData::INTERRUPTED:
2796       {
2797         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2798         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2799         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2800         mEventData->mDecorator->SetHighlightActive( false );
2801         mEventData->mDecorator->SetPopupActive( false );
2802         mEventData->mDecoratorUpdated = true;
2803         break;
2804       }
2805       case EventData::SELECTING:
2806       {
2807         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2808         mEventData->mDecorator->StopCursorBlink();
2809         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2810         if ( mEventData->mGrabHandleEnabled )
2811         {
2812           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2813           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2814         }
2815         mEventData->mDecorator->SetHighlightActive( true );
2816         if( mEventData->mGrabHandlePopupEnabled )
2817         {
2818           SetPopupButtons();
2819           mEventData->mDecorator->SetPopupActive( true );
2820         }
2821         mEventData->mDecoratorUpdated = true;
2822         break;
2823       }
2824       case EventData::EDITING:
2825       {
2826         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2827         if( mEventData->mCursorBlinkEnabled )
2828         {
2829           mEventData->mDecorator->StartCursorBlink();
2830         }
2831         // Grab handle is not shown until a tap is received whilst EDITING
2832         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2833         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2834         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2835         mEventData->mDecorator->SetHighlightActive( false );
2836         if( mEventData->mGrabHandlePopupEnabled )
2837         {
2838           mEventData->mDecorator->SetPopupActive( false );
2839         }
2840         mEventData->mDecoratorUpdated = true;
2841         break;
2842       }
2843       case EventData::EDITING_WITH_POPUP:
2844       {
2845         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
2846
2847         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2848         if( mEventData->mCursorBlinkEnabled )
2849         {
2850           mEventData->mDecorator->StartCursorBlink();
2851         }
2852         if( mEventData->mSelectionEnabled )
2853         {
2854           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2855           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2856           mEventData->mDecorator->SetHighlightActive( false );
2857         }
2858         else if ( mEventData->mGrabHandleEnabled )
2859         {
2860           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2861         }
2862         if( mEventData->mGrabHandlePopupEnabled )
2863         {
2864           SetPopupButtons();
2865           mEventData->mDecorator->SetPopupActive( true );
2866         }
2867         mEventData->mDecoratorUpdated = true;
2868         break;
2869       }
2870       case EventData::EDITING_WITH_GRAB_HANDLE:
2871       {
2872         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
2873
2874         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2875         if( mEventData->mCursorBlinkEnabled )
2876         {
2877           mEventData->mDecorator->StartCursorBlink();
2878         }
2879         // Grab handle is not shown until a tap is received whilst EDITING
2880         if ( mEventData->mGrabHandleEnabled )
2881         {
2882           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2883         }
2884         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2885         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2886         mEventData->mDecorator->SetHighlightActive( false );
2887         if( mEventData->mGrabHandlePopupEnabled )
2888         {
2889           mEventData->mDecorator->SetPopupActive( false );
2890         }
2891         mEventData->mDecoratorUpdated = true;
2892         break;
2893       }
2894       case EventData::SELECTION_HANDLE_PANNING:
2895       {
2896         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2897         mEventData->mDecorator->StopCursorBlink();
2898         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2899         if ( mEventData->mGrabHandleEnabled )
2900         {
2901           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2902           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2903         }
2904         mEventData->mDecorator->SetHighlightActive( true );
2905         if( mEventData->mGrabHandlePopupEnabled )
2906         {
2907           mEventData->mDecorator->SetPopupActive( false );
2908         }
2909         mEventData->mDecoratorUpdated = true;
2910         break;
2911       }
2912       case EventData::GRAB_HANDLE_PANNING:
2913       {
2914         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
2915
2916         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2917         if( mEventData->mCursorBlinkEnabled )
2918         {
2919           mEventData->mDecorator->StartCursorBlink();
2920         }
2921         if ( mEventData->mGrabHandleEnabled )
2922         {
2923           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2924         }
2925         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2926         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2927         mEventData->mDecorator->SetHighlightActive( false );
2928         if( mEventData->mGrabHandlePopupEnabled )
2929         {
2930           mEventData->mDecorator->SetPopupActive( false );
2931         }
2932         mEventData->mDecoratorUpdated = true;
2933         break;
2934       }
2935       case EventData::EDITING_WITH_PASTE_POPUP:
2936       {
2937         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
2938
2939         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2940         if( mEventData->mCursorBlinkEnabled )
2941         {
2942           mEventData->mDecorator->StartCursorBlink();
2943         }
2944
2945         if ( mEventData->mGrabHandleEnabled )
2946         {
2947           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2948         }
2949         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2950         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2951         mEventData->mDecorator->SetHighlightActive( false );
2952
2953         if( mEventData->mGrabHandlePopupEnabled )
2954         {
2955           SetPopupButtons();
2956           mEventData->mDecorator->SetPopupActive( true );
2957         }
2958         mEventData->mDecoratorUpdated = true;
2959         break;
2960       }
2961       case EventData::TEXT_PANNING:
2962       {
2963         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2964         mEventData->mDecorator->StopCursorBlink();
2965         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2966         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
2967             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
2968         {
2969           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2970           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2971           mEventData->mDecorator->SetHighlightActive( true );
2972         }
2973
2974         if( mEventData->mGrabHandlePopupEnabled )
2975         {
2976           mEventData->mDecorator->SetPopupActive( false );
2977         }
2978
2979         mEventData->mDecoratorUpdated = true;
2980         break;
2981       }
2982     }
2983   }
2984 }
2985
2986 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
2987                                           CursorInfo& cursorInfo )
2988 {
2989   if( !IsShowingRealText() )
2990   {
2991     // Do not want to use the place-holder text to set the cursor position.
2992