2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/text/text-controller.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/script-run.h>
35 #include <dali-toolkit/internal/text/segmentation.h>
36 #include <dali-toolkit/internal/text/shaper.h>
37 #include <dali-toolkit/internal/text/text-view.h>
38 #include <dali-toolkit/internal/text/visual-model.h>
44 const float MAX_FLOAT = std::numeric_limits<float>::max();
45 const std::string EMPTY_STRING;
57 struct Controller::TextInput
59 // Used to queue input events until DoRelayout()
62 KEYBOARD_FOCUS_GAIN_EVENT,
63 KEYBOARD_FOCUS_LOST_EVENT,
79 Event( EventType eventType )
99 TextInput( LogicalModelPtr logicalModel,
100 VisualModelPtr visualModel,
101 DecoratorPtr decorator )
102 : mLogicalModel( logicalModel ),
103 mVisualModel( visualModel ),
104 mDecorator( decorator ),
110 * @brief Helper to move the cursor, grab handle etc.
112 bool ProcessInputEvents()
114 mDecoratorUpdated = false;
118 for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
122 case KEYBOARD_FOCUS_GAIN_EVENT:
124 OnKeyboardFocus( true );
127 case KEYBOARD_FOCUS_LOST_EVENT:
129 OnKeyboardFocus( false );
142 case GRAB_HANDLE_EVENT:
144 OnGrabHandleEvent( *iter );
153 return mDecoratorUpdated;
156 void OnKeyboardFocus( bool hasFocus )
160 void OnKeyEvent( const Event& event )
162 int keyCode = event.p1.mInt;
164 // Handle state changes
165 if( Dali::DALI_KEY_ESCAPE == keyCode )
167 ChangeState( INACTIVE ); // Escape key ends edit mode
169 else if ( event.p2.mString )
171 // Some text may be selected, hiding keyboard causes an empty keystring to be sent, we don't want to delete highlight in this case
172 ChangeState( EDITING );
175 // Handle the actual key event
176 if( Dali::DALI_KEY_BACKSPACE == keyCode )
178 HandleBackspaceKey();
180 else if( Dali::DALI_KEY_CURSOR_LEFT == keyCode ||
181 Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
182 Dali::DALI_KEY_CURSOR_UP == keyCode ||
183 Dali::DALI_KEY_CURSOR_DOWN == keyCode )
185 HandleCursorKey( keyCode );
187 else if ( event.p2.mString )
189 HandleKeyString( event.p2.mString );
191 delete [] event.p2.mString;
195 void HandleBackspaceKey()
200 void HandleCursorKey( int keyCode )
205 void HandleKeyString( const char* keyString )
210 void OnTapEvent( const Event& event )
212 unsigned int tapCount = event.p1.mUint;
216 ChangeState( EDITING );
218 float xPosition = event.p2.mFloat;
219 float yPosition = event.p3.mFloat;
221 GetClosestCursorPosition( xPosition, yPosition, height );
222 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
224 mDecoratorUpdated = true;
226 else if( 2u == tapCount )
228 ChangeState( SELECTING );
232 void OnGrabHandleEvent( const Event& event )
234 unsigned int state = event.p1.mUint;
236 if( GRAB_HANDLE_PRESSED == state )
238 float xPosition = event.p2.mFloat;
239 float yPosition = event.p3.mFloat;
242 GetClosestCursorPosition( xPosition, yPosition, height );
244 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
245 mDecorator->HidePopup();
246 mDecoratorUpdated = true;
248 else if ( GRAB_HANDLE_RELEASED == state )
250 mDecorator->ShowPopup();
255 void ChangeState( State newState )
257 if( mState != newState )
261 if( INACTIVE == mState )
263 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
264 mDecorator->StopCursorBlink();
265 mDecorator->SetGrabHandleActive( false );
266 mDecorator->SetSelectionActive( false );
267 mDecorator->HidePopup();
268 mDecoratorUpdated = true;
270 else if ( SELECTING == mState )
272 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
273 mDecorator->StopCursorBlink();
274 mDecorator->SetGrabHandleActive( false );
275 mDecorator->SetSelectionActive( true );
276 mDecoratorUpdated = true;
278 else if( EDITING == mState )
280 mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
281 mDecorator->StartCursorBlink();
282 mDecorator->SetGrabHandleActive( true );
283 mDecorator->SetSelectionActive( false );
284 mDecoratorUpdated = true;
289 void GetClosestCursorPosition( float& x, float& y, float& height )
291 // TODO - Look at LineRuns first
293 Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
294 if( 0 == numberOfGlyphs )
299 Vector<GlyphInfo> glyphs;
300 glyphs.Resize( numberOfGlyphs );
301 mVisualModel->GetGlyphs( glyphs.Begin(), 0, numberOfGlyphs );
302 const GlyphInfo* const glyphsBuffer = glyphs.Begin();
304 Vector<Vector2> positions;
305 positions.Resize( numberOfGlyphs );
306 mVisualModel->GetGlyphPositions( positions.Begin(), 0, numberOfGlyphs );
307 const Vector2* const positionsBuffer = positions.Begin();
309 unsigned int closestGlyph = 0;
310 float closestDistance = MAX_FLOAT;
312 for( unsigned int i = 0, numberOfGLyphs = glyphs.Count(); i < numberOfGLyphs; ++i )
314 const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
315 const Vector2& position = *( positionsBuffer + i );
316 float glyphX = position.x + glyphInfo.width*0.5f;
317 float glyphY = position.y + glyphInfo.height*0.5f;
319 float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
321 if( distanceToGlyph < closestDistance )
323 closestDistance = distanceToGlyph;
328 // TODO - Consider RTL languages
329 x = positions[closestGlyph].x + glyphs[closestGlyph].width;
333 TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
334 height = metrics.height; // TODO - Fix for multi-line
337 LogicalModelPtr mLogicalModel;
338 VisualModelPtr mVisualModel;
339 DecoratorPtr mDecorator;
341 std::string mPlaceholderText;
344 * This is used to delay handling events until after the model has been updated.
345 * The number of updates to the model is minimized to improve performance.
347 vector<Event> mEventQueue; ///< The queue of touch events etc.
351 bool mDecoratorUpdated;
354 struct Controller::FontDefaults
357 : mDefaultPointSize(0.0f),
362 FontId GetFontId( TextAbstraction::FontClient& fontClient )
366 Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
367 mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
373 std::string mDefaultFontFamily;
374 std::string mDefaultFontStyle;
375 float mDefaultPointSize;
379 struct Controller::Impl
381 Impl( ControlInterface& controlInterface )
382 : mControlInterface( controlInterface ),
385 mFontDefaults( NULL ),
392 mOperationsPending( NO_OPERATION ),
393 mRecalculateNaturalSize( true )
395 mLogicalModel = LogicalModel::New();
396 mVisualModel = VisualModel::New();
398 mFontClient = TextAbstraction::FontClient::Get();
400 mView.SetVisualModel( mVisualModel );
408 ControlInterface& mControlInterface; ///< Reference to the text controller.
409 LogicalModelPtr mLogicalModel; ///< Pointer to the logical model.
410 VisualModelPtr mVisualModel; ///< Pointer to the visual model.
411 FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
412 Controller::TextInput* mTextInput; ///< Avoid allocating everything for text input until EnableTextInput().
413 TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
414 View mView; ///< The view interface to the rendering back-end.
415 LayoutEngine mLayoutEngine; ///< The layout engine.
416 std::string mNewText; ///< Temporary stores the text set until the next relayout.
417 Size mControlSize; ///< The size of the control.
418 OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
419 bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated.
422 ControllerPtr Controller::New( ControlInterface& controlInterface )
424 return ControllerPtr( new Controller( controlInterface ) );
427 void Controller::SetText( const std::string& text )
429 // Keep until size negotiation
430 mImpl->mNewText = text;
432 // All operations need to be done. (convert to utf32, get break info, ..., layout, ...)
433 mImpl->mOperationsPending = ALL_OPERATIONS;
435 // The natural size needs to be re-calculated.
436 mImpl->mRecalculateNaturalSize = true;
439 mImpl->mLogicalModel->SetText( NULL, 0u );
440 mImpl->mLogicalModel->SetScripts( NULL, 0u );
441 mImpl->mLogicalModel->SetFonts( NULL, 0u );
442 mImpl->mLogicalModel->SetLineBreakInfo( NULL, 0u );
443 mImpl->mLogicalModel->SetWordBreakInfo( NULL, 0u );
444 mImpl->mLogicalModel->SetBidirectionalInfo( NULL, 0u );
445 mImpl->mLogicalModel->SetVisualToLogicalMap( NULL, 0u );
446 mImpl->mVisualModel->SetGlyphs( NULL, NULL, NULL, 0u );
447 mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
448 mImpl->mVisualModel->SetLines( NULL, 0u );
450 if( mImpl->mTextInput )
452 // Cancel previously queued events
453 mImpl->mTextInput->mEventQueue.clear();
455 // TODO - Hide selection decorations
459 void Controller::GetText( std::string& text ) const
461 if( !mImpl->mNewText.empty() )
463 text = mImpl->mNewText;
467 // TODO - Convert from UTF-32
471 void Controller::SetPlaceholderText( const std::string& text )
473 if( !mImpl->mTextInput )
475 mImpl->mTextInput->mPlaceholderText = text;
479 void Controller::GetPlaceholderText( std::string& text ) const
481 if( !mImpl->mTextInput )
483 text = mImpl->mTextInput->mPlaceholderText;
487 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
489 if( !mImpl->mFontDefaults )
491 mImpl->mFontDefaults = new Controller::FontDefaults();
494 mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
495 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
496 mImpl->mOperationsPending = ALL_OPERATIONS;
497 mImpl->mRecalculateNaturalSize = true;
500 const std::string& Controller::GetDefaultFontFamily() const
502 if( mImpl->mFontDefaults )
504 return mImpl->mFontDefaults->mDefaultFontFamily;
510 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
512 if( !mImpl->mFontDefaults )
514 mImpl->mFontDefaults = new Controller::FontDefaults();
517 mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
518 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
519 mImpl->mOperationsPending = ALL_OPERATIONS;
520 mImpl->mRecalculateNaturalSize = true;
523 const std::string& Controller::GetDefaultFontStyle() const
525 if( mImpl->mFontDefaults )
527 return mImpl->mFontDefaults->mDefaultFontStyle;
533 void Controller::SetDefaultPointSize( float pointSize )
535 if( !mImpl->mFontDefaults )
537 mImpl->mFontDefaults = new Controller::FontDefaults();
540 mImpl->mFontDefaults->mDefaultPointSize = pointSize;
541 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
542 mImpl->mOperationsPending = ALL_OPERATIONS;
543 mImpl->mRecalculateNaturalSize = true;
546 float Controller::GetDefaultPointSize() const
548 if( mImpl->mFontDefaults )
550 return mImpl->mFontDefaults->mDefaultPointSize;
556 void Controller::EnableTextInput( DecoratorPtr decorator )
558 if( !mImpl->mTextInput )
560 mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
564 bool Controller::Relayout( const Vector2& size )
566 if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
568 // Not worth to relayout if width or height is equal to zero.
572 if( size != mImpl->mControlSize )
574 // Operations that need to be done if the size changes.
575 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
582 mImpl->mControlSize = size;
586 bool updated = DoRelayout( mImpl->mControlSize,
587 mImpl->mOperationsPending,
590 // Do not re-do any operation until something changes.
591 mImpl->mOperationsPending = NO_OPERATION;
593 if( mImpl->mTextInput )
595 // Move the cursor, grab handle etc.
596 updated = mImpl->mTextInput->ProcessInputEvents() || updated;
602 bool Controller::DoRelayout( const Vector2& size,
603 OperationsMask operationsRequired,
606 bool viewUpdated( false );
608 // Calculate the operations to be done.
609 const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
611 Vector<Character> utf32Characters;
612 Length characterCount = 0u;
613 if( CONVERT_TO_UTF32 & operations )
615 std::string& text = mImpl->mNewText;
617 // Convert text into UTF-32
618 utf32Characters.Resize( text.size() );
620 // This is a bit horrible but std::string returns a (signed) char*
621 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
623 // Transform a text array encoded in utf8 into an array encoded in utf32.
624 // It returns the actual number of characters.
625 characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
626 utf32Characters.Resize( characterCount );
628 // Sets the text into the model.
629 mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
631 // Discard temporary text
635 Vector<LineBreakInfo> lineBreakInfo;
636 if( GET_LINE_BREAKS & operations )
638 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
639 // calculate the bidirectional info for each 'paragraph'.
640 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
641 // is not shaped together).
642 lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
644 SetLineBreakInfo( utf32Characters,
647 mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
650 Vector<WordBreakInfo> wordBreakInfo;
651 if( GET_WORD_BREAKS & operations )
653 // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
654 wordBreakInfo.Resize( characterCount, TextAbstraction::WORD_NO_BREAK );
656 SetWordBreakInfo( utf32Characters,
659 mImpl->mLogicalModel->SetWordBreakInfo( wordBreakInfo.Begin(), characterCount );
662 const bool getScripts = GET_SCRIPTS & operations;
663 const bool validateFonts = VALIDATE_FONTS & operations;
665 Vector<ScriptRun> scripts;
666 Vector<FontRun> fonts;
668 if( mImpl->mFontDefaults )
670 // TODO - pass into ValidateFonts
673 if( getScripts || validateFonts )
675 // Validates the fonts assigned by the application or assigns default ones.
676 // It makes sure all the characters are going to be rendered by the correct font.
677 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
681 // Retrieves the scripts used in the text.
682 multilanguageSupport.SetScripts( utf32Characters,
686 // Sets the scripts into the model.
687 mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
692 // Validates the fonts. If there is a character with no assigned font it sets a default one.
693 // After this call, fonts are validated.
694 multilanguageSupport.ValidateFonts( utf32Characters,
698 // Sets the fonts into the model.
699 mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() );
703 Vector<BidirectionalParagraphInfoRun> bidirectionalInfo;
704 if( BIDI_INFO & operations )
706 // Some vectors with data needed to get the paragraph's bidirectional info may be void
707 // after the first time the text has been laid out.
708 // Fill the vectors again.
710 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
712 if( 0u == utf32Characters.Count() )
714 utf32Characters.Resize( numberOfCharacters );
716 mImpl->mLogicalModel->GetText( utf32Characters.Begin(),
718 numberOfCharacters );
721 if( 0u == lineBreakInfo.Count() )
723 lineBreakInfo.Resize( numberOfCharacters );
725 mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
727 numberOfCharacters );
730 if( 0u == scripts.Count() )
732 scripts.Resize( mImpl->mLogicalModel->GetNumberOfScriptRuns( 0u,
733 numberOfCharacters ) );
734 mImpl->mLogicalModel->GetScriptRuns( scripts.Begin(),
736 numberOfCharacters );
739 // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
740 // bidirectional info.
742 Length numberOfParagraphs = 0u;
744 const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
745 for( Length index = 0u; index < characterCount; ++index )
747 if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
749 ++numberOfParagraphs;
753 bidirectionalInfo.Reserve( numberOfParagraphs );
755 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
756 SetBidirectionalInfo( utf32Characters,
761 mImpl->mLogicalModel->SetBidirectionalInfo( bidirectionalInfo.Begin(),
762 bidirectionalInfo.Count() );
765 Vector<GlyphInfo> glyphs;
766 Vector<CharacterIndex> glyphsToCharactersMap;
767 Vector<Length> charactersPerGlyph;
768 if( SHAPE_TEXT & operations )
771 ShapeText( utf32Characters,
776 glyphsToCharactersMap,
777 charactersPerGlyph );
780 if( GET_GLYPH_METRICS & operations )
782 mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
785 Length numberOfGlyphs = glyphs.Count();
786 if( 0u != numberOfGlyphs )
788 // Sets the glyphs into the model.
789 mImpl->mVisualModel->SetGlyphs( glyphs.Begin(),
790 glyphsToCharactersMap.Begin(),
791 charactersPerGlyph.Begin(),
795 if( LAYOUT & operations )
797 // Some vectors with data needed to layout and reorder may be void
798 // after the first time the text has been laid out.
799 // Fill the vectors again.
801 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
802 numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
804 if( 0u == lineBreakInfo.Count() )
806 lineBreakInfo.Resize( numberOfCharacters );
807 mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(),
809 numberOfCharacters );
812 if( 0u == wordBreakInfo.Count() )
814 wordBreakInfo.Resize( numberOfCharacters );
815 mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(),
817 numberOfCharacters );
820 if( 0u == glyphs.Count() )
822 glyphs.Resize( numberOfGlyphs );
823 mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
828 if( 0u == glyphsToCharactersMap.Count() )
830 glyphsToCharactersMap.Resize( numberOfGlyphs );
831 mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(),
836 if( 0u == charactersPerGlyph.Count() )
838 charactersPerGlyph.Resize( numberOfGlyphs );
839 mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
844 // Set the layout parameters.
845 LayoutParameters layoutParameters( size,
846 lineBreakInfo.Begin(),
847 wordBreakInfo.Begin(),
850 glyphsToCharactersMap.Begin(),
851 charactersPerGlyph.Begin() );
853 // Reserve space to set the positions of the glyphs.
854 Vector<Vector2> glyphPositions;
855 glyphPositions.Resize( numberOfGlyphs );
857 // The laid-out lines.
858 // It's not possible to know in how many lines the text is going to be laid-out,
859 // but it can be resized at least with the number of 'paragraphs' to avoid
860 // some re-allocations.
861 Vector<LineRun> lines;
862 lines.Reserve( mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters ) );
864 // Update the visual model.
865 viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
873 if( REORDER & operations )
875 const Length numberOfBidiParagraphs = mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters );
877 if( 0u == bidirectionalInfo.Count() )
879 bidirectionalInfo.Resize( numberOfBidiParagraphs );
880 mImpl->mLogicalModel->GetBidirectionalInfo( bidirectionalInfo.Begin(),
882 numberOfCharacters );
885 // Check first if there are paragraphs with bidirectional info.
886 if( 0u != bidirectionalInfo.Count() )
889 const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
891 // Reorder the lines.
892 Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
893 lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
894 ReorderLines( bidirectionalInfo,
896 lineBidirectionalInfoRuns );
898 // Set the bidirectional info into the model.
899 const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
900 mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
901 numberOfBidirectionalInfoRuns );
903 // Set the bidirectional info per line into the layout parameters.
904 layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
905 layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
907 // Get the character to glyph conversion table and set into the layout.
908 Vector<GlyphIndex> characterToGlyphMap;
909 characterToGlyphMap.Resize( numberOfCharacters );
911 layoutParameters.charactersToGlyphsBuffer = characterToGlyphMap.Begin();
912 mImpl->mVisualModel->GetCharacterToGlyphMap( layoutParameters.charactersToGlyphsBuffer,
914 numberOfCharacters );
916 // Get the glyphs per character table and set into the layout.
917 Vector<Length> glyphsPerCharacter;
918 glyphsPerCharacter.Resize( numberOfCharacters );
920 layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
921 mImpl->mVisualModel->GetGlyphsPerCharacterMap( layoutParameters.glyphsPerCharacterBuffer,
923 numberOfCharacters );
925 // Re-layout the text. Reorder those lines with right to left characters.
926 mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
929 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
930 for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
931 endIt = lineBidirectionalInfoRuns.End();
935 BidirectionalLineInfoRun& bidiLineInfo = *it;
937 free( bidiLineInfo.visualToLogicalMap );
942 // Sets the positions into the model.
943 if( UPDATE_POSITIONS & operations )
945 mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(),
949 // Sets the lines into the model.
950 if( UPDATE_LINES & operations )
952 mImpl->mVisualModel->SetLines( lines.Begin(),
956 // Sets the actual size.
957 if( UPDATE_ACTUAL_SIZE & operations )
959 mImpl->mVisualModel->SetActualSize( layoutSize );
965 layoutSize = mImpl->mVisualModel->GetActualSize();
971 Vector3 Controller::GetNaturalSize()
975 if( mImpl->mRecalculateNaturalSize )
977 // Operations that can be done only once until the text changes.
978 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
986 // Operations that need to be done if the size changes.
987 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
990 DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
991 static_cast<OperationsMask>( onlyOnceOperations |
993 naturalSize.GetVectorXY() );
995 // Do not do again the only once operations.
996 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
998 // Do the size related operations again.
999 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1001 // Stores the natural size to avoid recalculate it again
1002 // unless the text/style changes.
1003 mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1005 mImpl->mRecalculateNaturalSize = false;
1009 naturalSize = mImpl->mVisualModel->GetNaturalSize();
1015 float Controller::GetHeightForWidth( float width )
1018 if( width != mImpl->mControlSize.width )
1020 // Operations that can be done only once until the text changes.
1021 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1027 GET_GLYPH_METRICS );
1029 // Operations that need to be done if the size changes.
1030 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
1033 DoRelayout( Size( width, MAX_FLOAT ),
1034 static_cast<OperationsMask>( onlyOnceOperations |
1038 // Do not do again the only once operations.
1039 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1041 // Do the size related operations again.
1042 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1046 layoutSize = mImpl->mVisualModel->GetActualSize();
1049 return layoutSize.height;
1052 View& Controller::GetView()
1054 return mImpl->mView;
1057 LayoutEngine& Controller::GetLayoutEngine()
1059 return mImpl->mLayoutEngine;
1062 void Controller::RequestRelayout()
1064 mImpl->mControlInterface.RequestTextRelayout();
1067 void Controller::KeyboardFocusGainEvent()
1069 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1071 if( mImpl->mTextInput )
1073 TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1074 mImpl->mTextInput->mEventQueue.push_back( event );
1080 void Controller::KeyboardFocusLostEvent()
1082 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1084 if( mImpl->mTextInput )
1086 TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1087 mImpl->mTextInput->mEventQueue.push_back( event );
1093 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1095 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1097 if( mImpl->mTextInput )
1099 TextInput::Event event( TextInput::KEY_EVENT );
1100 event.p1.mInt = keyEvent.keyCode;
1101 event.p2.mString = NULL;
1103 const std::string& keyString = keyEvent.keyPressed;
1104 if ( !keyString.empty() )
1106 event.p2.mString = new char[keyString.size() + 1];
1107 std::copy(keyString.begin(), keyString.end(), event.p2.mString);
1108 event.p2.mString[keyString.size()] = '\0';
1111 mImpl->mTextInput->mEventQueue.push_back( event );
1119 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1121 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1123 if( mImpl->mTextInput )
1125 TextInput::Event event( TextInput::TAP_EVENT );
1126 event.p1.mUint = tapCount;
1127 event.p2.mFloat = x;
1128 event.p3.mFloat = y;
1129 mImpl->mTextInput->mEventQueue.push_back( event );
1135 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1137 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1139 if( mImpl->mTextInput )
1141 TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1142 event.p1.mUint = state;
1143 event.p2.mFloat = x;
1144 event.p3.mFloat = y;
1145 mImpl->mTextInput->mEventQueue.push_back( event );
1151 Controller::~Controller()
1156 Controller::Controller( ControlInterface& controlInterface )
1159 mImpl = new Controller::Impl( controlInterface );
1164 } // namespace Toolkit