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