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