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