Merge "Implement some new ewk apis in web view." into devel/master
[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
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
27 #include <dali-toolkit/internal/text/bidirectional-support.h>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/color-segmentation.h>
30 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
31 #include <dali-toolkit/internal/text/multi-language-support.h>
32 #include <dali-toolkit/internal/text/segmentation.h>
33 #include <dali-toolkit/internal/text/shaper.h>
34 #include <dali-toolkit/internal/text/text-control-interface.h>
35 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
36 #include <dali-toolkit/internal/text/text-run-container.h>
37 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
38 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
39
40 using namespace Dali;
41
42 namespace
43 {
44
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
47 #endif
48
49 struct BackgroundVertex
50 {
51   Vector2 mPosition;        ///< Vertex posiiton
52   Vector4 mColor;           ///< Vertex color
53 };
54
55 struct BackgroundMesh
56 {
57   Vector< BackgroundVertex > mVertices;    ///< container of vertices
58   Vector< unsigned short > mIndices;       ///< container of indices
59 };
60
61 const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f );
62 const Dali::Vector4 BACKGROUND_SUB4( 0.58f, 0.87f, 0.96f, 1.f );
63 const Dali::Vector4 BACKGROUND_SUB5( 0.83f, 0.94f, 0.98f, 1.f );
64 const Dali::Vector4 BACKGROUND_SUB6( 1.f, 0.5f, 0.5f, 1.f );
65 const Dali::Vector4 BACKGROUND_SUB7( 1.f, 0.8f, 0.8f, 1.f );
66
67 } // namespace
68
69 namespace Dali
70 {
71
72 namespace Toolkit
73 {
74
75 namespace Text
76 {
77
78 EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
79 : mDecorator( decorator ),
80   mInputMethodContext( inputMethodContext ),
81   mPlaceholderFont( NULL ),
82   mPlaceholderTextActive(),
83   mPlaceholderTextInactive(),
84   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
85   mEventQueue(),
86   mInputStyleChangedQueue(),
87   mPreviousState( INACTIVE ),
88   mState( INACTIVE ),
89   mPrimaryCursorPosition( 0u ),
90   mLeftSelectionPosition( 0u ),
91   mRightSelectionPosition( 0u ),
92   mPreEditStartPosition( 0u ),
93   mPreEditLength( 0u ),
94   mCursorHookPositionX( 0.f ),
95   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
96   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
97   mIsShowingPlaceholderText( false ),
98   mPreEditFlag( false ),
99   mDecoratorUpdated( false ),
100   mCursorBlinkEnabled( true ),
101   mGrabHandleEnabled( true ),
102   mGrabHandlePopupEnabled( true ),
103   mSelectionEnabled( true ),
104   mUpdateCursorHookPosition( false ),
105   mUpdateCursorPosition( false ),
106   mUpdateGrabHandlePosition( false ),
107   mUpdateLeftSelectionPosition( false ),
108   mUpdateRightSelectionPosition( false ),
109   mIsLeftHandleSelected( false ),
110   mIsRightHandleSelected( false ),
111   mUpdateHighlightBox( false ),
112   mScrollAfterUpdatePosition( false ),
113   mScrollAfterDelete( false ),
114   mAllTextSelected( false ),
115   mUpdateInputStyle( false ),
116   mPasswordInput( false ),
117   mCheckScrollAmount( false ),
118   mIsPlaceholderPixelSize( false ),
119   mIsPlaceholderElideEnabled( false ),
120   mPlaceholderEllipsisFlag( false ),
121   mShiftSelectionFlag( true ),
122   mUpdateAlignment( false ),
123   mEditingEnabled( true )
124 {
125 }
126
127 bool Controller::Impl::ProcessInputEvents()
128 {
129   return ControllerImplEventHandler::ProcessInputEvents(*this);
130 }
131
132 void Controller::Impl::NotifyInputMethodContext()
133 {
134   if( mEventData && mEventData->mInputMethodContext )
135   {
136     CharacterIndex cursorPosition = GetLogicalCursorPosition();
137
138     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
139
140     // Update the cursor position by removing the initial white spaces.
141     if( cursorPosition < numberOfWhiteSpaces )
142     {
143       cursorPosition = 0u;
144     }
145     else
146     {
147       cursorPosition -= numberOfWhiteSpaces;
148     }
149
150     mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
151     mEventData->mInputMethodContext.NotifyCursorPosition();
152   }
153 }
154
155 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
156 {
157   if ( mEventData && mEventData->mInputMethodContext )
158   {
159     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
160     mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
161   }
162 }
163
164 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
165 {
166   CharacterIndex cursorPosition = 0u;
167
168   if( mEventData )
169   {
170     if( ( EventData::SELECTING == mEventData->mState ) ||
171         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
172     {
173       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
174     }
175     else
176     {
177       cursorPosition = mEventData->mPrimaryCursorPosition;
178     }
179   }
180
181   return cursorPosition;
182 }
183
184 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
185 {
186   Length numberOfWhiteSpaces = 0u;
187
188   // Get the buffer to the text.
189   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
190
191   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
192   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
193   {
194     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
195     {
196       break;
197     }
198   }
199
200   return numberOfWhiteSpaces;
201 }
202
203 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
204 {
205   // Get the total number of characters.
206   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
207
208   // Retrieve the text.
209   if( 0u != numberOfCharacters )
210   {
211     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
212   }
213 }
214
215 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
216 {
217   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
218   mTextUpdateInfo.mStartGlyphIndex = 0u;
219   mTextUpdateInfo.mStartLineIndex = 0u;
220   numberOfCharacters = 0u;
221
222   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
223   if( 0u == numberOfParagraphs )
224   {
225     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
226     numberOfCharacters = 0u;
227
228     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
229
230     // Nothing else to do if there are no paragraphs.
231     return;
232   }
233
234   // Find the paragraphs to be updated.
235   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
236   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
237   {
238     // Text is being added at the end of the current text.
239     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
240     {
241       // Text is being added in a new paragraph after the last character of the text.
242       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
243       numberOfCharacters = 0u;
244       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
245
246       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
247       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
248
249       // Nothing else to do;
250       return;
251     }
252
253     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
254   }
255   else
256   {
257     Length numberOfCharactersToUpdate = 0u;
258     if( mTextUpdateInfo.mFullRelayoutNeeded )
259     {
260       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
261     }
262     else
263     {
264       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
265     }
266     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
267                                            numberOfCharactersToUpdate,
268                                            paragraphsToBeUpdated );
269   }
270
271   if( 0u != paragraphsToBeUpdated.Count() )
272   {
273     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
274     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
275     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
276
277     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
278     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
279
280     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
281         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
282         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
283           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
284     {
285       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
286       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
287
288       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
289     }
290     else
291     {
292       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
293     }
294   }
295
296   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
297   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
298 }
299
300 void Controller::Impl::ClearFullModelData( OperationsMask operations )
301 {
302   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
303   {
304     mModel->mLogicalModel->mLineBreakInfo.Clear();
305     mModel->mLogicalModel->mParagraphInfo.Clear();
306   }
307
308   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
309   {
310     mModel->mLogicalModel->mScriptRuns.Clear();
311   }
312
313   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
314   {
315     mModel->mLogicalModel->mFontRuns.Clear();
316   }
317
318   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
319   {
320     if( NO_OPERATION != ( BIDI_INFO & operations ) )
321     {
322       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
323       mModel->mLogicalModel->mCharacterDirections.Clear();
324     }
325
326     if( NO_OPERATION != ( REORDER & operations ) )
327     {
328       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
329       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
330              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
331            it != endIt;
332            ++it )
333       {
334         BidirectionalLineInfoRun& bidiLineInfo = *it;
335
336         free( bidiLineInfo.visualToLogicalMap );
337         bidiLineInfo.visualToLogicalMap = NULL;
338       }
339       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
340     }
341   }
342
343   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
344   {
345     mModel->mVisualModel->mGlyphs.Clear();
346     mModel->mVisualModel->mGlyphsToCharacters.Clear();
347     mModel->mVisualModel->mCharactersToGlyph.Clear();
348     mModel->mVisualModel->mCharactersPerGlyph.Clear();
349     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
350     mModel->mVisualModel->mGlyphPositions.Clear();
351   }
352
353   if( NO_OPERATION != ( LAYOUT & operations ) )
354   {
355     mModel->mVisualModel->mLines.Clear();
356   }
357
358   if( NO_OPERATION != ( COLOR & operations ) )
359   {
360     mModel->mVisualModel->mColorIndices.Clear();
361     mModel->mVisualModel->mBackgroundColorIndices.Clear();
362   }
363 }
364
365 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
366 {
367   const CharacterIndex endIndexPlusOne = endIndex + 1u;
368
369   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
370   {
371     // Clear the line break info.
372     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
373
374     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
375                                                  lineBreakInfoBuffer + endIndexPlusOne );
376
377     // Clear the paragraphs.
378     ClearCharacterRuns( startIndex,
379                         endIndex,
380                         mModel->mLogicalModel->mParagraphInfo );
381   }
382
383   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
384   {
385     // Clear the scripts.
386     ClearCharacterRuns( startIndex,
387                         endIndex,
388                         mModel->mLogicalModel->mScriptRuns );
389   }
390
391   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
392   {
393     // Clear the fonts.
394     ClearCharacterRuns( startIndex,
395                         endIndex,
396                         mModel->mLogicalModel->mFontRuns );
397   }
398
399   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
400   {
401     if( NO_OPERATION != ( BIDI_INFO & operations ) )
402     {
403       // Clear the bidirectional paragraph info.
404       ClearCharacterRuns( startIndex,
405                           endIndex,
406                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
407
408       // Clear the character's directions.
409       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
410
411       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
412                                                          characterDirectionsBuffer + endIndexPlusOne );
413     }
414
415     if( NO_OPERATION != ( REORDER & operations ) )
416     {
417       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
418       uint32_t endRemoveIndex = startRemoveIndex;
419       ClearCharacterRuns( startIndex,
420                           endIndex,
421                           mModel->mLogicalModel->mBidirectionalLineInfo,
422                           startRemoveIndex,
423                           endRemoveIndex );
424
425       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
426
427       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
428       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
429              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
430            it != endIt;
431            ++it )
432       {
433         BidirectionalLineInfoRun& bidiLineInfo = *it;
434
435         free( bidiLineInfo.visualToLogicalMap );
436         bidiLineInfo.visualToLogicalMap = NULL;
437       }
438
439       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
440                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
441     }
442   }
443 }
444
445 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
446 {
447   const CharacterIndex endIndexPlusOne = endIndex + 1u;
448   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
449
450   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
451   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
452   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
453
454   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
455   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
456
457   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
458   {
459     // Update the character to glyph indices.
460     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
461            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
462          it != endIt;
463          ++it )
464     {
465       CharacterIndex& index = *it;
466       index -= numberOfGlyphsRemoved;
467     }
468
469     // Clear the character to glyph conversion table.
470     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
471                                                     charactersToGlyphBuffer + endIndexPlusOne );
472
473     // Clear the glyphs per character table.
474     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
475                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
476
477     // Clear the glyphs buffer.
478     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
479     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
480                                          glyphsBuffer + endGlyphIndexPlusOne );
481
482     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
483
484     // Update the glyph to character indices.
485     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
486            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
487          it != endIt;
488          ++it )
489     {
490       CharacterIndex& index = *it;
491       index -= numberOfCharactersRemoved;
492     }
493
494     // Clear the glyphs to characters buffer.
495     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
496                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
497
498     // Clear the characters per glyph buffer.
499     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
500     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
501                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
502
503     // Clear the positions buffer.
504     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
505     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
506                                                  positionsBuffer + endGlyphIndexPlusOne );
507   }
508
509   if( NO_OPERATION != ( LAYOUT & operations ) )
510   {
511     // Clear the lines.
512     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
513     uint32_t endRemoveIndex = startRemoveIndex;
514     ClearCharacterRuns( startIndex,
515                         endIndex,
516                         mModel->mVisualModel->mLines,
517                         startRemoveIndex,
518                         endRemoveIndex );
519
520     // Will update the glyph runs.
521     startRemoveIndex = mModel->mVisualModel->mLines.Count();
522     endRemoveIndex = startRemoveIndex;
523     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
524                     endGlyphIndexPlusOne - 1u,
525                     mModel->mVisualModel->mLines,
526                     startRemoveIndex,
527                     endRemoveIndex );
528
529     // Set the line index from where to insert the new laid-out lines.
530     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
531
532     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
533     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
534                                         linesBuffer + endRemoveIndex );
535   }
536
537   if( NO_OPERATION != ( COLOR & operations ) )
538   {
539     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
540     {
541       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
542       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
543                                                  colorIndexBuffer + endGlyphIndexPlusOne );
544     }
545
546     if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
547     {
548       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
549       mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
550                                                            backgroundColorIndexBuffer + endGlyphIndexPlusOne );
551     }
552   }
553 }
554
555 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
556 {
557   if( mTextUpdateInfo.mClearAll ||
558       ( ( 0u == startIndex ) &&
559         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
560   {
561     ClearFullModelData( operations );
562   }
563   else
564   {
565     // Clear the model data related with characters.
566     ClearCharacterModelData( startIndex, endIndex, operations );
567
568     // Clear the model data related with glyphs.
569     ClearGlyphModelData( startIndex, endIndex, operations );
570   }
571
572   // The estimated number of lines. Used to avoid reallocations when layouting.
573   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
574
575   mModel->mVisualModel->ClearCaches();
576 }
577
578 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
579 {
580   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
581
582   // Calculate the operations to be done.
583   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
584
585   if( NO_OPERATION == operations )
586   {
587     // Nothing to do if no operations are pending and required.
588     return false;
589   }
590
591   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
592   Vector<Character> displayCharacters;
593   bool useHiddenText = false;
594   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
595   {
596     mHiddenInput->Substitute( srcCharacters,displayCharacters );
597     useHiddenText = true;
598   }
599
600   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
601   const Length numberOfCharacters = utf32Characters.Count();
602
603   // Index to the first character of the first paragraph to be updated.
604   CharacterIndex startIndex = 0u;
605   // Number of characters of the paragraphs to be removed.
606   Length paragraphCharacters = 0u;
607
608   CalculateTextUpdateIndices( paragraphCharacters );
609
610   // Check whether the indices for updating the text is valid
611   if ( numberOfCharacters > 0u &&
612        ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
613          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
614   {
615     std::string currentText;
616     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
617
618     DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
619     DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
620
621     // Dump mTextUpdateInfo
622     DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
623     DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
624     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
625     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
626     DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
627     DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
628     DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
629     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
630     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
631     DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
632     DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
633     DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
634     DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
635
636     return false;
637   }
638
639   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
640
641   if( mTextUpdateInfo.mClearAll ||
642       ( 0u != paragraphCharacters ) )
643   {
644     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
645   }
646
647   mTextUpdateInfo.mClearAll = false;
648
649   // Whether the model is updated.
650   bool updated = false;
651
652   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
653   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
654
655   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
656   {
657     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
658     // calculate the bidirectional info for each 'paragraph'.
659     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
660     // is not shaped together).
661     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
662
663     SetLineBreakInfo( utf32Characters,
664                       startIndex,
665                       requestedNumberOfCharacters,
666                       lineBreakInfo );
667
668     // Create the paragraph info.
669     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
670                                                 requestedNumberOfCharacters );
671     updated = true;
672   }
673
674   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
675   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
676
677   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
678   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
679
680   if( getScripts || validateFonts )
681   {
682     // Validates the fonts assigned by the application or assigns default ones.
683     // It makes sure all the characters are going to be rendered by the correct font.
684     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
685
686     if( getScripts )
687     {
688       // Retrieves the scripts used in the text.
689       multilanguageSupport.SetScripts( utf32Characters,
690                                        startIndex,
691                                        requestedNumberOfCharacters,
692                                        scripts );
693     }
694
695     if( validateFonts )
696     {
697       // Validate the fonts set through the mark-up string.
698       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
699
700       // Get the default font's description.
701       TextAbstraction::FontDescription defaultFontDescription;
702       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
703
704       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
705       {
706         // If the placeholder font is set specifically, only placeholder font is changed.
707         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
708         if( mEventData->mPlaceholderFont->sizeDefined )
709         {
710           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * 64u;
711         }
712       }
713       else if( NULL != mFontDefaults )
714       {
715         // Set the normal font and the placeholder font.
716         defaultFontDescription = mFontDefaults->mFontDescription;
717
718         if( mTextFitEnabled )
719         {
720           defaultPointSize = mFontDefaults->mFitPointSize * 64u;
721         }
722         else
723         {
724           defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
725         }
726       }
727
728       // Validates the fonts. If there is a character with no assigned font it sets a default one.
729       // After this call, fonts are validated.
730       multilanguageSupport.ValidateFonts( utf32Characters,
731                                           scripts,
732                                           fontDescriptionRuns,
733                                           defaultFontDescription,
734                                           defaultPointSize,
735                                           startIndex,
736                                           requestedNumberOfCharacters,
737                                           validFonts );
738     }
739     updated = true;
740   }
741
742   Vector<Character> mirroredUtf32Characters;
743   bool textMirrored = false;
744   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
745   if( NO_OPERATION != ( BIDI_INFO & operations ) )
746   {
747     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
748     bidirectionalInfo.Reserve( numberOfParagraphs );
749
750     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
751     SetBidirectionalInfo( utf32Characters,
752                           scripts,
753                           lineBreakInfo,
754                           startIndex,
755                           requestedNumberOfCharacters,
756                           bidirectionalInfo,
757                           mModel->mMatchSystemLanguageDirection,
758                           mLayoutDirection );
759
760     if( 0u != bidirectionalInfo.Count() )
761     {
762       // Only set the character directions if there is right to left characters.
763       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
764       GetCharactersDirection( bidirectionalInfo,
765                               numberOfCharacters,
766                               startIndex,
767                               requestedNumberOfCharacters,
768                               directions );
769
770       // This paragraph has right to left text. Some characters may need to be mirrored.
771       // TODO: consider if the mirrored string can be stored as well.
772
773       textMirrored = GetMirroredText( utf32Characters,
774                                       directions,
775                                       bidirectionalInfo,
776                                       startIndex,
777                                       requestedNumberOfCharacters,
778                                       mirroredUtf32Characters );
779     }
780     else
781     {
782       // There is no right to left characters. Clear the directions vector.
783       mModel->mLogicalModel->mCharacterDirections.Clear();
784     }
785     updated = true;
786   }
787
788   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
789   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
790   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
791   Vector<GlyphIndex> newParagraphGlyphs;
792   newParagraphGlyphs.Reserve( numberOfParagraphs );
793
794   const Length currentNumberOfGlyphs = glyphs.Count();
795   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
796   {
797     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
798     // Shapes the text.
799     ShapeText( textToShape,
800                lineBreakInfo,
801                scripts,
802                validFonts,
803                startIndex,
804                mTextUpdateInfo.mStartGlyphIndex,
805                requestedNumberOfCharacters,
806                glyphs,
807                glyphsToCharactersMap,
808                charactersPerGlyph,
809                newParagraphGlyphs );
810
811     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
812     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
813     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
814     updated = true;
815   }
816
817   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
818
819   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
820   {
821     GlyphInfo* glyphsBuffer = glyphs.Begin();
822     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
823
824     // Update the width and advance of all new paragraph characters.
825     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
826     {
827       const GlyphIndex index = *it;
828       GlyphInfo& glyph = *( glyphsBuffer + index );
829
830       glyph.xBearing = 0.f;
831       glyph.width = 0.f;
832       glyph.advance = 0.f;
833     }
834     updated = true;
835   }
836
837   if( ( NULL != mEventData ) &&
838       mEventData->mPreEditFlag &&
839       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
840   {
841     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
842     mEventData->mInputMethodContext.GetPreeditStyle( attrs );
843     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
844
845     // Check the type of preedit and run it.
846     for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
847     {
848       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
849       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
850       type = attrData.preeditType;
851
852       // Check the number of commit characters for the start position.
853       unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
854       Length numberOfIndices = attrData.endIndex - attrData.startIndex;
855
856       switch( type )
857       {
858         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
859         {
860           // Add the underline for the pre-edit text.
861           GlyphRun underlineRun;
862           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
863           underlineRun.numberOfGlyphs = numberOfIndices;
864           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
865           break;
866         }
867         case Dali::InputMethodContext::PreeditStyle::REVERSE:
868         {
869           Vector4 textColor = mModel->mVisualModel->GetTextColor();
870           ColorRun backgroundColorRun;
871           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
872           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
873           backgroundColorRun.color = textColor;
874           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
875
876           Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
877           Vector<ColorRun>  colorRuns;
878           colorRuns.Resize( 1u );
879           ColorRun& colorRun = *( colorRuns.Begin() );
880           colorRun.color = backgroundColor;
881           colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
882           colorRun.characterRun.numberOfCharacters = numberOfIndices;
883
884           mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
885           break;
886         }
887         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
888         {
889           ColorRun backgroundColorRun;
890           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
891           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
892           backgroundColorRun.color = LIGHT_BLUE;
893           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
894           break;
895         }
896         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
897         {
898           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
899           ColorRun backgroundColorRun;
900           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
901           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
902           backgroundColorRun.color = BACKGROUND_SUB4;
903           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
904
905           GlyphRun underlineRun;
906           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
907           underlineRun.numberOfGlyphs = numberOfIndices;
908           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
909           break;
910         }
911         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
912         {
913           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
914           ColorRun backgroundColorRun;
915           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
916           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
917           backgroundColorRun.color = BACKGROUND_SUB5;
918           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
919
920           GlyphRun underlineRun;
921           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
922           underlineRun.numberOfGlyphs = numberOfIndices;
923           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
924           break;
925         }
926         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
927         {
928           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
929           ColorRun backgroundColorRun;
930           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
931           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
932           backgroundColorRun.color = BACKGROUND_SUB6;
933           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
934
935           GlyphRun underlineRun;
936           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
937           underlineRun.numberOfGlyphs = numberOfIndices;
938           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
939           break;
940         }
941         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
942         {
943           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
944           ColorRun backgroundColorRun;
945           backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
946           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
947           backgroundColorRun.color = BACKGROUND_SUB7;
948           mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
949
950           GlyphRun underlineRun;
951           underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
952           underlineRun.numberOfGlyphs = numberOfIndices;
953           mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
954           break;
955         }
956         case Dali::InputMethodContext::PreeditStyle::NONE:
957         default:
958         {
959           break;
960         }
961       }
962     }
963     attrs.Clear();
964     updated = true;
965   }
966
967   if( NO_OPERATION != ( COLOR & operations ) )
968   {
969     // Set the color runs in glyphs.
970     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
971                               mModel->mVisualModel->mCharactersToGlyph,
972                               mModel->mVisualModel->mGlyphsPerCharacter,
973                               startIndex,
974                               mTextUpdateInfo.mStartGlyphIndex,
975                               requestedNumberOfCharacters,
976                               mModel->mVisualModel->mColors,
977                               mModel->mVisualModel->mColorIndices );
978
979     // Set the background color runs in glyphs.
980     SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
981                               mModel->mVisualModel->mCharactersToGlyph,
982                               mModel->mVisualModel->mGlyphsPerCharacter,
983                               startIndex,
984                               mTextUpdateInfo.mStartGlyphIndex,
985                               requestedNumberOfCharacters,
986                               mModel->mVisualModel->mBackgroundColors,
987                               mModel->mVisualModel->mBackgroundColorIndices );
988
989     updated = true;
990   }
991
992
993   // The estimated number of lines. Used to avoid reallocations when layouting.
994   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
995
996   // Set the previous number of characters for the next time the text is updated.
997   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
998
999   return updated;
1000 }
1001
1002 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1003 {
1004   // Sets the default text's color.
1005   inputStyle.textColor = mTextColor;
1006   inputStyle.isDefaultColor = true;
1007
1008   inputStyle.familyName.clear();
1009   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1010   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1011   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1012   inputStyle.size = 0.f;
1013
1014   inputStyle.lineSpacing = 0.f;
1015
1016   inputStyle.underlineProperties.clear();
1017   inputStyle.shadowProperties.clear();
1018   inputStyle.embossProperties.clear();
1019   inputStyle.outlineProperties.clear();
1020
1021   inputStyle.isFamilyDefined = false;
1022   inputStyle.isWeightDefined = false;
1023   inputStyle.isWidthDefined = false;
1024   inputStyle.isSlantDefined = false;
1025   inputStyle.isSizeDefined = false;
1026
1027   inputStyle.isLineSpacingDefined = false;
1028
1029   inputStyle.isUnderlineDefined = false;
1030   inputStyle.isShadowDefined = false;
1031   inputStyle.isEmbossDefined = false;
1032   inputStyle.isOutlineDefined = false;
1033
1034   // Sets the default font's family name, weight, width, slant and size.
1035   if( mFontDefaults )
1036   {
1037     if( mFontDefaults->familyDefined )
1038     {
1039       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1040       inputStyle.isFamilyDefined = true;
1041     }
1042
1043     if( mFontDefaults->weightDefined )
1044     {
1045       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1046       inputStyle.isWeightDefined = true;
1047     }
1048
1049     if( mFontDefaults->widthDefined )
1050     {
1051       inputStyle.width = mFontDefaults->mFontDescription.width;
1052       inputStyle.isWidthDefined = true;
1053     }
1054
1055     if( mFontDefaults->slantDefined )
1056     {
1057       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1058       inputStyle.isSlantDefined = true;
1059     }
1060
1061     if( mFontDefaults->sizeDefined )
1062     {
1063       inputStyle.size = mFontDefaults->mDefaultPointSize;
1064       inputStyle.isSizeDefined = true;
1065     }
1066   }
1067 }
1068
1069 float Controller::Impl::GetDefaultFontLineHeight()
1070 {
1071   FontId defaultFontId = 0u;
1072   if( NULL == mFontDefaults )
1073   {
1074     TextAbstraction::FontDescription fontDescription;
1075     defaultFontId = mFontClient.GetFontId( fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale );
1076   }
1077   else
1078   {
1079     defaultFontId = mFontDefaults->GetFontId( mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale );
1080   }
1081
1082   Text::FontMetrics fontMetrics;
1083   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1084
1085   return( fontMetrics.ascender - fontMetrics.descender );
1086 }
1087
1088 void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
1089 {
1090   if( nullptr == mEventData )
1091   {
1092     // Nothing to do if there is no text.
1093     return;
1094   }
1095
1096   if( mEventData->mSelectionEnabled && (pStart || pEnd))
1097   {
1098     uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1099
1100     if (pStart)
1101     {
1102       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
1103     }
1104     if (pEnd)
1105     {
1106       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
1107     }
1108
1109     if (mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1110     {
1111       ChangeState( EventData::EDITING );
1112       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
1113       mEventData->mUpdateCursorPosition = true;
1114     }
1115     else
1116     {
1117       ChangeState( EventData::SELECTING );
1118       mEventData->mUpdateHighlightBox = true;
1119       mEventData->mUpdateLeftSelectionPosition = true;
1120       mEventData->mUpdateRightSelectionPosition = true;
1121     }
1122   }
1123 }
1124
1125 CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
1126 {
1127   if( nullptr == mEventData )
1128   {
1129     return 0;
1130   }
1131   return mEventData->mPrimaryCursorPosition;
1132 }
1133
1134 bool Controller::Impl::SetPrimaryCursorPosition( CharacterIndex index )
1135 {
1136   if( nullptr == mEventData )
1137   {
1138     // Nothing to do if there is no text.
1139     return false;
1140   }
1141
1142   if( mEventData->mPrimaryCursorPosition == index )
1143   {
1144     // Nothing for same cursor position.
1145     return false;
1146   }
1147
1148   uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1149   mEventData->mPrimaryCursorPosition = std::min(index, length);
1150   ChangeState( EventData::EDITING );
1151   mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1152   mEventData->mUpdateCursorPosition = true;
1153   ScrollTextToMatchCursor();
1154   return true;
1155 }
1156
1157 Uint32Pair Controller::Impl::GetTextSelectionRange() const
1158 {
1159   Uint32Pair range;
1160
1161   if( mEventData )
1162   {
1163     range.first = mEventData->mLeftSelectionPosition;
1164     range.second = mEventData->mRightSelectionPosition;
1165   }
1166
1167   return range;
1168 }
1169
1170 bool Controller::Impl::IsEditable() const
1171 {
1172   return mEventData && mEventData->mEditingEnabled;
1173 }
1174
1175 void Controller::Impl::SetEditable( bool editable )
1176 {
1177   if( mEventData)
1178   {
1179     mEventData->mEditingEnabled = editable;
1180   }
1181 }
1182
1183 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1184 {
1185   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1186   {
1187     // Nothing to select if handles are in the same place.
1188     selectedText.clear();
1189     return;
1190   }
1191
1192   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1193
1194   //Get start and end position of selection
1195   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1196   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1197
1198   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
1199   const Length numberOfCharacters = utf32Characters.Count();
1200
1201   // Validate the start and end selection points
1202   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1203   {
1204     //Get text as a UTF8 string
1205     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1206
1207     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1208     {
1209       // Keep a copy of the current input style.
1210       InputStyle currentInputStyle;
1211       currentInputStyle.Copy( mEventData->mInputStyle );
1212
1213       // Set as input style the style of the first deleted character.
1214       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1215
1216       // Compare if the input style has changed.
1217       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
1218
1219       if( hasInputStyleChanged )
1220       {
1221         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
1222         // Queue the input style changed signal.
1223         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
1224       }
1225
1226       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1227
1228       // Mark the paragraphs to be updated.
1229       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1230       {
1231         mTextUpdateInfo.mCharacterIndex = 0;
1232         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1233         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1234         mTextUpdateInfo.mClearAll = true;
1235       }
1236       else
1237       {
1238         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1239         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1240       }
1241
1242       // Delete text between handles
1243       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1244       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1245       utf32Characters.Erase( first, last );
1246
1247       // Will show the cursor at the first character of the selection.
1248       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1249     }
1250     else
1251     {
1252       // Will show the cursor at the last character of the selection.
1253       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1254     }
1255
1256     mEventData->mDecoratorUpdated = true;
1257   }
1258 }
1259
1260 void Controller::Impl::SetSelection( int start, int end )
1261 {
1262   mEventData->mLeftSelectionPosition = start;
1263   mEventData->mRightSelectionPosition = end;
1264   mEventData->mUpdateCursorPosition = true;
1265 }
1266
1267 std::pair< int, int > Controller::Impl::GetSelectionIndexes() const
1268 {
1269   return { mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition };
1270 }
1271
1272 void Controller::Impl::ShowClipboard()
1273 {
1274   if( mClipboard )
1275   {
1276     mClipboard.ShowClipboard();
1277   }
1278 }
1279
1280 void Controller::Impl::HideClipboard()
1281 {
1282   if( mClipboard && mClipboardHideEnabled )
1283   {
1284     mClipboard.HideClipboard();
1285   }
1286 }
1287
1288 void Controller::Impl::SetClipboardHideEnable(bool enable)
1289 {
1290   mClipboardHideEnabled = enable;
1291 }
1292
1293 bool Controller::Impl::CopyStringToClipboard( const std::string& source )
1294 {
1295   //Send string to clipboard
1296   return ( mClipboard && mClipboard.SetItem( source ) );
1297 }
1298
1299 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
1300 {
1301   std::string selectedText;
1302   RetrieveSelection( selectedText, deleteAfterSending );
1303   CopyStringToClipboard( selectedText );
1304   ChangeState( EventData::EDITING );
1305 }
1306
1307 void Controller::Impl::RequestGetTextFromClipboard()
1308 {
1309   if ( mClipboard )
1310   {
1311     mClipboard.RequestItem();
1312   }
1313 }
1314
1315 void Controller::Impl::RepositionSelectionHandles()
1316 {
1317   SelectionHandleController::Reposition(*this);
1318 }
1319 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
1320 {
1321   SelectionHandleController::Reposition(*this, visualX, visualY, action);
1322 }
1323
1324 void Controller::Impl::SetPopupButtons()
1325 {
1326   /**
1327    *  Sets the Popup buttons to be shown depending on State.
1328    *
1329    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
1330    *
1331    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
1332    */
1333
1334   bool isEditable = IsEditable();
1335   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
1336
1337   if( EventData::SELECTING == mEventData->mState )
1338   {
1339     buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
1340     if(isEditable)
1341     {
1342       buttonsToShow = TextSelectionPopup::Buttons( buttonsToShow | TextSelectionPopup::CUT );
1343     }
1344
1345     if( !IsClipboardEmpty() )
1346     {
1347       if(isEditable)
1348       {
1349         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1350       }
1351       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1352     }
1353
1354     if( !mEventData->mAllTextSelected )
1355     {
1356       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
1357     }
1358   }
1359   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
1360   {
1361     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
1362     {
1363       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
1364     }
1365
1366     if( !IsClipboardEmpty() )
1367     {
1368       if(isEditable)
1369       {
1370         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1371       }
1372       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1373     }
1374   }
1375   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
1376   {
1377     if ( !IsClipboardEmpty() )
1378     {
1379       if(isEditable)
1380       {
1381         buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
1382       }
1383       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
1384     }
1385   }
1386
1387   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
1388 }
1389
1390 void Controller::Impl::ChangeState( EventData::State newState )
1391 {
1392   if( NULL == mEventData )
1393   {
1394     // Nothing to do if there is no text input.
1395     return;
1396   }
1397
1398   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
1399
1400   if( mEventData->mState != newState )
1401   {
1402     mEventData->mPreviousState = mEventData->mState;
1403     mEventData->mState = newState;
1404
1405     switch( mEventData->mState )
1406     {
1407       case EventData::INACTIVE:
1408       {
1409         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1410         mEventData->mDecorator->StopCursorBlink();
1411         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1412         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1413         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1414         mEventData->mDecorator->SetHighlightActive( false );
1415         mEventData->mDecorator->SetPopupActive( false );
1416         mEventData->mDecoratorUpdated = true;
1417         break;
1418       }
1419       case EventData::INTERRUPTED:
1420       {
1421         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1422         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1423         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1424         mEventData->mDecorator->SetHighlightActive( false );
1425         mEventData->mDecorator->SetPopupActive( false );
1426         mEventData->mDecoratorUpdated = true;
1427         break;
1428       }
1429       case EventData::SELECTING:
1430       {
1431         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1432         mEventData->mDecorator->StopCursorBlink();
1433         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1434         if ( mEventData->mGrabHandleEnabled )
1435         {
1436           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
1437           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
1438         }
1439         mEventData->mDecorator->SetHighlightActive( true );
1440         if( mEventData->mGrabHandlePopupEnabled )
1441         {
1442           SetPopupButtons();
1443           mEventData->mDecorator->SetPopupActive( true );
1444         }
1445         mEventData->mDecoratorUpdated = true;
1446         break;
1447       }
1448       case EventData::EDITING:
1449       {
1450         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1451         if( mEventData->mCursorBlinkEnabled )
1452         {
1453           mEventData->mDecorator->StartCursorBlink();
1454         }
1455         // Grab handle is not shown until a tap is received whilst EDITING
1456         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1457         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1458         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1459         mEventData->mDecorator->SetHighlightActive( false );
1460         if( mEventData->mGrabHandlePopupEnabled )
1461         {
1462           mEventData->mDecorator->SetPopupActive( false );
1463         }
1464         mEventData->mDecoratorUpdated = true;
1465         break;
1466       }
1467       case EventData::EDITING_WITH_POPUP:
1468       {
1469         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
1470
1471         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1472         if( mEventData->mCursorBlinkEnabled )
1473         {
1474           mEventData->mDecorator->StartCursorBlink();
1475         }
1476         if( mEventData->mSelectionEnabled )
1477         {
1478           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1479           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1480           mEventData->mDecorator->SetHighlightActive( false );
1481         }
1482         else if ( mEventData->mGrabHandleEnabled )
1483         {
1484           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1485         }
1486         if( mEventData->mGrabHandlePopupEnabled )
1487         {
1488           SetPopupButtons();
1489           mEventData->mDecorator->SetPopupActive( true );
1490         }
1491         mEventData->mDecoratorUpdated = true;
1492         break;
1493       }
1494       case EventData::EDITING_WITH_GRAB_HANDLE:
1495       {
1496         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
1497
1498         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1499         if( mEventData->mCursorBlinkEnabled )
1500         {
1501           mEventData->mDecorator->StartCursorBlink();
1502         }
1503         // Grab handle is not shown until a tap is received whilst EDITING
1504         if ( mEventData->mGrabHandleEnabled )
1505         {
1506           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1507         }
1508         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1509         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1510         mEventData->mDecorator->SetHighlightActive( false );
1511         if( mEventData->mGrabHandlePopupEnabled )
1512         {
1513           mEventData->mDecorator->SetPopupActive( false );
1514         }
1515         mEventData->mDecoratorUpdated = true;
1516         break;
1517       }
1518       case EventData::SELECTION_HANDLE_PANNING:
1519       {
1520         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1521         mEventData->mDecorator->StopCursorBlink();
1522         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1523         if ( mEventData->mGrabHandleEnabled )
1524         {
1525           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
1526           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
1527         }
1528         mEventData->mDecorator->SetHighlightActive( true );
1529         if( mEventData->mGrabHandlePopupEnabled )
1530         {
1531           mEventData->mDecorator->SetPopupActive( false );
1532         }
1533         mEventData->mDecoratorUpdated = true;
1534         break;
1535       }
1536       case EventData::GRAB_HANDLE_PANNING:
1537       {
1538         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
1539
1540         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1541         if( mEventData->mCursorBlinkEnabled )
1542         {
1543           mEventData->mDecorator->StartCursorBlink();
1544         }
1545         if ( mEventData->mGrabHandleEnabled )
1546         {
1547           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1548         }
1549         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1550         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1551         mEventData->mDecorator->SetHighlightActive( false );
1552         if( mEventData->mGrabHandlePopupEnabled )
1553         {
1554           mEventData->mDecorator->SetPopupActive( false );
1555         }
1556         mEventData->mDecoratorUpdated = true;
1557         break;
1558       }
1559       case EventData::EDITING_WITH_PASTE_POPUP:
1560       {
1561         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
1562
1563         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1564         if( mEventData->mCursorBlinkEnabled )
1565         {
1566           mEventData->mDecorator->StartCursorBlink();
1567         }
1568
1569         if ( mEventData->mGrabHandleEnabled )
1570         {
1571           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1572         }
1573         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1574         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1575         mEventData->mDecorator->SetHighlightActive( false );
1576
1577         if( mEventData->mGrabHandlePopupEnabled )
1578         {
1579           SetPopupButtons();
1580           mEventData->mDecorator->SetPopupActive( true );
1581         }
1582         mEventData->mDecoratorUpdated = true;
1583         break;
1584       }
1585       case EventData::TEXT_PANNING:
1586       {
1587         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1588         mEventData->mDecorator->StopCursorBlink();
1589         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1590         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
1591             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
1592         {
1593           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1594           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1595           mEventData->mDecorator->SetHighlightActive( true );
1596         }
1597
1598         if( mEventData->mGrabHandlePopupEnabled )
1599         {
1600           mEventData->mDecorator->SetPopupActive( false );
1601         }
1602
1603         mEventData->mDecoratorUpdated = true;
1604         break;
1605       }
1606     }
1607   }
1608 }
1609
1610 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
1611                                           CursorInfo& cursorInfo )
1612 {
1613   if( !IsShowingRealText() )
1614   {
1615     // Do not want to use the place-holder text to set the cursor position.
1616
1617     // Use the line's height of the font's family set to set the cursor's size.
1618     // If there is no font's family set, use the default font.
1619     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1620
1621     cursorInfo.lineOffset = 0.f;
1622     cursorInfo.lineHeight = GetDefaultFontLineHeight();
1623     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1624
1625     bool isRTL = false;
1626     if( mModel->mMatchSystemLanguageDirection )
1627     {
1628       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1629     }
1630
1631     switch( mModel->mHorizontalAlignment )
1632     {
1633       case Text::HorizontalAlignment::BEGIN :
1634       {
1635         if( isRTL )
1636         {
1637           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1638         }
1639         else
1640         {
1641           cursorInfo.primaryPosition.x = 0.f;
1642         }
1643         break;
1644       }
1645       case Text::HorizontalAlignment::CENTER:
1646       {
1647         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
1648         break;
1649       }
1650       case Text::HorizontalAlignment::END:
1651       {
1652         if( isRTL )
1653         {
1654           cursorInfo.primaryPosition.x = 0.f;
1655         }
1656         else
1657         {
1658           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1659         }
1660         break;
1661       }
1662     }
1663
1664     // Nothing else to do.
1665     return;
1666   }
1667
1668   const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
1669   GetCursorPositionParameters parameters;
1670   parameters.visualModel = mModel->mVisualModel;
1671   parameters.logicalModel = mModel->mLogicalModel;
1672   parameters.metrics = mMetrics;
1673   parameters.logical = logical;
1674   parameters.isMultiline = isMultiLine;
1675
1676   Text::GetCursorPosition( parameters,
1677                            cursorInfo );
1678
1679   // Adds Outline offset.
1680   const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
1681   cursorInfo.primaryPosition.x += outlineWidth;
1682   cursorInfo.primaryPosition.y += outlineWidth;
1683   cursorInfo.secondaryPosition.x += outlineWidth;
1684   cursorInfo.secondaryPosition.y += outlineWidth;
1685
1686   if( isMultiLine )
1687   {
1688     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1689
1690     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1691     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1692
1693     if( 0.f > cursorInfo.primaryPosition.x )
1694     {
1695       cursorInfo.primaryPosition.x = 0.f;
1696     }
1697
1698     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
1699     if( cursorInfo.primaryPosition.x > edgeWidth )
1700     {
1701       cursorInfo.primaryPosition.x = edgeWidth;
1702     }
1703   }
1704 }
1705
1706 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
1707 {
1708   if( NULL == mEventData )
1709   {
1710     // Nothing to do if there is no text input.
1711     return 0u;
1712   }
1713
1714   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1715
1716   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1717   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1718
1719   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
1720   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
1721
1722   if( numberOfCharacters > 1u )
1723   {
1724     const Script script = mModel->mLogicalModel->GetScript( index );
1725     if( HasLigatureMustBreak( script ) )
1726     {
1727       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
1728       numberOfCharacters = 1u;
1729     }
1730   }
1731   else
1732   {
1733     while( 0u == numberOfCharacters )
1734     {
1735       ++glyphIndex;
1736       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
1737     }
1738   }
1739
1740   if( index < mEventData->mPrimaryCursorPosition )
1741   {
1742     cursorIndex -= numberOfCharacters;
1743   }
1744   else
1745   {
1746     cursorIndex += numberOfCharacters;
1747   }
1748
1749   // Will update the cursor hook position.
1750   mEventData->mUpdateCursorHookPosition = true;
1751
1752   return cursorIndex;
1753 }
1754
1755 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
1756 {
1757   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
1758   if( NULL == mEventData )
1759   {
1760     // Nothing to do if there is no text input.
1761     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
1762     return;
1763   }
1764
1765   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
1766
1767   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
1768
1769   // Sets the cursor position.
1770   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
1771                                        cursorPosition.x,
1772                                        cursorPosition.y,
1773                                        cursorInfo.primaryCursorHeight,
1774                                        cursorInfo.lineHeight );
1775   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
1776
1777   if( mEventData->mUpdateGrabHandlePosition )
1778   {
1779     // Sets the grab handle position.
1780     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
1781                                          cursorPosition.x,
1782                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
1783                                          cursorInfo.lineHeight );
1784   }
1785
1786   if( cursorInfo.isSecondaryCursor )
1787   {
1788     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
1789                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
1790                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
1791                                          cursorInfo.secondaryCursorHeight,
1792                                          cursorInfo.lineHeight );
1793     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
1794   }
1795
1796   // Set which cursors are active according the state.
1797   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
1798   {
1799     if( cursorInfo.isSecondaryCursor )
1800     {
1801       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
1802     }
1803     else
1804     {
1805       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
1806     }
1807   }
1808   else
1809   {
1810     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
1811   }
1812
1813   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
1814 }
1815
1816 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
1817                                               const CursorInfo& cursorInfo )
1818 {
1819   SelectionHandleController::Update(*this, handleType, cursorInfo);
1820 }
1821
1822 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
1823 {
1824   // Clamp between -space & -alignment offset.
1825
1826   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
1827   {
1828     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
1829     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
1830     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
1831
1832     mEventData->mDecoratorUpdated = true;
1833   }
1834   else
1835   {
1836     mModel->mScrollPosition.x = 0.f;
1837   }
1838 }
1839
1840 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
1841 {
1842   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1843   {
1844     // Nothing to do if the text is single line.
1845     return;
1846   }
1847
1848   // Clamp between -space & 0.
1849   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
1850   {
1851     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
1852     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
1853     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
1854
1855     mEventData->mDecoratorUpdated = true;
1856   }
1857   else
1858   {
1859     mModel->mScrollPosition.y = 0.f;
1860   }
1861 }
1862
1863 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
1864 {
1865   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
1866
1867   // position is in actor's coords.
1868   const float positionEndX = position.x + cursorWidth;
1869   const float positionEndY = position.y + lineHeight;
1870
1871   // Transform the position to decorator coords.
1872   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
1873   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
1874
1875   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
1876   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
1877
1878   if( decoratorPositionBeginX < 0.f )
1879   {
1880     mModel->mScrollPosition.x = -position.x;
1881   }
1882   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
1883   {
1884     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
1885   }
1886
1887   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
1888   {
1889     if( decoratorPositionBeginY < 0.f )
1890     {
1891       mModel->mScrollPosition.y = -position.y;
1892     }
1893     else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
1894     {
1895       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
1896     }
1897   }
1898 }
1899
1900 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
1901 {
1902   // Get the current cursor position in decorator coords.
1903   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
1904
1905   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
1906
1907
1908
1909   // Calculate the offset to match the cursor position before the character was deleted.
1910   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
1911
1912   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
1913   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
1914   {
1915     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
1916     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
1917   }
1918
1919
1920   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
1921   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
1922
1923   // Makes the new cursor position visible if needed.
1924   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
1925 }
1926
1927 void Controller::Impl::ScrollTextToMatchCursor()
1928 {
1929   CursorInfo cursorInfo;
1930   GetCursorPosition( mEventData->mPrimaryCursorPosition, cursorInfo );
1931   ScrollTextToMatchCursor(cursorInfo);
1932 }
1933
1934 void Controller::Impl::RequestRelayout()
1935 {
1936   if( NULL != mControlInterface )
1937   {
1938     mControlInterface->RequestTextRelayout();
1939   }
1940 }
1941
1942 Actor Controller::Impl::CreateBackgroundActor()
1943 {
1944   // NOTE: Currently we only support background color for one line left-to-right text,
1945   //       so the following calculation is based on one line left-to-right text only!
1946
1947   Actor actor;
1948
1949   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
1950   if( numberOfGlyphs > 0u )
1951   {
1952     Vector<GlyphInfo> glyphs;
1953     glyphs.Resize( numberOfGlyphs );
1954
1955     Vector<Vector2> positions;
1956     positions.Resize( numberOfGlyphs );
1957
1958     // Get the line where the glyphs are laid-out.
1959     const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
1960     float alignmentOffset = lineRun->alignmentOffset;
1961     numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
1962                                       positions.Begin(),
1963                                       alignmentOffset,
1964                                       0u,
1965                                       numberOfGlyphs );
1966
1967     glyphs.Resize( numberOfGlyphs );
1968     positions.Resize( numberOfGlyphs );
1969
1970     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
1971     const Vector2* const positionsBuffer = positions.Begin();
1972
1973     BackgroundMesh mesh;
1974     mesh.mVertices.Reserve( 4u * glyphs.Size() );
1975     mesh.mIndices.Reserve( 6u * glyphs.Size() );
1976
1977     const Vector2 textSize = mView.GetLayoutSize();
1978
1979     const float offsetX = textSize.width * 0.5f;
1980     const float offsetY = textSize.height * 0.5f;
1981
1982     const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
1983     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
1984     const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
1985
1986     Vector4 quad;
1987     uint32_t numberOfQuads = 0u;
1988
1989     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
1990     {
1991       const GlyphInfo& glyph = *( glyphsBuffer + i );
1992
1993       // Get the background color of the character.
1994       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
1995       const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
1996       const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? defaultBackgroundColor : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
1997
1998       // Only create quads for glyphs with a background color
1999       if ( backgroundColor != Color::TRANSPARENT )
2000       {
2001         const Vector2 position = *( positionsBuffer + i );
2002
2003         if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
2004         {
2005           quad.x = position.x;
2006           quad.y = 0.0f;
2007           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
2008           quad.w = textSize.height;
2009         }
2010         else if ( i == 0u ) // The first glyph in the whole text
2011         {
2012           quad.x = position.x;
2013           quad.y = 0.0f;
2014           quad.z = quad.x - glyph.xBearing + glyph.advance;
2015           quad.w = textSize.height;
2016         }
2017         else if ( i == glyphSize - 1u ) // The last glyph in the whole text
2018         {
2019           quad.x = position.x - glyph.xBearing;
2020           quad.y = 0.0f;
2021           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
2022           quad.w = textSize.height;
2023         }
2024         else // The glyph in the middle of the text
2025         {
2026           quad.x = position.x - glyph.xBearing;
2027           quad.y = 0.0f;
2028           quad.z = quad.x + glyph.advance;
2029           quad.w = textSize.height;
2030         }
2031
2032         BackgroundVertex vertex;
2033
2034         // Top left
2035         vertex.mPosition.x = quad.x - offsetX;
2036         vertex.mPosition.y = quad.y - offsetY;
2037         vertex.mColor = backgroundColor;
2038         mesh.mVertices.PushBack( vertex );
2039
2040         // Top right
2041         vertex.mPosition.x = quad.z - offsetX;
2042         vertex.mPosition.y = quad.y - offsetY;
2043         vertex.mColor = backgroundColor;
2044         mesh.mVertices.PushBack( vertex );
2045
2046         // Bottom left
2047         vertex.mPosition.x = quad.x - offsetX;
2048         vertex.mPosition.y = quad.w - offsetY;
2049         vertex.mColor = backgroundColor;
2050         mesh.mVertices.PushBack( vertex );
2051
2052         // Bottom right
2053         vertex.mPosition.x = quad.z - offsetX;
2054         vertex.mPosition.y = quad.w - offsetY;
2055         vertex.mColor = backgroundColor;
2056         mesh.mVertices.PushBack( vertex );
2057
2058         // Six indices in counter clockwise winding
2059         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
2060         mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
2061         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
2062         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
2063         mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
2064         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
2065
2066         numberOfQuads++;
2067       }
2068     }
2069
2070     // Only create the background actor if there are glyphs with background color
2071     if ( mesh.mVertices.Count() > 0u )
2072     {
2073       Property::Map quadVertexFormat;
2074       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
2075       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
2076
2077       VertexBuffer quadVertices = VertexBuffer::New( quadVertexFormat );
2078       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
2079
2080       Geometry quadGeometry = Geometry::New();
2081       quadGeometry.AddVertexBuffer( quadVertices );
2082       quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
2083
2084       if( !mShaderBackground )
2085       {
2086         mShaderBackground = Shader::New( SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG );
2087       }
2088
2089       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
2090       renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
2091       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
2092
2093       actor = Actor::New();
2094       actor.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
2095       actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
2096       actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
2097       actor.SetProperty( Actor::Property::SIZE, textSize );
2098       actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
2099       actor.AddRenderer( renderer );
2100     }
2101   }
2102
2103   return actor;
2104 }
2105
2106 } // namespace Text
2107
2108 } // namespace Toolkit
2109
2110 } // namespace Dali