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/public-api/text/text-controller.h>
22 #include <dali-toolkit/public-api/text/character-set-conversion.h>
23 #include <dali-toolkit/public-api/text/layouts/layout-engine.h>
24 #include <dali-toolkit/public-api/text/logical-model.h>
25 #include <dali-toolkit/public-api/text/multi-language-support.h>
26 #include <dali-toolkit/public-api/text/script-run.h>
27 #include <dali-toolkit/public-api/text/segmentation.h>
28 #include <dali-toolkit/public-api/text/shaper.h>
29 #include <dali-toolkit/public-api/text/text-view.h>
30 #include <dali-toolkit/public-api/text/visual-model.h>
33 #include <dali/public-api/text-abstraction/font-client.h>
45 struct Controller::TextInput
47 // Used to queue input events until DoRelayout()
50 KEYBOARD_FOCUS_GAIN_EVENT,
51 KEYBOARD_FOCUS_LOST_EVENT,
64 Event( EventType eventType )
76 TextInput( DecoratorPtr decorator )
77 : mDecorator( decorator )
81 DecoratorPtr mDecorator;
83 std::vector<Event> mEventQueue;
86 struct Controller::Impl
88 Impl( ControlInterface& controlInterface )
89 : mControlInterface( controlInterface ),
91 mOperations( NO_OPERATION ),
95 mLogicalModel = LogicalModel::New();
96 mVisualModel = VisualModel::New();
98 mView.SetVisualModel( mVisualModel );
100 mFontClient = TextAbstraction::FontClient::Get();
108 ControlInterface& mControlInterface;
110 std::string mNewText;
112 LogicalModelPtr mLogicalModel;
113 VisualModelPtr mVisualModel;
117 LayoutEngine mLayoutEngine;
119 TextAbstraction::FontClient mFontClient;
121 OperationsMask mOperations;
125 // Avoid allocating everything for text input until EnableTextInput()
126 Controller::TextInput* mTextInput;
129 ControllerPtr Controller::New( ControlInterface& controlInterface )
131 return ControllerPtr( new Controller( controlInterface ) );
134 void Controller::SetText( const std::string& text )
136 // Keep until size negotiation
137 mImpl->mNewText = text;
138 mImpl->mOperations = ALL_OPERATIONS;
140 if( mImpl->mTextInput )
142 // Cancel previously queued events
143 mImpl->mTextInput->mEventQueue.clear();
145 // TODO - Hide selection decorations
149 void Controller::EnableTextInput( DecoratorPtr decorator )
151 if( !mImpl->mTextInput )
153 mImpl->mTextInput = new TextInput( decorator );
157 bool Controller::Relayout( const Vector2& size )
159 if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
161 // Not worth to relayout if width or height is equal to zero.
165 bool viewUpdated = false;
167 if( size != mImpl->mControlSize )
169 viewUpdated = DoRelayout( size, mImpl->mOperations );
171 // Do not re-do any operation until something changes.
172 mImpl->mOperations = NO_OPERATION;
174 mImpl->mControlSize = size;
180 bool Controller::DoRelayout( const Vector2& size, OperationsMask operations )
182 bool viewUpdated( false );
184 Vector<Character> utf32Characters;
185 Length characterCount = 0u;
186 if( CONVERT_TO_UTF32 & operations )
188 std::string& text = mImpl->mNewText;
190 // Convert text into UTF-32
191 utf32Characters.Resize( text.size() );
193 // This is a bit horrible but std::string returns a (signed) char*
194 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
196 // Transform a text array encoded in utf8 into an array encoded in utf32.
197 // It returns the actual number of characters.
198 characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
199 utf32Characters.Resize( characterCount );
201 // Sets the text into the model.
202 mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount );
204 // Discard temporary text
208 Vector<LineBreakInfo> lineBreakInfo;
209 if( GET_LINE_BREAKS & operations )
211 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
212 // calculate the bidirectional info for each 'paragraph'.
213 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
214 // is not shaped together).
215 lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK );
217 SetLineBreakInfo( utf32Characters,
220 mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount );
223 const bool getScripts = GET_SCRIPTS & operations;
224 const bool validateFonts = VALIDATE_FONTS & operations;
226 Vector<ScriptRun> scripts;
227 Vector<FontRun> fonts;
228 if( getScripts || validateFonts )
230 // Validates the fonts assigned by the application or assigns default ones.
231 // It makes sure all the characters are going to be rendered by the correct font.
232 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
236 // Retrieves the scripts used in the text.
237 multilanguageSupport.SetScripts( utf32Characters,
241 // Sets the scripts into the model.
242 mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() );
247 // Validates the fonts. If there is a character with no assigned font it sets a default one.
248 // After this call, fonts are validated.
249 multilanguageSupport.ValidateFonts( utf32Characters,
253 // Sets the fonts into the model.
254 mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() );
258 Vector<GlyphInfo> glyphs;
259 Vector<CharacterIndex> characterIndices;
260 Vector<Length> charactersPerGlyph;
261 if( SHAPE_TEXT & operations )
264 ShapeText( utf32Characters,
270 charactersPerGlyph );
273 if( GET_GLYPH_METRICS & operations )
275 TextAbstraction::FontClient::Get().GetGlyphMetrics( glyphs.Begin(), glyphs.Count() );
278 if( LAYOUT & operations )
280 if( 0u == glyphs.Count() )
282 const Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
284 glyphs.Resize( numberOfGlyphs );
285 characterIndices.Resize( numberOfGlyphs );
286 charactersPerGlyph.Resize( numberOfGlyphs );
288 mImpl->mVisualModel->GetGlyphs( glyphs.Begin(),
292 mImpl->mVisualModel->GetGlyphToCharacterMap( characterIndices.Begin(),
296 mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(),
301 // Update the visual model
302 mImpl->mLayoutEngine.UpdateVisualModel( size,
306 *mImpl->mVisualModel );
311 // TODO - process input events to move grab handle
316 Vector3 Controller::GetNaturalSize()
318 // Operations that can be done only once until the text changes.
319 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
327 // Operations that need to be done if the size or the text changes.
328 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
331 const float maxFloat = std::numeric_limits<float>::max();
332 DoRelayout( Vector2( maxFloat, maxFloat ),
333 static_cast<OperationsMask>( onlyOnceOperations |
336 // Do not do again the only once operations.
337 mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
339 // Do the size related operations again.
340 mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
342 return Vector3( mImpl->mVisualModel->GetNaturalSize() );
345 float Controller::GetHeightForWidth( float width )
347 // Operations that can be done only once until the text changes.
348 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
356 // Operations that need to be done if the size or the text changes.
357 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
360 DoRelayout( Size( width, 0.f ),
361 static_cast<OperationsMask>( onlyOnceOperations |
364 // Do not do again the only once operations.
365 mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations & ~onlyOnceOperations );
367 // Do the size related operations again.
368 mImpl->mOperations = static_cast<OperationsMask>( mImpl->mOperations | sizeOperations );
370 return mImpl->mVisualModel->GetActualSize().height;
373 View& Controller::GetView()
378 LayoutEngine& Controller::GetLayoutEngine()
380 return mImpl->mLayoutEngine;
383 void Controller::RequestRelayout()
385 mImpl->mControlInterface.RequestTextRelayout();
388 void Controller::KeyboardFocusGainEvent()
390 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
392 if( mImpl->mTextInput )
394 TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
395 mImpl->mTextInput->mEventQueue.push_back( event );
401 void Controller::KeyboardFocusLostEvent()
403 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
405 if( mImpl->mTextInput )
407 TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
408 mImpl->mTextInput->mEventQueue.push_back( event );
414 void Controller::TapEvent( float x, float y)
416 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
418 if( mImpl->mTextInput )
420 TextInput::Event event( TextInput::TAP_EVENT );
428 void Controller::GrabHandleEvent( GrabHandleState state, float x )
430 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
432 if( mImpl->mTextInput )
434 TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
435 event.p1.mInt = state;
442 Controller::~Controller()
447 Controller::Controller( ControlInterface& controlInterface )
450 mImpl = new Controller::Impl( controlInterface );
455 } // namespace Toolkit