Make cursor invisible when exceeds the boundaries of the Text Control.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2015 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.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <dali/public-api/adaptor-framework/key.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/text/bidirectional-support.h>
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
29 #include <dali-toolkit/internal/text/multi-language-support.h>
30 #include <dali-toolkit/internal/text/script-run.h>
31 #include <dali-toolkit/internal/text/segmentation.h>
32 #include <dali-toolkit/internal/text/shaper.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34 #include <dali-toolkit/internal/text/text-io.h>
35 #include <dali-toolkit/internal/text/text-view.h>
36
37 namespace
38 {
39
40 const float MAX_FLOAT = std::numeric_limits<float>::max();
41
42 const std::string EMPTY_STRING("");
43
44 } // namespace
45
46 namespace Dali
47 {
48
49 namespace Toolkit
50 {
51
52 namespace Text
53 {
54
55 ControllerPtr Controller::New( ControlInterface& controlInterface )
56 {
57   return ControllerPtr( new Controller( controlInterface ) );
58 }
59
60 void Controller::SetText( const std::string& text )
61 {
62   // Cancel previously queued inserts etc.
63   mImpl->mModifyEvents.clear();
64
65   // Keep until size negotiation
66   ModifyEvent event;
67   event.type = ModifyEvent::REPLACE_TEXT;
68   event.text = text;
69   mImpl->mModifyEvents.push_back( event );
70
71   if( mImpl->mEventData )
72   {
73     // Cancel previously queued events
74     mImpl->mEventData->mEventQueue.clear();
75
76     // TODO - Hide selection decorations
77   }
78 }
79
80 void Controller::GetText( std::string& text ) const
81 {
82   if( !mImpl->mModifyEvents.empty() &&
83        ModifyEvent::REPLACE_TEXT == mImpl->mModifyEvents[0].type )
84   {
85     text = mImpl->mModifyEvents[0].text;
86   }
87   else
88   {
89     // TODO - Convert from UTF-32
90   }
91 }
92
93 void Controller::SetPlaceholderText( const std::string& text )
94 {
95   if( !mImpl->mEventData )
96   {
97     mImpl->mEventData->mPlaceholderText = text;
98   }
99 }
100
101 void Controller::GetPlaceholderText( std::string& text ) const
102 {
103   if( !mImpl->mEventData )
104   {
105     text = mImpl->mEventData->mPlaceholderText;
106   }
107 }
108
109 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
110 {
111   if( !mImpl->mFontDefaults )
112   {
113     mImpl->mFontDefaults = new FontDefaults();
114   }
115
116   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
117   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
118   mImpl->mOperationsPending = ALL_OPERATIONS;
119   mImpl->mRecalculateNaturalSize = true;
120
121   // Clear the font-specific data
122   mImpl->mLogicalModel->mFontRuns.Clear();
123   mImpl->mVisualModel->mGlyphs.Clear();
124   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
125   mImpl->mVisualModel->mCharactersToGlyph.Clear();
126   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
127   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
128   mImpl->mVisualModel->mGlyphPositions.Clear();
129   mImpl->mVisualModel->mLines.Clear();
130   mImpl->mVisualModel->ClearCaches();
131
132   mImpl->RequestRelayout();
133 }
134
135 const std::string& Controller::GetDefaultFontFamily() const
136 {
137   if( mImpl->mFontDefaults )
138   {
139     return mImpl->mFontDefaults->mDefaultFontFamily;
140   }
141
142   return EMPTY_STRING;
143 }
144
145 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
146 {
147   if( !mImpl->mFontDefaults )
148   {
149     mImpl->mFontDefaults = new FontDefaults();
150   }
151
152   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
153   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
154   mImpl->mOperationsPending = ALL_OPERATIONS;
155   mImpl->mRecalculateNaturalSize = true;
156
157   // Clear the font-specific data
158   mImpl->mLogicalModel->mFontRuns.Clear();
159   mImpl->mVisualModel->mGlyphs.Clear();
160   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
161   mImpl->mVisualModel->mCharactersToGlyph.Clear();
162   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
163   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
164   mImpl->mVisualModel->mGlyphPositions.Clear();
165   mImpl->mVisualModel->mLines.Clear();
166   mImpl->mVisualModel->ClearCaches();
167
168   mImpl->RequestRelayout();
169 }
170
171 const std::string& Controller::GetDefaultFontStyle() const
172 {
173   if( mImpl->mFontDefaults )
174   {
175     return mImpl->mFontDefaults->mDefaultFontStyle;
176   }
177
178   return EMPTY_STRING;
179 }
180
181 void Controller::SetDefaultPointSize( float pointSize )
182 {
183   if( !mImpl->mFontDefaults )
184   {
185     mImpl->mFontDefaults = new FontDefaults();
186   }
187
188   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
189   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
190   mImpl->mOperationsPending = ALL_OPERATIONS;
191   mImpl->mRecalculateNaturalSize = true;
192
193   // Clear the font-specific data
194   mImpl->mLogicalModel->mFontRuns.Clear();
195   mImpl->mVisualModel->mGlyphs.Clear();
196   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
197   mImpl->mVisualModel->mCharactersToGlyph.Clear();
198   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
199   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
200   mImpl->mVisualModel->mGlyphPositions.Clear();
201   mImpl->mVisualModel->mLines.Clear();
202   mImpl->mVisualModel->ClearCaches();
203
204   mImpl->RequestRelayout();
205 }
206
207 float Controller::GetDefaultPointSize() const
208 {
209   if( mImpl->mFontDefaults )
210   {
211     return mImpl->mFontDefaults->mDefaultPointSize;
212   }
213
214   return 0.0f;
215 }
216
217 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters ) const
218 {
219   if( mImpl->mFontDefaults )
220   {
221     FontRun fontRun;
222     fontRun.characterRun.characterIndex = 0;
223     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
224     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
225     fontRun.isDefault = true;
226
227     fonts.PushBack( fontRun );
228   }
229 }
230
231 void Controller::SetTextColor( const Vector4& textColor )
232 {
233   mImpl->mVisualModel->SetTextColor( textColor );
234 }
235
236 const Vector4& Controller::GetTextColor() const
237 {
238   return mImpl->mVisualModel->GetTextColor();
239 }
240
241 void Controller::SetShadowOffset( const Vector2& shadowOffset )
242 {
243   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
244 }
245
246 const Vector2& Controller::GetShadowOffset() const
247 {
248   return mImpl->mVisualModel->GetShadowOffset();
249 }
250
251 void Controller::SetShadowColor( const Vector4& shadowColor )
252 {
253   mImpl->mVisualModel->SetShadowColor( shadowColor );
254 }
255
256 const Vector4& Controller::GetShadowColor() const
257 {
258   return mImpl->mVisualModel->GetShadowColor();
259 }
260
261 void Controller::SetUnderlineColor( const Vector4& color )
262 {
263   mImpl->mVisualModel->SetUnderlineColor( color );
264 }
265
266 const Vector4& Controller::GetUnderlineColor() const
267 {
268   return mImpl->mVisualModel->GetUnderlineColor();
269 }
270
271 void Controller::SetUnderlineEnabled( bool enabled )
272 {
273   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
274 }
275
276 bool Controller::IsUnderlineEnabled() const
277 {
278   return mImpl->mVisualModel->IsUnderlineEnabled();
279 }
280
281 void Controller::SetUnderlineHeight( float height )
282 {
283   mImpl->mVisualModel->SetUnderlineHeight( height );
284 }
285
286 float Controller::GetUnderlineHeight() const
287 {
288   return mImpl->mVisualModel->GetUnderlineHeight();
289 }
290
291 void Controller::EnableTextInput( DecoratorPtr decorator )
292 {
293   if( !mImpl->mEventData )
294   {
295     mImpl->mEventData = new EventData( decorator );
296   }
297 }
298
299 void Controller::SetEnableCursorBlink( bool enable )
300 {
301   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
302
303   if( mImpl->mEventData )
304   {
305     mImpl->mEventData->mCursorBlinkEnabled = enable;
306
307     if( !enable &&
308         mImpl->mEventData->mDecorator )
309     {
310       mImpl->mEventData->mDecorator->StopCursorBlink();
311     }
312   }
313 }
314
315 bool Controller::GetEnableCursorBlink() const
316 {
317   if( mImpl->mEventData )
318   {
319     return mImpl->mEventData->mCursorBlinkEnabled;
320   }
321
322   return false;
323 }
324
325 const Vector2& Controller::GetScrollPosition() const
326 {
327   if( mImpl->mEventData )
328   {
329     return mImpl->mEventData->mScrollPosition;
330   }
331
332   return Vector2::ZERO;
333 }
334
335 const Vector2& Controller::GetAlignmentOffset() const
336 {
337   return mImpl->mAlignmentOffset;
338 }
339
340 Vector3 Controller::GetNaturalSize()
341 {
342   Vector3 naturalSize;
343
344   // Make sure the model is up-to-date before layouting
345   ProcessModifyEvents();
346
347   if( mImpl->mRecalculateNaturalSize )
348   {
349     // Operations that can be done only once until the text changes.
350     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
351                                                                            GET_SCRIPTS       |
352                                                                            VALIDATE_FONTS    |
353                                                                            GET_LINE_BREAKS   |
354                                                                            GET_WORD_BREAKS   |
355                                                                            BIDI_INFO         |
356                                                                            SHAPE_TEXT        |
357                                                                            GET_GLYPH_METRICS );
358     // Make sure the model is up-to-date before layouting
359     UpdateModel( onlyOnceOperations );
360
361     // Operations that need to be done if the size changes.
362     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
363                                                                         ALIGN  |
364                                                                         REORDER );
365
366     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
367                 static_cast<OperationsMask>( onlyOnceOperations |
368                                              sizeOperations ),
369                 naturalSize.GetVectorXY() );
370
371     // Do not do again the only once operations.
372     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
373
374     // Do the size related operations again.
375     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
376
377     // Stores the natural size to avoid recalculate it again
378     // unless the text/style changes.
379     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
380
381     mImpl->mRecalculateNaturalSize = false;
382   }
383   else
384   {
385     naturalSize = mImpl->mVisualModel->GetNaturalSize();
386   }
387
388   return naturalSize;
389 }
390
391 float Controller::GetHeightForWidth( float width )
392 {
393   // Make sure the model is up-to-date before layouting
394   ProcessModifyEvents();
395
396   Size layoutSize;
397   if( width != mImpl->mControlSize.width )
398   {
399     // Operations that can be done only once until the text changes.
400     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
401                                                                            GET_SCRIPTS       |
402                                                                            VALIDATE_FONTS    |
403                                                                            GET_LINE_BREAKS   |
404                                                                            GET_WORD_BREAKS   |
405                                                                            BIDI_INFO         |
406                                                                            SHAPE_TEXT        |
407                                                                            GET_GLYPH_METRICS );
408     // Make sure the model is up-to-date before layouting
409     UpdateModel( onlyOnceOperations );
410
411     // Operations that need to be done if the size changes.
412     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
413                                                                         ALIGN  |
414                                                                         REORDER );
415
416     DoRelayout( Size( width, MAX_FLOAT ),
417                 static_cast<OperationsMask>( onlyOnceOperations |
418                                              sizeOperations ),
419                 layoutSize );
420
421     // Do not do again the only once operations.
422     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
423
424     // Do the size related operations again.
425     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
426   }
427   else
428   {
429     layoutSize = mImpl->mVisualModel->GetActualSize();
430   }
431
432   return layoutSize.height;
433 }
434
435 bool Controller::Relayout( const Size& size )
436 {
437   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
438   {
439     bool glyphsRemoved( false );
440     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
441     {
442       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
443       glyphsRemoved = true;
444     }
445     // Not worth to relayout if width or height is equal to zero.
446     return glyphsRemoved;
447   }
448
449   if( size != mImpl->mControlSize )
450   {
451     // Operations that need to be done if the size changes.
452     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
453                                                              LAYOUT                    |
454                                                              ALIGN                     |
455                                                              UPDATE_ACTUAL_SIZE        |
456                                                              REORDER );
457
458     mImpl->mControlSize = size;
459   }
460
461   // Make sure the model is up-to-date before layouting
462   ProcessModifyEvents();
463   UpdateModel( mImpl->mOperationsPending );
464
465   Size layoutSize;
466   bool updated = DoRelayout( mImpl->mControlSize,
467                              mImpl->mOperationsPending,
468                              layoutSize );
469
470   // Do not re-do any operation until something changes.
471   mImpl->mOperationsPending = NO_OPERATION;
472
473   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
474   CalculateTextAlignment( size );
475
476   if( mImpl->mEventData )
477   {
478     // Move the cursor, grab handle etc.
479     updated = mImpl->ProcessInputEvents() || updated;
480   }
481
482   return updated;
483 }
484
485 void Controller::ProcessModifyEvents()
486 {
487   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
488
489   for( unsigned int i=0; i<events.size(); ++i )
490   {
491     if( ModifyEvent::REPLACE_TEXT == events[0].type )
492     {
493       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
494       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
495
496       ReplaceTextEvent( events[0].text );
497     }
498     else if( ModifyEvent::INSERT_TEXT == events[0].type )
499     {
500       InsertTextEvent( events[0].text );
501     }
502     else if( ModifyEvent::DELETE_TEXT == events[0].type )
503     {
504       DeleteTextEvent();
505     }
506   }
507
508   // Discard temporary text
509   events.clear();
510 }
511
512 void Controller::ReplaceTextEvent( const std::string& text )
513 {
514   // Reset buffers.
515   mImpl->mLogicalModel->mText.Clear();
516   mImpl->mLogicalModel->mScriptRuns.Clear();
517   mImpl->mLogicalModel->mFontRuns.Clear();
518   mImpl->mLogicalModel->mLineBreakInfo.Clear();
519   mImpl->mLogicalModel->mWordBreakInfo.Clear();
520   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
521   mImpl->mLogicalModel->mCharacterDirections.Clear();
522   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
523   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
524   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
525   mImpl->mVisualModel->mGlyphs.Clear();
526   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
527   mImpl->mVisualModel->mCharactersToGlyph.Clear();
528   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
529   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
530   mImpl->mVisualModel->mGlyphPositions.Clear();
531   mImpl->mVisualModel->mLines.Clear();
532   mImpl->mVisualModel->ClearCaches();
533
534   //  Convert text into UTF-32
535   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
536   utf32Characters.Resize( text.size() );
537
538   // This is a bit horrible but std::string returns a (signed) char*
539   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
540
541   // Transform a text array encoded in utf8 into an array encoded in utf32.
542   // It returns the actual number of characters.
543   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
544   utf32Characters.Resize( characterCount );
545
546   // Reset the cursor position
547   if( mImpl->mEventData )
548   {
549     mImpl->mEventData->mPrimaryCursorPosition = characterCount;
550     // TODO - handle secondary cursor
551   }
552
553   // The natural size needs to be re-calculated.
554   mImpl->mRecalculateNaturalSize = true;
555
556   // Apply modifications to the model
557   mImpl->mOperationsPending = ALL_OPERATIONS;
558   UpdateModel( ALL_OPERATIONS );
559   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
560                                                            ALIGN              |
561                                                            UPDATE_ACTUAL_SIZE |
562                                                            REORDER );
563 }
564
565 void Controller::InsertTextEvent( const std::string& text )
566 {
567   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertTextEvent" );
568
569   // TODO - Optimize this
570   mImpl->mLogicalModel->mScriptRuns.Clear();
571   mImpl->mLogicalModel->mFontRuns.Clear();
572   mImpl->mLogicalModel->mLineBreakInfo.Clear();
573   mImpl->mLogicalModel->mWordBreakInfo.Clear();
574   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
575   mImpl->mLogicalModel->mCharacterDirections.Clear();
576   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
577   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
578   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
579   mImpl->mVisualModel->mGlyphs.Clear();
580   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
581   mImpl->mVisualModel->mCharactersToGlyph.Clear();
582   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
583   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
584   mImpl->mVisualModel->mGlyphPositions.Clear();
585   mImpl->mVisualModel->mLines.Clear();
586   mImpl->mVisualModel->ClearCaches();
587
588   //  Convert text into UTF-32
589   Vector<Character> utf32Characters;
590   utf32Characters.Resize( text.size() );
591
592   // This is a bit horrible but std::string returns a (signed) char*
593   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
594
595   // Transform a text array encoded in utf8 into an array encoded in utf32.
596   // It returns the actual number of characters.
597   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
598   utf32Characters.Resize( characterCount );
599
600   // Insert at current cursor position
601   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
602   CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
603
604   if( cursorIndex < modifyText.Count() )
605   {
606     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
607   }
608   else
609   {
610     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
611   }
612
613   // Advance the cursor position
614   ++cursorIndex;
615
616   // The natural size needs to be re-calculated.
617   mImpl->mRecalculateNaturalSize = true;
618
619   // Apply modifications to the model; TODO - Optimize this
620   mImpl->mOperationsPending = ALL_OPERATIONS;
621   UpdateModel( ALL_OPERATIONS );
622   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
623                                                            ALIGN              |
624                                                            UPDATE_ACTUAL_SIZE |
625                                                            REORDER );
626
627   // Queue a cursor reposition event; this must wait until after DoRelayout()
628   mImpl->mEventData->mUpdateCursorPosition = true;
629   mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
630 }
631
632 void Controller::DeleteTextEvent()
633 {
634   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertTextEvent" );
635
636   // TODO - Optimize this
637   mImpl->mLogicalModel->mScriptRuns.Clear();
638   mImpl->mLogicalModel->mFontRuns.Clear();
639   mImpl->mLogicalModel->mLineBreakInfo.Clear();
640   mImpl->mLogicalModel->mWordBreakInfo.Clear();
641   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
642   mImpl->mLogicalModel->mCharacterDirections.Clear();
643   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
644   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
645   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
646   mImpl->mVisualModel->mGlyphs.Clear();
647   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
648   mImpl->mVisualModel->mCharactersToGlyph.Clear();
649   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
650   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
651   mImpl->mVisualModel->mGlyphPositions.Clear();
652   mImpl->mVisualModel->mLines.Clear();
653   mImpl->mVisualModel->ClearCaches();
654
655   // Delte at current cursor position
656   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
657   CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
658
659   if( cursorIndex > 0 &&
660       cursorIndex-1 < modifyText.Count() )
661   {
662     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
663
664     // Cursor position retreat
665     --cursorIndex;
666   }
667
668   // The natural size needs to be re-calculated.
669   mImpl->mRecalculateNaturalSize = true;
670
671   // Apply modifications to the model; TODO - Optimize this
672   mImpl->mOperationsPending = ALL_OPERATIONS;
673   UpdateModel( ALL_OPERATIONS );
674   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
675                                                            ALIGN              |
676                                                            UPDATE_ACTUAL_SIZE |
677                                                            REORDER );
678
679   // Queue a cursor reposition event; this must wait until after DoRelayout()
680   mImpl->mEventData->mUpdateCursorPosition = true;
681   mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
682 }
683
684 void Controller::UpdateModel( OperationsMask operationsRequired )
685 {
686   // Calculate the operations to be done.
687   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
688
689   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
690
691   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
692
693   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
694   if( GET_LINE_BREAKS & operations )
695   {
696     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
697     // calculate the bidirectional info for each 'paragraph'.
698     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
699     // is not shaped together).
700     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
701
702     SetLineBreakInfo( utf32Characters,
703                       lineBreakInfo );
704   }
705
706   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
707   if( GET_WORD_BREAKS & operations )
708   {
709     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
710     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
711
712     SetWordBreakInfo( utf32Characters,
713                       wordBreakInfo );
714   }
715
716   const bool getScripts = GET_SCRIPTS & operations;
717   const bool validateFonts = VALIDATE_FONTS & operations;
718
719   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
720   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
721
722   if( getScripts || validateFonts )
723   {
724     // Validates the fonts assigned by the application or assigns default ones.
725     // It makes sure all the characters are going to be rendered by the correct font.
726     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
727
728     if( getScripts )
729     {
730       // Retrieves the scripts used in the text.
731       multilanguageSupport.SetScripts( utf32Characters,
732                                        lineBreakInfo,
733                                        scripts );
734     }
735
736     if( validateFonts )
737     {
738       if( 0u == validFonts.Count() )
739       {
740         // Copy the requested font defaults received via the property system.
741         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
742         GetDefaultFonts( validFonts, numberOfCharacters );
743       }
744
745       // Validates the fonts. If there is a character with no assigned font it sets a default one.
746       // After this call, fonts are validated.
747       multilanguageSupport.ValidateFonts( utf32Characters,
748                                           scripts,
749                                           validFonts );
750     }
751   }
752
753   Vector<Character> mirroredUtf32Characters;
754   bool textMirrored = false;
755   if( BIDI_INFO & operations )
756   {
757     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
758     // bidirectional info.
759
760     Length numberOfParagraphs = 0u;
761
762     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
763     for( Length index = 0u; index < numberOfCharacters; ++index )
764     {
765       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
766       {
767         ++numberOfParagraphs;
768       }
769     }
770
771     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
772     bidirectionalInfo.Reserve( numberOfParagraphs );
773
774     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
775     SetBidirectionalInfo( utf32Characters,
776                           scripts,
777                           lineBreakInfo,
778                           bidirectionalInfo );
779
780     if( 0u != bidirectionalInfo.Count() )
781     {
782       // This paragraph has right to left text. Some characters may need to be mirrored.
783       // TODO: consider if the mirrored string can be stored as well.
784
785       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
786
787       // Only set the character directions if there is right to left characters.
788       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
789       directions.Resize( numberOfCharacters );
790
791       GetCharactersDirection( bidirectionalInfo,
792                               directions );
793     }
794     else
795     {
796       // There is no right to left characters. Clear the directions vector.
797       mImpl->mLogicalModel->mCharacterDirections.Clear();
798     }
799
800    }
801
802   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
803   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
804   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
805   if( SHAPE_TEXT & operations )
806   {
807     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
808     // Shapes the text.
809     ShapeText( textToShape,
810                lineBreakInfo,
811                scripts,
812                validFonts,
813                glyphs,
814                glyphsToCharactersMap,
815                charactersPerGlyph );
816
817     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
818     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
819     mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
820   }
821
822   const Length numberOfGlyphs = glyphs.Count();
823
824   if( GET_GLYPH_METRICS & operations )
825   {
826     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
827   }
828 }
829
830 bool Controller::DoRelayout( const Size& size,
831                              OperationsMask operationsRequired,
832                              Size& layoutSize )
833 {
834   bool viewUpdated( false );
835
836   // Calculate the operations to be done.
837   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
838
839   if( LAYOUT & operations )
840   {
841     // Some vectors with data needed to layout and reorder may be void
842     // after the first time the text has been laid out.
843     // Fill the vectors again.
844
845     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
846
847     if( 0u == numberOfGlyphs )
848     {
849       // Nothing else to do if there is no glyphs.
850       return true;
851     }
852
853     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
854     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
855     Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
856     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
857     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
858     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
859
860     // Set the layout parameters.
861     LayoutParameters layoutParameters( size,
862                                        mImpl->mLogicalModel->mText.Begin(),
863                                        lineBreakInfo.Begin(),
864                                        wordBreakInfo.Begin(),
865                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
866                                        numberOfGlyphs,
867                                        glyphs.Begin(),
868                                        glyphsToCharactersMap.Begin(),
869                                        charactersPerGlyph.Begin() );
870
871     // The laid-out lines.
872     // It's not possible to know in how many lines the text is going to be laid-out,
873     // but it can be resized at least with the number of 'paragraphs' to avoid
874     // some re-allocations.
875     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
876
877     // Delete any previous laid out lines before setting the new ones.
878     lines.Clear();
879
880     // The capacity of the bidirectional paragraph info is the number of paragraphs.
881     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
882
883     // Resize the vector of positions to have the same size than the vector of glyphs.
884     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
885     glyphPositions.Resize( numberOfGlyphs );
886
887     // Update the visual model.
888     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
889                                                    glyphPositions,
890                                                    lines,
891                                                    layoutSize );
892
893     if( viewUpdated )
894     {
895       // Reorder the lines
896       if( REORDER & operations )
897       {
898         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
899
900         // Check first if there are paragraphs with bidirectional info.
901         if( 0u != bidirectionalInfo.Count() )
902         {
903           // Get the lines
904           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
905
906           // Reorder the lines.
907           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
908           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
909           ReorderLines( bidirectionalInfo,
910                         lines,
911                         lineBidirectionalInfoRuns );
912
913           // Set the bidirectional info into the model.
914           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
915           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
916                                                        numberOfBidirectionalInfoRuns );
917
918           // Set the bidirectional info per line into the layout parameters.
919           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
920           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
921
922           // Get the character to glyph conversion table and set into the layout.
923           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
924
925           // Get the glyphs per character table and set into the layout.
926           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
927
928           // Re-layout the text. Reorder those lines with right to left characters.
929           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
930                                                          glyphPositions );
931
932           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
933           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
934                  endIt = lineBidirectionalInfoRuns.End();
935                it != endIt;
936                ++it )
937           {
938             BidirectionalLineInfoRun& bidiLineInfo = *it;
939
940             free( bidiLineInfo.visualToLogicalMap );
941           }
942         }
943       } // REORDER
944
945       if( ALIGN & operations )
946       {
947         mImpl->mLayoutEngine.Align( layoutParameters,
948                                     layoutSize,
949                                     lines,
950                                     glyphPositions );
951       }
952
953       // Sets the actual size.
954       if( UPDATE_ACTUAL_SIZE & operations )
955       {
956         mImpl->mVisualModel->SetActualSize( layoutSize );
957       }
958     } // view updated
959   }
960   else
961   {
962     layoutSize = mImpl->mVisualModel->GetActualSize();
963   }
964
965   return viewUpdated;
966 }
967
968 void Controller::CalculateTextAlignment( const Size& size )
969 {
970   // Get the direction of the first character.
971   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
972
973   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
974
975   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
976   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
977   if( firstParagraphDirection &&
978       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
979   {
980     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
981     {
982       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
983     }
984     else
985     {
986       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
987     }
988   }
989
990   switch( horizontalAlignment )
991   {
992     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
993     {
994       mImpl->mAlignmentOffset.x = 0.f;
995       break;
996     }
997     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
998     {
999       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1000       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1001       break;
1002     }
1003     case LayoutEngine::HORIZONTAL_ALIGN_END:
1004     {
1005       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1006       break;
1007     }
1008   }
1009
1010   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1011   switch( verticalAlignment )
1012   {
1013     case LayoutEngine::VERTICAL_ALIGN_TOP:
1014     {
1015       mImpl->mAlignmentOffset.y = 0.f;
1016       break;
1017     }
1018     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1019     {
1020       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1021       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1022       break;
1023     }
1024     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1025     {
1026       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1027       break;
1028     }
1029   }
1030 }
1031
1032 LayoutEngine& Controller::GetLayoutEngine()
1033 {
1034   return mImpl->mLayoutEngine;
1035 }
1036
1037 View& Controller::GetView()
1038 {
1039   return mImpl->mView;
1040 }
1041
1042 void Controller::KeyboardFocusGainEvent()
1043 {
1044   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1045
1046   if( mImpl->mEventData )
1047   {
1048     Event event( Event::KEYBOARD_FOCUS_GAIN_EVENT );
1049     mImpl->mEventData->mEventQueue.push_back( event );
1050
1051     mImpl->RequestRelayout();
1052   }
1053 }
1054
1055 void Controller::KeyboardFocusLostEvent()
1056 {
1057   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1058
1059   if( mImpl->mEventData )
1060   {
1061     Event event( Event::KEYBOARD_FOCUS_LOST_EVENT );
1062     mImpl->mEventData->mEventQueue.push_back( event );
1063
1064     mImpl->RequestRelayout();
1065   }
1066 }
1067
1068 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1069 {
1070   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1071
1072   if( mImpl->mEventData &&
1073       keyEvent.state == KeyEvent::Down )
1074   {
1075     int keyCode = keyEvent.keyCode;
1076     const std::string& keyString = keyEvent.keyPressed;
1077
1078     // Pre-process to separate modifying events from non-modifying input events.
1079     if( Dali::DALI_KEY_ESCAPE == keyCode )
1080     {
1081       // Escape key is a special case which causes focus loss
1082       KeyboardFocusLostEvent();
1083     }
1084     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1085              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1086              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1087              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1088     {
1089       Event event( Event::CURSOR_KEY_EVENT );
1090       event.p1.mInt = keyCode;
1091       mImpl->mEventData->mEventQueue.push_back( event );
1092     }
1093     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1094     {
1095       // Queue a delete event
1096       ModifyEvent event;
1097       event.type = ModifyEvent::DELETE_TEXT;
1098       mImpl->mModifyEvents.push_back( event );
1099     }
1100     else if( !keyString.empty() )
1101     {
1102       // Queue an insert event
1103       ModifyEvent event;
1104       event.type = ModifyEvent::INSERT_TEXT;
1105       event.text = keyString;
1106       mImpl->mModifyEvents.push_back( event );
1107     }
1108
1109     mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
1110
1111     mImpl->RequestRelayout();
1112   }
1113
1114   return false;
1115 }
1116
1117 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1118 {
1119   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1120
1121   if( mImpl->mEventData )
1122   {
1123     Event event( Event::TAP_EVENT );
1124     event.p1.mUint = tapCount;
1125     event.p2.mFloat = x;
1126     event.p3.mFloat = y;
1127     mImpl->mEventData->mEventQueue.push_back( event );
1128
1129     mImpl->RequestRelayout();
1130   }
1131 }
1132
1133 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1134 {
1135   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1136
1137   if( mImpl->mEventData )
1138   {
1139     Event event( Event::PAN_EVENT );
1140     event.p1.mInt = state;
1141     event.p2.mFloat = displacement.x;
1142     event.p3.mFloat = displacement.y;
1143     mImpl->mEventData->mEventQueue.push_back( event );
1144
1145     mImpl->RequestRelayout();
1146   }
1147 }
1148
1149 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1150 {
1151   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected GrabHandleEvent" );
1152
1153   if( mImpl->mEventData )
1154   {
1155     Event event( Event::GRAB_HANDLE_EVENT );
1156     event.p1.mUint  = state;
1157     event.p2.mFloat = x;
1158     event.p3.mFloat = y;
1159     
1160     mImpl->mEventData->mEventQueue.push_back( event );
1161
1162     mImpl->RequestRelayout();
1163   }
1164 }
1165
1166 Controller::~Controller()
1167 {
1168   delete mImpl;
1169 }
1170
1171 Controller::Controller( ControlInterface& controlInterface )
1172 : mImpl( NULL )
1173 {
1174   mImpl = new Controller::Impl( controlInterface );
1175 }
1176
1177 } // namespace Text
1178
1179 } // namespace Toolkit
1180
1181 } // namespace Dali