Merge "KeyEvent class pimpling" 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 int state = event.p1.mInt;
1605
1606   switch( state )
1607   {
1608     case Gesture::Started:
1609     {
1610       // Will remove the cursor, handles or text's popup, ...
1611       ChangeState( EventData::TEXT_PANNING );
1612       break;
1613     }
1614     case Gesture::Continuing:
1615     {
1616       const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1617       const Vector2 currentScroll = mModel->mScrollPosition;
1618
1619       if( isHorizontalScrollEnabled )
1620       {
1621         const float displacementX = event.p2.mFloat;
1622         mModel->mScrollPosition.x += displacementX;
1623
1624         ClampHorizontalScroll( layoutSize );
1625       }
1626
1627       if( isVerticalScrollEnabled )
1628       {
1629         const float displacementY = event.p3.mFloat;
1630         mModel->mScrollPosition.y += displacementY;
1631
1632         ClampVerticalScroll( layoutSize );
1633       }
1634
1635       mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
1636       break;
1637     }
1638     case Gesture::Finished:
1639     case Gesture::Cancelled: // FALLTHROUGH
1640     {
1641       // Will go back to the previous state to show the cursor, handles, the text's popup, ...
1642       ChangeState( mEventData->mPreviousState );
1643       break;
1644     }
1645     default:
1646       break;
1647   }
1648 }
1649
1650 void Controller::Impl::OnLongPressEvent( const Event& event )
1651 {
1652   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
1653
1654   if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
1655   {
1656     ChangeState( EventData::EDITING_WITH_POPUP );
1657     mEventData->mDecoratorUpdated = true;
1658     mEventData->mUpdateInputStyle = true;
1659   }
1660   else
1661   {
1662     if( mEventData->mSelectionEnabled )
1663     {
1664       // Convert from control's coords to text's coords.
1665       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1666       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1667
1668       // Calculates the logical position from the x,y coords.
1669       RepositionSelectionHandles( xPosition,
1670                                   yPosition,
1671                                   mEventData->mLongPressAction );
1672     }
1673   }
1674 }
1675
1676 void Controller::Impl::OnHandleEvent( const Event& event )
1677 {
1678   if( NULL == mEventData )
1679   {
1680     // Nothing to do if there is no text input.
1681     return;
1682   }
1683
1684   const unsigned int state = event.p1.mUint;
1685   const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
1686   const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
1687
1688   if( HANDLE_PRESSED == state )
1689   {
1690     // Convert from decorator's coords to text's coords.
1691     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1692     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1693
1694     // Need to calculate the handle's new position.
1695     bool matchedCharacter = false;
1696     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1697                                                                           mModel->mLogicalModel,
1698                                                                           mMetrics,
1699                                                                           xPosition,
1700                                                                           yPosition,
1701                                                                           CharacterHitTest::SCROLL,
1702                                                                           matchedCharacter );
1703
1704     if( Event::GRAB_HANDLE_EVENT == event.type )
1705     {
1706       ChangeState ( EventData::GRAB_HANDLE_PANNING );
1707
1708       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
1709       {
1710         // Updates the cursor position if the handle's new position is different than the current one.
1711         mEventData->mUpdateCursorPosition = true;
1712         // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
1713         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1714         mEventData->mPrimaryCursorPosition = handleNewPosition;
1715       }
1716
1717       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1718       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1719     }
1720     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1721     {
1722       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1723
1724       if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
1725           ( handleNewPosition != mEventData->mRightSelectionPosition ) )
1726       {
1727         // Updates the highlight box if the handle's new position is different than the current one.
1728         mEventData->mUpdateHighlightBox = true;
1729         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1730         mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1731         mEventData->mLeftSelectionPosition = handleNewPosition;
1732       }
1733
1734       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1735       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1736
1737       // Will define the order to scroll the text to match the handle position.
1738       mEventData->mIsLeftHandleSelected = true;
1739       mEventData->mIsRightHandleSelected = false;
1740     }
1741     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1742     {
1743       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1744
1745       if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
1746           ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
1747       {
1748         // Updates the highlight box if the handle's new position is different than the current one.
1749         mEventData->mUpdateHighlightBox = true;
1750         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1751         mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1752         mEventData->mRightSelectionPosition = handleNewPosition;
1753       }
1754
1755       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1756       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1757
1758       // Will define the order to scroll the text to match the handle position.
1759       mEventData->mIsLeftHandleSelected = false;
1760       mEventData->mIsRightHandleSelected = true;
1761     }
1762   } // end ( HANDLE_PRESSED == state )
1763   else if( ( HANDLE_RELEASED == state ) ||
1764            handleStopScrolling )
1765   {
1766     CharacterIndex handlePosition = 0u;
1767     if( handleStopScrolling || isSmoothHandlePanEnabled )
1768     {
1769       // Convert from decorator's coords to text's coords.
1770       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1771       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1772
1773       bool matchedCharacter = false;
1774       handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1775                                                     mModel->mLogicalModel,
1776                                                     mMetrics,
1777                                                     xPosition,
1778                                                     yPosition,
1779                                                     CharacterHitTest::SCROLL,
1780                                                     matchedCharacter );
1781     }
1782
1783     if( Event::GRAB_HANDLE_EVENT == event.type )
1784     {
1785       mEventData->mUpdateCursorPosition = true;
1786       mEventData->mUpdateGrabHandlePosition = true;
1787       mEventData->mUpdateInputStyle = true;
1788
1789       if( !IsClipboardEmpty() )
1790       {
1791         ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
1792       }
1793
1794       if( handleStopScrolling || isSmoothHandlePanEnabled )
1795       {
1796         mEventData->mScrollAfterUpdatePosition = true;
1797         mEventData->mPrimaryCursorPosition = handlePosition;
1798       }
1799     }
1800     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1801     {
1802       ChangeState( EventData::SELECTING );
1803
1804       mEventData->mUpdateHighlightBox = true;
1805       mEventData->mUpdateLeftSelectionPosition = true;
1806       mEventData->mUpdateRightSelectionPosition = true;
1807
1808       if( handleStopScrolling || isSmoothHandlePanEnabled )
1809       {
1810         mEventData->mScrollAfterUpdatePosition = true;
1811
1812         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1813             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1814         {
1815           mEventData->mLeftSelectionPosition = handlePosition;
1816         }
1817       }
1818     }
1819     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1820     {
1821       ChangeState( EventData::SELECTING );
1822
1823       mEventData->mUpdateHighlightBox = true;
1824       mEventData->mUpdateRightSelectionPosition = true;
1825       mEventData->mUpdateLeftSelectionPosition = true;
1826
1827       if( handleStopScrolling || isSmoothHandlePanEnabled )
1828       {
1829         mEventData->mScrollAfterUpdatePosition = true;
1830         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1831             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1832         {
1833           mEventData->mRightSelectionPosition = handlePosition;
1834         }
1835       }
1836     }
1837
1838     mEventData->mDecoratorUpdated = true;
1839   } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
1840   else if( HANDLE_SCROLLING == state )
1841   {
1842     const float xSpeed = event.p2.mFloat;
1843     const float ySpeed = event.p3.mFloat;
1844     const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1845     const Vector2 currentScrollPosition = mModel->mScrollPosition;
1846
1847     mModel->mScrollPosition.x += xSpeed;
1848     mModel->mScrollPosition.y += ySpeed;
1849
1850     ClampHorizontalScroll( layoutSize );
1851     ClampVerticalScroll( layoutSize );
1852
1853     bool endOfScroll = false;
1854     if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
1855     {
1856       // Notify the decorator there is no more text to scroll.
1857       // The decorator won't send more scroll events.
1858       mEventData->mDecorator->NotifyEndOfScroll();
1859       // Still need to set the position of the handle.
1860       endOfScroll = true;
1861     }
1862
1863     // Set the position of the handle.
1864     const bool scrollRightDirection = xSpeed > 0.f;
1865     const bool scrollBottomDirection = ySpeed > 0.f;
1866     const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
1867     const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
1868
1869     if( Event::GRAB_HANDLE_EVENT == event.type )
1870     {
1871       ChangeState( EventData::GRAB_HANDLE_PANNING );
1872
1873       // Get the grab handle position in decorator coords.
1874       Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
1875
1876       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1877       {
1878         // Position the grag handle close to either the left or right edge.
1879         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1880       }
1881
1882       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1883       {
1884         position.x = mEventData->mCursorHookPositionX;
1885
1886         // Position the grag handle close to either the top or bottom edge.
1887         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1888       }
1889
1890       // Get the new handle position.
1891       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
1892       bool matchedCharacter = false;
1893       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1894                                                                          mModel->mLogicalModel,
1895                                                                          mMetrics,
1896                                                                          position.x - mModel->mScrollPosition.x,
1897                                                                          position.y - mModel->mScrollPosition.y,
1898                                                                          CharacterHitTest::SCROLL,
1899                                                                          matchedCharacter );
1900
1901       if( mEventData->mPrimaryCursorPosition != handlePosition )
1902       {
1903         mEventData->mUpdateCursorPosition = true;
1904         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1905         mEventData->mScrollAfterUpdatePosition = true;
1906         mEventData->mPrimaryCursorPosition = handlePosition;
1907       }
1908       mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
1909
1910       // Updates the decorator if the soft handle panning is enabled.
1911       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1912     }
1913     else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
1914     {
1915       ChangeState( EventData::SELECTION_HANDLE_PANNING );
1916
1917       // Get the selection handle position in decorator coords.
1918       Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
1919
1920       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1921       {
1922         // Position the selection handle close to either the left or right edge.
1923         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1924       }
1925
1926       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1927       {
1928         position.x = mEventData->mCursorHookPositionX;
1929
1930         // Position the grag handle close to either the top or bottom edge.
1931         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1932       }
1933
1934       // Get the new handle position.
1935       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
1936       bool matchedCharacter = false;
1937       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1938                                                                          mModel->mLogicalModel,
1939                                                                          mMetrics,
1940                                                                          position.x - mModel->mScrollPosition.x,
1941                                                                          position.y - mModel->mScrollPosition.y,
1942                                                                          CharacterHitTest::SCROLL,
1943                                                                          matchedCharacter );
1944
1945       if( leftSelectionHandleEvent )
1946       {
1947         const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
1948
1949         if( differentHandles || endOfScroll )
1950         {
1951           mEventData->mUpdateHighlightBox = true;
1952           mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1953           mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
1954           mEventData->mLeftSelectionPosition = handlePosition;
1955         }
1956       }
1957       else
1958       {
1959         const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
1960         if( differentHandles || endOfScroll )
1961         {
1962           mEventData->mUpdateHighlightBox = true;
1963           mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1964           mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
1965           mEventData->mRightSelectionPosition = handlePosition;
1966         }
1967       }
1968
1969       if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
1970       {
1971         RepositionSelectionHandles();
1972
1973         mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
1974       }
1975     }
1976     mEventData->mDecoratorUpdated = true;
1977   } // end ( HANDLE_SCROLLING == state )
1978 }
1979
1980 void Controller::Impl::OnSelectEvent( const Event& event )
1981 {
1982   if( NULL == mEventData )
1983   {
1984     // Nothing to do if there is no text.
1985     return;
1986   }
1987
1988   if( mEventData->mSelectionEnabled )
1989   {
1990     // Convert from control's coords to text's coords.
1991     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1992     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1993
1994     // Calculates the logical position from the x,y coords.
1995     RepositionSelectionHandles( xPosition,
1996                                 yPosition,
1997                                 Controller::NoTextTap::HIGHLIGHT );
1998   }
1999 }
2000
2001 void Controller::Impl::OnSelectAllEvent()
2002 {
2003   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
2004
2005   if( NULL == mEventData )
2006   {
2007     // Nothing to do if there is no text.
2008     return;
2009   }
2010
2011   if( mEventData->mSelectionEnabled )
2012   {
2013     // Calculates the logical position from the start.
2014     RepositionSelectionHandles( 0.f - mModel->mScrollPosition.x,
2015                                 0.f - mModel->mScrollPosition.y,
2016                                 Controller::NoTextTap::HIGHLIGHT );
2017
2018     mEventData->mLeftSelectionPosition = 0u;
2019     mEventData->mRightSelectionPosition = mModel->mLogicalModel->mText.Count();
2020   }
2021 }
2022
2023 void Controller::Impl::OnSelectNoneEvent()
2024 {
2025   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectNoneEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
2026
2027   if( NULL == mEventData )
2028   {
2029     // Nothing to do if there is no text.
2030     return;
2031   }
2032
2033   if( mEventData->mSelectionEnabled && mEventData->mState == EventData::SELECTING)
2034   {
2035     mEventData->mPrimaryCursorPosition = 0u;
2036     mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
2037     ChangeState( EventData::INACTIVE );
2038     mEventData->mUpdateCursorPosition = true;
2039     mEventData->mUpdateInputStyle = true;
2040     mEventData->mScrollAfterUpdatePosition = true;
2041   }
2042 }
2043
2044 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
2045 {
2046   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
2047   {
2048     // Nothing to select if handles are in the same place.
2049     selectedText.clear();
2050     return;
2051   }
2052
2053   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
2054
2055   //Get start and end position of selection
2056   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
2057   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
2058
2059   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
2060   const Length numberOfCharacters = utf32Characters.Count();
2061
2062   // Validate the start and end selection points
2063   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
2064   {
2065     //Get text as a UTF8 string
2066     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
2067
2068     if( deleteAfterRetrieval ) // Only delete text if copied successfully
2069     {
2070       // Keep a copy of the current input style.
2071       InputStyle currentInputStyle;
2072       currentInputStyle.Copy( mEventData->mInputStyle );
2073
2074       // Set as input style the style of the first deleted character.
2075       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
2076
2077       // Compare if the input style has changed.
2078       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
2079
2080       if( hasInputStyleChanged )
2081       {
2082         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
2083         // Queue the input style changed signal.
2084         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
2085       }
2086
2087       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
2088
2089       // Mark the paragraphs to be updated.
2090       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
2091       {
2092         mTextUpdateInfo.mCharacterIndex = 0;
2093         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
2094         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
2095         mTextUpdateInfo.mClearAll = true;
2096       }
2097       else
2098       {
2099         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
2100         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
2101       }
2102
2103       // Delete text between handles
2104       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
2105       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
2106       utf32Characters.Erase( first, last );
2107
2108       // Will show the cursor at the first character of the selection.
2109       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
2110     }
2111     else
2112     {
2113       // Will show the cursor at the last character of the selection.
2114       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
2115     }
2116
2117     mEventData->mDecoratorUpdated = true;
2118   }
2119 }
2120
2121 void Controller::Impl::ShowClipboard()
2122 {
2123   if( mClipboard )
2124   {
2125     mClipboard.ShowClipboard();
2126   }
2127 }
2128
2129 void Controller::Impl::HideClipboard()
2130 {
2131   if( mClipboard && mClipboardHideEnabled )
2132   {
2133     mClipboard.HideClipboard();
2134   }
2135 }
2136
2137 void Controller::Impl::SetClipboardHideEnable(bool enable)
2138 {
2139   mClipboardHideEnabled = enable;
2140 }
2141
2142 bool Controller::Impl::CopyStringToClipboard( std::string& source )
2143 {
2144   //Send string to clipboard
2145   return ( mClipboard && mClipboard.SetItem( source ) );
2146 }
2147
2148 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
2149 {
2150   std::string selectedText;
2151   RetrieveSelection( selectedText, deleteAfterSending );
2152   CopyStringToClipboard( selectedText );
2153   ChangeState( EventData::EDITING );
2154 }
2155
2156 void Controller::Impl::RequestGetTextFromClipboard()
2157 {
2158   if ( mClipboard )
2159   {
2160     mClipboard.RequestItem();
2161   }
2162 }
2163
2164 void Controller::Impl::RepositionSelectionHandles()
2165 {
2166   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
2167   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
2168
2169   if( selectionStart == selectionEnd )
2170   {
2171     // Nothing to select if handles are in the same place.
2172     // So, deactive Highlight box.
2173     mEventData->mDecorator->SetHighlightActive( false );
2174     return;
2175   }
2176
2177   mEventData->mDecorator->ClearHighlights();
2178
2179   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2180   const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
2181   const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
2182   const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
2183   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2184   const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
2185   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
2186
2187   const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
2188   const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
2189   const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
2190
2191   // Swap the indices if the start is greater than the end.
2192   const bool indicesSwapped = selectionStart > selectionEnd;
2193
2194   // Tell the decorator to flip the selection handles if needed.
2195   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
2196
2197   if( indicesSwapped )
2198   {
2199     std::swap( selectionStart, selectionEnd );
2200   }
2201
2202   // Get the indices to the first and last selected glyphs.
2203   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
2204   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
2205   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
2206   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
2207
2208   // Get the lines where the glyphs are laid-out.
2209   const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
2210
2211   LineIndex lineIndex = 0u;
2212   Length numberOfLines = 0u;
2213   mModel->mVisualModel->GetNumberOfLines( glyphStart,
2214                                           1u + glyphEnd - glyphStart,
2215                                           lineIndex,
2216                                           numberOfLines );
2217   const LineIndex firstLineIndex = lineIndex;
2218
2219   // Create the structure to store some selection box info.
2220   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
2221   selectionBoxLinesInfo.Resize( numberOfLines );
2222
2223   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
2224   selectionBoxInfo->minX = MAX_FLOAT;
2225   selectionBoxInfo->maxX = MIN_FLOAT;
2226
2227   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
2228   float minHighlightX = std::numeric_limits<float>::max();
2229   float maxHighlightX = std::numeric_limits<float>::min();
2230   Size highLightSize;
2231   Vector2 highLightPosition; // The highlight position in decorator's coords.
2232
2233   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
2234
2235   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
2236   selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
2237                                                       firstLineIndex );
2238
2239   // Transform to decorator's (control) coords.
2240   selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
2241
2242   lineRun += firstLineIndex;
2243
2244   // The line height is the addition of the line ascender and the line descender.
2245   // However, the line descender has a negative value, hence the subtraction.
2246   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2247
2248   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2249
2250   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
2251   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
2252   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
2253
2254   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
2255   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
2256   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
2257
2258   // The number of quads of the selection box.
2259   const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
2260   mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
2261
2262   // Count the actual number of quads.
2263   unsigned int actualNumberOfQuads = 0u;
2264   Vector4 quad;
2265
2266   // Traverse the glyphs.
2267   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
2268   {
2269     const GlyphInfo& glyph = *( glyphsBuffer + index );
2270     const Vector2& position = *( positionsBuffer + index );
2271
2272     if( splitStartGlyph )
2273     {
2274       // 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.
2275
2276       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
2277       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
2278       // Get the direction of the character.
2279       CharacterDirection isCurrentRightToLeft = false;
2280       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2281       {
2282         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
2283       }
2284
2285       // The end point could be in the middle of the ligature.
2286       // Calculate the number of characters selected.
2287       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
2288
2289       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
2290       quad.y = selectionBoxInfo->lineOffset;
2291       quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
2292       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
2293
2294       // Store the min and max 'x' for each line.
2295       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2296       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2297
2298       mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
2299       ++actualNumberOfQuads;
2300
2301       splitStartGlyph = false;
2302       continue;
2303     }
2304
2305     if( splitEndGlyph && ( index == glyphEnd ) )
2306     {
2307       // 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.
2308
2309       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
2310       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
2311       // Get the direction of the character.
2312       CharacterDirection isCurrentRightToLeft = false;
2313       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2314       {
2315         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
2316       }
2317
2318       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
2319
2320       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
2321       quad.y = selectionBoxInfo->lineOffset;
2322       quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
2323       quad.w = quad.y + selectionBoxInfo->lineHeight;
2324
2325       // Store the min and max 'x' for each line.
2326       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2327       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2328
2329       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2330                                             quad );
2331       ++actualNumberOfQuads;
2332
2333       splitEndGlyph = false;
2334       continue;
2335     }
2336
2337     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
2338     quad.y = selectionBoxInfo->lineOffset;
2339     quad.z = quad.x + glyph.advance;
2340     quad.w = quad.y + selectionBoxInfo->lineHeight;
2341
2342     // Store the min and max 'x' for each line.
2343     selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2344     selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2345
2346     mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2347                                           quad );
2348     ++actualNumberOfQuads;
2349
2350     // Whether to retrieve the next line.
2351     if( index == lastGlyphOfLine )
2352     {
2353       ++lineIndex;
2354       if( lineIndex < firstLineIndex + numberOfLines )
2355       {
2356         // Retrieve the next line.
2357         ++lineRun;
2358
2359         // Get the last glyph of the new line.
2360         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2361
2362         // Keep the offset and height of the current selection box.
2363         const float currentLineOffset = selectionBoxInfo->lineOffset;
2364         const float currentLineHeight = selectionBoxInfo->lineHeight;
2365
2366         // Get the selection box info for the next line.
2367         ++selectionBoxInfo;
2368
2369         selectionBoxInfo->minX = MAX_FLOAT;
2370         selectionBoxInfo->maxX = MIN_FLOAT;
2371
2372         // Update the line's vertical offset.
2373         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
2374
2375         // The line height is the addition of the line ascender and the line descender.
2376         // However, the line descender has a negative value, hence the subtraction.
2377         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2378       }
2379     }
2380   }
2381
2382   // Traverses all the lines and updates the min and max 'x' positions and the total height.
2383   // The final width is calculated after 'boxifying' the selection.
2384   for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
2385          endIt = selectionBoxLinesInfo.End();
2386        it != endIt;
2387        ++it )
2388   {
2389     const SelectionBoxInfo& info = *it;
2390
2391     // Update the size of the highlighted text.
2392     highLightSize.height += info.lineHeight;
2393     minHighlightX = std::min( minHighlightX, info.minX );
2394     maxHighlightX = std::max( maxHighlightX, info.maxX );
2395   }
2396
2397   // Add extra geometry to 'boxify' the selection.
2398
2399   if( 1u < numberOfLines )
2400   {
2401     // Boxify the first line.
2402     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
2403     const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2404
2405     bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
2406     bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
2407
2408     if( boxifyBegin )
2409     {
2410       quad.x = 0.f;
2411       quad.y = firstSelectionBoxLineInfo.lineOffset;
2412       quad.z = firstSelectionBoxLineInfo.minX;
2413       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2414
2415       // Boxify at the beginning of the line.
2416       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2417                                             quad );
2418       ++actualNumberOfQuads;
2419
2420       // Update the size of the highlighted text.
2421       minHighlightX = 0.f;
2422     }
2423
2424     if( boxifyEnd )
2425     {
2426       quad.x = firstSelectionBoxLineInfo.maxX;
2427       quad.y = firstSelectionBoxLineInfo.lineOffset;
2428       quad.z = mModel->mVisualModel->mControlSize.width;
2429       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2430
2431       // Boxify at the end of the line.
2432       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2433                                             quad );
2434       ++actualNumberOfQuads;
2435
2436       // Update the size of the highlighted text.
2437       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2438     }
2439
2440     // Boxify the central lines.
2441     if( 2u < numberOfLines )
2442     {
2443       for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
2444              endIt = selectionBoxLinesInfo.End() - 1u;
2445            it != endIt;
2446            ++it )
2447       {
2448         const SelectionBoxInfo& info = *it;
2449
2450         quad.x = 0.f;
2451         quad.y = info.lineOffset;
2452         quad.z = info.minX;
2453         quad.w = info.lineOffset + info.lineHeight;
2454
2455         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2456                                               quad );
2457         ++actualNumberOfQuads;
2458
2459         quad.x = info.maxX;
2460         quad.y = info.lineOffset;
2461         quad.z = mModel->mVisualModel->mControlSize.width;
2462         quad.w = info.lineOffset + info.lineHeight;
2463
2464         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2465                                               quad );
2466         ++actualNumberOfQuads;
2467       }
2468
2469       // Update the size of the highlighted text.
2470       minHighlightX = 0.f;
2471       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2472     }
2473
2474     // Boxify the last line.
2475     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
2476     const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
2477
2478     boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
2479     boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
2480
2481     if( boxifyBegin )
2482     {
2483       quad.x = 0.f;
2484       quad.y = lastSelectionBoxLineInfo.lineOffset;
2485       quad.z = lastSelectionBoxLineInfo.minX;
2486       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2487
2488       // Boxify at the beginning of the line.
2489       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2490                                             quad );
2491       ++actualNumberOfQuads;
2492
2493       // Update the size of the highlighted text.
2494       minHighlightX = 0.f;
2495     }
2496
2497     if( boxifyEnd )
2498     {
2499       quad.x = lastSelectionBoxLineInfo.maxX;
2500       quad.y = lastSelectionBoxLineInfo.lineOffset;
2501       quad.z = mModel->mVisualModel->mControlSize.width;
2502       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2503
2504       // Boxify at the end of the line.
2505       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2506                                             quad );
2507       ++actualNumberOfQuads;
2508
2509       // Update the size of the highlighted text.
2510       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2511     }
2512   }
2513
2514   // Set the actual number of quads.
2515   mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
2516
2517   // Sets the highlight's size and position. In decorator's coords.
2518   // The highlight's height has been calculated above (before 'boxifying' the highlight).
2519   highLightSize.width = maxHighlightX - minHighlightX;
2520
2521   highLightPosition.x = minHighlightX;
2522   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2523   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
2524
2525   mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
2526
2527   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
2528   {
2529     CursorInfo primaryCursorInfo;
2530     GetCursorPosition( mEventData->mLeftSelectionPosition,
2531                        primaryCursorInfo );
2532
2533     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2534
2535     mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
2536                                          primaryPosition.x,
2537                                          primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2538                                          primaryCursorInfo.lineHeight );
2539
2540     CursorInfo secondaryCursorInfo;
2541     GetCursorPosition( mEventData->mRightSelectionPosition,
2542                        secondaryCursorInfo );
2543
2544     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2545
2546     mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
2547                                          secondaryPosition.x,
2548                                          secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2549                                          secondaryCursorInfo.lineHeight );
2550   }
2551
2552   // Set the flag to update the decorator.
2553   mEventData->mDecoratorUpdated = true;
2554 }
2555
2556 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
2557 {
2558   if( NULL == mEventData )
2559   {
2560     // Nothing to do if there is no text input.
2561     return;
2562   }
2563
2564   if( IsShowingPlaceholderText() )
2565   {
2566     // Nothing to do if there is the place-holder text.
2567     return;
2568   }
2569
2570   const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
2571   const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
2572   if( ( 0 == numberOfGlyphs ) ||
2573       ( 0 == numberOfLines ) )
2574   {
2575     // Nothing to do if there is no text.
2576     return;
2577   }
2578
2579   // Find which word was selected
2580   CharacterIndex selectionStart( 0 );
2581   CharacterIndex selectionEnd( 0 );
2582   CharacterIndex noTextHitIndex( 0 );
2583   const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
2584                                                   mModel->mLogicalModel,
2585                                                   mMetrics,
2586                                                   visualX,
2587                                                   visualY,
2588                                                   selectionStart,
2589                                                   selectionEnd,
2590                                                   noTextHitIndex );
2591   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
2592
2593   if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
2594   {
2595     ChangeState( EventData::SELECTING );
2596
2597     mEventData->mLeftSelectionPosition = selectionStart;
2598     mEventData->mRightSelectionPosition = selectionEnd;
2599
2600     mEventData->mUpdateLeftSelectionPosition = true;
2601     mEventData->mUpdateRightSelectionPosition = true;
2602     mEventData->mUpdateHighlightBox = true;
2603
2604     // It may happen an InputMethodContext commit event arrives before the selection event
2605     // if the InputMethodContext is in pre-edit state. The commit event will set the
2606     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
2607     // to false, the highlight box won't be updated.
2608     mEventData->mUpdateCursorPosition = false;
2609
2610     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
2611
2612     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
2613     mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2614   }
2615   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
2616   {
2617     // Nothing to select. i.e. a white space, out of bounds
2618     ChangeState( EventData::EDITING_WITH_POPUP );
2619
2620     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2621
2622     mEventData->mUpdateCursorPosition = true;
2623     mEventData->mUpdateGrabHandlePosition = true;
2624     mEventData->mScrollAfterUpdatePosition = true;
2625     mEventData->mUpdateInputStyle = true;
2626   }
2627   else if( Controller::NoTextTap::NO_ACTION == action )
2628   {
2629     // Nothing to select. i.e. a white space, out of bounds
2630     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2631
2632     mEventData->mUpdateCursorPosition = true;
2633     mEventData->mUpdateGrabHandlePosition = true;
2634     mEventData->mScrollAfterUpdatePosition = true;
2635     mEventData->mUpdateInputStyle = true;
2636   }
2637 }
2638
2639 void Controller::Impl::SetPopupButtons()
2640 {
2641   /**
2642    *  Sets the Popup buttons to be shown depending on State.
2643    *
2644    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
2645    *
2646    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
2647    */
2648
2649   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
2650
2651   if( EventData::SELECTING == mEventData->mState )
2652   {
2653     buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
2654
2655     if( !IsClipboardEmpty() )
2656     {
2657       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2658       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2659     }
2660
2661     if( !mEventData->mAllTextSelected )
2662     {
2663       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
2664     }
2665   }
2666   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
2667   {
2668     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
2669     {
2670       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
2671     }
2672
2673     if( !IsClipboardEmpty() )
2674     {
2675       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2676       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2677     }
2678   }
2679   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
2680   {
2681     if ( !IsClipboardEmpty() )
2682     {
2683       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2684       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2685     }
2686   }
2687
2688   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
2689 }
2690
2691 void Controller::Impl::ChangeState( EventData::State newState )
2692 {
2693   if( NULL == mEventData )
2694   {
2695     // Nothing to do if there is no text input.
2696     return;
2697   }
2698
2699   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
2700
2701   if( mEventData->mState != newState )
2702   {
2703     mEventData->mPreviousState = mEventData->mState;
2704     mEventData->mState = newState;
2705
2706     switch( mEventData->mState )
2707     {
2708       case EventData::INACTIVE:
2709       {
2710         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2711         mEventData->mDecorator->StopCursorBlink();
2712         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2713         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2714         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2715         mEventData->mDecorator->SetHighlightActive( false );
2716         mEventData->mDecorator->SetPopupActive( false );
2717         mEventData->mDecoratorUpdated = true;
2718         break;
2719       }
2720       case EventData::INTERRUPTED:
2721       {
2722         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2723         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2724         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2725         mEventData->mDecorator->SetHighlightActive( false );
2726         mEventData->mDecorator->SetPopupActive( false );
2727         mEventData->mDecoratorUpdated = true;
2728         break;
2729       }
2730       case EventData::SELECTING:
2731       {
2732         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2733         mEventData->mDecorator->StopCursorBlink();
2734         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2735         if ( mEventData->mGrabHandleEnabled )
2736         {
2737           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2738           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2739         }
2740         mEventData->mDecorator->SetHighlightActive( true );
2741         if( mEventData->mGrabHandlePopupEnabled )
2742         {
2743           SetPopupButtons();
2744           mEventData->mDecorator->SetPopupActive( true );
2745         }
2746         mEventData->mDecoratorUpdated = true;
2747         break;
2748       }
2749       case EventData::EDITING:
2750       {
2751         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2752         if( mEventData->mCursorBlinkEnabled )
2753         {
2754           mEventData->mDecorator->StartCursorBlink();
2755         }
2756         // Grab handle is not shown until a tap is received whilst EDITING
2757         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2758         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2759         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2760         mEventData->mDecorator->SetHighlightActive( false );
2761         if( mEventData->mGrabHandlePopupEnabled )
2762         {
2763           mEventData->mDecorator->SetPopupActive( false );
2764         }
2765         mEventData->mDecoratorUpdated = true;
2766         break;
2767       }
2768       case EventData::EDITING_WITH_POPUP:
2769       {
2770         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
2771
2772         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2773         if( mEventData->mCursorBlinkEnabled )
2774         {
2775           mEventData->mDecorator->StartCursorBlink();
2776         }
2777         if( mEventData->mSelectionEnabled )
2778         {
2779           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2780           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2781           mEventData->mDecorator->SetHighlightActive( false );
2782         }
2783         else if ( mEventData->mGrabHandleEnabled )
2784         {
2785           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2786         }
2787         if( mEventData->mGrabHandlePopupEnabled )
2788         {
2789           SetPopupButtons();
2790           mEventData->mDecorator->SetPopupActive( true );
2791         }
2792         mEventData->mDecoratorUpdated = true;
2793         break;
2794       }
2795       case EventData::EDITING_WITH_GRAB_HANDLE:
2796       {
2797         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
2798
2799         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2800         if( mEventData->mCursorBlinkEnabled )
2801         {
2802           mEventData->mDecorator->StartCursorBlink();
2803         }
2804         // Grab handle is not shown until a tap is received whilst EDITING
2805         if ( mEventData->mGrabHandleEnabled )
2806         {
2807           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2808         }
2809         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2810         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2811         mEventData->mDecorator->SetHighlightActive( false );
2812         if( mEventData->mGrabHandlePopupEnabled )
2813         {
2814           mEventData->mDecorator->SetPopupActive( false );
2815         }
2816         mEventData->mDecoratorUpdated = true;
2817         break;
2818       }
2819       case EventData::SELECTION_HANDLE_PANNING:
2820       {
2821         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2822         mEventData->mDecorator->StopCursorBlink();
2823         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2824         if ( mEventData->mGrabHandleEnabled )
2825         {
2826           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2827           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2828         }
2829         mEventData->mDecorator->SetHighlightActive( true );
2830         if( mEventData->mGrabHandlePopupEnabled )
2831         {
2832           mEventData->mDecorator->SetPopupActive( false );
2833         }
2834         mEventData->mDecoratorUpdated = true;
2835         break;
2836       }
2837       case EventData::GRAB_HANDLE_PANNING:
2838       {
2839         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
2840
2841         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2842         if( mEventData->mCursorBlinkEnabled )
2843         {
2844           mEventData->mDecorator->StartCursorBlink();
2845         }
2846         if ( mEventData->mGrabHandleEnabled )
2847         {
2848           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2849         }
2850         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2851         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2852         mEventData->mDecorator->SetHighlightActive( false );
2853         if( mEventData->mGrabHandlePopupEnabled )
2854         {
2855           mEventData->mDecorator->SetPopupActive( false );
2856         }
2857         mEventData->mDecoratorUpdated = true;
2858         break;
2859       }
2860       case EventData::EDITING_WITH_PASTE_POPUP:
2861       {
2862         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
2863
2864         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2865         if( mEventData->mCursorBlinkEnabled )
2866         {
2867           mEventData->mDecorator->StartCursorBlink();
2868         }
2869
2870         if ( mEventData->mGrabHandleEnabled )
2871         {
2872           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2873         }
2874         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2875         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2876         mEventData->mDecorator->SetHighlightActive( false );
2877
2878         if( mEventData->mGrabHandlePopupEnabled )
2879         {
2880           SetPopupButtons();
2881           mEventData->mDecorator->SetPopupActive( true );
2882         }
2883         mEventData->mDecoratorUpdated = true;
2884         break;
2885       }
2886       case EventData::TEXT_PANNING:
2887       {
2888         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2889         mEventData->mDecorator->StopCursorBlink();
2890         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2891         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
2892             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
2893         {
2894           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2895           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2896           mEventData->mDecorator->SetHighlightActive( true );
2897         }
2898
2899         if( mEventData->mGrabHandlePopupEnabled )
2900         {
2901           mEventData->mDecorator->SetPopupActive( false );
2902         }
2903
2904         mEventData->mDecoratorUpdated = true;
2905         break;
2906       }
2907     }
2908   }
2909 }
2910
2911 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
2912                                           CursorInfo& cursorInfo )
2913 {
2914   if( !IsShowingRealText() )
2915   {
2916     // Do not want to use the place-holder text to set the cursor position.
2917
2918     // Use the line's height of the font's family set to set the cursor's size.
2919     // If there is no font's family set, use the default font.
2920     // Use the current alignment to place the cursor at the beginning, center or end of the box.
2921
2922     cursorInfo.lineOffset = 0.f;
2923     cursorInfo.lineHeight = GetDefaultFontLineHeight();
2924     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
2925
2926     bool isRTL = false;
2927     if( mModel->mMatchSystemLanguageDirection )
2928     {
2929       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
2930     }
2931
2932     switch( mModel->mHorizontalAlignment )
2933     {
2934       case Text::HorizontalAlignment::BEGIN :
2935       {
2936         if( isRTL )
2937         {
2938           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2939         }
2940         else
2941         {
2942           cursorInfo.primaryPosition.x = 0.f;
2943         }
2944         break;
2945       }
2946       case Text::HorizontalAlignment::CENTER:
2947       {
2948         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
2949         break;
2950       }
2951       case Text::HorizontalAlignment::END:
2952       {
2953         if( isRTL )
2954         {
2955           cursorInfo.primaryPosition.x = 0.f;
2956         }
2957         else
2958         {
2959           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2960         }
2961         break;
2962       }
2963     }
2964
2965     // Nothing else to do.
2966     return;
2967   }
2968
2969   const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
2970   GetCursorPositionParameters parameters;
2971   parameters.visualModel = mModel->mVisualModel;
2972   parameters.logicalModel = mModel->mLogicalModel;
2973   parameters.metrics = mMetrics;
2974   parameters.logical = logical;
2975   parameters.isMultiline = isMultiLine;
2976
2977   Text::GetCursorPosition( parameters,
2978                            cursorInfo );
2979
2980   // Adds Outline offset.
2981   const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
2982   cursorInfo.primaryPosition.x += outlineWidth;
2983   cursorInfo.primaryPosition.y += outlineWidth;
2984   cursorInfo.secondaryPosition.x += outlineWidth;
2985   cursorInfo.secondaryPosition.y += outlineWidth;
2986
2987   if( isMultiLine )
2988   {
2989     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
2990
2991     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
2992     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
2993
2994     if( 0.f > cursorInfo.primaryPosition.x )
2995     {
2996       cursorInfo.primaryPosition.x = 0.f;
2997     }
2998
2999     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
3000     if( cursorInfo.primaryPosition.x > edgeWidth )
3001     {
3002       cursorInfo.primaryPosition.x = edgeWidth;
3003     }
3004   }
3005 }
3006
3007 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
3008 {
3009   if( NULL == mEventData )
3010   {
3011     // Nothing to do if there is no text input.
3012     return 0u;
3013   }
3014
3015   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
3016
3017   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
3018   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
3019
3020   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
3021   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
3022
3023   if( numberOfCharacters > 1u )
3024   {
3025     const Script script = mModel->mLogicalModel->GetScript( index );
3026     if( HasLigatureMustBreak( script ) )
3027     {
3028       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
3029       numberOfCharacters = 1u;
3030     }
3031   }
3032   else
3033   {
3034     while( 0u == numberOfCharacters )
3035     {
3036       ++glyphIndex;
3037       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
3038     }
3039   }
3040
3041   if( index < mEventData->mPrimaryCursorPosition )
3042   {
3043     cursorIndex -= numberOfCharacters;
3044   }
3045   else
3046   {
3047     cursorIndex += numberOfCharacters;
3048   }
3049
3050   // Will update the cursor hook position.
3051   mEventData->mUpdateCursorHookPosition = true;
3052
3053   return cursorIndex;
3054 }
3055
3056 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
3057 {
3058   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
3059   if( NULL == mEventData )
3060   {
3061     // Nothing to do if there is no text input.
3062     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
3063     return;
3064   }
3065
3066   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
3067
3068   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
3069
3070   // Sets the cursor position.
3071   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
3072                                        cursorPosition.x,
3073                                        cursorPosition.y,
3074                                        cursorInfo.primaryCursorHeight,
3075                                        cursorInfo.lineHeight );
3076   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
3077
3078   if( mEventData->mUpdateGrabHandlePosition )
3079   {
3080     // Sets the grab handle position.
3081     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
3082                                          cursorPosition.x,
3083                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
3084                                          cursorInfo.lineHeight );
3085   }
3086
3087   if( cursorInfo.isSecondaryCursor )
3088   {
3089     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
3090                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
3091                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
3092                                          cursorInfo.secondaryCursorHeight,
3093                                          cursorInfo.lineHeight );
3094     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
3095   }
3096
3097   // Set which cursors are active according the state.
3098   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
3099   {
3100     if( cursorInfo.isSecondaryCursor )
3101     {
3102       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
3103     }
3104     else
3105     {
3106       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
3107     }
3108   }
3109   else
3110   {
3111     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
3112   }
3113
3114   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
3115 }
3116
3117 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
3118                                               const CursorInfo& cursorInfo )
3119 {
3120   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
3121       ( RIGHT_SELECTION_HANDLE != handleType ) )
3122   {
3123     return;
3124   }
3125
3126   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
3127
3128   // Sets the handle's position.
3129   mEventData->mDecorator->SetPosition( handleType,
3130                                        cursorPosition.x,
3131                                        cursorInfo.lineOffset + mModel->mScrollPosition.y,
3132                                        cursorInfo.lineHeight );
3133
3134   // If selection handle at start of the text and other at end of the text then all text is selected.
3135   const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
3136   const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
3137   mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
3138 }
3139
3140 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
3141 {
3142   // Clamp between -space & -alignment offset.
3143
3144   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
3145   {
3146     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
3147     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
3148     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
3149
3150     mEventData->mDecoratorUpdated = true;
3151   }
3152   else
3153   {
3154     mModel->mScrollPosition.x = 0.f;
3155   }
3156 }
3157
3158 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
3159 {
3160   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
3161   {
3162     // Nothing to do if the text is single line.
3163     return;
3164   }
3165
3166   // Clamp between -space & 0.
3167   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
3168   {
3169     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
3170     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
3171     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
3172
3173     mEventData->mDecoratorUpdated = true;
3174   }
3175   else
3176   {
3177     mModel->mScrollPosition.y = 0.f;
3178   }
3179 }
3180
3181 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
3182 {
3183   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
3184
3185   // position is in actor's coords.
3186   const float positionEndX = position.x + cursorWidth;
3187   const float positionEndY = position.y + lineHeight;
3188
3189   // Transform the position to decorator coords.
3190   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
3191   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
3192
3193   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
3194   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
3195
3196   if( decoratorPositionBeginX < 0.f )
3197   {
3198     mModel->mScrollPosition.x = -position.x;
3199   }
3200   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
3201   {
3202     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
3203   }
3204
3205   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
3206   {
3207     if( decoratorPositionBeginY < 0.f )
3208     {
3209       mModel->mScrollPosition.y = -position.y;
3210     }
3211     else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
3212     {
3213       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
3214     }
3215   }
3216 }
3217
3218 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
3219 {
3220   // Get the current cursor position in decorator coords.
3221   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
3222
3223   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
3224
3225
3226
3227   // Calculate the offset to match the cursor position before the character was deleted.
3228   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
3229
3230   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
3231   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
3232   {
3233     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
3234     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
3235   }
3236
3237
3238   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
3239   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
3240
3241   // Makes the new cursor position visible if needed.
3242   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
3243 }
3244
3245 void Controller::Impl::RequestRelayout()
3246 {
3247   if( NULL != mControlInterface )
3248   {
3249     mControlInterface->RequestTextRelayout();
3250   }
3251 }
3252
3253 Actor Controller::Impl::CreateBackgroundActor()
3254 {
3255   // NOTE: Currently we only support background color for one line left-to-right text,
3256   //       so the following calculation is based on one line left-to-right text only!
3257
3258   Actor actor;
3259
3260   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
3261   if( numberOfGlyphs > 0u )
3262   {
3263     Vector<GlyphInfo> glyphs;
3264     glyphs.Resize( numberOfGlyphs );
3265
3266     Vector<Vector2> positions;
3267     positions.Resize( numberOfGlyphs );
3268
3269     // Get the line where the glyphs are laid-out.
3270     const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
3271     float alignmentOffset = lineRun->alignmentOffset;
3272     numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
3273                                       positions.Begin(),
3274                                       alignmentOffset,
3275                                       0u,
3276                                       numberOfGlyphs );
3277
3278     glyphs.Resize( numberOfGlyphs );
3279     positions.Resize( numberOfGlyphs );
3280
3281     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
3282     const Vector2* const positionsBuffer = positions.Begin();
3283
3284     BackgroundMesh mesh;
3285     mesh.mVertices.Reserve( 4u * glyphs.Size() );
3286     mesh.mIndices.Reserve( 6u * glyphs.Size() );
3287
3288     const Vector2 textSize = mView.GetLayoutSize();
3289
3290     const float offsetX = textSize.width * 0.5f;
3291     const float offsetY = textSize.height * 0.5f;
3292
3293     const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
3294     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
3295     const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
3296
3297     Vector4 quad;
3298     uint32_t numberOfQuads = 0u;
3299
3300     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
3301     {
3302       const GlyphInfo& glyph = *( glyphsBuffer + i );
3303
3304       // Get the background color of the character.
3305       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
3306       const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
3307       const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? defaultBackgroundColor : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
3308
3309       // Only create quads for glyphs with a background color
3310       if ( backgroundColor != Color::TRANSPARENT )
3311       {
3312         const Vector2 position = *( positionsBuffer + i );
3313
3314         if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
3315         {
3316           quad.x = position.x;
3317           quad.y = 0.0f;
3318           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
3319           quad.w = textSize.height;
3320         }
3321         else if ( i == 0u ) // The first glyph in the whole text
3322         {
3323           quad.x = position.x;
3324           quad.y = 0.0f;
3325           quad.z = quad.x - glyph.xBearing + glyph.advance;
3326           quad.w = textSize.height;
3327         }
3328         else if ( i == glyphSize - 1u ) // The last glyph in the whole text
3329         {
3330           quad.x = position.x - glyph.xBearing;
3331           quad.y = 0.0f;
3332           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
3333           quad.w = textSize.height;
3334         }
3335         else // The glyph in the middle of the text
3336         {
3337           quad.x = position.x - glyph.xBearing;
3338           quad.y = 0.0f;
3339           quad.z = quad.x + glyph.advance;
3340           quad.w = textSize.height;
3341         }
3342
3343         BackgroundVertex vertex;
3344
3345         // Top left
3346         vertex.mPosition.x = quad.x - offsetX;
3347         vertex.mPosition.y = quad.y - offsetY;
3348         vertex.mColor = backgroundColor;
3349         mesh.mVertices.PushBack( vertex );
3350
3351         // Top right
3352         vertex.mPosition.x = quad.z - offsetX;
3353         vertex.mPosition.y = quad.y - offsetY;
3354         vertex.mColor = backgroundColor;
3355         mesh.mVertices.PushBack( vertex );
3356
3357         // Bottom left
3358         vertex.mPosition.x = quad.x - offsetX;
3359         vertex.mPosition.y = quad.w - offsetY;
3360         vertex.mColor = backgroundColor;
3361         mesh.mVertices.PushBack( vertex );
3362
3363         // Bottom right
3364         vertex.mPosition.x = quad.z - offsetX;
3365         vertex.mPosition.y = quad.w - offsetY;
3366         vertex.mColor = backgroundColor;
3367         mesh.mVertices.PushBack( vertex );
3368
3369         // Six indices in counter clockwise winding
3370         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
3371         mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
3372         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
3373         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
3374         mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
3375         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
3376
3377         numberOfQuads++;
3378       }
3379     }
3380
3381     // Only create the background actor if there are glyphs with background color
3382     if ( mesh.mVertices.Count() > 0u )
3383     {
3384       Property::Map quadVertexFormat;
3385       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
3386       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
3387
3388       PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
3389       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
3390
3391       Geometry quadGeometry = Geometry::New();
3392       quadGeometry.AddVertexBuffer( quadVertices );
3393       quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
3394
3395       if( !mShaderBackground )
3396       {
3397         mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
3398       }
3399
3400       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
3401       renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
3402       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
3403
3404       actor = Actor::New();
3405       actor.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
3406       actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
3407       actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
3408       actor.SetProperty( Actor::Property::SIZE, textSize );
3409       actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
3410       actor.AddRenderer( renderer );
3411     }
3412   }
3413
3414   return actor;
3415 }
3416
3417 } // namespace Text
3418
3419 } // namespace Toolkit
3420
3421 } // namespace Dali